]> git.proxmox.com Git - proxmox-backup.git/blobdiff - src/bin/proxmox_backup_client/catalog.rs
move some API return types to pbs-api-types
[proxmox-backup.git] / src / bin / proxmox_backup_client / catalog.rs
index 595b5bab08bf0e6297a85f75fad51a7436b0e0af..adb8fcdc36f5eb24baa68b9d9072c770b4d6fd0e 100644 (file)
@@ -1,6 +1,5 @@
 use std::os::unix::fs::OpenOptionsExt;
 use std::io::{Seek, SeekFrom};
-use std::path::PathBuf;
 use std::sync::Arc;
 
 use anyhow::{bail, format_err, Error};
@@ -8,21 +7,24 @@ use serde_json::Value;
 
 use proxmox::api::{api, cli::*};
 
-use proxmox_backup::tools;
-
-use proxmox_backup::client::*;
+use pbs_client::tools::key_source::get_encryption_key_password;
+use pbs_client::{BackupReader, RemoteChunkReader};
+use pbs_tools::json::required_string_param;
 
 use crate::{
     REPO_URL_SCHEMA,
+    KEYFD_SCHEMA,
     extract_repository_from_value,
+    format_key_source,
     record_repository,
-    load_and_decrypt_key,
+    decrypt_key,
     api_datastore_latest_snapshot,
     complete_repository,
     complete_backup_snapshot,
     complete_group_or_snapshot,
     complete_pxar_archive_name,
     connect,
+    crypto_parameters,
     BackupDir,
     BackupGroup,
     BufferedDynamicReader,
@@ -35,8 +37,6 @@ use crate::{
     Shell,
 };
 
-use crate::key::get_encryption_key_password;
-
 #[api(
    input: {
         properties: {
@@ -48,6 +48,15 @@ use crate::key::get_encryption_key_password;
                 type: String,
                 description: "Snapshot path.",
              },
+            "keyfile": {
+                optional: true,
+                type: String,
+                description: "Path to encryption key.",
+            },
+            "keyfd": {
+                schema: KEYFD_SCHEMA,
+                optional: true,
+            },
         }
    }
 )]
