Skip to content

Commit

Permalink
Merge branch 'main' into pr/frederikrothenberger/1408
Browse files Browse the repository at this point in the history
  • Loading branch information
itsyaasir committed Sep 9, 2024
2 parents 7b8676c + ba36609 commit ea97960
Show file tree
Hide file tree
Showing 28 changed files with 1,258 additions and 138 deletions.
1 change: 1 addition & 0 deletions bindings/wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ async-trait = { version = "0.1", default-features = false }
bls12_381_plus = "0.8.17"
console_error_panic_hook = { version = "0.1" }
futures = { version = "0.3" }
identity_ecdsa_verifier = { path = "../../identity_ecdsa_verifier", default-features = false, features = ["es256", "es256k"] }
identity_eddsa_verifier = { path = "../../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
js-sys = { version = "0.3.61" }
json-proof-token = "0.3.4"
Expand Down
355 changes: 270 additions & 85 deletions bindings/wasm/docs/api-reference.md

Large diffs are not rendered by default.

27 changes: 26 additions & 1 deletion bindings/wasm/examples/src/0_basic/2_resolve_did.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { IotaDocument, IotaIdentityClient, JwkMemStore, KeyIdMemStore, Storage } from "@iota/identity-wasm/node";
import {
CoreDocument,
DIDJwk,
IotaDocument,
IotaIdentityClient,
IToCoreDocument,
JwkMemStore,
KeyIdMemStore,
Resolver,
Storage,
} from "@iota/identity-wasm/node";
import { AliasOutput, Client, MnemonicSecretManager, Utils } from "@iota/sdk-wasm/node";
import { API_ENDPOINT, createDid } from "../util";

const DID_JWK: string =
"did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6ImFjYklRaXVNczNpOF91c3pFakoydHBUdFJNNEVVM3l6OTFQSDZDZEgyVjAiLCJ5IjoiX0tjeUxqOXZXTXB0bm1LdG00NkdxRHo4d2Y3NEk1TEtncmwyR3pIM25TRSJ9";

/** Demonstrates how to resolve an existing DID in an Alias Output. */
export async function resolveIdentity() {
const client = new Client({
Expand Down Expand Up @@ -34,4 +47,16 @@ export async function resolveIdentity() {
// We can also resolve the Alias Output directly.
const aliasOutput: AliasOutput = await didClient.resolveDidOutput(did);
console.log("The Alias Output holds " + aliasOutput.getAmount() + " tokens");

// did:jwk can be resolved as well.
const handlers = new Map<string, (did: string) => Promise<CoreDocument | IToCoreDocument>>();
handlers.set("jwk", didJwkHandler);
const resolver = new Resolver({ handlers });
const did_jwk_resolved_doc = await resolver.resolve(DID_JWK);
console.log(`DID ${DID_JWK} resolves to:\n ${JSON.stringify(did_jwk_resolved_doc, null, 2)}`);
}

const didJwkHandler = async (did: string) => {
let did_jwk = DIDJwk.parse(did);
return CoreDocument.expandDIDJwk(did_jwk);
};
6 changes: 3 additions & 3 deletions bindings/wasm/src/credential/domain_linkage_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ pub struct WasmJwtDomainLinkageValidator {
#[wasm_bindgen(js_class = JwtDomainLinkageValidator)]
impl WasmJwtDomainLinkageValidator {
/// Creates a new {@link JwtDomainLinkageValidator}. If a `signatureVerifier` is provided it will be used when
/// verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA`
/// algorithm will be used.
/// verifying decoded JWS signatures, otherwise a default verifier capable of handling the `EdDSA`, `ES256`, `ES256K`
/// algorithms will be used.
#[wasm_bindgen(constructor)]
#[allow(non_snake_case)]
pub fn new(signatureVerifier: IJwsVerifier) -> WasmJwtDomainLinkageValidator {
pub fn new(signatureVerifier: Option<IJwsVerifier>) -> WasmJwtDomainLinkageValidator {
let signature_verifier = WasmJwsVerifier::new(signatureVerifier);
WasmJwtDomainLinkageValidator {
validator: JwtDomainLinkageValidator::with_signature_verifier(signature_verifier),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ pub struct WasmJwtCredentialValidator(JwtCredentialValidator<WasmJwsVerifier>);
#[wasm_bindgen(js_class = JwtCredentialValidator)]
impl WasmJwtCredentialValidator {
/// Creates a new {@link JwtCredentialValidator}. If a `signatureVerifier` is provided it will be used when
/// verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA`
/// algorithm will be used.
/// verifying decoded JWS signatures, otherwise a default verifier capable of handling the `EdDSA`, `ES256`, `ES256K`
/// algorithms will be used.
#[wasm_bindgen(constructor)]
#[allow(non_snake_case)]
pub fn new(signatureVerifier: IJwsVerifier) -> WasmJwtCredentialValidator {
pub fn new(signatureVerifier: Option<IJwsVerifier>) -> WasmJwtCredentialValidator {
let signature_verifier = WasmJwsVerifier::new(signatureVerifier);
WasmJwtCredentialValidator(JwtCredentialValidator::with_signature_verifier(signature_verifier))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ pub struct WasmSdJwtCredentialValidator(SdJwtCredentialValidator<WasmJwsVerifier
#[wasm_bindgen(js_class = SdJwtCredentialValidator)]
impl WasmSdJwtCredentialValidator {
/// Creates a new `SdJwtCredentialValidator`. If a `signatureVerifier` is provided it will be used when
/// verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA`
/// algorithm will be used.
/// verifying decoded JWS signatures, otherwise a default verifier capable of handling the `EdDSA`, `ES256`, `ES256K`
/// algorithms will be used.
#[wasm_bindgen(constructor)]
#[allow(non_snake_case)]
pub fn new(signatureVerifier: IJwsVerifier) -> WasmSdJwtCredentialValidator {
pub fn new(signatureVerifier: Option<IJwsVerifier>) -> WasmSdJwtCredentialValidator {
let signature_verifier = WasmJwsVerifier::new(signatureVerifier);
WasmSdJwtCredentialValidator(SdJwtCredentialValidator::with_signature_verifier(
signature_verifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ pub struct WasmJwtPresentationValidator(JwtPresentationValidator<WasmJwsVerifier
#[wasm_bindgen(js_class = JwtPresentationValidator)]
impl WasmJwtPresentationValidator {
/// Creates a new {@link JwtPresentationValidator}. If a `signatureVerifier` is provided it will be used when
/// verifying decoded JWS signatures, otherwise the default which is only capable of handling the `EdDSA`
/// algorithm will be used.
/// verifying decoded JWS signatures, otherwise a default verifier capable of handling the `EdDSA`, `ES256`, `ES256K`
/// algorithms will be used.
#[wasm_bindgen(constructor)]
#[allow(non_snake_case)]
pub fn new(signatureVerifier: IJwsVerifier) -> WasmJwtPresentationValidator {
pub fn new(signatureVerifier: Option<IJwsVerifier>) -> WasmJwtPresentationValidator {
let signature_verifier = WasmJwsVerifier::new(signatureVerifier);
WasmJwtPresentationValidator(JwtPresentationValidator::with_signature_verifier(signature_verifier))
}
Expand Down
109 changes: 109 additions & 0 deletions bindings/wasm/src/credential/linked_verifiable_presentation_service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use crate::common::ArrayString;
use crate::did::WasmService;
use crate::error::Result;
use crate::error::WasmResult;
use identity_iota::core::Object;
use identity_iota::core::OneOrSet;
use identity_iota::core::Url;
use identity_iota::credential::LinkedVerifiablePresentationService;
use identity_iota::did::DIDUrl;
use identity_iota::document::Service;
use proc_typescript::typescript;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;

#[wasm_bindgen(js_name = LinkedVerifiablePresentationService, inspectable)]
pub struct WasmLinkedVerifiablePresentationService(LinkedVerifiablePresentationService);

/// A service wrapper for a [Linked Verifiable Presentation Service Endpoint](https://identity.foundation/linked-vp/#linked-verifiable-presentation-service-endpoint).
#[wasm_bindgen(js_class = LinkedVerifiablePresentationService)]
impl WasmLinkedVerifiablePresentationService {
/// Constructs a new {@link LinkedVerifiablePresentationService} that wraps a spec compliant [Linked Verifiable Presentation Service Endpoint](https://identity.foundation/linked-vp/#linked-verifiable-presentation-service-endpoint).
#[wasm_bindgen(constructor)]
pub fn new(options: ILinkedVerifiablePresentationService) -> Result<WasmLinkedVerifiablePresentationService> {
let ILinkedVerifiablePresentationServiceHelper {
id,
linked_vp,
properties,
} = options
.into_serde::<ILinkedVerifiablePresentationServiceHelper>()
.wasm_result()?;
Ok(Self(
LinkedVerifiablePresentationService::new(id, linked_vp, properties).wasm_result()?,
))
}

/// Returns the domains contained in the Linked Verifiable Presentation Service.
#[wasm_bindgen(js_name = verifiablePresentationUrls)]
pub fn vp_urls(&self) -> ArrayString {
self
.0
.verifiable_presentation_urls()
.iter()
.map(|url| url.to_string())
.map(JsValue::from)
.collect::<js_sys::Array>()
.unchecked_into::<ArrayString>()
}

/// Returns the inner service which can be added to a DID Document.
#[wasm_bindgen(js_name = toService)]
pub fn to_service(&self) -> WasmService {
let service: Service = self.0.clone().into();
WasmService(service)
}

/// Creates a new {@link LinkedVerifiablePresentationService} from a {@link Service}.
///
/// # Error
///
/// Errors if `service` is not a valid Linked Verifiable Presentation Service.
#[wasm_bindgen(js_name = fromService)]
pub fn from_service(service: &WasmService) -> Result<WasmLinkedVerifiablePresentationService> {
Ok(Self(
LinkedVerifiablePresentationService::try_from(service.0.clone()).wasm_result()?,
))
}

/// Returns `true` if a {@link Service} is a valid Linked Verifiable Presentation Service.
#[wasm_bindgen(js_name = isValid)]
pub fn is_valid(service: &WasmService) -> bool {
LinkedVerifiablePresentationService::check_structure(&service.0).is_ok()
}
}

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(typescript_type = "ILinkedVerifiablePresentationService")]
pub type ILinkedVerifiablePresentationService;
}

/// Fields for constructing a new {@link LinkedVerifiablePresentationService}.
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
#[typescript(name = "ILinkedVerifiablePresentationService", readonly, optional)]
struct ILinkedVerifiablePresentationServiceHelper {
/// Service id.
#[typescript(optional = false, type = "DIDUrl")]
id: DIDUrl,
/// A unique URI that may be used to identify the {@link Credential}.
#[typescript(optional = false, type = "string | string[]")]
linked_vp: OneOrSet<Url>,
/// Miscellaneous properties.
#[serde(flatten)]
#[typescript(optional = false, name = "[properties: string]", type = "unknown")]
properties: Object,
}

impl_wasm_clone!(
WasmLinkedVerifiablePresentationService,
LinkedVerifiablePresentationService
);
impl_wasm_json!(
WasmLinkedVerifiablePresentationService,
LinkedVerifiablePresentationService
);
2 changes: 2 additions & 0 deletions bindings/wasm/src/credential/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub use self::jws::WasmJws;
pub use self::jwt::WasmJwt;
pub use self::jwt_credential_validation::*;
pub use self::jwt_presentation_validation::*;
pub use self::linked_verifiable_presentation_service::*;
pub use self::options::WasmFailFast;
pub use self::options::WasmSubjectHolderRelationship;
pub use self::presentation::*;
Expand All @@ -33,6 +34,7 @@ mod jwt;
mod jwt_credential_validation;
mod jwt_presentation_validation;
mod linked_domain_service;
mod linked_verifiable_presentation_service;
mod options;
mod presentation;
mod proof;
Expand Down
105 changes: 105 additions & 0 deletions bindings/wasm/src/did/did_jwk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2020-2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use identity_iota::did::DIDJwk;
use identity_iota::did::DID as _;
use wasm_bindgen::prelude::*;

use super::wasm_core_did::get_core_did_clone;
use super::IToCoreDID;
use super::WasmCoreDID;
use crate::error::Result;
use crate::error::WasmResult;
use crate::jose::WasmJwk;

/// `did:jwk` DID.
#[wasm_bindgen(js_name = DIDJwk)]
pub struct WasmDIDJwk(pub(crate) DIDJwk);

#[wasm_bindgen(js_class = DIDJwk)]
impl WasmDIDJwk {
#[wasm_bindgen(constructor)]
/// Creates a new {@link DIDJwk} from a {@link CoreDID}.
///
/// ### Errors
/// Throws an error if the given did is not a valid `did:jwk` DID.
pub fn new(did: IToCoreDID) -> Result<WasmDIDJwk> {
let did = get_core_did_clone(&did).0;
DIDJwk::try_from(did).wasm_result().map(Self)
}
/// Parses a {@link DIDJwk} from the given `input`.
///
/// ### Errors
///
/// Throws an error if the input is not a valid {@link DIDJwk}.
#[wasm_bindgen]
pub fn parse(input: &str) -> Result<WasmDIDJwk> {
DIDJwk::parse(input).wasm_result().map(Self)
}

/// Returns the JSON WEB KEY (JWK) encoded inside this `did:jwk`.
#[wasm_bindgen]
pub fn jwk(&self) -> WasmJwk {
self.0.jwk().into()
}

// ===========================================================================
// DID trait
// ===========================================================================

/// Returns the {@link CoreDID} scheme.
///
/// E.g.
/// - `"did:example:12345678" -> "did"`
/// - `"did:iota:smr:12345678" -> "did"`
#[wasm_bindgen]
pub fn scheme(&self) -> String {
self.0.scheme().to_owned()
}

/// Returns the {@link CoreDID} authority: the method name and method-id.
///
/// E.g.
/// - `"did:example:12345678" -> "example:12345678"`
/// - `"did:iota:smr:12345678" -> "iota:smr:12345678"`
#[wasm_bindgen]
pub fn authority(&self) -> String {
self.0.authority().to_owned()
}

/// Returns the {@link CoreDID} method name.
///
/// E.g.
/// - `"did:example:12345678" -> "example"`
/// - `"did:iota:smr:12345678" -> "iota"`
#[wasm_bindgen]
pub fn method(&self) -> String {
self.0.method().to_owned()
}

/// Returns the {@link CoreDID} method-specific ID.
///
/// E.g.
/// - `"did:example:12345678" -> "12345678"`
/// - `"did:iota:smr:12345678" -> "smr:12345678"`
#[wasm_bindgen(js_name = methodId)]
pub fn method_id(&self) -> String {
self.0.method_id().to_owned()
}

/// Returns the {@link CoreDID} as a string.
#[allow(clippy::inherent_to_string)]
#[wasm_bindgen(js_name = toString)]
pub fn to_string(&self) -> String {
self.0.to_string()
}

// Only intended to be called internally.
#[wasm_bindgen(js_name = toCoreDid, skip_typescript)]
pub fn to_core_did(&self) -> WasmCoreDID {
WasmCoreDID(self.0.clone().into())
}
}

impl_wasm_json!(WasmDIDJwk, DIDJwk);
impl_wasm_clone!(WasmDIDJwk, DIDJwk);
2 changes: 2 additions & 0 deletions bindings/wasm/src/did/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

mod did_jwk;
mod jws_verification_options;
mod service;
mod wasm_core_did;
Expand All @@ -19,5 +20,6 @@ pub use self::wasm_core_document::PromiseJws;
pub use self::wasm_core_document::PromiseJwt;
pub use self::wasm_core_document::WasmCoreDocument;
pub use self::wasm_did_url::WasmDIDUrl;
pub use did_jwk::*;

pub use self::jws_verification_options::*;
14 changes: 11 additions & 3 deletions bindings/wasm/src/did/wasm_core_document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::credential::WasmJwt;
use crate::credential::WasmPresentation;
use crate::did::service::WasmService;
use crate::did::wasm_did_url::WasmDIDUrl;
use crate::did::WasmDIDJwk;
use crate::error::Result;
use crate::error::WasmResult;
use crate::jose::WasmDecodedJws;
Expand Down Expand Up @@ -494,8 +495,9 @@ impl WasmCoreDocument {
// ===========================================================================

/// Decodes and verifies the provided JWS according to the passed `options` and `signatureVerifier`.
/// If no `signatureVerifier` argument is provided a default verifier will be used that is (only) capable of
/// verifying EdDSA signatures.
/// If a `signatureVerifier` is provided it will be used when
/// verifying decoded JWS signatures, otherwise a default verifier capable of handling the `EdDSA`, `ES256`, `ES256K`
/// algorithms will be used.
///
/// Regardless of which options are passed the following conditions must be met in order for a verification attempt to
/// take place.
Expand All @@ -508,7 +510,7 @@ impl WasmCoreDocument {
&self,
jws: &WasmJws,
options: &WasmJwsVerificationOptions,
signatureVerifier: IJwsVerifier,
signatureVerifier: Option<IJwsVerifier>,
detachedPayload: Option<String>,
) -> Result<WasmDecodedJws> {
let jws_verifier = WasmJwsVerifier::new(signatureVerifier);
Expand Down Expand Up @@ -765,6 +767,12 @@ impl WasmCoreDocument {
});
Ok(promise.unchecked_into())
}

/// Creates a {@link CoreDocument} from the given {@link DIDJwk}.
#[wasm_bindgen(js_name = expandDIDJwk)]
pub fn expand_did_jwk(did: WasmDIDJwk) -> Result<WasmCoreDocument> {
CoreDocument::expand_did_jwk(did.0).wasm_result().map(Self::from)
}
}

#[wasm_bindgen]
Expand Down
Loading

0 comments on commit ea97960

Please sign in to comment.