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, kid: &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(kid).unwrap(),
345 type_: "Multikey".to_string(),
346 controller: Url::from_str(did).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
359 if let Some(id) = method_specific_id.strip_prefix('0') {
361 return DIDKey::resolve(&["did:key:", id].concat()).map_err(|e| {
362 DIDPeerError::InternalError(format!(
363 "Resolving version 0 of did:peer resulted in the following error: {e}"
364 ))
365 });
366 }
367
368 if !method_specific_id.starts_with('2') {
370 return Err(DIDPeerError::MethodNotSupported);
371 }
372
373 let mut context = BTreeMap::new();
374 context.insert("@base".to_string(), serde_json::json!(method_specific_id));
375
376 let mut verification_methods: Vec<VerificationMethod> = Vec::new();
377
378 let mut key_agreements: Vec<VerificationRelationship> = Vec::new();
379 let mut key_authentications: Vec<VerificationRelationship> = Vec::new();
380 let mut key_assertion_methods: Vec<VerificationRelationship> = Vec::new();
381 let mut key_capability_delegation: Vec<VerificationRelationship> = Vec::new();
382 let mut key_capability_invocation: Vec<VerificationRelationship> = Vec::new();
383 let mut services: Vec<Service> = Vec::new();
384
385 let parts: Vec<&str> = method_specific_id[2..].split('.').collect();
388 let mut key_count: u32 = 0;
389 let mut service_idx: u32 = 0;
390
391 for part in parts {
392 key_count += 1;
393 let kid = [did, "#key-", &key_count.to_string()].concat();
394 let ch = part.chars().next();
395 match ch {
396 Some(e) => {
397 match e {
398 'A' => {
399 verification_methods.push(process_key(did, &kid, &part[1..]));
401
402 key_assertion_methods.push(VerificationRelationship::Reference(
403 Url::from_str(&kid).unwrap(),
404 ));
405 }
406 'D' => {
407 verification_methods.push(process_key(did, &kid, &part[1..]));
409
410 key_capability_delegation.push(VerificationRelationship::Reference(
411 Url::from_str(&kid).unwrap(),
412 ));
413 }
414 'E' => {
415 verification_methods.push(process_key(did, &kid, &part[1..]));
417
418 key_agreements.push(VerificationRelationship::Reference(
419 Url::from_str(&kid).unwrap(),
420 ));
421 }
422 'I' => {
423 verification_methods.push(process_key(did, &kid, &part[1..]));
425
426 key_capability_invocation.push(VerificationRelationship::Reference(
427 Url::from_str(&kid).unwrap(),
428 ));
429 }
430 'V' => {
431 verification_methods.push(process_key(did, &kid, &part[1..]));
433
434 key_authentications.push(VerificationRelationship::Reference(
435 Url::from_str(&kid).unwrap(),
436 ));
437
438 key_assertion_methods.push(VerificationRelationship::Reference(
439 Url::from_str(&kid).unwrap(),
440 ));
441 }
442 'S' => {
443 let service = convert_service(did, part, service_idx)
445 .map_err(|e| DIDPeerError::InternalError(e.to_string()))?;
446 services.push(service);
447 service_idx += 1;
448 }
449 other => {
450 return Err(DIDPeerError::EncodingError(format!(
451 "An invalid Purpose Code ({other}) was found in the DID",
452 )));
453 }
454 }
455 }
456 None => {
457 }
460 }
461 }
462
463 let mut parameters_set = HashMap::new();
464 parameters_set.insert(
465 "@context".to_string(),
466 json!(["https://www.w3.org/ns/did/v1.1".to_string()]),
467 );
468
469 Ok(Document {
470 id: Url::from_str(["did:peer:", method_specific_id].concat().as_str()).unwrap(),
471 verification_method: verification_methods,
472 assertion_method: key_assertion_methods,
473 authentication: key_authentications,
474 capability_delegation: key_capability_delegation,
475 capability_invocation: key_capability_invocation,
476 key_agreement: key_agreements,
477 service: services,
478 parameters_set,
479 })
480 }
481}
482
483impl DIDPeer {
484 pub fn create_peer_did(
531 keys: &Vec<DIDPeerCreateKeys>,
532 services: Option<&Vec<DIDPeerService>>,
533 ) -> Result<(String, Vec<DIDPeerCreatedKeys>), DIDPeerError> {
534 let mut result = String::from("did:peer:2");
535
536 let mut private_keys: Vec<DIDPeerCreatedKeys> = vec![];
537 for key in keys {
538 let public_key = if let Some(key) = key.public_key_multibase.as_ref() {
540 key.clone()
541 } else {
542 let (did, secret) = match &key.type_ {
543 Some(type_) => match type_ {
544 DIDPeerKeyType::Ed25519 => {
545 DIDKey::generate(KeyType::Ed25519).map_err(|e| {
546 DIDPeerError::InternalError(format!(
547 "Couldn't create Ed25519 did:key reason: {e}"
548 ))
549 })?
550 }
551 DIDPeerKeyType::Secp256k1 => {
552 DIDKey::generate(KeyType::Secp256k1).map_err(|e| {
553 DIDPeerError::InternalError(format!(
554 "Couldn't create Secp256k1 did:key reason: {e}"
555 ))
556 })?
557 }
558 DIDPeerKeyType::P256 => DIDKey::generate(KeyType::P256).map_err(|e| {
559 DIDPeerError::InternalError(format!(
560 "Couldn't create P256 did:key reason: {e}"
561 ))
562 })?,
563 },
564 None => return Err(DIDPeerError::UnsupportedKeyType),
565 };
566
567 if let SecretMaterial::JWK(jwk) = secret.secret_material {
568 match jwk.params {
569 Params::OKP(map) => {
570 let d = if let Some(d) = &map.d {
571 d
572 } else {
573 return Err(DIDPeerError::KeyParsingError(
574 "Missing private key".to_string(),
575 ));
576 };
577 private_keys.push(DIDPeerCreatedKeys {
578 key_multibase: did[8..].to_string(),
579 curve: map.curve.clone(),
580 d: d.clone(),
581 x: map.x.clone(),
582 y: None,
583 })
584 }
585 Params::EC(map) => {
586 let d = if let Some(d) = &map.d {
587 d
588 } else {
589 return Err(DIDPeerError::KeyParsingError(
590 "Missing private key".to_string(),
591 ));
592 };
593
594 private_keys.push(DIDPeerCreatedKeys {
595 key_multibase: did[8..].to_string(),
596 curve: map.curve.clone(),
597 d: String::from(d),
598 x: map.x.clone(),
599 y: Some(map.y.clone()),
600 })
601 }
602 }
603 } else {
604 return Err(DIDPeerError::InternalError(
605 "Expected Secret Material to be in JWK format!".to_string(),
606 ));
607 }
608
609 did[8..].to_string()
610 };
611
612 match key.purpose {
614 DIDPeerKeys::Verification => {
615 result.push_str(&format!(".V{public_key}",));
616 }
617 DIDPeerKeys::Encryption => {
618 result.push_str(&format!(".E{public_key}",));
619 }
620 }
621 }
622
623 if let Some(services) = services {
624 for service in services {
625 let service = serde_json::to_string(&service).map_err(|e| {
626 DIDPeerError::SyntaxErrorServiceDefinition(format!(
627 "Error parsing service: {e}",
628 ))
629 })?;
630 result.push_str(&format!(".S{}", BASE64_URL_SAFE_NO_PAD.encode(service)));
631 }
632 }
633
634 Ok((result, private_keys))
635 }
636
637 pub async fn expand_keys(doc: &Document) -> Result<Document, DIDPeerError> {
641 let mut new_doc = doc.clone();
642
643 let mut new_vms: Vec<VerificationMethod> = vec![];
644 for v_method in &doc.verification_method {
645 new_vms.push(Self::_convert_vm(v_method).await?);
646 }
647
648 new_doc.verification_method = new_vms;
649 Ok(new_doc)
650 }
651
652 async fn _convert_vm(method: &VerificationMethod) -> Result<VerificationMethod, DIDPeerError> {
654 let current_controller = method.controller.clone();
655 let current_id = method.id.clone();
656
657 let did_key = if let Some(key) = method.property_set.get("publicKeyBase58") {
658 ["did:key:", key.as_str().unwrap()].concat()
659 } else if let Some(key) = method.property_set.get("publicKeyMultibase") {
660 ["did:key:", key.as_str().unwrap()].concat()
661 } else {
662 return Err(DIDPeerError::KeyParsingError(
663 "Failed to convert verification_method. Reason: Missing publicKeyBase58"
664 .to_string(),
665 ));
666 };
667
668 let document = match DIDKey::resolve(&did_key) {
669 Ok(document) => document,
670 Err(e) => {
671 return Err(DIDPeerError::KeyParsingError(format!(
672 "Failed to resolve key ({did_key}). Reason: {e}",
673 )));
674 }
675 };
676
677 if let Some(vm) = document.verification_method.first() {
678 let mut properties: HashMap<String, Value> = HashMap::new();
679 for (k, v) in vm.property_set.iter() {
680 properties.insert(k.clone(), v.clone());
681 }
682
683 Ok(VerificationMethod {
684 id: current_id,
685 type_: vm.type_.clone(),
686 controller: current_controller,
687 expires: None,
688 revoked: None,
689 property_set: properties,
690 })
691 } else {
692 Err(DIDPeerError::KeyParsingError(
693 "Failed to convert verification_method. Reason: Missing verification_method"
694 .to_string(),
695 ))
696 }
697 }
698}
699
700#[cfg(test)]
701mod test {
702 use affinidi_did_common::{one_or_many::OneOrMany, verification_method::VerificationMethod};
703 use affinidi_did_key::DIDKey;
704 use affinidi_secrets_resolver::secrets::KeyType;
705
706 use crate::{
707 DIDPeer, DIDPeerCreateKeys, DIDPeerKeyType, DIDPeerKeys, DIDPeerService,
708 PeerServiceEndPoint, PeerServiceEndPointLong, PeerServiceEndPointLongMap,
709 };
710
711 const DID_PEER: &str = "did:peer:2.Vz6MkiToqovww7vYtxm1xNM15u9JzqzUFZ1k7s7MazYJUyAxv.EzQ3shQLqRUza6AMJFbPuMdvFRFWm1wKviQRnQSC1fScovJN4s.SeyJ0IjoiRElEQ29tbU1lc3NhZ2luZyIsInMiOnsidXJpIjoiaHR0cHM6Ly8xMjcuMC4wLjE6NzAzNyIsImEiOlsiZGlkY29tbS92MiJdLCJyIjpbXX19";
712
713 #[should_panic(
714 expected = "Failed to convert verification_method. Reason: Missing publicKeyBase58"
715 )]
716 #[tokio::test]
717 async fn expand_keys_throws_key_parsing_missing_pbk58_error() {
718 let peer = DIDPeer;
719 let output = peer.resolve(DID_PEER).await.unwrap();
720
721 let mut document = output.clone();
722 let mut new_vms: Vec<VerificationMethod> = vec![];
723 for mut vm in document.verification_method {
724 vm.property_set.remove("publicKeyMultibase");
725 new_vms.push(vm);
726 }
727
728 document.verification_method = new_vms;
729 let _expanded_doc = DIDPeer::expand_keys(&document).await.unwrap();
730 }
731
732 #[tokio::test]
733 async fn expand_keys_works() {
734 let peer = DIDPeer;
735 let document = peer.resolve(DID_PEER).await.expect("Couldn't resolve DID");
736
737 let vm_before_expansion = document.verification_method.clone();
738 let expanded_doc = DIDPeer::expand_keys(&document).await.unwrap();
739 let vms_after_expansion = expanded_doc.verification_method;
740
741 for vm in vms_after_expansion.clone() {
742 assert!(vm.id.as_str().starts_with("did:peer"));
743 }
744 assert_eq!(vm_before_expansion.len(), vms_after_expansion.len())
745 }
746
747 #[tokio::test]
748 async fn create_peer_did_without_keys_and_services() {
749 let keys: Vec<DIDPeerCreateKeys> = vec![];
750 let services: Vec<DIDPeerService> = vec![];
751
752 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
753 let parts: Vec<&str> = did.split(":").collect();
754
755 assert_eq!(parts.len(), 3);
756 assert_eq!(parts[1], "peer");
757 assert!(parts[2].len() == 1);
758 }
759
760 #[tokio::test]
761 async fn create_peer_did_without_keys() {
762 let keys: Vec<DIDPeerCreateKeys> = vec![];
763 let services = vec![DIDPeerService {
764 _type: "dm".into(),
765 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
766 OneOrMany::One(PeerServiceEndPointLongMap {
767 uri: "https://localhost:7037".into(),
768 accept: vec!["didcomm/v2".into()],
769 routing_keys: vec![],
770 }),
771 )),
772 id: None,
773 }];
774
775 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
776 let parts: Vec<&str> = did.split(":").collect();
777 let method_ids: Vec<&str> = parts[2].split(".").collect();
778
779 assert_eq!(parts.len(), 3);
780 assert_eq!(parts[1], "peer");
781 assert!(method_ids.len() > 1);
782 assert!(method_ids[1].len() > 1);
783 }
784
785 #[tokio::test]
786 async fn create_peer_did_without_services() {
787 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::Ed25519), true);
788 let services: Vec<DIDPeerService> = vec![];
789
790 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
791 let parts: Vec<&str> = did.split(":").collect();
792 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
793 method_ids = method_ids[1..].to_vec();
794 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
795
796 method_ids.iter().take(2).for_each(|id| {
797 assert!(keys_multibase.contains(&id[1..].to_string()));
798 });
799 assert_eq!(parts.len(), 3);
800 assert_eq!(parts[1], "peer");
801 }
802
803 #[should_panic(expected = "UnsupportedKeyType")]
804 #[tokio::test]
805 async fn create_peer_did_should_throw_unsupported_key_error_p384() {
806 let (_, _, keys) = _get_keys(None, false);
807 let services = vec![DIDPeerService {
809 _type: "dm".into(),
810 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
811 OneOrMany::One(PeerServiceEndPointLongMap {
812 uri: "https://localhost:7037".into(),
813 accept: vec!["didcomm/v2".into()],
814 routing_keys: vec![],
815 }),
816 )),
817 id: None,
818 }];
819
820 DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
821 }
822
823 #[tokio::test]
824 async fn create_peer_did_works_ed25519_without_passing_pub_key() {
825 let (_, _, keys) = _get_keys(Some(DIDPeerKeyType::Ed25519), false);
826
827 let services = vec![DIDPeerService {
829 _type: "dm".into(),
830 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
831 OneOrMany::One(PeerServiceEndPointLongMap {
832 uri: "https://localhost:7037".into(),
833 accept: vec!["didcomm/v2".into()],
834 routing_keys: vec![],
835 }),
836 )),
837 id: None,
838 }];
839
840 let (did, keys) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
841 let parts: Vec<&str> = did.split(":").collect();
842 let method_ids: Vec<&str> = parts[2].split(".").collect();
843
844 assert_eq!(keys.len(), 2);
845 assert_eq!(parts.len(), 3);
846 assert_eq!(parts[1], "peer");
847 assert_eq!(method_ids.first().unwrap().parse::<i32>().unwrap(), 2);
848 assert_eq!(method_ids.len(), 4);
849 }
850
851 #[tokio::test]
852 async fn create_peer_did_works_p256_without_passing_pub_key() {
853 let (_, _, keys) = _get_keys(Some(DIDPeerKeyType::P256), false);
854
855 let services = vec![DIDPeerService {
857 _type: "dm".into(),
858 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
859 OneOrMany::One(PeerServiceEndPointLongMap {
860 uri: "https://localhost:7037".into(),
861 accept: vec!["didcomm/v2".into()],
862 routing_keys: vec![],
863 }),
864 )),
865 id: None,
866 }];
867
868 let (did, keys) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
869 let parts: Vec<&str> = did.split(":").collect();
870 let method_ids: Vec<&str> = parts[2].split(".").collect();
871
872 assert_eq!(keys.len(), 2);
873 assert_eq!(parts.len(), 3);
874 assert_eq!(parts[1], "peer");
875 assert_eq!(method_ids.first().unwrap().parse::<i32>().unwrap(), 2);
876 assert_eq!(method_ids.len(), 4);
877 }
878
879 #[tokio::test]
880 async fn create_peer_did_works_secp256k1_without_passing_pub_key() {
881 let (_, _, keys) = _get_keys(Some(DIDPeerKeyType::Secp256k1), false);
882
883 let services = vec![DIDPeerService {
885 _type: "dm".into(),
886 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
887 OneOrMany::One(PeerServiceEndPointLongMap {
888 uri: "https://localhost:7037".into(),
889 accept: vec!["didcomm/v2".into()],
890 routing_keys: vec![],
891 }),
892 )),
893 id: None,
894 }];
895
896 let (did, keys) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
897
898 let parts: Vec<&str> = did.split(":").collect();
899 let method_ids: Vec<&str> = parts[2].split(".").collect();
900
901 assert_eq!(keys.len(), 2);
902 assert_eq!(parts.len(), 3);
903 assert_eq!(parts[1], "peer");
904 assert_eq!(method_ids.first().unwrap().parse::<i32>().unwrap(), 2);
905 assert_eq!(method_ids.len(), 4);
906 }
907
908 #[tokio::test]
909 async fn create_peer_did_works_ed25519() {
910 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::Ed25519), true);
911
912 let services = vec![DIDPeerService {
914 _type: "dm".into(),
915 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
916 OneOrMany::One(PeerServiceEndPointLongMap {
917 uri: "https://localhost:7037".into(),
918 accept: vec!["didcomm/v2".into()],
919 routing_keys: vec![],
920 }),
921 )),
922 id: None,
923 }];
924
925 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
926 let parts: Vec<&str> = did.split(":").collect();
927 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
928 method_ids = method_ids[1..].to_vec();
929 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
930
931 method_ids.iter().take(2).for_each(|id| {
932 assert!(keys_multibase.contains(&id[1..].to_string()));
933 });
934
935 assert_eq!(parts.len(), 3);
936 assert_eq!(parts[1], "peer");
937 }
938
939 #[tokio::test]
940 async fn create_peer_did_works_p256() {
941 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::P256), true);
942 let services = vec![DIDPeerService {
944 _type: "dm".into(),
945 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
946 OneOrMany::One(PeerServiceEndPointLongMap {
947 uri: "https://localhost:7037".into(),
948 accept: vec!["didcomm/v2".into()],
949 routing_keys: vec![],
950 }),
951 )),
952 id: None,
953 }];
954
955 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
956 let parts: Vec<&str> = did.split(":").collect();
957 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
958 method_ids = method_ids[1..].to_vec();
959 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
960
961 method_ids.iter().take(2).for_each(|id| {
962 assert!(keys_multibase.contains(&id[1..].to_string()));
963 });
964 assert_eq!(parts.len(), 3);
965 assert_eq!(parts[1], "peer");
966 }
967
968 #[tokio::test]
969 async fn create_peer_did_works_secp256k1() {
970 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::Secp256k1), true);
971 let services = vec![DIDPeerService {
973 _type: "dm".into(),
974 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
975 OneOrMany::One(PeerServiceEndPointLongMap {
976 uri: "https://localhost:7037".into(),
977 accept: vec!["didcomm/v2".into()],
978 routing_keys: vec![],
979 }),
980 )),
981 id: None,
982 }];
983
984 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
985 let parts: Vec<&str> = did.split(":").collect();
986 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
987 method_ids = method_ids[1..].to_vec();
988 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
989
990 method_ids.iter().take(2).for_each(|id| {
991 assert!(keys_multibase.contains(&id[1..].to_string()));
992 });
993 assert_eq!(parts.len(), 3);
994 assert_eq!(parts[1], "peer");
995 }
996
997 fn _get_keys(
998 key_type: Option<DIDPeerKeyType>,
999 with_pub_key: bool,
1000 ) -> (String, String, Vec<DIDPeerCreateKeys>) {
1001 let (e_did_key, _) = match key_type {
1002 Some(DIDPeerKeyType::Ed25519) => {
1003 DIDKey::generate(KeyType::Ed25519).expect("Failed to create did:key")
1004 }
1005 Some(DIDPeerKeyType::P256) => {
1006 DIDKey::generate(KeyType::P256).expect("Failed to create did:key")
1007 }
1008 Some(DIDPeerKeyType::Secp256k1) => {
1009 DIDKey::generate(KeyType::Secp256k1).expect("Failed to create did:key")
1010 }
1011 None => DIDKey::generate(KeyType::P384).expect("Failed to create did:key"),
1012 };
1013 let (v_did_key, _) = match key_type {
1014 Some(DIDPeerKeyType::Ed25519) => {
1015 DIDKey::generate(KeyType::Ed25519).expect("Failed to create did:key")
1016 }
1017 Some(DIDPeerKeyType::P256) => {
1018 DIDKey::generate(KeyType::P256).expect("Failed to create did:key")
1019 }
1020 Some(DIDPeerKeyType::Secp256k1) => {
1021 DIDKey::generate(KeyType::Secp256k1).expect("Failed to create did:key")
1022 }
1023 None => DIDKey::generate(KeyType::P384).expect("Failed to create did:key"),
1024 };
1025
1026 let keys = vec![
1028 DIDPeerCreateKeys {
1029 purpose: DIDPeerKeys::Verification,
1030 type_: key_type.clone(),
1031 public_key_multibase: if with_pub_key {
1032 Some(v_did_key[8..].to_string())
1033 } else {
1034 None
1035 },
1036 },
1037 DIDPeerCreateKeys {
1038 purpose: DIDPeerKeys::Encryption,
1039 type_: key_type.clone(),
1040 public_key_multibase: if with_pub_key {
1041 Some(e_did_key[8..].to_string())
1042 } else {
1043 None
1044 },
1045 },
1046 ];
1047
1048 (e_did_key, v_did_key, keys)
1049 }
1050}
1051
1052#[wasm_bindgen(getter_with_clone)]
1066#[derive(Clone, Serialize, Deserialize)]
1067pub struct DIDService {
1068 pub _type: Option<String>,
1069 pub uri: String,
1070 pub accept: Vec<String>,
1071 pub routing_keys: Vec<String>,
1072 pub id: Option<String>,
1073}
1074
1075#[wasm_bindgen]
1076impl DIDService {
1077 #[wasm_bindgen(constructor)]
1078 pub fn new(
1079 uri: String,
1080 accept: Vec<String>,
1081 routing_keys: Vec<String>,
1082 id: Option<String>,
1083 ) -> Self {
1084 DIDService {
1085 _type: None,
1086 uri,
1087 accept,
1088 routing_keys,
1089 id,
1090 }
1091 }
1092}
1093
1094impl From<DIDService> for DIDPeerService {
1095 fn from(service: DIDService) -> Self {
1096 DIDPeerService {
1097 _type: service._type.unwrap_or("DIDCommMessaging".into()),
1098 service_end_point: PeerServiceEndPoint::Short(PeerServiceEndPointShort::Map(
1099 OneOrMany::One(PeerServiceEndPointShortMap {
1100 uri: service.uri,
1101 a: service.accept,
1102 r: service.routing_keys,
1103 }),
1104 )),
1105 id: service.id,
1106 }
1107 }
1108}
1109
1110impl From<&DIDService> for DIDPeerService {
1111 fn from(service: &DIDService) -> Self {
1112 service.clone().into()
1113 }
1114}
1115
1116#[derive(Clone)]
1124#[wasm_bindgen(getter_with_clone)]
1125pub struct DidPeerCreate {
1126 pub keys: Vec<DIDPeerCreateKeys>,
1127 pub services: Option<Vec<DIDService>>,
1128}
1129
1130#[wasm_bindgen]
1131impl DidPeerCreate {
1132 #[wasm_bindgen(constructor)]
1133 pub fn new(keys: Vec<DIDPeerCreateKeys>, services: Option<Vec<DIDService>>) -> Self {
1134 DidPeerCreate { keys, services }
1135 }
1136}
1137
1138#[derive(Serialize, Deserialize)]
1139#[wasm_bindgen(getter_with_clone)]
1140pub struct DIDPeerResult {
1141 pub did: String,
1142 pub keys: Vec<DIDPeerCreatedKeys>,
1143}
1144
1145#[wasm_bindgen]
1146pub fn create_did_peer(input: &DidPeerCreate) -> Result<DIDPeerResult, DIDPeerError> {
1156 let mut new_services: Vec<DIDPeerService> = vec![];
1158 if let Some(services) = input.services.as_ref() {
1159 for service in services {
1160 new_services.push(service.into());
1161 }
1162 }
1163
1164 let response = DIDPeer::create_peer_did(&input.keys, Some(&new_services));
1166
1167 if let Ok((did, keys)) = response {
1168 Ok(DIDPeerResult { did, keys })
1169 } else {
1170 Err(response.unwrap_err())
1171 }
1172}
1173
1174#[wasm_bindgen]
1175pub async fn resolve_did_peer(did: &str) -> Result<String, DIDPeerError> {
1181 let peer = DIDPeer;
1182
1183 match peer.resolve(did).await {
1184 Ok(document) => match serde_json::to_string_pretty(&document) {
1185 Ok(json) => Ok(json),
1186 Err(e) => Err(DIDPeerError::JsonParsingError(format!(
1187 "Couldn't convert DID Document to JSON. Reason: {e}",
1188 ))),
1189 },
1190 Err(e) => Err(DIDPeerError::KeyParsingError(format!(
1191 "Failed to resolve key ({did}). Reason: {e}",
1192 ))),
1193 }
1194}