@@ -56,20 +65,25 @@ async fn dump_catalog(param: Value) -> Result<Value, Error> {
 
     let repo = extract_repository_from_value(&param)?;
 
-    let path = tools::required_string_param(&param, "snapshot")?;
+    let path = required_string_param(&param, "snapshot")?;
     let snapshot: BackupDir = path.parse()?;
 
-    let keyfile = param["keyfile"].as_str().map(PathBuf::from);
+    let crypto = crypto_parameters(&param)?;
 
-    let crypt_config = match keyfile {
+    let crypt_config = match crypto.enc_key {
         None => None,
-        Some(path) => {
-            let (key, _) = load_and_decrypt_key(&path, &get_encryption_key_password)?;
-            Some(Arc::new(CryptConfig::new(key)?))
+        Some(key) => {
+            let (key, _created, _fingerprint) = decrypt_key(&key.key, &get_encryption_key_password)
+                .map_err(|err| {
+                    eprintln!("{}", format_key_source(&key.source, "encryption"));
+                    err
+                })?;
+            let crypt_config = CryptConfig::new(key)?;
+            Some(Arc::new(crypt_config))
         }
     };
 
-    let client = connect(repo.host(), repo.user())?;
+    let client = connect(&repo)?;
 
     let client = BackupReader::start(
         client,
@@ -81,13 +95,16 @@ async fn dump_catalog(param: Value) -> Result<Value, Error> {
         true,
     ).await?;
 
-    let manifest = client.download_manifest().await?;
+    let (manifest, _) = client.download_manifest().await?;
+    manifest.check_fingerprint(crypt_config.as_ref().map(Arc::as_ref))?;
 
     let index = client.download_dynamic_index(&manifest, CATALOG_NAME).await?;
 
     let most_used = index.find_most_used_chunks(8);
 
-    let chunk_reader = RemoteChunkReader::new(client.clone(), crypt_config, most_used);
+    let file_info = manifest.lookup_file_info(&CATALOG_NAME)?;
+
+    let chunk_reader = RemoteChunkReader::new(client.clone(), crypt_config, file_info.chunk_crypt_mode(), most_used);
 
     let mut reader = BufferedDynamicReader::new(index, chunk_reader);
 
@@ -131,15 +148,19 @@ async fn dump_catalog(param: Value) -> Result<Value, Error> {
                 type: String,
                 description: "Path to encryption key.",
             },
-        },
+            "keyfd": {
+                schema: KEYFD_SCHEMA,
+                optional: true,
+            },
+         },
     },
 )]
 /// Shell to interactively inspect and restore snapshots.
 async fn catalog_shell(param: Value) -> Result<(), Error> {
     let repo = extract_repository_from_value(&param)?;
-    let client = connect(repo.host(), repo.user())?;
-    let path = tools::required_string_param(&param, "snapshot")?;
-    let archive_name = tools::required_string_param(&param, "archive-name")?;
+    let client = connect(&repo)?;
+    let path = required_string_param(&param, "snapshot")?;
+    let archive_name = required_string_param(&param, "archive-name")?;
 
     let (backup_type, backup_id, backup_time) = if path.matches('/').count() == 1 {
         let group: BackupGroup = path.parse()?;
@@ -149,12 +170,18 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
         (snapshot.group().backup_type().to_owned(), snapshot.group().backup_id().to_owned(), snapshot.backup_time())
     };
 
-    let keyfile = param["keyfile"].as_str().map(|p| PathBuf::from(p));
-    let crypt_config = match keyfile {
+    let crypto = crypto_parameters(&param)?;
+
+    let crypt_config = match crypto.enc_key {
         None => None,
-        Some(path) => {
-            let (key, _) = load_and_decrypt_key(&path, &get_encryption_key_password)?;
-            Some(Arc::new(CryptConfig::new(key)?))
+        Some(key) => {
+            let (key, _created, _fingerprint) = decrypt_key(&key.key, &get_encryption_key_password)
+                .map_err(|err| {
+                    eprintln!("{}", format_key_source(&key.source, "encryption"));
+                    err
+                })?;
+            let crypt_config = CryptConfig::new(key)?;
+            Some(Arc::new(crypt_config))
         }
     };
 
@@ -180,16 +207,19 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
         .custom_flags(libc::O_TMPFILE)
         .open("/tmp")?;
 
-    let manifest = client.download_manifest().await?;
+    let (manifest, _) = client.download_manifest().await?;
+    manifest.check_fingerprint(crypt_config.as_ref().map(Arc::as_ref))?;
 
     let index = client.download_dynamic_index(&manifest, &server_archive_name).await?;
     let most_used = index.find_most_used_chunks(8);
-    let chunk_reader = RemoteChunkReader::new(client.clone(), crypt_config.clone(), most_used);
+
+    let file_info = manifest.lookup_file_info(&server_archive_name)?;
+    let chunk_reader = RemoteChunkReader::new(client.clone(), crypt_config.clone(), file_info.chunk_crypt_mode(), most_used);
     let reader = BufferedDynamicReader::new(index, chunk_reader);
     let archive_size = reader.archive_size();
-    let reader: proxmox_backup::pxar::fuse::Reader =
+    let reader: pbs_client::pxar::fuse::Reader =
         Arc::new(BufferedDynamicReadAt::new(reader));
-    let decoder = proxmox_backup::pxar::fuse::Accessor::new(reader, archive_size).await?;
+    let decoder = pbs_client::pxar::fuse::Accessor::new(reader, archive_size).await?;
 
     client.download(CATALOG_NAME, &mut tmpfile).await?;
     let index = DynamicIndexReader::new(tmpfile)
@@ -200,7 +230,9 @@ async fn catalog_shell(param: Value) -> Result<(), Error> {
     manifest.verify_file(CATALOG_NAME, &csum, size)?;
 
     let most_used = index.find_most_used_chunks(8);
-    let chunk_reader = RemoteChunkReader::new(client.clone(), crypt_config, most_used);
+
+    let file_info = manifest.lookup_file_info(&CATALOG_NAME)?;
+    let chunk_reader = RemoteChunkReader::new(client.clone(), crypt_config, file_info.chunk_crypt_mode(), most_used);
     let mut reader = BufferedDynamicReader::new(index, chunk_reader);
     let mut catalogfile = std::fs::OpenOptions::new()
         .write(true)