From b83db9a13c2ae31b2b5fcc0a81702be75e25dc43 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 03:15:07 +0000 Subject: [PATCH 01/18] Automatically migrate unencrypted databases on request --- crates/lair_keystore/src/lib.rs | 3 - crates/lair_keystore/src/store_sqlite.rs | 109 ++++++++++++++++-- crates/lair_keystore/tests/common.rs | 40 +++++++ .../tests/migrate_unencrypted.rs | 44 +++++++ .../{src => tests}/server_test.rs | 36 +----- 5 files changed, 185 insertions(+), 47 deletions(-) create mode 100644 crates/lair_keystore/tests/common.rs create mode 100644 crates/lair_keystore/tests/migrate_unencrypted.rs rename crates/lair_keystore/{src => tests}/server_test.rs (80%) diff --git a/crates/lair_keystore/src/lib.rs b/crates/lair_keystore/src/lib.rs index f902596..b03971e 100644 --- a/crates/lair_keystore/src/lib.rs +++ b/crates/lair_keystore/src/lib.rs @@ -75,6 +75,3 @@ pub mod store_sqlite; #[doc(inline)] pub use store_sqlite::create_sql_pool_factory; - -#[cfg(test)] -mod server_test; diff --git a/crates/lair_keystore/src/store_sqlite.rs b/crates/lair_keystore/src/store_sqlite.rs index 9ab18c5..6fdfbe6 100644 --- a/crates/lair_keystore/src/store_sqlite.rs +++ b/crates/lair_keystore/src/store_sqlite.rs @@ -163,18 +163,22 @@ impl SqlPool { // initialize the sqlcipher key pragma let key_pragma = secure_write_key_pragma(dbk_secret)?; - // open a single write connection to the database - let mut write_con = rusqlite::Connection::open_with_flags( - &path, - OpenFlags::SQLITE_OPEN_READ_WRITE - | OpenFlags::SQLITE_OPEN_CREATE - | OpenFlags::SQLITE_OPEN_NO_MUTEX - | OpenFlags::SQLITE_OPEN_URI, - ) - .map_err(one_err::OneErr::new)?; - - // set generic pragmas - set_pragmas(&write_con, key_pragma.clone())?; + let mut write_con = match create_configured_db_connection(&path, key_pragma.clone()) { + Ok(con) => con, + Err(e) => { + if "true" == std::env::var("LAIR_MIGRATE_UNENCRYPTED").unwrap_or_default().as_str() { + // Known SQLite error when the database is not encrypted, try to encrypt it and retry starting the server + if let Some("file is not a database") = e.get_field::<&str, &str>("error") { + encrypt_unencrypted_database(&path, key_pragma.clone())?; + create_configured_db_connection(&path, key_pragma.clone())? + } else { + return Err(e); + } + } else { + return Err(e); + } + } + }; // only set WAL mode on the first write connection // it's a slow operation, and not needed on subsequent connections. @@ -289,6 +293,25 @@ impl SqlPool { } } +fn create_configured_db_connection(path: &std::path::PathBuf, key_pragma: BufRead) -> LairResult { + use rusqlite::OpenFlags; + + // open a single write connection to the database + let write_con = rusqlite::Connection::open_with_flags( + &path, + OpenFlags::SQLITE_OPEN_READ_WRITE + | OpenFlags::SQLITE_OPEN_CREATE + | OpenFlags::SQLITE_OPEN_NO_MUTEX + | OpenFlags::SQLITE_OPEN_URI, + ) + .map_err(one_err::OneErr::new)?; + + // set generic pragmas + set_pragmas(&write_con, key_pragma)?; + + Ok(write_con) +} + impl AsLairStore for SqlPool { fn get_bidi_ctx_key(&self) -> sodoken::BufReadSized<32> { self.0.lock().ctx_secret.clone() @@ -504,6 +527,68 @@ fn set_pragmas( Ok(()) } +fn encrypt_unencrypted_database(path: &std::path::PathBuf, key_pragma: BufRead) -> LairResult<()> { + // e.g. keystore/store_file -> keystore/store_file-encrypted + let encrypted_path = path + .parent() + .ok_or_else(|| -> one_err::OneErr { + format!("Database file path has no parent: {:?}", path).into() + })? + .join( + path.file_stem() + .and_then(|s| s.to_str()) + .ok_or_else(|| -> one_err::OneErr { + format!("Database file path has no name: {:?}", path).into() + })? + .to_string() + + "-encrypted" + + &path + .extension() + .and_then(|s| s.to_str()) + .map(|p| ".".to_string() + p) + .unwrap_or_default(), + ); + + tracing::warn!( + "Attempting encryption of unencrypted database: {:?} -> {:?}", + path, + encrypted_path + ); + + // Migrate the database + { + let conn = rusqlite::Connection::open(path).map_err(one_err::OneErr::new)?; + + // Ensure everything in the WAL is written to the main database + conn.execute("VACUUM", ()).map_err(one_err::OneErr::new)?; + + // Start an exclusive transaction to avoid anybody writing to the database while we're migrating it + conn.execute("BEGIN EXCLUSIVE", ()).map_err(one_err::OneErr::new)?; + + let lock = key_pragma.read_lock(); + conn.execute( + "ATTACH DATABASE :db_name AS encrypted KEY :key", + rusqlite::named_params! { + ":db_name": encrypted_path.to_str(), + ":key": &lock[14..81], + }, + ).map_err(one_err::OneErr::new)?; + + conn.query_row("SELECT sqlcipher_export('encrypted')", (), |_| Ok(0)).map_err(one_err::OneErr::new)?; + + conn.execute("COMMIT", ()).map_err(one_err::OneErr::new)?; + + conn.execute("DETACH DATABASE encrypted", ()).map_err(one_err::OneErr::new)?; + conn.close().map_err(|(_, err)| err).map_err(one_err::OneErr::new)?; + } + + // Swap the databases over + std::fs::remove_file(path)?; + std::fs::rename(encrypted_path, path)?; + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/lair_keystore/tests/common.rs b/crates/lair_keystore/tests/common.rs new file mode 100644 index 0000000..cf0d795 --- /dev/null +++ b/crates/lair_keystore/tests/common.rs @@ -0,0 +1,40 @@ +use lair_keystore::dependencies::*; +use lair_keystore_api::prelude::*; +use std::sync::Arc; + +pub async fn create_config(tmpdir: &tempdir::TempDir, passphrase: sodoken::BufRead) -> Arc { + // create the config for the test server + Arc::new( + hc_seed_bundle::PwHashLimits::Minimum + .with_exec(|| { + LairServerConfigInner::new(tmpdir.path(), passphrase.clone()) + }) + .await + .unwrap(), + ) +} + +pub async fn connect_with_config(config: Arc, passphrase: sodoken::BufRead) -> LairResult { + // execute the server + lair_keystore::server::StandaloneServer::new(config.clone()) + .await? + .run(passphrase.clone()) + .await?; + + // create a client connection + lair_keystore_api::ipc_keystore::ipc_keystore_connect( + config.connection_url.clone(), + passphrase, + ) + .await +} + +#[allow(dead_code)] +pub async fn connect(tmpdir: &tempdir::TempDir) -> lair_keystore_api::LairClient { + // set up a passphrase + let passphrase = sodoken::BufRead::from(&b"passphrase"[..]); + + let config = create_config(tmpdir, passphrase.clone()).await; + + connect_with_config(config, passphrase).await.unwrap() +} diff --git a/crates/lair_keystore/tests/migrate_unencrypted.rs b/crates/lair_keystore/tests/migrate_unencrypted.rs new file mode 100644 index 0000000..19cfd79 --- /dev/null +++ b/crates/lair_keystore/tests/migrate_unencrypted.rs @@ -0,0 +1,44 @@ +use lair_keystore_api::dependencies::{sodoken, tokio}; +use common::{create_config, connect_with_config}; + +mod common; + +#[tokio::test(flavor = "multi_thread")] +async fn migrate_unencrypted() { + use rusqlite::Connection; + + let tmpdir = tempdir::TempDir::new("lair keystore test").unwrap(); + + let passphrase = sodoken::BufRead::from(&b"passphrase"[..]); + + let config = create_config(&tmpdir, passphrase.clone()).await; + + // Set up an unencrypted database, by not setting a key on the connection + { + let conn = Connection::open(&config.store_file).unwrap(); + + // Needs to contain data otherwise encryption will just succeed! + conn.execute("CREATE TABLE migrate_me (name TEXT NOT NULL)", ()) + .unwrap(); + conn.execute( + "INSERT INTO migrate_me (name) VALUES ('hello_migrated')", + (), + ) + .unwrap(); + + conn.close().unwrap(); + } + + match connect_with_config(config.clone(), passphrase.clone()).await { + Ok(_) => { + panic!("Shouldn't have been able to spawn lair-keystore"); + }, + Err(_) => { + // That's good, we shouldn't have been able to connect because the database won't auto-migrate without `LAIR_MIGRATE_UNENCRYPTED` + } + } + + std::env::set_var("LAIR_MIGRATE_UNENCRYPTED", "true"); + + connect_with_config(config.clone(), passphrase.clone()).await.unwrap(); +} diff --git a/crates/lair_keystore/src/server_test.rs b/crates/lair_keystore/tests/server_test.rs similarity index 80% rename from crates/lair_keystore/src/server_test.rs rename to crates/lair_keystore/tests/server_test.rs index 0fe0b13..5357e55 100644 --- a/crates/lair_keystore/src/server_test.rs +++ b/crates/lair_keystore/tests/server_test.rs @@ -1,36 +1,8 @@ -use crate::*; -use std::sync::Arc; - -async fn connect(tmpdir: &tempdir::TempDir) -> lair_keystore_api::LairClient { - // set up a passphrase - let passphrase = sodoken::BufRead::from(&b"passphrase"[..]); - - // create the config for the test server - let config = Arc::new( - hc_seed_bundle::PwHashLimits::Minimum - .with_exec(|| { - LairServerConfigInner::new(tmpdir.path(), passphrase.clone()) - }) - .await - .unwrap(), - ); - - // execute the server - crate::server::StandaloneServer::new(config.clone()) - .await - .unwrap() - .run(passphrase.clone()) - .await - .unwrap(); +use lair_keystore::dependencies::*; +use lair_keystore_api::prelude::*; +use common::connect; - // create a client connection - lair_keystore_api::ipc_keystore::ipc_keystore_connect( - config.connection_url.clone(), - passphrase, - ) - .await - .unwrap() -} +mod common; #[tokio::test(flavor = "multi_thread")] async fn server_test_happy_path() { From 670a1858f6c7d4cd9acb66e0373327e1d49b4709 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 03:16:07 +0000 Subject: [PATCH 02/18] Format --- crates/lair_keystore/src/store_sqlite.rs | 66 +++++++++++++------ crates/lair_keystore/tests/common.rs | 14 +++- .../tests/migrate_unencrypted.rs | 14 ++-- crates/lair_keystore/tests/server_test.rs | 2 +- 4 files changed, 66 insertions(+), 30 deletions(-) diff --git a/crates/lair_keystore/src/store_sqlite.rs b/crates/lair_keystore/src/store_sqlite.rs index 6fdfbe6..3719224 100644 --- a/crates/lair_keystore/src/store_sqlite.rs +++ b/crates/lair_keystore/src/store_sqlite.rs @@ -163,22 +163,35 @@ impl SqlPool { // initialize the sqlcipher key pragma let key_pragma = secure_write_key_pragma(dbk_secret)?; - let mut write_con = match create_configured_db_connection(&path, key_pragma.clone()) { - Ok(con) => con, - Err(e) => { - if "true" == std::env::var("LAIR_MIGRATE_UNENCRYPTED").unwrap_or_default().as_str() { - // Known SQLite error when the database is not encrypted, try to encrypt it and retry starting the server - if let Some("file is not a database") = e.get_field::<&str, &str>("error") { - encrypt_unencrypted_database(&path, key_pragma.clone())?; - create_configured_db_connection(&path, key_pragma.clone())? + let mut write_con = + match create_configured_db_connection(&path, key_pragma.clone()) { + Ok(con) => con, + Err(e) => { + if "true" + == std::env::var("LAIR_MIGRATE_UNENCRYPTED") + .unwrap_or_default() + .as_str() + { + // Known SQLite error when the database is not encrypted, try to encrypt it and retry starting the server + if let Some("file is not a database") = + e.get_field::<&str, &str>("error") + { + encrypt_unencrypted_database( + &path, + key_pragma.clone(), + )?; + create_configured_db_connection( + &path, + key_pragma.clone(), + )? + } else { + return Err(e); + } } else { return Err(e); } - } else { - return Err(e); } - } - }; + }; // only set WAL mode on the first write connection // it's a slow operation, and not needed on subsequent connections. @@ -293,7 +306,10 @@ impl SqlPool { } } -fn create_configured_db_connection(path: &std::path::PathBuf, key_pragma: BufRead) -> LairResult { +fn create_configured_db_connection( + path: &std::path::PathBuf, + key_pragma: BufRead, +) -> LairResult { use rusqlite::OpenFlags; // open a single write connection to the database @@ -527,7 +543,10 @@ fn set_pragmas( Ok(()) } -fn encrypt_unencrypted_database(path: &std::path::PathBuf, key_pragma: BufRead) -> LairResult<()> { +fn encrypt_unencrypted_database( + path: &std::path::PathBuf, + key_pragma: BufRead, +) -> LairResult<()> { // e.g. keystore/store_file -> keystore/store_file-encrypted let encrypted_path = path .parent() @@ -557,13 +576,15 @@ fn encrypt_unencrypted_database(path: &std::path::PathBuf, key_pragma: BufRead) // Migrate the database { - let conn = rusqlite::Connection::open(path).map_err(one_err::OneErr::new)?; + let conn = + rusqlite::Connection::open(path).map_err(one_err::OneErr::new)?; // Ensure everything in the WAL is written to the main database conn.execute("VACUUM", ()).map_err(one_err::OneErr::new)?; // Start an exclusive transaction to avoid anybody writing to the database while we're migrating it - conn.execute("BEGIN EXCLUSIVE", ()).map_err(one_err::OneErr::new)?; + conn.execute("BEGIN EXCLUSIVE", ()) + .map_err(one_err::OneErr::new)?; let lock = key_pragma.read_lock(); conn.execute( @@ -572,14 +593,19 @@ fn encrypt_unencrypted_database(path: &std::path::PathBuf, key_pragma: BufRead) ":db_name": encrypted_path.to_str(), ":key": &lock[14..81], }, - ).map_err(one_err::OneErr::new)?; + ) + .map_err(one_err::OneErr::new)?; - conn.query_row("SELECT sqlcipher_export('encrypted')", (), |_| Ok(0)).map_err(one_err::OneErr::new)?; + conn.query_row("SELECT sqlcipher_export('encrypted')", (), |_| Ok(0)) + .map_err(one_err::OneErr::new)?; conn.execute("COMMIT", ()).map_err(one_err::OneErr::new)?; - conn.execute("DETACH DATABASE encrypted", ()).map_err(one_err::OneErr::new)?; - conn.close().map_err(|(_, err)| err).map_err(one_err::OneErr::new)?; + conn.execute("DETACH DATABASE encrypted", ()) + .map_err(one_err::OneErr::new)?; + conn.close() + .map_err(|(_, err)| err) + .map_err(one_err::OneErr::new)?; } // Swap the databases over diff --git a/crates/lair_keystore/tests/common.rs b/crates/lair_keystore/tests/common.rs index cf0d795..55a1671 100644 --- a/crates/lair_keystore/tests/common.rs +++ b/crates/lair_keystore/tests/common.rs @@ -2,7 +2,10 @@ use lair_keystore::dependencies::*; use lair_keystore_api::prelude::*; use std::sync::Arc; -pub async fn create_config(tmpdir: &tempdir::TempDir, passphrase: sodoken::BufRead) -> Arc { +pub async fn create_config( + tmpdir: &tempdir::TempDir, + passphrase: sodoken::BufRead, +) -> Arc { // create the config for the test server Arc::new( hc_seed_bundle::PwHashLimits::Minimum @@ -14,7 +17,10 @@ pub async fn create_config(tmpdir: &tempdir::TempDir, passphrase: sodoken::BufRe ) } -pub async fn connect_with_config(config: Arc, passphrase: sodoken::BufRead) -> LairResult { +pub async fn connect_with_config( + config: Arc, + passphrase: sodoken::BufRead, +) -> LairResult { // execute the server lair_keystore::server::StandaloneServer::new(config.clone()) .await? @@ -30,7 +36,9 @@ pub async fn connect_with_config(config: Arc, passphrase: } #[allow(dead_code)] -pub async fn connect(tmpdir: &tempdir::TempDir) -> lair_keystore_api::LairClient { +pub async fn connect( + tmpdir: &tempdir::TempDir, +) -> lair_keystore_api::LairClient { // set up a passphrase let passphrase = sodoken::BufRead::from(&b"passphrase"[..]); diff --git a/crates/lair_keystore/tests/migrate_unencrypted.rs b/crates/lair_keystore/tests/migrate_unencrypted.rs index 19cfd79..7e9717b 100644 --- a/crates/lair_keystore/tests/migrate_unencrypted.rs +++ b/crates/lair_keystore/tests/migrate_unencrypted.rs @@ -1,5 +1,5 @@ +use common::{connect_with_config, create_config}; use lair_keystore_api::dependencies::{sodoken, tokio}; -use common::{create_config, connect_with_config}; mod common; @@ -10,9 +10,9 @@ async fn migrate_unencrypted() { let tmpdir = tempdir::TempDir::new("lair keystore test").unwrap(); let passphrase = sodoken::BufRead::from(&b"passphrase"[..]); - + let config = create_config(&tmpdir, passphrase.clone()).await; - + // Set up an unencrypted database, by not setting a key on the connection { let conn = Connection::open(&config.store_file).unwrap(); @@ -32,13 +32,15 @@ async fn migrate_unencrypted() { match connect_with_config(config.clone(), passphrase.clone()).await { Ok(_) => { panic!("Shouldn't have been able to spawn lair-keystore"); - }, + } Err(_) => { - // That's good, we shouldn't have been able to connect because the database won't auto-migrate without `LAIR_MIGRATE_UNENCRYPTED` + // That's good, we shouldn't have been able to connect because the database won't auto-migrate without `LAIR_MIGRATE_UNENCRYPTED` } } std::env::set_var("LAIR_MIGRATE_UNENCRYPTED", "true"); - connect_with_config(config.clone(), passphrase.clone()).await.unwrap(); + connect_with_config(config.clone(), passphrase.clone()) + .await + .unwrap(); } diff --git a/crates/lair_keystore/tests/server_test.rs b/crates/lair_keystore/tests/server_test.rs index 5357e55..bae44f9 100644 --- a/crates/lair_keystore/tests/server_test.rs +++ b/crates/lair_keystore/tests/server_test.rs @@ -1,6 +1,6 @@ +use common::connect; use lair_keystore::dependencies::*; use lair_keystore_api::prelude::*; -use common::connect; mod common; From f70df9994378e34419a017973e21d22269474ff3 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 03:16:22 +0000 Subject: [PATCH 03/18] Clippy --- crates/lair_keystore/src/store_sqlite.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/lair_keystore/src/store_sqlite.rs b/crates/lair_keystore/src/store_sqlite.rs index 3719224..94f7f36 100644 --- a/crates/lair_keystore/src/store_sqlite.rs +++ b/crates/lair_keystore/src/store_sqlite.rs @@ -314,7 +314,7 @@ fn create_configured_db_connection( // open a single write connection to the database let write_con = rusqlite::Connection::open_with_flags( - &path, + path, OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE | OpenFlags::SQLITE_OPEN_NO_MUTEX From a2bd5660b1bfcd4570ea19ef10f8bc39ff2dc4c9 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 11:58:35 +0000 Subject: [PATCH 04/18] Improve error handling without strings --- crates/lair_keystore/src/store_sqlite.rs | 56 ++++++++++-------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/crates/lair_keystore/src/store_sqlite.rs b/crates/lair_keystore/src/store_sqlite.rs index 94f7f36..eeb10c6 100644 --- a/crates/lair_keystore/src/store_sqlite.rs +++ b/crates/lair_keystore/src/store_sqlite.rs @@ -111,20 +111,19 @@ impl SqlCon { /// extension trait for execute that we don't care about results trait ExecExt { - fn execute_optional

