Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add key manager unit tests, add Web5Error::Mutex #304

Merged
merged 5 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions bindings/web5_uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use web5_uniffi_wrapper::{
did::Did,
methods::{
did_dht::{did_dht_resolve, DidDht},
did_jwk::{did_jwk_resolve, DidJwk},
did_jwk::{did_jwk_create, did_jwk_resolve, DidJwkCreateOptions},
did_web::{did_web_resolve, DidWeb},
},
portable_did::PortableDid,
Expand All @@ -36,10 +36,7 @@ use web5::{
verification_method::VerificationMethod as VerificationMethodData,
},
did::Did as DidData,
methods::{
did_dht::DidDht as DidDhtData, did_jwk::DidJwk as DidJwkData,
did_web::DidWeb as DidWebData,
},
methods::{did_dht::DidDht as DidDhtData, did_web::DidWeb as DidWebData},
portable_did::PortableDid as PortableDidData,
resolution::{
document_metadata::DocumentMetadata as DocumentMetadataData,
Expand Down
26 changes: 12 additions & 14 deletions bindings/web5_uniffi/src/web5.udl
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
namespace web5 {
JwkData ed25519_generator_generate();

[Throws=Web5Error]
BearerDid did_jwk_create(DidJwkCreateOptions? options);
ResolutionResult did_jwk_resolve([ByRef] string uri);

[Async, Throws=Web5Error]
ResolutionResult did_web_resolve([ByRef] string uri);
[Throws=Web5Error]
Expand Down Expand Up @@ -31,21 +34,24 @@ interface Jwk {

[Trait, WithForeign]
interface KeyManager {
[Throws=Web5Error]
JwkData import_private_jwk(JwkData private_jwk);
[Throws=Web5Error]
Signer get_signer(JwkData public_jwk);
};

interface InMemoryKeyManager {
constructor();
[Throws=Web5Error]
Signer get_signer(JwkData public_jwk);
JwkData import_private_jwk(JwkData private_jwk);
[Throws=Web5Error]
JwkData import_private_jwk(JwkData private_key);
Signer get_signer(JwkData public_jwk);
KeyManager get_as_key_manager();
};

enum Dsa {
"Ed25519"
"Ed25519",
"Secp256k1"
};

[Trait, WithForeign]
Expand Down Expand Up @@ -158,17 +164,9 @@ interface ResolutionResult {
ResolutionResultData get_data();
};

dictionary DidJwkData {
DidData did;
DocumentData document;
};

interface DidJwk {
[Name=from_public_jwk, Throws=Web5Error]
constructor(JwkData public_jwk);
[Name=from_uri, Throws=Web5Error]
constructor([ByRef] string uri);
DidJwkData get_data();
dictionary DidJwkCreateOptions {
KeyManager? key_manager;
Dsa? dsa;
};

dictionary DidWebData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use web5::crypto::{
jwk::Jwk,
key_managers::{
in_memory_key_manager::InMemoryKeyManager as InnerInMemoryKeyManager,
key_manager::KeyManager as InnerKeyManager,
KeyManager as InnerKeyManager,
},
};

Expand All @@ -30,6 +30,10 @@ impl InMemoryKeyManager {
}

impl KeyManager for InMemoryKeyManager {
fn import_private_jwk(&self, private_jwk: Jwk) -> Result<Jwk> {
Ok(self.0.import_private_jwk(private_jwk)?)
}

fn get_signer(&self, public_jwk: Jwk) -> Result<Arc<dyn Signer>> {
let signer = self.0.get_signer(public_jwk)?;
let outer_signer = ToOuterSigner(signer);
Expand Down
13 changes: 11 additions & 2 deletions bindings/web5_uniffi_wrapper/src/crypto/key_manager.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
use super::dsa::{Signer, ToInnerSigner, ToOuterSigner};
use crate::errors::Result;
use std::sync::Arc;
use web5::crypto::{jwk::Jwk, key_managers::key_manager::KeyManager as InnerKeyManager};
use web5::crypto::{jwk::Jwk, key_managers::KeyManager as InnerKeyManager};

pub trait KeyManager: Send + Sync {
fn import_private_jwk(&self, private_jwk: Jwk) -> Result<Jwk>;
fn get_signer(&self, public_jwk: Jwk) -> Result<Arc<dyn Signer>>;
}

pub struct ToOuterKeyManager(pub Arc<dyn InnerKeyManager>);

impl KeyManager for ToOuterKeyManager {
fn import_private_jwk(&self, private_jwk: Jwk) -> Result<Jwk> {
Ok(self.0.import_private_jwk(private_jwk)?)
}

fn get_signer(&self, public_jwk: Jwk) -> Result<Arc<dyn Signer>> {
let signer = self.0.get_signer(public_jwk)?;
let outer_signer = ToOuterSigner(signer);
Expand All @@ -20,10 +25,14 @@ impl KeyManager for ToOuterKeyManager {
pub struct ToInnerKeyManager(pub Arc<dyn KeyManager>);

impl InnerKeyManager for ToInnerKeyManager {
fn import_private_jwk(&self, private_jwk: Jwk) -> web5::errors::Result<Jwk> {
Ok(self.0.import_private_jwk(private_jwk)?)
}

fn get_signer(
&self,
public_jwk: Jwk,
) -> web5::crypto::key_managers::Result<Arc<dyn web5::crypto::dsa::Signer>> {
) -> web5::errors::Result<Arc<dyn web5::crypto::dsa::Signer>> {
let outer_signer = self.0.get_signer(public_jwk)?;
let inner_signer = Arc::new(ToInnerSigner(outer_signer));
Ok(inner_signer)
Expand Down
38 changes: 24 additions & 14 deletions bindings/web5_uniffi_wrapper/src/dids/methods/did_jwk.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
use crate::{dids::resolution::resolution_result::ResolutionResult, errors::Result};
use crate::{
crypto::key_manager::{KeyManager, ToInnerKeyManager},
dids::{bearer_did::BearerDid, resolution::resolution_result::ResolutionResult},
errors::Result,
};
use std::sync::Arc;
use web5::{crypto::jwk::Jwk, dids::methods::did_jwk::DidJwk as InnerDidJwk};
use web5::{
crypto::dsa::Dsa,
dids::methods::did_jwk::{DidJwk as InnerDidJwk, DidJwkCreateOptions as InnerCreateOptions},
};

pub struct DidJwk(pub InnerDidJwk);

Expand All @@ -9,18 +16,21 @@ pub fn did_jwk_resolve(uri: &str) -> Arc<ResolutionResult> {
Arc::new(ResolutionResult(resolution_result))
}

impl DidJwk {
pub fn from_public_jwk(public_key: Jwk) -> Result<Self> {
let did_jwk = InnerDidJwk::from_public_jwk(public_key)?;
Ok(Self(did_jwk))
}
#[derive(Default)]
pub struct DidJwkCreateOptions {
pub key_manager: Option<Arc<dyn KeyManager>>,
pub dsa: Option<Dsa>,
}

pub fn from_uri(uri: &str) -> Result<Self> {
let did_jwk = InnerDidJwk::from_uri(uri)?;
Ok(Self(did_jwk))
}
pub fn did_jwk_create(options: Option<DidJwkCreateOptions>) -> Result<Arc<BearerDid>> {
let inner_options = options.map(|o| InnerCreateOptions {
dsa: o.dsa,
key_manager: match o.key_manager {
None => None,
Some(km) => Some(Arc::new(ToInnerKeyManager(km))),
},
});

pub fn get_data(&self) -> InnerDidJwk {
self.0.clone()
}
let inner_bearer_did = InnerDidJwk::create(inner_options)?;
Ok(Arc::new(BearerDid(inner_bearer_did)))
}
49 changes: 9 additions & 40 deletions bindings/web5_uniffi_wrapper/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::{any::type_name, fmt::Debug};
use thiserror::Error;
use web5::credentials::presentation_definition::PexError;
use web5::credentials::CredentialError;
use web5::crypto::key_managers::KeyManagerError;
use web5::dids::bearer_did::BearerDidError;
use web5::dids::methods::MethodError;
use web5::errors::Web5Error as InnerWeb5Error;
Expand Down Expand Up @@ -76,12 +75,6 @@ where
variant_name.to_string()
}

impl From<KeyManagerError> for Web5Error {
fn from(error: KeyManagerError) -> Self {
Web5Error::new(error)
}
}

impl From<MethodError> for Web5Error {
fn from(error: MethodError) -> Self {
Web5Error::new(error)
Expand Down Expand Up @@ -112,45 +105,21 @@ impl From<SerdeJsonError> for Web5Error {
}
}

impl From<Web5Error> for KeyManagerError {
fn from(error: Web5Error) -> Self {
let variant = error.variant();
let msg = error.msg();

if variant == variant_name(&KeyManagerError::KeyGenerationFailed) {
return KeyManagerError::KeyGenerationFailed;
} else if variant
== variant_name(&KeyManagerError::InternalKeyStoreError(String::default()))
{
return KeyManagerError::InternalKeyStoreError(msg.to_string());
} else if variant == variant_name(&KeyManagerError::KeyNotFound(String::default())) {
return KeyManagerError::KeyNotFound(msg.to_string());
}

KeyManagerError::Unknown
}
}

impl From<Web5Error> for InnerWeb5Error {
fn from(error: Web5Error) -> Self {
let variant = error.variant();
let msg = error.msg();

if variant == variant_name(&InnerWeb5Error::Json(String::default())) {
return InnerWeb5Error::Json(msg);
} else if variant == variant_name(&InnerWeb5Error::Parameter(String::default())) {
return InnerWeb5Error::Parameter(msg);
} else if variant == variant_name(&InnerWeb5Error::DataMember(String::default())) {
return InnerWeb5Error::DataMember(msg);
} else if variant == variant_name(&InnerWeb5Error::NotFound(String::default())) {
return InnerWeb5Error::NotFound(msg);
} else if variant == variant_name(&InnerWeb5Error::Crypto(String::default())) {
return InnerWeb5Error::Crypto(msg);
} else if variant == variant_name(&InnerWeb5Error::Encoding(String::default())) {
return InnerWeb5Error::Encoding(msg);
match variant.as_str() {
"Json" => InnerWeb5Error::Json(msg),
"Parameter" => InnerWeb5Error::Parameter(msg),
"DataMember" => InnerWeb5Error::DataMember(msg),
"NotFound" => InnerWeb5Error::NotFound(msg),
"Crypto" => InnerWeb5Error::Crypto(msg),
"Encoding" => InnerWeb5Error::Encoding(msg),
"Mutex" => InnerWeb5Error::Mutex(msg),
_ => InnerWeb5Error::Unknown(format!("unknown variant {} with msg {}", variant, msg)),
}

InnerWeb5Error::Unknown(format!("unknown variant {} with msg {}", variant, msg))
}
}

Expand Down
33 changes: 15 additions & 18 deletions bound/kt/src/main/kotlin/web5/sdk/crypto/keys/InMemoryKeyManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,29 @@ import web5.sdk.rust.InMemoryKeyManager as RustCoreInMemoryKeyManager

/**
* A class for managing cryptographic keys in-memory.
*
* @param privateJwks A list of private keys represented as JWKs (JSON Web Keys).
*/
class InMemoryKeyManager : KeyManager {
class InMemoryKeyManager (privateJwks: List<Jwk>) : KeyManager {
private val rustCoreInMemoryKeyManager = RustCoreInMemoryKeyManager()

/**
* Constructs an InMemoryKeyManager with the given private keys.
*
* @param privateJwks A list of private keys represented as JWKs (JSON Web Keys).
*/
constructor(privateJwks: List<Jwk>) {
init {
privateJwks.forEach {
this.rustCoreInMemoryKeyManager.importPrivateJwk(it.rustCoreJwkData)
}
}

/**
* Imports a private key which may be stored somewhere such as environment variables.
*
* @param privateJwk The private key represented as a JWK.
* @return Jwk The public key represented as a JWK.
*/
override fun importPrivateJwk(privateJwk: Jwk): Jwk {
val rustCoreJwkData = this.rustCoreInMemoryKeyManager.importPrivateJwk(privateJwk.rustCoreJwkData)
return Jwk.fromRustCoreJwkData(rustCoreJwkData)
}

/**
* Returns the Signer for the given public key.
*
Expand All @@ -31,15 +39,4 @@ class InMemoryKeyManager : KeyManager {
val rustCoreSigner = this.rustCoreInMemoryKeyManager.getSigner(publicJwk.rustCoreJwkData)
return ToOuterSigner(rustCoreSigner)
}

/**
* Imports a private key which may be stored somewhere such as environment variables.
*
* @param privateJwk The private key represented as a JWK.
* @return Jwk The public key represented as a JWK.
*/
fun importPrivateJwk(privateJwk: Jwk): Jwk {
val rustCoreJwkData = this.rustCoreInMemoryKeyManager.importPrivateJwk(privateJwk.rustCoreJwkData)
return Jwk.fromRustCoreJwkData(rustCoreJwkData)
}
}
13 changes: 13 additions & 0 deletions bound/kt/src/main/kotlin/web5/sdk/crypto/keys/KeyManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,35 @@ package web5.sdk.crypto.keys
import web5.sdk.crypto.signers.ToOuterSigner
import web5.sdk.crypto.signers.Signer
import web5.sdk.crypto.signers.ToInnerSigner
import web5.sdk.rust.JwkData
import web5.sdk.rust.JwkData as RustCoreJwkData
import web5.sdk.rust.KeyManager as RustCoreKeyManager
import web5.sdk.rust.Signer as RustCoreSigner

interface KeyManager {
fun importPrivateJwk(privateJwk: Jwk): Jwk
fun getSigner(publicJwk: Jwk): Signer
}

internal class ToOuterKeyManager(private val rustCoreKeyManager: RustCoreKeyManager) : KeyManager {
override fun importPrivateJwk(privateJwk: Jwk): Jwk {
val rustCoreJwkData = rustCoreKeyManager.importPrivateJwk(privateJwk.rustCoreJwkData)
return Jwk.fromRustCoreJwkData(rustCoreJwkData)
}

override fun getSigner(publicJwk: Jwk): Signer {
val rustCoreSigner = rustCoreKeyManager.getSigner(publicJwk.rustCoreJwkData)
return ToOuterSigner(rustCoreSigner)
}
}

internal class ToInnerKeyManager(private val keyManager: KeyManager) : RustCoreKeyManager {
override fun importPrivateJwk(privateJwk: JwkData): JwkData {
val rustCoreJwkData = Jwk.fromRustCoreJwkData(privateJwk)
val jwk = keyManager.importPrivateJwk(rustCoreJwkData)
return jwk.rustCoreJwkData
}

override fun getSigner(publicJwk: RustCoreJwkData): RustCoreSigner {
val jwk = Jwk.fromRustCoreJwkData(publicJwk)
val signer = keyManager.getSigner(jwk)
Expand Down
Loading
Loading