feat: Add support for sqlcipher

This commit is contained in:
benthecarman
2025-03-08 21:58:29 -06:00
parent b787951dbc
commit 40c53e83df
12 changed files with 93 additions and 1 deletions

View File

@@ -5,7 +5,10 @@ use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
use sqlx::{Error, Pool, Sqlite};
#[inline(always)]
pub async fn create_sqlite_pool(path: &str) -> Result<Pool<Sqlite>, Error> {
pub async fn create_sqlite_pool(
path: &str,
#[cfg(feature = "sqlcipher")] password: String,
) -> Result<Pool<Sqlite>, Error> {
let db_options = SqliteConnectOptions::from_str(path)?
.busy_timeout(Duration::from_secs(10))
.read_only(false)
@@ -17,6 +20,9 @@ pub async fn create_sqlite_pool(path: &str) -> Result<Pool<Sqlite>, Error> {
.shared_cache(true)
.create_if_missing(true);
#[cfg(feature = "sqlcipher")]
let db_options = db_options.pragma("key", password);
let pool = SqlitePoolOptions::new()
.min_connections(1)
.max_connections(1)

View File

@@ -12,7 +12,10 @@ use super::MintSqliteDatabase;
/// Creates a new in-memory [`MintSqliteDatabase`] instance
pub async fn empty() -> Result<MintSqliteDatabase, database::Error> {
#[cfg(not(feature = "sqlcipher"))]
let db = MintSqliteDatabase::new(":memory:").await?;
#[cfg(feature = "sqlcipher")]
let db = MintSqliteDatabase::new(":memory:", "memory".to_string()).await?;
db.migrate().await;
Ok(db)
}

View File

@@ -68,12 +68,25 @@ impl MintSqliteDatabase {
}
/// Create new [`MintSqliteDatabase`]
#[cfg(not(feature = "sqlcipher"))]
pub async fn new<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
Ok(Self {
pool: create_sqlite_pool(path.as_ref().to_str().ok_or(Error::InvalidDbPath)?).await?,
})
}
/// Create new [`MintSqliteDatabase`]
#[cfg(feature = "sqlcipher")]
pub async fn new<P: AsRef<Path>>(path: P, password: String) -> Result<Self, Error> {
Ok(Self {
pool: create_sqlite_pool(
path.as_ref().to_str().ok_or(Error::InvalidDbPath)?,
password,
)
.await?,
})
}
/// Migrate [`MintSqliteDatabase`]
pub async fn migrate(&self) {
sqlx::migrate!("./src/mint/migrations")

View File

@@ -33,12 +33,25 @@ pub struct WalletSqliteDatabase {
impl WalletSqliteDatabase {
/// Create new [`WalletSqliteDatabase`]
#[cfg(not(feature = "sqlcipher"))]
pub async fn new<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
Ok(Self {
pool: create_sqlite_pool(path.as_ref().to_str().ok_or(Error::InvalidDbPath)?).await?,
})
}
/// Create new [`WalletSqliteDatabase`]
#[cfg(feature = "sqlcipher")]
pub async fn new<P: AsRef<Path>>(path: P, password: String) -> Result<Self, Error> {
Ok(Self {
pool: create_sqlite_pool(
path.as_ref().to_str().ok_or(Error::InvalidDbPath)?,
password,
)
.await?,
})
}
/// Migrate [`WalletSqliteDatabase`]
pub async fn migrate(&self) {
sqlx::migrate!("./src/wallet/migrations")
@@ -954,3 +967,32 @@ fn sqlite_row_to_proof_info(row: &SqliteRow) -> Result<ProofInfo, Error> {
unit: CurrencyUnit::from_str(&row_unit).map_err(Error::from)?,
})
}
#[cfg(test)]
mod tests {
use std::env::temp_dir;
#[tokio::test]
#[cfg(feature = "sqlcipher")]
async fn test_sqlcipher() {
use super::*;
let path = std::env::temp_dir()
.to_path_buf()
.join(format!("cdk-test-{}.sqlite", uuid::Uuid::new_v4()));
let db = WalletSqliteDatabase::new(path, "password".to_string())
.await
.unwrap();
db.migrate().await;
// do something simple to test the database
let pk = PublicKey::from_hex(
"02194603ffa36356f4a56b7df9371fc3192472351453ec7398b8da8117e7c3e104",
)
.unwrap();
let last_checked = 6969;
db.add_nostr_last_checked(pk, last_checked).await.unwrap();
let res = db.get_nostr_last_checked(&pk).await.unwrap();
assert_eq!(res, Some(last_checked));
}
}