(&self, sql: &str, params: P) -> LairResult<()> + fn execute_optional

(&self, sql: &str, params: P) -> rusqlite::Result<()> where P: rusqlite::Params; } impl ExecExt for rusqlite::Connection { - fn execute_optional

(&self, sql: &str, params: P) -> LairResult<()> + fn execute_optional

(&self, sql: &str, params: P) -> rusqlite::Result<()> where P: rusqlite::Params, { use rusqlite::OptionalExtension; self.query_row(sql, params, |_| Ok(())) - .optional() - .map_err(one_err::OneErr::new)?; + .optional()?; Ok(()) } } @@ -166,31 +165,28 @@ impl SqlPool { let mut write_con = match create_configured_db_connection(&path, key_pragma.clone()) { Ok(con) => con, - Err(e) => { + Err(err @ rusqlite::Error::SqliteFailure(rusqlite::ffi::Error { + code: rusqlite::ffi::ErrorCode::NotADatabase, + .. + }, ..)) => { if "true" == std::env::var("LAIR_MIGRATE_UNENCRYPTED") .unwrap_or_default() .as_str() { - // Known SQLite error when the database is not encrypted, try to encrypt it and retry starting the server - if let Some("file is not a database") = - e.get_field::<&str, &str>("error") - { - encrypt_unencrypted_database( - &path, - key_pragma.clone(), - )?; - create_configured_db_connection( - &path, - key_pragma.clone(), - )? - } else { - return Err(e); - } + encrypt_unencrypted_database( + &path, + key_pragma.clone(), + )?; + create_configured_db_connection( + &path, + key_pragma.clone(), + ).map_err(one_err::OneErr::new)? } else { - return Err(e); + return Err(one_err::OneErr::new(err)); } } + Err(e) => return Err(one_err::OneErr::new(e)), }; // only set WAL mode on the first write connection @@ -230,7 +226,7 @@ impl SqlPool { .map_err(one_err::OneErr::new)?; // set generic pragmas - set_pragmas(&read_con, key_pragma.clone())?; + set_pragmas(&read_con, key_pragma.clone()).map_err(one_err::OneErr::new)?; *rc_mut = Some(read_con); } @@ -309,7 +305,7 @@ impl SqlPool { fn create_configured_db_connection( path: &std::path::PathBuf, key_pragma: BufRead, -) -> LairResult { +) -> rusqlite::Result { use rusqlite::OpenFlags; // open a single write connection to the database @@ -319,8 +315,7 @@ fn create_configured_db_connection( | OpenFlags::SQLITE_OPEN_CREATE | OpenFlags::SQLITE_OPEN_NO_MUTEX | OpenFlags::SQLITE_OPEN_URI, - ) - .map_err(one_err::OneErr::new)?; + )?; // set generic pragmas set_pragmas(&write_con, key_pragma)?; @@ -525,20 +520,17 @@ fn secure_write_key_pragma( fn set_pragmas( con: &rusqlite::Connection, key_pragma: BufRead, -) -> LairResult<()> { - con.busy_timeout(std::time::Duration::from_millis(30_000)) - .map_err(one_err::OneErr::new)?; +) -> rusqlite::Result<()> { + con.busy_timeout(std::time::Duration::from_millis(30_000))?; con.execute_optional( std::str::from_utf8(&key_pragma.read_lock()).unwrap(), [], )?; - con.pragma_update(None, "trusted_schema", "0".to_string()) - .map_err(one_err::OneErr::new)?; + con.pragma_update(None, "trusted_schema", "0".to_string())?; - con.pragma_update(None, "synchronous", "1".to_string()) - .map_err(one_err::OneErr::new)?; + con.pragma_update(None, "synchronous", "1".to_string())?; Ok(()) } From 6c237f37ba9f8ffef1c8f55d161fb9ca5dca2de6 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 12:03:22 +0000 Subject: [PATCH 05/18] Format --- crates/lair_keystore/src/store_sqlite.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/lair_keystore/src/store_sqlite.rs b/crates/lair_keystore/src/store_sqlite.rs index eeb10c6..1c82a70 100644 --- a/crates/lair_keystore/src/store_sqlite.rs +++ b/crates/lair_keystore/src/store_sqlite.rs @@ -122,8 +122,7 @@ impl ExecExt for rusqlite::Connection { P: rusqlite::Params, { use rusqlite::OptionalExtension; - self.query_row(sql, params, |_| Ok(())) - .optional()?; + self.query_row(sql, params, |_| Ok(())).optional()?; Ok(()) } } @@ -165,10 +164,15 @@ impl SqlPool { let mut write_con = match create_configured_db_connection(&path, key_pragma.clone()) { Ok(con) => con, - Err(err @ rusqlite::Error::SqliteFailure(rusqlite::ffi::Error { - code: rusqlite::ffi::ErrorCode::NotADatabase, - .. - }, ..)) => { + Err( + err @ rusqlite::Error::SqliteFailure( + rusqlite::ffi::Error { + code: rusqlite::ffi::ErrorCode::NotADatabase, + .. + }, + .., + ), + ) => { if "true" == std::env::var("LAIR_MIGRATE_UNENCRYPTED") .unwrap_or_default() @@ -181,7 +185,8 @@ impl SqlPool { create_configured_db_connection( &path, key_pragma.clone(), - ).map_err(one_err::OneErr::new)? + ) + .map_err(one_err::OneErr::new)? } else { return Err(one_err::OneErr::new(err)); } @@ -226,7 +231,8 @@ impl SqlPool { .map_err(one_err::OneErr::new)?; // set generic pragmas - set_pragmas(&read_con, key_pragma.clone()).map_err(one_err::OneErr::new)?; + set_pragmas(&read_con, key_pragma.clone()) + .map_err(one_err::OneErr::new)?; *rc_mut = Some(read_con); } From ab9ab6ecb664bd655dc6747de90e1db09e940e24 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 12:12:12 +0000 Subject: [PATCH 06/18] Clippy lint ignore --- crates/lair_keystore/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/lair_keystore/src/lib.rs b/crates/lair_keystore/src/lib.rs index b03971e..ad75d60 100644 --- a/crates/lair_keystore/src/lib.rs +++ b/crates/lair_keystore/src/lib.rs @@ -54,6 +54,8 @@ include!(concat!(env!("OUT_DIR"), "/ver.rs")); /// Re-exported dependencies. pub mod dependencies { + // Not sure why Clippy picks this up as unused, it's exported to be used elsewhere + #[allow(unused_imports)] pub use hc_seed_bundle::dependencies::*; pub use lair_keystore_api; pub use lair_keystore_api::dependencies::*; From 3f5cc5bef6d0cec98d3d23d7433c0baa614a6ded Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 12:19:55 +0000 Subject: [PATCH 07/18] Skip encrypt migration test on Windows --- crates/lair_keystore/tests/migrate_unencrypted.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/lair_keystore/tests/migrate_unencrypted.rs b/crates/lair_keystore/tests/migrate_unencrypted.rs index 7e9717b..6735f65 100644 --- a/crates/lair_keystore/tests/migrate_unencrypted.rs +++ b/crates/lair_keystore/tests/migrate_unencrypted.rs @@ -3,6 +3,7 @@ use lair_keystore_api::dependencies::{sodoken, tokio}; mod common; +#[cfg(not(windows))] // No encryption on Windows, ignore this test #[tokio::test(flavor = "multi_thread")] async fn migrate_unencrypted() { use rusqlite::Connection; From dfa590213ac14e4fd3efe45f53b185d7e6c85490 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 12:28:58 +0000 Subject: [PATCH 08/18] Update changelog --- crates/lair_keystore/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/lair_keystore/CHANGELOG.md b/crates/lair_keystore/CHANGELOG.md index 62c8de4..60243f3 100644 --- a/crates/lair_keystore/CHANGELOG.md +++ b/crates/lair_keystore/CHANGELOG.md @@ -1 +1,9 @@ +## 0.4.1 + +- Add a way to migrate unencrypted databases to encrypted by providing an environment variable `LAIR_MIGRATE_UNENCRYPTED="true"`, Lair will detect databases which can't be opened and attempt migration. #121 + +# 0.4.0 + +- pin serde and rmp-serde #119 + ## 0.0.2 From 631632022f5f22d4bdef34c27d96b5ff2c41af1c Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 14:19:42 +0000 Subject: [PATCH 09/18] Fail fast false --- .github/workflows/release.yml | 1 + .github/workflows/static.yml | 1 + .github/workflows/test.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index db623b6..2420ec3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,6 +11,7 @@ jobs: name: Release Build runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ ubuntu-latest, diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index a952965..a80aa2e 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -11,6 +11,7 @@ jobs: name: Static Analysis runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ ubuntu-latest, diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bd98785..65aee3a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,7 @@ jobs: name: Test runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ ubuntu-latest, From b0c712f7df22d89fc049478abbfa1e56da679288 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 17:05:39 +0000 Subject: [PATCH 10/18] Try vcpkg --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 65aee3a..3be5d7f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,4 +32,6 @@ jobs: toolchain: ${{ matrix.toolchain }} - name: Make Test + env: + SODIUM_USE_PKG_CONFIG: "true" run: make test From afafd7c70a11369ed6bd1de5dd557117e730ac2a Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 17:43:06 +0000 Subject: [PATCH 11/18] Try getting libsodium from vcpkg --- .github/workflows/test.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3be5d7f..e0642bb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,6 +31,16 @@ jobs: with: toolchain: ${{ matrix.toolchain }} + - name: vcpkg build + if: matrix.os == 'windows-latest' + uses: johnwason/vcpkg-action@v6 + id: vcpkg + with: + pkgs: libsodium + triplet: x64-windows-release + token: ${{ github.token }} + github-binarycache: true + - name: Make Test env: SODIUM_USE_PKG_CONFIG: "true" From 1dc961b263747840998d90a88d53b3e42506f9ae Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 17:55:08 +0000 Subject: [PATCH 12/18] lib dir? --- .github/workflows/test.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e0642bb..f60061b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,6 +42,13 @@ jobs: github-binarycache: true - name: Make Test + if: matrix.os == 'windows-latest' env: SODIUM_USE_PKG_CONFIG: "true" + run: |- + SODIUM_LIB_DIR=${{ steps.vcpkg.outputs.lib_dir }} + make test + + - name: Make Test + if: matrix.os != 'windows-latest' run: make test From 121d61f2e8f806ef82647e94a3cb250d0ce87aa7 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 17:57:38 +0000 Subject: [PATCH 13/18] Lib dir with pwsh --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f60061b..3cbe21a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,7 +46,7 @@ jobs: env: SODIUM_USE_PKG_CONFIG: "true" run: |- - SODIUM_LIB_DIR=${{ steps.vcpkg.outputs.lib_dir }} + $env:SODIUM_LIB_DIR="$(pwd)\packages\libsodium_x64-windows\lib" make test - name: Make Test From b1fe3dac4ff5c080964c8ab1bce434546e485fc9 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 18:08:00 +0000 Subject: [PATCH 14/18] Set one var and correct path --- .github/workflows/test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3cbe21a..a3a15b5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,10 +43,8 @@ jobs: - name: Make Test if: matrix.os == 'windows-latest' - env: - SODIUM_USE_PKG_CONFIG: "true" run: |- - $env:SODIUM_LIB_DIR="$(pwd)\packages\libsodium_x64-windows\lib" + $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows\lib" make test - name: Make Test From f8fb856b435d1d162b746af0d993882fdfcdd405 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 18:13:58 +0000 Subject: [PATCH 15/18] Check dir --- .github/workflows/release.yml | 18 +++++++++++++++++- .github/workflows/static.yml | 2 +- .github/workflows/test.yml | 6 ++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2420ec3..3db7e35 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,12 +24,28 @@ jobs: ] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Toolchain uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.toolchain }} + - name: Install vcpkg Packages + if: matrix.os == 'windows-latest' + uses: johnwason/vcpkg-action@v6 + id: vcpkg + with: + pkgs: libsodium + triplet: x64-windows-release + token: ${{ github.token }} + github-binarycache: true + + - name: Make Release + if: matrix.os == 'windows-latest' + run: |- + $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows\lib" + make release + - name: Make Release run: make release diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index a80aa2e..38d89c3 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -22,7 +22,7 @@ jobs: ] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Toolchain uses: actions-rs/toolchain@v1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a3a15b5..7834c0a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,14 +24,14 @@ jobs: ] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Toolchain uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.toolchain }} - - name: vcpkg build + - name: Install vcpkg Packages if: matrix.os == 'windows-latest' uses: johnwason/vcpkg-action@v6 id: vcpkg @@ -45,6 +45,8 @@ jobs: if: matrix.os == 'windows-latest' run: |- $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows\lib" + ls + ls $SODIUM_LIB_DIR make test - name: Make Test From f979226defb6c6770c3a0bdc2863815f142e1b99 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 18:16:44 +0000 Subject: [PATCH 16/18] More listing --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7834c0a..f063d1c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,6 +46,10 @@ jobs: run: |- $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows\lib" ls + ls .\vcpkg + ls .\vcpkg\packages + ls .\vcpkg\packages\libsodium_x64-windows + ls .\vcpkg\packages\libsodium_x64-windows\lib ls $SODIUM_LIB_DIR make test From 4def8db12ff8a3a2a8461b5a653b11238f9a72fb Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 18:19:25 +0000 Subject: [PATCH 17/18] It's in release --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f063d1c..6fee77c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,12 +44,12 @@ jobs: - name: Make Test if: matrix.os == 'windows-latest' run: |- - $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows\lib" + $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows-release\lib" ls ls .\vcpkg ls .\vcpkg\packages - ls .\vcpkg\packages\libsodium_x64-windows - ls .\vcpkg\packages\libsodium_x64-windows\lib + ls .\vcpkg\packages\libsodium_x64-windows-release + ls .\vcpkg\packages\libsodium_x64-windows-release\lib ls $SODIUM_LIB_DIR make test From e23f5922e2136fec36e84d2746a0eb8b63213587 Mon Sep 17 00:00:00 2001 From: ThetaSinner Date: Tue, 23 Jan 2024 18:41:29 +0000 Subject: [PATCH 18/18] Finish fixing build --- .github/workflows/release.yml | 4 ++-- .github/workflows/test.yml | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3db7e35..80e8943 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,10 +41,10 @@ jobs: token: ${{ github.token }} github-binarycache: true - - name: Make Release + - name: Make Release Windows if: matrix.os == 'windows-latest' run: |- - $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows\lib" + $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows-release\lib" make release - name: Make Release diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6fee77c..62c8f88 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,16 +41,10 @@ jobs: token: ${{ github.token }} github-binarycache: true - - name: Make Test + - name: Make Test Windows if: matrix.os == 'windows-latest' run: |- $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows-release\lib" - ls - ls .\vcpkg - ls .\vcpkg\packages - ls .\vcpkg\packages\libsodium_x64-windows-release - ls .\vcpkg\packages\libsodium_x64-windows-release\lib - ls $SODIUM_LIB_DIR make test - name: Make Test