rewrite CryptoKeys with Storage abstraction

This commit is contained in:
Quentin 2023-11-21 09:56:31 +01:00
parent bd6c3464e6
commit 6e8b2cfc9f
Signed by: quentin
GPG key ID: E9602264D639FF68
4 changed files with 38 additions and 84 deletions

View file

@ -6,13 +6,7 @@ use std::sync::Arc;
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use async_trait::async_trait; use async_trait::async_trait;
use k2v_client::{
BatchInsertOp, BatchReadOp, CausalValue, CausalityToken, Filter, K2vClient, K2vValue,
};
use rand::prelude::*; use rand::prelude::*;
use rusoto_core::HttpClient;
use rusoto_credential::{AwsCredentials, StaticProvider};
use rusoto_s3::S3Client;
use crate::cryptoblob::*; use crate::cryptoblob::*;
use crate::storage::*; use crate::storage::*;
@ -90,12 +84,12 @@ impl Credentials {
impl CryptoKeys { impl CryptoKeys {
pub async fn init( pub async fn init(
storage: &StorageCredentials, storage: &Builders,
user_secrets: &UserSecrets, user_secrets: &UserSecrets,
password: &str, password: &str,
) -> Result<Self> { ) -> Result<Self> {
// Check that salt and public don't exist already // Check that salt and public don't exist already
let k2v = storage.k2v_client()?; let k2v = storage.row_store()?;
let (salt_ct, public_ct) = Self::check_uninitialized(&k2v).await?; let (salt_ct, public_ct) = Self::check_uninitialized(&k2v).await?;
// Generate salt for password identifiers // Generate salt for password identifiers
@ -140,12 +134,12 @@ impl CryptoKeys {
} }
pub async fn init_without_password( pub async fn init_without_password(
storage: &StorageCredentials, storage: &Builders,
master: &Key, master: &Key,
secret: &SecretKey, secret: &SecretKey,
) -> Result<Self> { ) -> Result<Self> {
// Check that salt and public don't exist already // Check that salt and public don't exist already
let k2v = storage.k2v_client()?; let k2v = storage.row_store()?;
let (salt_ct, public_ct) = Self::check_uninitialized(&k2v).await?; let (salt_ct, public_ct) = Self::check_uninitialized(&k2v).await?;
// Generate salt for password identifiers // Generate salt for password identifiers
@ -172,7 +166,7 @@ impl CryptoKeys {
} }
pub async fn open( pub async fn open(
storage: &StorageCredentials, storage: &Builders,
user_secrets: &UserSecrets, user_secrets: &UserSecrets,
password: &str, password: &str,
) -> Result<Self> { ) -> Result<Self> {
@ -215,11 +209,11 @@ impl CryptoKeys {
} }
pub async fn open_without_password( pub async fn open_without_password(
storage: &StorageCredentials, storage: &Builders,
master: &Key, master: &Key,
secret: &SecretKey, secret: &SecretKey,
) -> Result<Self> { ) -> Result<Self> {
let k2v = storage.k2v_client()?; let k2v = storage.row_store()?;
let (_ident_salt, expected_public) = Self::load_salt_and_public(&k2v).await?; let (_ident_salt, expected_public) = Self::load_salt_and_public(&k2v).await?;
// Create CryptoKeys struct from given keys // Create CryptoKeys struct from given keys
@ -240,11 +234,11 @@ impl CryptoKeys {
pub async fn add_password( pub async fn add_password(
&self, &self,
storage: &StorageCredentials, storage: &Builders,
user_secrets: &UserSecrets, user_secrets: &UserSecrets,
password: &str, password: &str,
) -> Result<()> { ) -> Result<()> {
let k2v = storage.k2v_client()?; let k2v = storage.row_store()?;
let (ident_salt, _public) = Self::load_salt_and_public(&k2v).await?; let (ident_salt, _public) = Self::load_salt_and_public(&k2v).await?;
// Generate short password digest (= password identity) // Generate short password digest (= password identity)
@ -289,11 +283,11 @@ impl CryptoKeys {
} }
pub async fn delete_password( pub async fn delete_password(
storage: &StorageCredentials, storage: &Builders,
password: &str, password: &str,
allow_delete_all: bool, allow_delete_all: bool,
) -> Result<()> { ) -> Result<()> {
let k2v = storage.k2v_client()?; let k2v = storage.row_client()?;
let (ident_salt, _public) = Self::load_salt_and_public(&k2v).await?; let (ident_salt, _public) = Self::load_salt_and_public(&k2v).await?;
// Generate short password digest (= password identity) // Generate short password digest (= password identity)
@ -322,47 +316,32 @@ impl CryptoKeys {
// ---- STORAGE UTIL ---- // ---- STORAGE UTIL ----
async fn check_uninitialized( async fn check_uninitialized(
k2v: &K2vClient, k2v: &RowStore,
) -> Result<(Option<CausalityToken>, Option<CausalityToken>)> { ) -> Result<(RowRef, RowRef)> {
let params = k2v let params = k2v
.read_batch(&[ .select(Selector::List(vec![
k2v_read_single_key("keys", "salt", true), ("keys", "salt"),
k2v_read_single_key("keys", "public", true), ("keys", "public"),
]) ]))
.await .await
.context("ReadBatch for salt and public in check_uninitialized")?; .context("ReadBatch for salt and public in check_uninitialized")?;
if params.len() != 2 { if params.len() != 2 {
bail!( bail!(
"Invalid response from k2v storage: {:?} (expected two items)", "Invalid response from k2v storage: {:?} (expected two items)",
params params
); );
} }
if params[0].items.len() > 1 || params[1].items.len() > 1 {
bail!( let salt_ct = params[0].to_ref();
"invalid response from k2v storage: {:?} (several items in single_item read)", if params[0].content().iter().any(|x| matches!(x, Alternative::Value(_))) {
params bail!("key storage already initialized");
);
} }
let salt_ct = match params[0].items.iter().next() { let public_ct = params[1].to_ref();
None => None, if params[1].content().iter().any(|x| matches!(x, Alternative::Value(_))) {
Some((_, CausalValue { causality, value })) => { bail!("key storage already initialized");
if value.iter().any(|x| matches!(x, K2vValue::Value(_))) { }
bail!("key storage already initialized");
}
Some(causality.clone())
}
};
let public_ct = match params[1].items.iter().next() {
None => None,
Some((_, CausalValue { causality, value })) => {
if value.iter().any(|x| matches!(x, K2vValue::Value(_))) {
bail!("key storage already initialized");
}
Some(causality.clone())
}
};
Ok((salt_ct, public_ct)) Ok((salt_ct, public_ct))
} }
@ -511,37 +490,3 @@ pub fn argon2_kdf(salt: &[u8], password: &[u8], output_len: usize) -> Result<Vec
assert!(hash.len() == output_len); assert!(hash.len() == output_len);
Ok(hash.as_bytes().to_vec()) Ok(hash.as_bytes().to_vec())
} }
pub fn k2v_read_single_key<'a>(
partition_key: &'a str,
sort_key: &'a str,
tombstones: bool,
) -> BatchReadOp<'a> {
BatchReadOp {
partition_key,
filter: Filter {
start: Some(sort_key),
end: None,
prefix: None,
limit: None,
reverse: false,
},
conflicts_only: false,
tombstones,
single_item: true,
}
}
pub fn k2v_insert_single_key<'a>(
partition_key: &'a str,
sort_key: &'a str,
causality: Option<CausalityToken>,
value: impl AsRef<[u8]>,
) -> BatchInsertOp<'a> {
BatchInsertOp {
partition_key,
sort_key,
causality,
value: K2vValue::Value(value.as_ref().to_vec()),
}
}

View file

@ -85,7 +85,11 @@ impl IRowValue for GrgValue {
} }
} }
impl std::fmt::Debug for GrgValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unimplemented!();
}
}
/* /*

View file

@ -90,4 +90,8 @@ impl IRowValue for MemValue {
} }
} }
impl std::fmt::Debug for MemValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unimplemented!();
}
}

View file

@ -44,6 +44,7 @@ impl std::fmt::Display for StorageError {
match self { match self {
Self::NotFound => f.write_str("Item not found"), Self::NotFound => f.write_str("Item not found"),
Self::Internal => f.write_str("An internal error occured"), Self::Internal => f.write_str("An internal error occured"),
Self::IncompatibleOrphan => f.write_str("Incompatible orphan"),
} }
} }
} }
@ -110,7 +111,7 @@ pub type RowRef = Box<dyn IRowRef + Send + Sync>;
}*/ }*/
pub trait IRowValue pub trait IRowValue: std::fmt::Debug
{ {
fn to_ref(&self) -> RowRef; fn to_ref(&self) -> RowRef;
fn content(&self) -> ConcurrentValues; fn content(&self) -> ConcurrentValues;