1use affinidi_did_common::{
21 Document,
22 one_or_many::OneOrMany,
23 service::{Endpoint, Service},
24 verification_method::{VerificationMethod, VerificationRelationship},
25};
26use affinidi_did_key::DIDKey;
27use affinidi_secrets_resolver::{
28 jwk::Params,
29 secrets::{KeyType, SecretMaterial},
30};
31use base64::prelude::*;
32use serde::{Deserialize, Serialize};
33use serde_json::{Value, json};
34use service::convert_service;
35use std::{
36 collections::{BTreeMap, HashMap},
37 fmt,
38 str::FromStr,
39};
40use thiserror::Error;
41use url::Url;
42use wasm_bindgen::prelude::*;
43
44pub mod service;
45
46#[derive(Error, Debug)]
47pub enum DIDPeerError {
48 #[error("Unsupported key type")]
49 UnsupportedKeyType,
50 #[error("Unsupported curve: {0}")]
51 UnsupportedCurve(String),
52 #[error("Unsupported source")]
53 UnsupportedSource,
54 #[error("Syntax error on Service definition: {0}")]
55 SyntaxErrorServiceDefinition(String),
56 #[error("Unsupported Method. Must be method 2")]
57 MethodNotSupported,
58 #[error("Key Parsing error {0}")]
59 KeyParsingError(String),
60 #[error("DID Document doesn't contain any verificationMethod items")]
61 MissingVerificationMethods,
62 #[error("JSON Parsing error: {0}")]
63 JsonParsingError(String),
64 #[error("Internal error: {0}")]
65 InternalError(String),
66 #[error("Encoding error: {0}")]
67 EncodingError(String),
68}
69
70impl From<DIDPeerError> for JsValue {
72 fn from(err: DIDPeerError) -> JsValue {
73 JsValue::from(err.to_string())
74 }
75}
76
77pub struct DIDPeer;
78
79#[derive(Debug, Serialize, Deserialize)]
83#[serde(untagged)]
84pub enum PeerServiceEndPoint {
85 Short(PeerServiceEndPointShort),
86 Long(PeerServiceEndPointLong),
87}
88
89impl PeerServiceEndPoint {
90 pub fn to_short(&self) -> PeerServiceEndPointShort {
91 match self {
92 PeerServiceEndPoint::Short(short) => short.clone(),
93 PeerServiceEndPoint::Long(long) => match long {
94 PeerServiceEndPointLong::URI(uri) => PeerServiceEndPointShort::URI(uri.to_string()),
95 PeerServiceEndPointLong::Map(map) => match map {
96 OneOrMany::One(single) => {
97 PeerServiceEndPointShort::Map(OneOrMany::One(PeerServiceEndPointShortMap {
98 uri: single.uri.to_string(),
99 a: single.accept.clone(),
100 r: single.routing_keys.clone(),
101 }))
102 }
103 OneOrMany::Many(many) => PeerServiceEndPointShort::Map(OneOrMany::Many(
104 many.iter()
105 .map(|m| PeerServiceEndPointShortMap {
106 uri: m.uri.to_string(),
107 a: m.accept.clone(),
108 r: m.routing_keys.clone(),
109 })
110 .collect(),
111 )),
112 },
113 },
114 }
115 }
116
117 pub fn to_long(&self) -> PeerServiceEndPointLong {
118 match self {
119 PeerServiceEndPoint::Short(short) => PeerServiceEndPointLong::from(short.clone()),
120 PeerServiceEndPoint::Long(long) => long.clone(),
121 }
122 }
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127#[serde(untagged)]
128pub enum PeerServiceEndPointShort {
129 URI(String),
130 Map(OneOrMany<PeerServiceEndPointShortMap>),
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct PeerServiceEndPointShortMap {
135 pub uri: String,
136 pub a: Vec<String>,
137 pub r: Vec<String>,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
142#[serde(untagged)]
143pub enum PeerServiceEndPointLong {
144 URI(String),
145 Map(OneOrMany<PeerServiceEndPointLongMap>),
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct PeerServiceEndPointLongMap {
150 pub uri: String,
151 pub accept: Vec<String>,
152 pub routing_keys: Vec<String>,
153}
154
155impl From<PeerServiceEndPointShort> for PeerServiceEndPointLong {
156 fn from(service: PeerServiceEndPointShort) -> Self {
157 match service {
158 PeerServiceEndPointShort::URI(uri) => PeerServiceEndPointLong::URI(uri),
159 PeerServiceEndPointShort::Map(map) => match map {
160 OneOrMany::One(single) => {
161 PeerServiceEndPointLong::Map(OneOrMany::One(PeerServiceEndPointLongMap {
162 uri: single.uri,
163 accept: single.a,
164 routing_keys: single.r,
165 }))
166 }
167 OneOrMany::Many(many) => PeerServiceEndPointLong::Map(OneOrMany::Many(
168 many.iter()
169 .map(|m| PeerServiceEndPointLongMap {
170 uri: m.uri.clone(),
171 accept: m.a.clone(),
172 routing_keys: m.r.clone(),
173 })
174 .collect(),
175 )),
176 },
177 }
178 }
179}
180
181#[derive(Debug, Serialize, Deserialize)]
183pub struct DIDPeerService {
184 #[serde(rename = "t")]
185 #[serde(alias = "t")]
186 pub _type: String,
187 #[serde(rename = "s")]
188 #[serde(alias = "s")]
189 pub service_end_point: PeerServiceEndPoint, #[serde(skip_serializing_if = "Option::is_none")]
193 pub id: Option<String>,
194}
195
196impl DIDPeerService {
197 fn convert(did: &str, service: DIDPeerService) -> Result<Service, DIDPeerError> {
198 let service_endpoint = match serde_json::to_value(PeerServiceEndPoint::to_long(
199 &service.service_end_point,
200 )) {
201 Ok(value) => {
202 if value.is_string() {
203 if let Some(value) = value.as_str() {
204 if let Ok(url) = Url::from_str(value) {
205 Endpoint::Url(url)
206 } else {
207 return Err(DIDPeerError::SyntaxErrorServiceDefinition(format!(
208 "Couldn't convert ServiceEndPoint to a valid URI: {value}",
209 )));
210 }
211 } else {
212 return Err(DIDPeerError::SyntaxErrorServiceDefinition(format!(
213 "Service URI appears to be a string, but can't parse as a string: {value}",
214 )));
215 }
216 } else {
217 Endpoint::Map(value)
218 }
219 }
220 Err(err) => {
221 return Err(DIDPeerError::SyntaxErrorServiceDefinition(format!(
222 "Couldn't convert ServiceEndPoint to a valid representation. Reason: {err}",
223 )));
224 }
225 };
226
227 let id = if let Some(id) = service.id {
228 [did, &id].concat()
229 } else {
230 [did, "#service"].concat()
231 };
232
233 let id = match Url::from_str(&id) {
234 Ok(uri) => uri,
235 Err(e) => {
236 return Err(DIDPeerError::SyntaxErrorServiceDefinition(format!(
237 "Error parsing service id: {id}. Reason: {e:?}",
238 )));
239 }
240 };
241
242 Ok(Service {
243 id: Some(id),
244 type_: vec!["DIDCommMessaging".to_string()],
245 service_endpoint,
246 property_set: HashMap::new(),
247 })
248 }
249}
250
251#[derive(Clone)]
252#[wasm_bindgen]
253pub enum DIDPeerKeys {
257 Verification,
258 Encryption,
259}
260
261impl fmt::Display for DIDPeerKeys {
262 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
263 match *self {
264 DIDPeerKeys::Verification => write!(f, "verification"),
265 DIDPeerKeys::Encryption => write!(f, "encryption"),
266 }
267 }
268}
269
270#[derive(Clone)]
271#[wasm_bindgen]
272pub enum DIDPeerKeyType {
274 Ed25519,
275 Secp256k1,
276 P256,
277}
278
279impl fmt::Display for DIDPeerKeyType {
280 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
281 match *self {
282 DIDPeerKeyType::Ed25519 => write!(f, "ed25519"),
283 DIDPeerKeyType::Secp256k1 => write!(f, "secp256k1"),
284 DIDPeerKeyType::P256 => write!(f, "p256"),
285 }
286 }
287}
288
289#[derive(Clone)]
290#[wasm_bindgen(getter_with_clone)]
291pub struct DIDPeerCreateKeys {
296 pub purpose: DIDPeerKeys,
297 pub type_: Option<DIDPeerKeyType>,
298 pub public_key_multibase: Option<String>,
299}
300
301#[wasm_bindgen]
302impl DIDPeerCreateKeys {
303 #[wasm_bindgen(constructor)]
304 pub fn new(
305 purpose: DIDPeerKeys,
306 type_: Option<DIDPeerKeyType>,
307 public_key_multibase: Option<String>,
308 ) -> Self {
309 DIDPeerCreateKeys {
310 purpose,
311 type_,
312 public_key_multibase,
313 }
314 }
315}
316
317#[derive(Clone, Debug, Serialize, Deserialize)]
325#[wasm_bindgen(getter_with_clone)]
326pub struct DIDPeerCreatedKeys {
327 pub key_multibase: String,
328 pub curve: String,
329 pub d: String,
330 pub x: String,
331 pub y: Option<String>,
332}
333
334fn process_key(did: &str, id: &str, public_key: &str) -> VerificationMethod {
336 let mut property_set = HashMap::new();
337
338 property_set.insert(
339 "publicKeyMultibase".to_string(),
340 Value::String(public_key.to_string()),
341 );
342
343 VerificationMethod {
344 id: Url::from_str(&["did:peer:", did, id].concat()).unwrap(),
345 type_: "Multikey".to_string(),
346 controller: Url::from_str(&["did:peer:", did].concat()).unwrap(),
347 expires: None,
348 revoked: None,
349 property_set,
350 }
351}
352
353impl DIDPeer {
354 pub async fn resolve(&self, did: &str) -> Result<Document, DIDPeerError> {
355 let Some(method_specific_id) = did.strip_prefix("did:peer:") else {
356 return Err(DIDPeerError::MethodNotSupported);
357 };
358 let did = ["did:peer:", method_specific_id].concat();
359
360 if let Some(id) = method_specific_id.strip_prefix('0') {
362 return DIDKey::resolve(&["did:key:", id].concat()).map_err(|e| {
363 DIDPeerError::InternalError(format!(
364 "Resolving version 0 of did:peer resulted in the following error: {e}"
365 ))
366 });
367 }
368
369 if !method_specific_id.starts_with('2') {
371 return Err(DIDPeerError::MethodNotSupported);
372 }
373
374 let mut context = BTreeMap::new();
375 context.insert("@base".to_string(), serde_json::json!(method_specific_id));
376
377 let mut verification_methods: Vec<VerificationMethod> = Vec::new();
378
379 let mut key_agreements: Vec<VerificationRelationship> = Vec::new();
380 let mut key_authentications: Vec<VerificationRelationship> = Vec::new();
381 let mut key_assertion_methods: Vec<VerificationRelationship> = Vec::new();
382 let mut key_capability_delegation: Vec<VerificationRelationship> = Vec::new();
383 let mut key_capability_invocation: Vec<VerificationRelationship> = Vec::new();
384 let mut services: Vec<Service> = Vec::new();
385
386 let parts: Vec<&str> = method_specific_id[2..].split('.').collect();
389 let mut key_count: u32 = 1;
390 let mut service_idx: u32 = 0;
391
392 for part in parts {
393 let ch = part.chars().next();
394 match ch {
395 Some(e) => {
396 match e {
397 'A' => {
398 verification_methods.push(process_key(
400 method_specific_id,
401 &["#key-", &key_count.to_string()].concat(),
402 &part[1..],
403 ));
404
405 key_assertion_methods.push(VerificationRelationship::Reference(
406 Url::from_str(&["#key-", &key_count.to_string()].concat()).unwrap(),
407 ));
408
409 key_count += 1;
410 }
411 'D' => {
412 verification_methods.push(process_key(
414 method_specific_id,
415 &["#key-", &key_count.to_string()].concat(),
416 &part[1..],
417 ));
418
419 key_capability_delegation.push(VerificationRelationship::Reference(
420 Url::from_str(&["did:peer:#key-", &key_count.to_string()].concat())
421 .unwrap(),
422 ));
423
424 key_count += 1;
425 }
426 'E' => {
427 verification_methods.push(process_key(
429 method_specific_id,
430 &["#key-", &key_count.to_string()].concat(),
431 &part[1..],
432 ));
433
434 key_agreements.push(VerificationRelationship::Reference(
435 Url::from_str(&["did:peer:#key-", &key_count.to_string()].concat())
436 .unwrap(),
437 ));
438
439 key_count += 1;
440 }
441 'I' => {
442 verification_methods.push(process_key(
444 method_specific_id,
445 &["#key-", &key_count.to_string()].concat(),
446 &part[1..],
447 ));
448
449 key_capability_invocation.push(VerificationRelationship::Reference(
450 Url::from_str(&["did:peer:#key-", &key_count.to_string()].concat())
451 .unwrap(),
452 ));
453
454 key_count += 1;
455 }
456 'V' => {
457 verification_methods.push(process_key(
459 method_specific_id,
460 &["#key-", &key_count.to_string()].concat(),
461 &part[1..],
462 ));
463
464 key_authentications.push(VerificationRelationship::Reference(
465 Url::from_str(&["did:peer:#key-", &key_count.to_string()].concat())
466 .unwrap(),
467 ));
468
469 key_assertion_methods.push(VerificationRelationship::Reference(
470 Url::from_str(&["did:peer:#key-", &key_count.to_string()].concat())
471 .unwrap(),
472 ));
473
474 key_count += 1;
475 }
476 'S' => {
477 let service = convert_service(&did, part, service_idx)
479 .map_err(|e| DIDPeerError::InternalError(e.to_string()))?;
480 services.push(service);
481 service_idx += 1;
482 }
483 other => {
484 return Err(DIDPeerError::EncodingError(format!(
485 "An invalid Purpose Code ({other}) was found in the DID",
486 )));
487 }
488 }
489 }
490 None => {
491 }
494 }
495 }
496
497 let mut parameters_set = HashMap::new();
498 parameters_set.insert(
499 "@context".to_string(),
500 json!(["https://www.w3.org/ns/did/v1.1".to_string()]),
501 );
502
503 Ok(Document {
504 id: Url::from_str(["did:peer:", method_specific_id].concat().as_str()).unwrap(),
505 verification_method: verification_methods,
506 assertion_method: key_assertion_methods,
507 authentication: key_authentications,
508 capability_delegation: key_capability_delegation,
509 capability_invocation: key_capability_invocation,
510 key_agreement: key_agreements,
511 service: services,
512 parameters_set,
513 })
514 }
515}
516
517impl DIDPeer {
518 pub fn create_peer_did(
565 keys: &Vec<DIDPeerCreateKeys>,
566 services: Option<&Vec<DIDPeerService>>,
567 ) -> Result<(String, Vec<DIDPeerCreatedKeys>), DIDPeerError> {
568 let mut result = String::from("did:peer:2");
569
570 let mut private_keys: Vec<DIDPeerCreatedKeys> = vec![];
571 for key in keys {
572 let public_key = if let Some(key) = key.public_key_multibase.as_ref() {
574 key.clone()
575 } else {
576 let (did, secret) = match &key.type_ {
577 Some(type_) => match type_ {
578 DIDPeerKeyType::Ed25519 => {
579 DIDKey::generate(KeyType::Ed25519).map_err(|e| {
580 DIDPeerError::InternalError(format!(
581 "Couldn't create Ed25519 did:key reason: {e}"
582 ))
583 })?
584 }
585 DIDPeerKeyType::Secp256k1 => {
586 DIDKey::generate(KeyType::Secp256k1).map_err(|e| {
587 DIDPeerError::InternalError(format!(
588 "Couldn't create Secp256k1 did:key reason: {e}"
589 ))
590 })?
591 }
592 DIDPeerKeyType::P256 => DIDKey::generate(KeyType::P256).map_err(|e| {
593 DIDPeerError::InternalError(format!(
594 "Couldn't create P256 did:key reason: {e}"
595 ))
596 })?,
597 },
598 None => return Err(DIDPeerError::UnsupportedKeyType),
599 };
600
601 if let SecretMaterial::JWK(jwk) = secret.secret_material {
602 match jwk.params {
603 Params::OKP(map) => {
604 let d = if let Some(d) = &map.d {
605 d
606 } else {
607 return Err(DIDPeerError::KeyParsingError(
608 "Missing private key".to_string(),
609 ));
610 };
611 private_keys.push(DIDPeerCreatedKeys {
612 key_multibase: did[8..].to_string(),
613 curve: map.curve.clone(),
614 d: d.clone(),
615 x: map.x.clone(),
616 y: None,
617 })
618 }
619 Params::EC(map) => {
620 let d = if let Some(d) = &map.d {
621 d
622 } else {
623 return Err(DIDPeerError::KeyParsingError(
624 "Missing private key".to_string(),
625 ));
626 };
627
628 private_keys.push(DIDPeerCreatedKeys {
629 key_multibase: did[8..].to_string(),
630 curve: map.curve.clone(),
631 d: String::from(d),
632 x: map.x.clone(),
633 y: Some(map.y.clone()),
634 })
635 }
636 }
637 } else {
638 return Err(DIDPeerError::InternalError(
639 "Expected Secret Material to be in JWK format!".to_string(),
640 ));
641 }
642
643 did[8..].to_string()
644 };
645
646 match key.purpose {
648 DIDPeerKeys::Verification => {
649 result.push_str(&format!(".V{public_key}",));
650 }
651 DIDPeerKeys::Encryption => {
652 result.push_str(&format!(".E{public_key}",));
653 }
654 }
655 }
656
657 if let Some(services) = services {
658 for service in services {
659 let service = serde_json::to_string(&service).map_err(|e| {
660 DIDPeerError::SyntaxErrorServiceDefinition(format!(
661 "Error parsing service: {e}",
662 ))
663 })?;
664 result.push_str(&format!(".S{}", BASE64_URL_SAFE_NO_PAD.encode(service)));
665 }
666 }
667
668 Ok((result, private_keys))
669 }
670
671 pub async fn expand_keys(doc: &Document) -> Result<Document, DIDPeerError> {
675 let mut new_doc = doc.clone();
676
677 let mut new_vms: Vec<VerificationMethod> = vec![];
678 for v_method in &doc.verification_method {
679 new_vms.push(Self::_convert_vm(v_method).await?);
680 }
681
682 new_doc.verification_method = new_vms;
683 Ok(new_doc)
684 }
685
686 async fn _convert_vm(method: &VerificationMethod) -> Result<VerificationMethod, DIDPeerError> {
688 let current_controller = method.controller.clone();
689 let current_id = method.id.clone();
690
691 let did_key = if let Some(key) = method.property_set.get("publicKeyBase58") {
692 ["did:key:", key.as_str().unwrap()].concat()
693 } else if let Some(key) = method.property_set.get("publicKeyMultibase") {
694 ["did:key:", key.as_str().unwrap()].concat()
695 } else {
696 return Err(DIDPeerError::KeyParsingError(
697 "Failed to convert verification_method. Reason: Missing publicKeyBase58"
698 .to_string(),
699 ));
700 };
701
702 let document = match DIDKey::resolve(&did_key) {
703 Ok(document) => document,
704 Err(e) => {
705 return Err(DIDPeerError::KeyParsingError(format!(
706 "Failed to resolve key ({did_key}). Reason: {e}",
707 )));
708 }
709 };
710
711 if let Some(vm) = document.verification_method.first() {
712 let mut properties: HashMap<String, Value> = HashMap::new();
713 for (k, v) in vm.property_set.iter() {
714 properties.insert(k.clone(), v.clone());
715 }
716
717 Ok(VerificationMethod {
718 id: current_id,
719 type_: vm.type_.clone(),
720 controller: current_controller,
721 expires: None,
722 revoked: None,
723 property_set: properties,
724 })
725 } else {
726 Err(DIDPeerError::KeyParsingError(
727 "Failed to convert verification_method. Reason: Missing verification_method"
728 .to_string(),
729 ))
730 }
731 }
732}
733
734#[cfg(test)]
735mod test {
736 use affinidi_did_common::{one_or_many::OneOrMany, verification_method::VerificationMethod};
737 use affinidi_did_key::DIDKey;
738 use affinidi_secrets_resolver::secrets::KeyType;
739
740 use crate::{
741 DIDPeer, DIDPeerCreateKeys, DIDPeerKeyType, DIDPeerKeys, DIDPeerService,
742 PeerServiceEndPoint, PeerServiceEndPointLong, PeerServiceEndPointLongMap,
743 };
744
745 const DID_PEER: &str = "did:peer:2.Vz6MkiToqovww7vYtxm1xNM15u9JzqzUFZ1k7s7MazYJUyAxv.EzQ3shQLqRUza6AMJFbPuMdvFRFWm1wKviQRnQSC1fScovJN4s.SeyJ0IjoiRElEQ29tbU1lc3NhZ2luZyIsInMiOnsidXJpIjoiaHR0cHM6Ly8xMjcuMC4wLjE6NzAzNyIsImEiOlsiZGlkY29tbS92MiJdLCJyIjpbXX19";
746
747 #[should_panic(
748 expected = "Failed to convert verification_method. Reason: Missing publicKeyBase58"
749 )]
750 #[tokio::test]
751 async fn expand_keys_throws_key_parsing_missing_pbk58_error() {
752 let peer = DIDPeer;
753 let output = peer.resolve(DID_PEER).await.unwrap();
754
755 let mut document = output.clone();
756 let mut new_vms: Vec<VerificationMethod> = vec![];
757 for mut vm in document.verification_method {
758 vm.property_set.remove("publicKeyMultibase");
759 new_vms.push(vm);
760 }
761
762 document.verification_method = new_vms;
763 let _expanded_doc = DIDPeer::expand_keys(&document).await.unwrap();
764 }
765
766 #[tokio::test]
767 async fn expand_keys_works() {
768 let peer = DIDPeer;
769 let document = peer.resolve(DID_PEER).await.expect("Couldn't resolve DID");
770
771 let vm_before_expansion = document.verification_method.clone();
772 let expanded_doc = DIDPeer::expand_keys(&document).await.unwrap();
773 let vms_after_expansion = expanded_doc.verification_method;
774
775 for vm in vms_after_expansion.clone() {
776 assert!(vm.id.as_str().starts_with("did:peer"));
777 }
778 assert_eq!(vm_before_expansion.len(), vms_after_expansion.len())
779 }
780
781 #[tokio::test]
782 async fn create_peer_did_without_keys_and_services() {
783 let keys: Vec<DIDPeerCreateKeys> = vec![];
784 let services: Vec<DIDPeerService> = vec![];
785
786 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
787 let parts: Vec<&str> = did.split(":").collect();
788
789 assert_eq!(parts.len(), 3);
790 assert_eq!(parts[1], "peer");
791 assert!(parts[2].len() == 1);
792 }
793
794 #[tokio::test]
795 async fn create_peer_did_without_keys() {
796 let keys: Vec<DIDPeerCreateKeys> = vec![];
797 let services = vec![DIDPeerService {
798 _type: "dm".into(),
799 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
800 OneOrMany::One(PeerServiceEndPointLongMap {
801 uri: "https://localhost:7037".into(),
802 accept: vec!["didcomm/v2".into()],
803 routing_keys: vec![],
804 }),
805 )),
806 id: None,
807 }];
808
809 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
810 let parts: Vec<&str> = did.split(":").collect();
811 let method_ids: Vec<&str> = parts[2].split(".").collect();
812
813 assert_eq!(parts.len(), 3);
814 assert_eq!(parts[1], "peer");
815 assert!(method_ids.len() > 1);
816 assert!(method_ids[1].len() > 1);
817 }
818
819 #[tokio::test]
820 async fn create_peer_did_without_services() {
821 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::Ed25519), true);
822 let services: Vec<DIDPeerService> = vec![];
823
824 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
825 let parts: Vec<&str> = did.split(":").collect();
826 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
827 method_ids = method_ids[1..].to_vec();
828 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
829
830 method_ids.iter().take(2).for_each(|id| {
831 assert!(keys_multibase.contains(&id[1..].to_string()));
832 });
833 assert_eq!(parts.len(), 3);
834 assert_eq!(parts[1], "peer");
835 }
836
837 #[should_panic(expected = "UnsupportedKeyType")]
838 #[tokio::test]
839 async fn create_peer_did_should_throw_unsupported_key_error_p384() {
840 let (_, _, keys) = _get_keys(None, false);
841 let services = vec![DIDPeerService {
843 _type: "dm".into(),
844 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
845 OneOrMany::One(PeerServiceEndPointLongMap {
846 uri: "https://localhost:7037".into(),
847 accept: vec!["didcomm/v2".into()],
848 routing_keys: vec![],
849 }),
850 )),
851 id: None,
852 }];
853
854 DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
855 }
856
857 #[tokio::test]
858 async fn create_peer_did_works_ed25519_without_passing_pub_key() {
859 let (_, _, keys) = _get_keys(Some(DIDPeerKeyType::Ed25519), false);
860
861 let services = vec![DIDPeerService {
863 _type: "dm".into(),
864 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
865 OneOrMany::One(PeerServiceEndPointLongMap {
866 uri: "https://localhost:7037".into(),
867 accept: vec!["didcomm/v2".into()],
868 routing_keys: vec![],
869 }),
870 )),
871 id: None,
872 }];
873
874 let (did, keys) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
875 let parts: Vec<&str> = did.split(":").collect();
876 let method_ids: Vec<&str> = parts[2].split(".").collect();
877
878 assert_eq!(keys.len(), 2);
879 assert_eq!(parts.len(), 3);
880 assert_eq!(parts[1], "peer");
881 assert_eq!(method_ids.first().unwrap().parse::<i32>().unwrap(), 2);
882 assert_eq!(method_ids.len(), 4);
883 }
884
885 #[tokio::test]
886 async fn create_peer_did_works_p256_without_passing_pub_key() {
887 let (_, _, keys) = _get_keys(Some(DIDPeerKeyType::P256), false);
888
889 let services = vec![DIDPeerService {
891 _type: "dm".into(),
892 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
893 OneOrMany::One(PeerServiceEndPointLongMap {
894 uri: "https://localhost:7037".into(),
895 accept: vec!["didcomm/v2".into()],
896 routing_keys: vec![],
897 }),
898 )),
899 id: None,
900 }];
901
902 let (did, keys) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
903 let parts: Vec<&str> = did.split(":").collect();
904 let method_ids: Vec<&str> = parts[2].split(".").collect();
905
906 assert_eq!(keys.len(), 2);
907 assert_eq!(parts.len(), 3);
908 assert_eq!(parts[1], "peer");
909 assert_eq!(method_ids.first().unwrap().parse::<i32>().unwrap(), 2);
910 assert_eq!(method_ids.len(), 4);
911 }
912
913 #[tokio::test]
914 async fn create_peer_did_works_secp256k1_without_passing_pub_key() {
915 let (_, _, keys) = _get_keys(Some(DIDPeerKeyType::Secp256k1), false);
916
917 let services = vec![DIDPeerService {
919 _type: "dm".into(),
920 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
921 OneOrMany::One(PeerServiceEndPointLongMap {
922 uri: "https://localhost:7037".into(),
923 accept: vec!["didcomm/v2".into()],
924 routing_keys: vec![],
925 }),
926 )),
927 id: None,
928 }];
929
930 let (did, keys) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
931
932 let parts: Vec<&str> = did.split(":").collect();
933 let method_ids: Vec<&str> = parts[2].split(".").collect();
934
935 assert_eq!(keys.len(), 2);
936 assert_eq!(parts.len(), 3);
937 assert_eq!(parts[1], "peer");
938 assert_eq!(method_ids.first().unwrap().parse::<i32>().unwrap(), 2);
939 assert_eq!(method_ids.len(), 4);
940 }
941
942 #[tokio::test]
943 async fn create_peer_did_works_ed25519() {
944 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::Ed25519), true);
945
946 let services = vec![DIDPeerService {
948 _type: "dm".into(),
949 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
950 OneOrMany::One(PeerServiceEndPointLongMap {
951 uri: "https://localhost:7037".into(),
952 accept: vec!["didcomm/v2".into()],
953 routing_keys: vec![],
954 }),
955 )),
956 id: None,
957 }];
958
959 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
960 let parts: Vec<&str> = did.split(":").collect();
961 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
962 method_ids = method_ids[1..].to_vec();
963 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
964
965 method_ids.iter().take(2).for_each(|id| {
966 assert!(keys_multibase.contains(&id[1..].to_string()));
967 });
968
969 assert_eq!(parts.len(), 3);
970 assert_eq!(parts[1], "peer");
971 }
972
973 #[tokio::test]
974 async fn create_peer_did_works_p256() {
975 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::P256), true);
976 let services = vec![DIDPeerService {
978 _type: "dm".into(),
979 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
980 OneOrMany::One(PeerServiceEndPointLongMap {
981 uri: "https://localhost:7037".into(),
982 accept: vec!["didcomm/v2".into()],
983 routing_keys: vec![],
984 }),
985 )),
986 id: None,
987 }];
988
989 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
990 let parts: Vec<&str> = did.split(":").collect();
991 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
992 method_ids = method_ids[1..].to_vec();
993 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
994
995 method_ids.iter().take(2).for_each(|id| {
996 assert!(keys_multibase.contains(&id[1..].to_string()));
997 });
998 assert_eq!(parts.len(), 3);
999 assert_eq!(parts[1], "peer");
1000 }
1001
1002 #[tokio::test]
1003 async fn create_peer_did_works_secp256k1() {
1004 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::Secp256k1), true);
1005 let services = vec![DIDPeerService {
1007 _type: "dm".into(),
1008 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
1009 OneOrMany::One(PeerServiceEndPointLongMap {
1010 uri: "https://localhost:7037".into(),
1011 accept: vec!["didcomm/v2".into()],
1012 routing_keys: vec![],
1013 }),
1014 )),
1015 id: None,
1016 }];
1017
1018 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
1019 let parts: Vec<&str> = did.split(":").collect();
1020 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
1021 method_ids = method_ids[1..].to_vec();
1022 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
1023
1024 method_ids.iter().take(2).for_each(|id| {
1025 assert!(keys_multibase.contains(&id[1..].to_string()));
1026 });
1027 assert_eq!(parts.len(), 3);
1028 assert_eq!(parts[1], "peer");
1029 }
1030
1031 fn _get_keys(
1032 key_type: Option<DIDPeerKeyType>,
1033 with_pub_key: bool,
1034 ) -> (String, String, Vec<DIDPeerCreateKeys>) {
1035 let (e_did_key, _) = match key_type {
1036 Some(DIDPeerKeyType::Ed25519) => {
1037 DIDKey::generate(KeyType::Ed25519).expect("Failed to create did:key")
1038 }
1039 Some(DIDPeerKeyType::P256) => {
1040 DIDKey::generate(KeyType::P256).expect("Failed to create did:key")
1041 }
1042 Some(DIDPeerKeyType::Secp256k1) => {
1043 DIDKey::generate(KeyType::Secp256k1).expect("Failed to create did:key")
1044 }
1045 None => DIDKey::generate(KeyType::P384).expect("Failed to create did:key"),
1046 };
1047 let (v_did_key, _) = match key_type {
1048 Some(DIDPeerKeyType::Ed25519) => {
1049 DIDKey::generate(KeyType::Ed25519).expect("Failed to create did:key")
1050 }
1051 Some(DIDPeerKeyType::P256) => {
1052 DIDKey::generate(KeyType::P256).expect("Failed to create did:key")
1053 }
1054 Some(DIDPeerKeyType::Secp256k1) => {
1055 DIDKey::generate(KeyType::Secp256k1).expect("Failed to create did:key")
1056 }
1057 None => DIDKey::generate(KeyType::P384).expect("Failed to create did:key"),
1058 };
1059
1060 let keys = vec![
1062 DIDPeerCreateKeys {
1063 purpose: DIDPeerKeys::Verification,
1064 type_: key_type.clone(),
1065 public_key_multibase: if with_pub_key {
1066 Some(v_did_key[8..].to_string())
1067 } else {
1068 None
1069 },
1070 },
1071 DIDPeerCreateKeys {
1072 purpose: DIDPeerKeys::Encryption,
1073 type_: key_type.clone(),
1074 public_key_multibase: if with_pub_key {
1075 Some(e_did_key[8..].to_string())
1076 } else {
1077 None
1078 },
1079 },
1080 ];
1081
1082 (e_did_key, v_did_key, keys)
1083 }
1084}
1085
1086#[wasm_bindgen(getter_with_clone)]
1100#[derive(Clone, Serialize, Deserialize)]
1101pub struct DIDService {
1102 pub _type: Option<String>,
1103 pub uri: String,
1104 pub accept: Vec<String>,
1105 pub routing_keys: Vec<String>,
1106 pub id: Option<String>,
1107}
1108
1109#[wasm_bindgen]
1110impl DIDService {
1111 #[wasm_bindgen(constructor)]
1112 pub fn new(
1113 uri: String,
1114 accept: Vec<String>,
1115 routing_keys: Vec<String>,
1116 id: Option<String>,
1117 ) -> Self {
1118 DIDService {
1119 _type: None,
1120 uri,
1121 accept,
1122 routing_keys,
1123 id,
1124 }
1125 }
1126}
1127
1128impl From<DIDService> for DIDPeerService {
1129 fn from(service: DIDService) -> Self {
1130 DIDPeerService {
1131 _type: service._type.unwrap_or("DIDCommMessaging".into()),
1132 service_end_point: PeerServiceEndPoint::Short(PeerServiceEndPointShort::Map(
1133 OneOrMany::One(PeerServiceEndPointShortMap {
1134 uri: service.uri,
1135 a: service.accept,
1136 r: service.routing_keys,
1137 }),
1138 )),
1139 id: service.id,
1140 }
1141 }
1142}
1143
1144impl From<&DIDService> for DIDPeerService {
1145 fn from(service: &DIDService) -> Self {
1146 service.clone().into()
1147 }
1148}
1149
1150#[derive(Clone)]
1158#[wasm_bindgen(getter_with_clone)]
1159pub struct DidPeerCreate {
1160 pub keys: Vec<DIDPeerCreateKeys>,
1161 pub services: Option<Vec<DIDService>>,
1162}
1163
1164#[wasm_bindgen]
1165impl DidPeerCreate {
1166 #[wasm_bindgen(constructor)]
1167 pub fn new(keys: Vec<DIDPeerCreateKeys>, services: Option<Vec<DIDService>>) -> Self {
1168 DidPeerCreate { keys, services }
1169 }
1170}
1171
1172#[derive(Serialize, Deserialize)]
1173#[wasm_bindgen(getter_with_clone)]
1174pub struct DIDPeerResult {
1175 pub did: String,
1176 pub keys: Vec<DIDPeerCreatedKeys>,
1177}
1178
1179#[wasm_bindgen]
1180pub fn create_did_peer(input: &DidPeerCreate) -> Result<DIDPeerResult, DIDPeerError> {
1190 let mut new_services: Vec<DIDPeerService> = vec![];
1192 if let Some(services) = input.services.as_ref() {
1193 for service in services {
1194 new_services.push(service.into());
1195 }
1196 }
1197
1198 let response = DIDPeer::create_peer_did(&input.keys, Some(&new_services));
1200
1201 if let Ok((did, keys)) = response {
1202 Ok(DIDPeerResult { did, keys })
1203 } else {
1204 Err(response.unwrap_err())
1205 }
1206}
1207
1208#[wasm_bindgen]
1209pub async fn resolve_did_peer(did: &str) -> Result<String, DIDPeerError> {
1215 let peer = DIDPeer;
1216
1217 match peer.resolve(did).await {
1218 Ok(document) => match serde_json::to_string_pretty(&document) {
1219 Ok(json) => Ok(json),
1220 Err(e) => Err(DIDPeerError::JsonParsingError(format!(
1221 "Couldn't convert DID Document to JSON. Reason: {e}",
1222 ))),
1223 },
1224 Err(e) => Err(DIDPeerError::KeyParsingError(format!(
1225 "Failed to resolve key ({did}). Reason: {e}",
1226 ))),
1227 }
1228}