proxmox_client_tools: move common key related functions to key_source.rs
Add a new module containing key-related functions and schemata from all over, code moved is not changed as much as possible. Requires adapting some 'use' statements across proxmox-backup-client and putting the XDG helpers quite cozily into proxmox_client_tools/mod.rs Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
This commit is contained in:
		
				
					committed by
					
						 Thomas Lamprecht
						Thomas Lamprecht
					
				
			
			
				
	
			
			
			
						parent
						
							4876393562
						
					
				
				
					commit
					ff8945fd2f
				
			| @ -34,6 +34,8 @@ use crate::{ | ||||
|     connect, | ||||
| }; | ||||
|  | ||||
| use crate::proxmox_client_tools::key_source::get_encryption_key_password; | ||||
|  | ||||
| #[api()] | ||||
| #[derive(Copy, Clone, Serialize)] | ||||
| /// Speed test result | ||||
| @ -152,7 +154,7 @@ pub async fn benchmark( | ||||
|     let crypt_config = match keyfile { | ||||
|         None => None, | ||||
|         Some(path) => { | ||||
|             let (key, _, _) = load_and_decrypt_key(&path, &crate::key::get_encryption_key_password)?; | ||||
|             let (key, _, _) = load_and_decrypt_key(&path, &get_encryption_key_password)?; | ||||
|             let crypt_config = CryptConfig::new(key)?; | ||||
|             Some(Arc::new(crypt_config)) | ||||
|         } | ||||
|  | ||||
| @ -17,7 +17,6 @@ use crate::{ | ||||
|     extract_repository_from_value, | ||||
|     format_key_source, | ||||
|     record_repository, | ||||
|     key::get_encryption_key_password, | ||||
|     decrypt_key, | ||||
|     api_datastore_latest_snapshot, | ||||
|     complete_repository, | ||||
| @ -38,6 +37,8 @@ use crate::{ | ||||
|     Shell, | ||||
| }; | ||||
|  | ||||
| use crate::proxmox_client_tools::key_source::get_encryption_key_password; | ||||
|  | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
|  | ||||
| @ -20,114 +20,10 @@ use proxmox_backup::{ | ||||
|     tools::paperkey::{generate_paper_key, PaperkeyFormat}, | ||||
| }; | ||||
|  | ||||
| use crate::KeyWithSource; | ||||
|  | ||||
| pub const DEFAULT_ENCRYPTION_KEY_FILE_NAME: &str = "encryption-key.json"; | ||||
| pub const DEFAULT_MASTER_PUBKEY_FILE_NAME: &str = "master-public.pem"; | ||||
|  | ||||
| pub fn find_default_master_pubkey() -> Result<Option<PathBuf>, Error> { | ||||
|     super::find_xdg_file( | ||||
|         DEFAULT_MASTER_PUBKEY_FILE_NAME, | ||||
|         "default master public key file", | ||||
|     ) | ||||
| } | ||||
|  | ||||
| pub fn place_default_master_pubkey() -> Result<PathBuf, Error> { | ||||
|     super::place_xdg_file( | ||||
|         DEFAULT_MASTER_PUBKEY_FILE_NAME, | ||||
|         "default master public key file", | ||||
|     ) | ||||
| } | ||||
|  | ||||
| pub fn find_default_encryption_key() -> Result<Option<PathBuf>, Error> { | ||||
|     super::find_xdg_file( | ||||
|         DEFAULT_ENCRYPTION_KEY_FILE_NAME, | ||||
|         "default encryption key file", | ||||
|     ) | ||||
| } | ||||
|  | ||||
| pub fn place_default_encryption_key() -> Result<PathBuf, Error> { | ||||
|     super::place_xdg_file( | ||||
|         DEFAULT_ENCRYPTION_KEY_FILE_NAME, | ||||
|         "default encryption key file", | ||||
|     ) | ||||
| } | ||||
|  | ||||
| #[cfg(not(test))] | ||||
| pub(crate) fn read_optional_default_encryption_key() -> Result<Option<KeyWithSource>, Error> { | ||||
|     find_default_encryption_key()? | ||||
|         .map(|path| file_get_contents(path).map(KeyWithSource::from_default)) | ||||
|         .transpose() | ||||
| } | ||||
|  | ||||
| #[cfg(not(test))] | ||||
| pub(crate) fn read_optional_default_master_pubkey() -> Result<Option<KeyWithSource>, Error> { | ||||
|     find_default_master_pubkey()? | ||||
|         .map(|path| file_get_contents(path).map(KeyWithSource::from_default)) | ||||
|         .transpose() | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| static mut TEST_DEFAULT_ENCRYPTION_KEY: Result<Option<Vec<u8>>, Error> = Ok(None); | ||||
|  | ||||
| #[cfg(test)] | ||||
| pub(crate) fn read_optional_default_encryption_key() -> Result<Option<KeyWithSource>, Error> { | ||||
|     // not safe when multiple concurrent test cases end up here! | ||||
|     unsafe { | ||||
|         match &TEST_DEFAULT_ENCRYPTION_KEY { | ||||
|             Ok(Some(key)) => Ok(Some(KeyWithSource::from_default(key.clone()))), | ||||
|             Ok(None) => Ok(None), | ||||
|             Err(_) => bail!("test error"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| // not safe when multiple concurrent test cases end up here! | ||||
| pub(crate) unsafe fn set_test_encryption_key(value: Result<Option<Vec<u8>>, Error>) { | ||||
|     TEST_DEFAULT_ENCRYPTION_KEY = value; | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| static mut TEST_DEFAULT_MASTER_PUBKEY: Result<Option<Vec<u8>>, Error> = Ok(None); | ||||
|  | ||||
| #[cfg(test)] | ||||
| pub(crate) fn read_optional_default_master_pubkey() -> Result<Option<KeyWithSource>, Error> { | ||||
|     // not safe when multiple concurrent test cases end up here! | ||||
|     unsafe { | ||||
|         match &TEST_DEFAULT_MASTER_PUBKEY { | ||||
|             Ok(Some(key)) => Ok(Some(KeyWithSource::from_default(key.clone()))), | ||||
|             Ok(None) => Ok(None), | ||||
|             Err(_) => bail!("test error"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| // not safe when multiple concurrent test cases end up here! | ||||
| pub(crate) unsafe fn set_test_default_master_pubkey(value: Result<Option<Vec<u8>>, Error>) { | ||||
|     TEST_DEFAULT_MASTER_PUBKEY = value; | ||||
| } | ||||
|  | ||||
| pub fn get_encryption_key_password() -> Result<Vec<u8>, Error> { | ||||
|     // fixme: implement other input methods | ||||
|  | ||||
|     use std::env::VarError::*; | ||||
|     match std::env::var("PBS_ENCRYPTION_PASSWORD") { | ||||
|         Ok(p) => return Ok(p.as_bytes().to_vec()), | ||||
|         Err(NotUnicode(_)) => bail!("PBS_ENCRYPTION_PASSWORD contains bad characters"), | ||||
|         Err(NotPresent) => { | ||||
|             // Try another method | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // If we're on a TTY, query the user for a password | ||||
|     if tty::stdin_isatty() { | ||||
|         return Ok(tty::read_password("Encryption Key Password: ")?); | ||||
|     } | ||||
|  | ||||
|     bail!("no password input mechanism available"); | ||||
| } | ||||
| use crate::proxmox_client_tools::key_source::{ | ||||
|     find_default_encryption_key, find_default_master_pubkey, get_encryption_key_password, | ||||
|     place_default_encryption_key, place_default_master_pubkey, | ||||
| }; | ||||
|  | ||||
| #[api( | ||||
|     input: { | ||||
|  | ||||
| @ -1,5 +1,3 @@ | ||||
| use anyhow::{Context, Error}; | ||||
|  | ||||
| mod benchmark; | ||||
| pub use benchmark::*; | ||||
| mod mount; | ||||
| @ -13,29 +11,3 @@ pub use snapshot::*; | ||||
|  | ||||
| pub mod key; | ||||
|  | ||||
| pub fn base_directories() -> Result<xdg::BaseDirectories, Error> { | ||||
|     xdg::BaseDirectories::with_prefix("proxmox-backup").map_err(Error::from) | ||||
| } | ||||
|  | ||||
| /// Convenience helper for better error messages: | ||||
| pub fn find_xdg_file( | ||||
|     file_name: impl AsRef<std::path::Path>, | ||||
|     description: &'static str, | ||||
| ) -> Result<Option<std::path::PathBuf>, Error> { | ||||
|     let file_name = file_name.as_ref(); | ||||
|     base_directories() | ||||
|         .map(|base| base.find_config_file(file_name)) | ||||
|         .with_context(|| format!("error searching for {}", description)) | ||||
| } | ||||
|  | ||||
| pub fn place_xdg_file( | ||||
|     file_name: impl AsRef<std::path::Path>, | ||||
|     description: &'static str, | ||||
| ) -> Result<std::path::PathBuf, Error> { | ||||
|     let file_name = file_name.as_ref(); | ||||
|     base_directories() | ||||
|         .and_then(|base| { | ||||
|             base.place_config_file(file_name).map_err(Error::from) | ||||
|         }) | ||||
|         .with_context(|| format!("failed to place {} in xdg home", description)) | ||||
| } | ||||
|  | ||||
| @ -43,6 +43,8 @@ use crate::{ | ||||
|     BufferedDynamicReadAt, | ||||
| }; | ||||
|  | ||||
| use crate::proxmox_client_tools::key_source::get_encryption_key_password; | ||||
|  | ||||
| #[sortable] | ||||
| const API_METHOD_MOUNT: ApiMethod = ApiMethod::new( | ||||
|     &ApiHandler::Sync(&mount), | ||||
| @ -182,7 +184,7 @@ async fn mount_do(param: Value, pipe: Option<Fd>) -> Result<Value, Error> { | ||||
|         None => None, | ||||
|         Some(path) => { | ||||
|             println!("Encryption key file: '{:?}'", path); | ||||
|             let (key, _, fingerprint) = load_and_decrypt_key(&path, &crate::key::get_encryption_key_password)?; | ||||
|             let (key, _, fingerprint) = load_and_decrypt_key(&path, &get_encryption_key_password)?; | ||||
|             println!("Encryption key fingerprint: '{}'", fingerprint); | ||||
|             Some(Arc::new(CryptConfig::new(key)?)) | ||||
|         } | ||||
|  | ||||
| @ -35,6 +35,8 @@ use crate::{ | ||||
|     record_repository, | ||||
| }; | ||||
|  | ||||
| use crate::proxmox_client_tools::key_source::get_encryption_key_password; | ||||
|  | ||||
| #[api( | ||||
|    input: { | ||||
|         properties: { | ||||
| @ -239,7 +241,7 @@ async fn upload_log(param: Value) -> Result<Value, Error> { | ||||
|     let crypt_config = match crypto.enc_key { | ||||
|         None => None, | ||||
|         Some(key) => { | ||||
|             let (key, _created, _) = decrypt_key(&key.key, &crate::key::get_encryption_key_password)?; | ||||
|             let (key, _created, _) = decrypt_key(&key.key, &get_encryption_key_password)?; | ||||
|             let crypt_config = CryptConfig::new(key)?; | ||||
|             Some(Arc::new(crypt_config)) | ||||
|         } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user