Skip to content

Commit

Permalink
feat(): fixing failing tests from change
Browse files Browse the repository at this point in the history
  • Loading branch information
Christiantyemele committed Nov 27, 2024
1 parent ad33cab commit 7bbe8d2
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 69 deletions.
189 changes: 135 additions & 54 deletions crates/keystore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,35 @@ use tokio::{runtime::EnterGuard, sync::RwLock};
static SECRETS_COLLECTION: OnceCell<Collection<Secrets>> = OnceCell::new();
#[async_trait]
pub trait Material {
async fn securestore(&self, secret: Secrets) -> Result<Secrets, RepositoryError>;
async fn find_one_by(&self, kid: String) -> Result<Option<Secrets>, RepositoryError>;
async fn securestore(
&self,
secret: Secrets,
master_key: [u8; 32],
) -> Result<Secrets, RepositoryError>;
async fn find_one_by(
&self,
kid: String,
master_key: [u8; 32],
) -> Result<Option<Secrets>, RepositoryError>;
}

#[async_trait]
impl Material for SecretStore {
async fn securestore(&self, secret: Secrets) -> Result<Secrets, RepositoryError> {
async fn securestore(
&self,
secret: Secrets,
master_key: [u8; 32],
) -> Result<Secrets, RepositoryError> {
// read master key for encryption
let master_key = std::env::var("MASTER_KEY").unwrap_or_default();
let master_key = master_key;

let mut secret = secret;

let seed = &[0; 32];
let secret_material = secret.secret_material.as_bytes();
let mut cocoon = MiniCocoon::from_key(master_key.as_bytes(), seed);
let wrapped_key = cocoon.wrap(secret_material).unwrap_or_default();
secret.secret_material = String::from_utf8(wrapped_key).unwrap_or_default();
let secret_material = secret.secret_material;
let mut cocoon = MiniCocoon::from_key(&master_key, seed);
let wrapped_key = cocoon.wrap(&secret_material).unwrap_or_default();
secret.secret_material = wrapped_key;

// Insert the new entity into the database
let metadata = self
Expand All @@ -51,7 +63,11 @@ impl Material for SecretStore {
Ok(secret)
}

async fn find_one_by(&self, kid: String) -> Result<Option<Secrets>, RepositoryError> {
async fn find_one_by(
&self,
kid: String,
master_key: [u8; 32],
) -> Result<Option<Secrets>, RepositoryError> {
let collection = self.keystore.clone();

let secret = collection
Expand All @@ -60,13 +76,11 @@ impl Material for SecretStore {
.await?;
if let Some(mut secrets) = secret {
let wrapped_secret_material = secrets.secret_material;
let master_key = std::env::var("MASTER_KEY").unwrap_or_default();
let master_key = master_key;
let seed = &[0; 32];
let cocoon = MiniCocoon::from_key(master_key.as_bytes(), seed);
let unwrap_secret = cocoon
.unwrap(wrapped_secret_material.as_bytes())
.unwrap_or_default();
secrets.secret_material = String::from_utf8(unwrap_secret).unwrap_or_default();
let cocoon = MiniCocoon::from_key(&master_key, seed);
let unwrap_secret = cocoon.unwrap(&wrapped_secret_material).unwrap_or_default();
secrets.secret_material = unwrap_secret;
Ok(Some(secrets))
} else {
Ok(None)
Expand All @@ -93,7 +107,7 @@ pub struct Secrets {

pub kid: String,

pub secret_material: String,
pub secret_material: Vec<u8>,
}

impl Identifiable for Secrets {
Expand Down Expand Up @@ -166,25 +180,14 @@ where
}
}

#[async_trait]
impl Repository<Secrets> for SecretStore {
fn get_collection(&self) -> Arc<RwLock<Collection<Secrets>>> {
Arc::new(RwLock::new(self.keystore.collection.clone()))
}

async fn store(&self, entity: Secrets) -> Result<Secrets, RepositoryError> {
let secrets = self.securestore(entity).await?;
Ok(secrets)
}
}

#[cfg(any(test, feature = "test-utils"))]
pub mod tests {
use super::*;
use database::{Repository, RepositoryError};
use did_utils::jwk::Key;
use mongodb::bson::{doc, Bson, Document};
use rand::Rng;
use serde_json::json;
use serde_json::{json, to_string, Value};
use std::{borrow::Borrow, collections::HashMap, sync::RwLock};

#[derive(Default)]
Expand Down Expand Up @@ -271,26 +274,31 @@ pub mod tests {

#[async_trait]
impl Material for MockSecretStore {
async fn securestore(&self, secrets: Secrets) -> Result<Secrets, RepositoryError> {
// read master key for encryption
// let master_key = "masterkey".to_string();
let master_key = rand::thread_rng().gen::<[u8; 32]>();

async fn securestore(
&self,
secrets: Secrets,
master_key: [u8; 32],
) -> Result<Secrets, RepositoryError> {
let mut secret = secrets;

let seed = &[0; 32];
let secret_material = secret.secret_material.as_bytes();
let secret_material = secret.secret_material;
let mut cocoon = MiniCocoon::from_key(&master_key, seed);
let wrapped_key = cocoon.wrap(secret_material).unwrap();
secret.secret_material = String::from_utf8(wrapped_key.clone()).unwrap();
let a= String::from_utf8(wrapped_key).unwrap();

let wrapped_key = cocoon.wrap(&secret_material).unwrap();

secret.secret_material = wrapped_key;

// Insert the new entity into the database
self.keystore.write().unwrap().push(secret.clone());
Ok(secret)
}

async fn find_one_by(&self, kid: String) -> Result<Option<Secrets>, RepositoryError> {
async fn find_one_by(
&self,
kid: String,
master_key: [u8; 32],
) -> Result<Option<Secrets>, RepositoryError> {
let secret = self
.keystore
.read()
Expand All @@ -305,14 +313,12 @@ pub mod tests {
.cloned();

if let Some(mut secrets) = secret {
let wrapped_secret_material = secrets.secret_material;
let master_key = "masterkey".to_string();
let wrapped_secret_material = &secrets.secret_material;
let seed = &[0; 32];
let cocoon = MiniCocoon::from_key(master_key.as_bytes(), seed);
let unwrap_secret = cocoon
.unwrap(wrapped_secret_material.as_bytes())
.unwrap_or_default();
secrets.secret_material = String::from_utf8(unwrap_secret).unwrap_or_default();
let cocoon = MiniCocoon::from_key(&master_key, seed);
let unwrap_secret = cocoon.unwrap(&wrapped_secret_material).unwrap();
secrets.secret_material = unwrap_secret;

Ok(Some(secrets))
} else {
Ok(None)
Expand Down Expand Up @@ -340,14 +346,12 @@ pub mod tests {
}"#,
)
.unwrap();
let secret1 = serde_json::to_string(&secret1).unwrap();
let secret1 = serde_json::to_vec(&secret1).unwrap();

let secret1 = String::from_utf8(secret1).unwrap_or_default();

let secret2 = serde_json::to_string(&secret2).unwrap();
let secret2 = serde_json::to_vec(&secret2).unwrap();

let secret2 = String::from_utf8(secret2).unwrap_or_default();

let secrets = vec![
Secrets {
id: Some(ObjectId::new()),
Expand All @@ -362,10 +366,6 @@ pub mod tests {
];

let keystore = MockKeyStore::new(vec![]);
let secretstore = MockSecretStore::new(vec![]);
secretstore.securestore(secrets[0].clone()).await.unwrap();
secretstore.securestore(secrets[1].clone()).await.unwrap();


keystore.store(secrets[0].clone()).await.unwrap();
keystore.store(secrets[1].clone()).await.unwrap();
Expand All @@ -390,4 +390,85 @@ pub mod tests {

assert_eq!(keystore.find_all().await.unwrap(), vec![secrets[1].clone()]);
}
#[tokio::test]
async fn test_secretstore_flow() {
let secret1: Jwk = serde_json::from_str(
r#"{
"kty": "OKP",
"crv": "X25519",
"x": "SHSUZ6V3x355FqCzIUfgoPzrZB0BQs0JKyag4UfMqHQ",
"d": "0A8SSFkGHg3N9gmVDRnl63ih5fcwtEvnQu9912SVplY"
}"#,
)
.unwrap();

let secret2: Jwk = serde_json::from_str(
r#"{
"kty": "OKP",
"crv": "Ed25519",
"x": "Z0GqpN71rMcnAkky6_J6Bfknr8B-TBsekG3qdI0EQX4",
"d": "fI1u4riKKd99eox08GlThknq-vEJXcKBI28aiUqArLo"
}"#,
)
.unwrap();
let secret1 = serde_json::to_string(&secret1).unwrap();
let secret1 = serde_json::to_vec(&secret1).unwrap();

let secret2 = serde_json::to_string(&secret2).unwrap();
let secret2 = serde_json::to_vec(&secret2).unwrap();
let secrets = vec![
Secrets {
id: Some(ObjectId::new()),
kid: "1".to_string(),
secret_material: secret1.clone(),
},
Secrets {
id: Some(ObjectId::new()),
kid: "2".to_string(),
secret_material: secret2.clone(),
},
];

let master_key = rand::thread_rng().gen::<[u8; 32]>();
let secretstore = MockSecretStore::new(vec![]);
let secret = secretstore
.securestore(secrets[0].clone(), master_key)
.await
.unwrap();

assert_ne!(secret.secret_material, secret1);

let secret = secretstore
.securestore(secrets[1].clone(), master_key)
.await
.unwrap();
assert_ne!(secret.secret_material, secret2);

let secret = secretstore
.find_one_by("1".to_string(), master_key)
.await
.unwrap();

assert_eq!(secret.unwrap().secret_material, secret1);
let secret = secretstore
.find_one_by("2".to_string(), master_key)
.await
.unwrap();
assert_eq!(secret.clone().unwrap().secret_material, secret2);

let parsed_secret: serde_json::Value =
serde_json::from_slice(&secret.unwrap().secret_material).unwrap();
let parsed_secret = parsed_secret.as_str().unwrap();
let secret2 = r#"{
"kty": "OKP",
"crv": "Ed25519",
"x": "Z0GqpN71rMcnAkky6_J6Bfknr8B-TBsekG3qdI0EQX4",
"d": "fI1u4riKKd99eox08GlThknq-vEJXcKBI28aiUqArLo"
}"#;
let secret2: Value = serde_json::from_value(json!(secret2)).unwrap();
let jwk: Jwk = serde_json::from_str(parsed_secret).unwrap();
let jwk: String = serde_json::to_string(&jwk).unwrap();

assert_eq!(jwk, secret2.as_str().unwrap())
}
}
52 changes: 44 additions & 8 deletions crates/web-plugins/did-endpoint/src/didgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub fn didgen<K, F>(
server_public_domain: &str,
keystore: &K,
filesystem: &mut F,
master_key: [u8; 32],
) -> Result<Document, Error>
where
K: Repository<Secrets>,
Expand Down Expand Up @@ -78,8 +79,20 @@ where
.map_err(|_| Error::KeyConversionError)?;

// Store authentication and agreement keys in the keystore.
store_key(auth_keys_jwk, &diddoc, &diddoc.authentication, keystore)?;
store_key(agreem_keys_jwk, &diddoc, &diddoc.key_agreement, keystore)?;
store_key(
auth_keys_jwk,
&diddoc,
master_key,
&diddoc.authentication,
keystore,
)?;
store_key(
agreem_keys_jwk,
&diddoc,
master_key,
&diddoc.key_agreement,
keystore,
)?;

// Serialize DID document and persist to filesystem
persist_did_document(storage_dirpath, &diddoc, filesystem)?;
Expand Down Expand Up @@ -107,13 +120,13 @@ fn generate_did_document(
fn store_key<S>(
key: Jwk,
diddoc: &Document,
master_key: [u8; 32],
field: &Option<Vec<VerificationMethodType>>,
keystore: &S,
) -> Result<(), Error>
where
S: Repository<Secrets>,
S: Material

S: Material,
{
// Extract key ID from the DID document
let kid = match field.as_ref().unwrap()[0].clone() {
Expand All @@ -122,7 +135,6 @@ where
};
let kid = util::handle_vm_id(&kid, diddoc);
let key = serde_json::to_vec(&key).unwrap_or_default();
let key = String::from_utf8(key).unwrap_or_default();

// Create Secrets for the key
let secret = Secrets {
Expand All @@ -134,7 +146,7 @@ where
// Store the secret in the keystore
task::block_in_place(move || {
Handle::current().block_on(async move {
match keystore.securestore(secret).await {
match keystore.securestore(secret, master_key).await {
Ok(_) => tracing::info!("Successfully stored secret."),
Err(error) => tracing::error!("Error storing secret: {:?}", error),
}
Expand Down Expand Up @@ -229,6 +241,7 @@ where
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use axum::async_trait;
use database::RepositoryError;
use filesystem::FileSystem;
use mockall::{
Expand Down Expand Up @@ -299,12 +312,35 @@ pub(crate) mod tests {
.expect_store()
.times(2)
.returning(move |_| Ok(secret.clone()));
let master_key = [0; 32];

let result = didgen(&path, "https://example.com", &mock_keystore, &mut mock_fs);
let result = didgen(
&path,
"https://example.com",
&mock_keystore,
&mut mock_fs,
master_key,
);

assert!(result.is_ok());
}

#[async_trait]
impl Material for MockKeystore {
async fn find_one_by(
&self,
_kid: String,
_master_key: [u8; 32],
) -> Result<Option<Secrets>, RepositoryError> {
todo!()
}
async fn securestore(
&self,
_secret: Secrets,
_master_key: [u8; 32],
) -> Result<Secrets, RepositoryError> {
todo!()
}
}
#[tokio::test(flavor = "multi_thread")]
async fn test_did_validation() {
let mut mock_fs = MockFileSystem::new();
Expand Down
Loading

0 comments on commit 7bbe8d2

Please sign in to comment.