From 6ff8ae4535cdb3821ec2ed114bfbac7c5eca9ae3 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Wed, 27 Nov 2024 11:35:47 -0500 Subject: [PATCH] sqlcipher check (#1348) --- .../src/storage/encrypted_store/native.rs | 8 ++++ .../encrypted_store/sqlcipher_connection.rs | 39 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/xmtp_mls/src/storage/encrypted_store/native.rs b/xmtp_mls/src/storage/encrypted_store/native.rs index f951116b3..b254f820e 100644 --- a/xmtp_mls/src/storage/encrypted_store/native.rs +++ b/xmtp_mls/src/storage/encrypted_store/native.rs @@ -79,6 +79,14 @@ impl StorageOption { Ephemeral => SqliteConnection::establish(":memory:"), } } + + pub(super) fn path(&self) -> Option<&String> { + use StorageOption::*; + match self { + Persistent(path) => Some(path), + _ => None, + } + } } #[derive(Clone, Debug)] diff --git a/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs b/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs index 19b0e6145..25dfb379f 100644 --- a/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs +++ b/xmtp_mls/src/storage/encrypted_store/sqlcipher_connection.rs @@ -46,6 +46,8 @@ impl EncryptedConnection { /// Creates a file for the salt and stores it pub fn new(key: EncryptionKey, opts: &StorageOption) -> Result { use super::StorageOption::*; + Self::check_for_sqlcipher(opts)?; + let salt = match opts { Ephemeral => None, Persistent(ref db_path) => { @@ -56,6 +58,13 @@ impl EncryptedConnection { match (salt_path.try_exists()?, db_pathbuf.try_exists()?) { // db and salt exist (true, true) => { + tracing::debug!( + salt = %salt_path.display(), + db = %db_pathbuf.display(), + "salt and database exist, db=[{}], salt=[{}]", + db_pathbuf.display(), + salt_path.display(), + ); let file = File::open(salt_path)?; salt = ::from_hex( file.bytes().take(32).collect::, _>>()?, @@ -63,18 +72,31 @@ impl EncryptedConnection { } // the db exists and needs to be migrated (false, true) => { - tracing::debug!("migrating sqlcipher db to plaintext header."); + tracing::debug!( + "migrating sqlcipher db=[{}] to plaintext header with salt=[{}]", + db_pathbuf.display(), + salt_path.display() + ); Self::migrate(db_path, key, &mut salt)?; } // the db doesn't exist yet and needs to be created (false, false) => { - tracing::debug!("creating new sqlcipher db"); + tracing::debug!( + "creating new sqlcipher db=[{}] with salt=[{}]", + db_pathbuf.display(), + salt_path.display() + ); Self::create(db_path, key, &mut salt)?; } // the db doesn't exist but the salt does // This generally doesn't make sense & shouldn't happen. // Create a new database and delete the salt file. (true, false) => { + tracing::debug!( + "database [{}] does not exist, but the salt [{}] does, re-creating", + db_pathbuf.display(), + salt_path.display(), + ); std::fs::remove_file(salt_path)?; Self::create(db_path, key, &mut salt)?; } @@ -199,6 +221,19 @@ impl EncryptedConnection { ) } } + + fn check_for_sqlcipher(opts: &StorageOption) -> Result<(), StorageError> { + if let Some(path) = opts.path() { + let exists = std::path::Path::new(path).exists(); + tracing::debug!("db @ [{}] exists? [{}]", path, exists); + } + let conn = &mut opts.conn()?; + let cipher_version = sql_query("PRAGMA cipher_version").load::(conn)?; + if cipher_version.is_empty() { + return Err(StorageError::SqlCipherNotLoaded); + } + Ok(()) + } } impl super::native::ValidatedConnection for EncryptedConnection {