diff --git a/bindings/wasm/README.md b/bindings/wasm/README.md index eb4cf31edc..c3f7cf838f 100644 --- a/bindings/wasm/README.md +++ b/bindings/wasm/README.md @@ -108,6 +108,8 @@ import * as identity from "@iota/identity-wasm/web"; identity.init().then(() => { const key = new identity.KeyPair(identity.KeyType.Ed25519) const doc = identity.Document.fromKeyPair(key) + // Or, if using the testnet: + // const doc = identity.Document.fromKeyPair(key, "test") console.log("Key Pair", key) console.log("DID Document: ", doc) }); @@ -118,6 +120,8 @@ identity.init().then(() => { await identity.init() const key = new identity.KeyPair(identity.KeyType.Ed25519) const doc = identity.Document.fromKeyPair(key) + // Or, if using the testnet: + // const doc = identity.Document.fromKeyPair(key, "test") console.log("Key Pair", key) console.log("DID Document: ", doc) })() diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md index 6dffdcb246..db76e3c6d1 100644 --- a/bindings/wasm/docs/api-reference.md +++ b/bindings/wasm/docs/api-reference.md @@ -725,13 +725,16 @@ Serializes a `Document` object as a JSON object. ### Document.fromKeyPair(key) ⇒ [Document](#Document) -Creates a new DID Document from the given KeyPair. +Creates a new DID Document from the given KeyPair and optional network. + +If unspecified, the network defaults to the mainnet. **Kind**: static method of [Document](#Document) | Param | Type | | --- | --- | | key | [KeyPair](#KeyPair) | +| network | string \| undefined | diff --git a/bindings/wasm/src/wasm_document.rs b/bindings/wasm/src/wasm_document.rs index aa68c34ba3..0902706904 100644 --- a/bindings/wasm/src/wasm_document.rs +++ b/bindings/wasm/src/wasm_document.rs @@ -80,10 +80,16 @@ impl WasmDocument { }) } - /// Creates a new DID Document from the given KeyPair. + /// Creates a new DID Document from the given KeyPair and optional network. + /// + /// If unspecified, network defaults to the mainnet. #[wasm_bindgen(js_name = fromKeyPair)] - pub fn from_keypair(key: &KeyPair) -> Result { - IotaDocument::from_keypair(&key.0).map_err(err).map(Self) + pub fn from_keypair(key: &KeyPair, network: Option) -> Result { + let doc = match network { + Some(net) => IotaDocument::from_keypair_with_network(&key.0, &net), + None => IotaDocument::from_keypair(&key.0) + }; + doc.map_err(err).map(Self) } /// Creates a new DID Document from the given verification [`method`][`Method`]. diff --git a/identity-iota/src/did/doc/iota_document.rs b/identity-iota/src/did/doc/iota_document.rs index 427242d222..b4c5988b0d 100644 --- a/identity-iota/src/did/doc/iota_document.rs +++ b/identity-iota/src/did/doc/iota_document.rs @@ -82,6 +82,22 @@ impl IotaDocument { Ok(unsafe { Self::from_authentication_unchecked(method) }) } + /// Creates a new DID Document from the given KeyPair and network. + /// + /// The DID Document will be pre-populated with a single authentication + /// method based on the provided [KeyPair]. + /// + /// The authentication method will have the DID URL fragment `#authentication` + /// and can be easily retrieved with [Document::authentication]. + pub fn from_keypair_with_network(keypair: &KeyPair, network: &str) -> Result { + let method: IotaVerificationMethod = + IotaVerificationMethod::from_keypair_with_network(keypair, "authentication", network)?; + + // SAFETY: We don't create invalid Methods. Method::from_keypair() uses the MethodBuilder + // internally which verifies correctness on construction. + Ok(unsafe { Self::from_authentication_unchecked(method) }) + } + /// Creates a new DID Document from the given verification [`method`][VerificationMethod]. pub fn from_authentication(method: IotaVerificationMethod) -> Result { Self::check_authentication(&method)?; @@ -631,6 +647,8 @@ mod tests { const DID_ID: &str = "did:iota:HGE4tecHWL2YiZv5qAGtH7gaeQcaz2Z1CR15GWmMjY1M"; const DID_AUTH: &str = "did:iota:HGE4tecHWL2YiZv5qAGtH7gaeQcaz2Z1CR15GWmMjY1M#authentication"; + const DID_TESTNET_ID: &str = "did:iota:test:HGE4tecHWL2YiZv5qAGtH7gaeQcaz2Z1CR15GWmMjY1M"; + const DID_TESTNET_AUTH: &str = "did:iota:test:HGE4tecHWL2YiZv5qAGtH7gaeQcaz2Z1CR15GWmMjY1M#authentication"; fn valid_did() -> DID { DID_ID.parse().unwrap() @@ -716,6 +734,19 @@ mod tests { ); } + fn compare_document_testnet(document: &IotaDocument) { + assert_eq!(document.id().to_string(), DID_TESTNET_ID); + assert_eq!(document.authentication_id(), DID_TESTNET_AUTH); + assert_eq!( + document.authentication().key_type(), + MethodType::Ed25519VerificationKey2018 + ); + assert_eq!( + document.authentication().key_data(), + &MethodData::PublicKeyBase58(String::from("FJsXMk9UqpJf3ZTKnfEQAhvBrVLKMSx9ZeYwQME6c6tT")) + ); + } + #[test] fn test_invalid_try_from_core_invalid_id() { let invalid_did: DID = "did:invalid:HGE4tecHWL2YiZv5qAGtH7gaeQcaz2Z1CR15GWmMjY1M" @@ -891,6 +922,14 @@ mod tests { compare_document(&document); } + #[test] + fn test_from_keypair_with_network() { + //from keypair + let keypair: KeyPair = generate_testkey(); + let document: IotaDocument = IotaDocument::from_keypair_with_network(&keypair, "test").unwrap(); + compare_document_testnet(&document); + } + #[test] fn test_no_controler() { let keypair: KeyPair = generate_testkey(); diff --git a/identity-iota/src/did/doc/iota_verification_method.rs b/identity-iota/src/did/doc/iota_verification_method.rs index 08ed092bc4..7df5340aeb 100644 --- a/identity-iota/src/did/doc/iota_verification_method.rs +++ b/identity-iota/src/did/doc/iota_verification_method.rs @@ -66,6 +66,17 @@ impl IotaVerificationMethod { Self::from_did(did, keypair, fragment) } + /// Creates a new [`IotaVerificationMethod`] object from the given `keypair` on the specified `network`. + pub fn from_keypair_with_network<'a, F>(keypair: &KeyPair, fragment: F, network: &str) -> Result + where + F: Into>, + { + let key: &[u8] = keypair.public().as_ref(); + let did: IotaDID = IotaDID::with_network(key, &network)?; + + Self::from_did(did, keypair, fragment) + } + /// Creates a new [`Method`] object from the given `did` and `keypair`. /// /// If the `fragment` resolves to `Option::None` then the default verification method tag will be