1use base64::prelude::*;
21use iref::UriBuf;
22use serde::{Deserialize, Serialize};
23use serde_json::Value;
24use service::convert_service;
25use ssi::{
26 OneOrMany,
27 dids::{
28 DID, DIDBuf, DIDKey, DIDMethod, DIDMethodResolver, DIDURL, DIDURLBuf, DIDURLReferenceBuf,
29 Document, RelativeDIDURLBuf,
30 document::{
31 self, DIDVerificationMethod, Resource, Service, VerificationRelationships,
32 representation::{self, MediaType},
33 service::Endpoint,
34 verification_method,
35 },
36 key::VerificationMethodType,
37 resolution::{self, Content, Error, Options, Output, Parameters},
38 },
39 jwk::Params,
40 prelude::*,
41};
42use std::{collections::BTreeMap, fmt};
43use thiserror::Error;
44use wasm_bindgen::prelude::*;
45
46pub mod service;
47
48#[derive(Error, Debug)]
49pub enum DIDPeerError {
50 #[error("Unsupported key type")]
51 UnsupportedKeyType,
52 #[error("Unsupported curve: {0}")]
53 UnsupportedCurve(String),
54 #[error("Unsupported source")]
55 UnsupportedSource,
56 #[error("Syntax error on Service definition: {0}")]
57 SyntaxErrorServiceDefinition(String),
58 #[error("Unsupported Method. Must be method 2")]
59 MethodNotSupported,
60 #[error("Key Parsing error {0}")]
61 KeyParsingError(String),
62 #[error("DID Document doesn't contain any verificationMethod items")]
63 MissingVerificationMethods,
64 #[error("JSON Parsing error: {0}")]
65 JsonParsingError(String),
66 #[error("Internal error: {0}")]
67 InternalError(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#[derive(Debug, Serialize, Deserialize)]
182pub struct DIDPeerService {
183 #[serde(rename = "t")]
184 #[serde(alias = "t")]
185 pub _type: String,
186 #[serde(rename = "s")]
187 #[serde(alias = "s")]
188 pub service_end_point: PeerServiceEndPoint, #[serde(skip_serializing_if = "Option::is_none")]
192 pub id: Option<String>,
193}
194
195impl DIDPeerService {
196 fn convert(did: &str, service: DIDPeerService) -> Result<Service, DIDPeerError> {
197 let service_endpoint = match serde_json::to_value(PeerServiceEndPoint::to_long(
198 &service.service_end_point,
199 )) {
200 Ok(value) => {
201 if value.is_string() {
202 if let Some(value) = value.as_str() {
203 if let Ok(uri) = UriBuf::new(value.as_bytes().to_vec()) {
204 Some(OneOrMany::One(Endpoint::Uri(uri)))
205 } else {
206 return Err(DIDPeerError::SyntaxErrorServiceDefinition(format!(
207 "Couldn't convert ServiceEndPoint to a valid URI: {value}",
208 )));
209 }
210 } else {
211 return Err(DIDPeerError::SyntaxErrorServiceDefinition(format!(
212 "Service URI appears to be a string, but can't parse as a string: {value}",
213 )));
214 }
215 } else {
216 Some(OneOrMany::One(Endpoint::Map(value)))
217 }
218 }
219 Err(err) => {
220 return Err(DIDPeerError::SyntaxErrorServiceDefinition(format!(
221 "Couldn't convert ServiceEndPoint to a valid representation. Reason: {err}",
222 )));
223 }
224 };
225
226 let id = if let Some(id) = service.id {
227 [did, &id].concat()
228 } else {
229 [did, "#service"].concat()
230 };
231
232 let id = match UriBuf::new(id.as_bytes().to_vec()) {
233 Ok(uri) => uri,
234 Err(e) => {
235 return Err(DIDPeerError::SyntaxErrorServiceDefinition(format!(
236 "Error parsing service id: {id}. Reason: {e:?}",
237 )));
238 }
239 };
240
241 Ok(Service {
242 id,
243 type_: OneOrMany::One("DIDCommMessaging".into()),
244 service_endpoint,
245 property_set: BTreeMap::new(),
246 })
247 }
248}
249
250#[derive(Clone)]
251#[wasm_bindgen]
252pub enum DIDPeerKeys {
256 Verification,
257 Encryption,
258}
259
260impl fmt::Display for DIDPeerKeys {
261 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
262 match *self {
263 DIDPeerKeys::Verification => write!(f, "verification"),
264 DIDPeerKeys::Encryption => write!(f, "encryption"),
265 }
266 }
267}
268
269#[derive(Clone)]
270#[wasm_bindgen]
271pub enum DIDPeerKeyType {
273 Ed25519,
274 Secp256k1,
275 P256,
276}
277
278impl fmt::Display for DIDPeerKeyType {
279 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280 match *self {
281 DIDPeerKeyType::Ed25519 => write!(f, "ed25519"),
282 DIDPeerKeyType::Secp256k1 => write!(f, "secp256k1"),
283 DIDPeerKeyType::P256 => write!(f, "p256"),
284 }
285 }
286}
287
288#[derive(Clone)]
289#[wasm_bindgen(getter_with_clone)]
290pub struct DIDPeerCreateKeys {
295 pub purpose: DIDPeerKeys,
296 pub type_: Option<DIDPeerKeyType>,
297 pub public_key_multibase: Option<String>,
298}
299
300#[wasm_bindgen]
301impl DIDPeerCreateKeys {
302 #[wasm_bindgen(constructor)]
303 pub fn new(
304 purpose: DIDPeerKeys,
305 type_: Option<DIDPeerKeyType>,
306 public_key_multibase: Option<String>,
307 ) -> Self {
308 DIDPeerCreateKeys {
309 purpose,
310 type_,
311 public_key_multibase,
312 }
313 }
314}
315
316#[derive(Clone, Debug, Serialize, Deserialize)]
324#[wasm_bindgen(getter_with_clone)]
325pub struct DIDPeerCreatedKeys {
326 pub key_multibase: String,
327 pub curve: String,
328 pub d: String,
329 pub x: String,
330 pub y: Option<String>,
331}
332
333fn process_key(did: &str, id: &str, public_key: &str) -> Result<DIDVerificationMethod, Error> {
335 let mut properties = BTreeMap::new();
336
337 properties.insert(
338 "publicKeyMultibase".to_string(),
339 Value::String(public_key.to_string()),
340 );
341
342 Ok(DIDVerificationMethod {
343 id: DIDURLBuf::from_string(["did:peer:", did, id].concat()).unwrap(),
344 type_: "Multikey".to_string(),
345 controller: DIDBuf::from_string(["did:peer:", did].concat()).unwrap(),
346 properties,
347 })
348}
349
350impl DIDMethodResolver for DIDPeer {
351 async fn resolve_method_representation<'a>(
352 &'a self,
353 method_specific_id: &'a str,
354 options: Options,
355 ) -> Result<Output<Vec<u8>>, Error> {
356 let did = ["did:peer:", method_specific_id].concat();
357
358 if let Some(id) = method_specific_id.strip_prefix('0') {
360 return DIDKey.resolve_method_representation(id, options).await;
361 }
362
363 if !method_specific_id.starts_with('2') {
365 return Err(Error::MethodNotSupported(
366 "did:peer version 2 supported only".to_string(),
367 ));
368 }
369
370 let mut context = BTreeMap::new();
371 context.insert("@base".to_string(), serde_json::json!(method_specific_id));
372
373 let mut verification_methods: Vec<DIDVerificationMethod> = Vec::new();
374 let mut verification_relationships: VerificationRelationships =
375 VerificationRelationships::default();
376
377 let mut services: Vec<Service> = Vec::new();
381
382 let parts: Vec<&str> = method_specific_id[2..].split('.').collect();
385 let mut key_count: u32 = 1;
386 let mut service_idx: u32 = 0;
387
388 for part in parts {
389 let ch = part.chars().next();
390 match ch {
391 Some(e) => {
392 match e {
393 'A' => {
394 verification_methods.push(process_key(
396 method_specific_id,
397 &["#key-", &key_count.to_string()].concat(),
398 &part[1..],
399 )?);
400
401 verification_relationships.assertion_method.push(
402 verification_method::ValueOrReference::Reference(
403 DIDURLReferenceBuf::Relative(
404 RelativeDIDURLBuf::new(
405 ["#key-", &key_count.to_string()]
406 .concat()
407 .as_bytes()
408 .to_vec(),
409 )
410 .unwrap(),
411 ),
412 ),
413 );
414 key_count += 1;
415 }
416 'D' => {
417 verification_methods.push(process_key(
419 method_specific_id,
420 &["#key-", &key_count.to_string()].concat(),
421 &part[1..],
422 )?);
423
424 verification_relationships.capability_delegation.push(
425 verification_method::ValueOrReference::Reference(
426 DIDURLReferenceBuf::Relative(
427 RelativeDIDURLBuf::new(
428 ["#key-", &key_count.to_string()]
429 .concat()
430 .as_bytes()
431 .to_vec(),
432 )
433 .unwrap(),
434 ),
435 ),
436 );
437 key_count += 1;
438 }
439 'E' => {
440 verification_methods.push(process_key(
442 method_specific_id,
443 &["#key-", &key_count.to_string()].concat(),
444 &part[1..],
445 )?);
446 verification_relationships.key_agreement.push(
447 verification_method::ValueOrReference::Reference(
448 DIDURLReferenceBuf::Relative(
449 RelativeDIDURLBuf::new(
450 ["#key-", &key_count.to_string()]
451 .concat()
452 .as_bytes()
453 .to_vec(),
454 )
455 .unwrap(),
456 ),
457 ),
458 );
459 key_count += 1;
460 }
461 'I' => {
462 verification_methods.push(process_key(
464 method_specific_id,
465 &["#key-", &key_count.to_string()].concat(),
466 &part[1..],
467 )?);
468
469 verification_relationships.capability_invocation.push(
470 verification_method::ValueOrReference::Reference(
471 DIDURLReferenceBuf::Relative(
472 RelativeDIDURLBuf::new(
473 ["#key-", &key_count.to_string()]
474 .concat()
475 .as_bytes()
476 .to_vec(),
477 )
478 .unwrap(),
479 ),
480 ),
481 );
482 key_count += 1;
483 }
484 'V' => {
485 verification_methods.push(process_key(
487 method_specific_id,
488 &["#key-", &key_count.to_string()].concat(),
489 &part[1..],
490 )?);
491
492 verification_relationships.authentication.push(
493 verification_method::ValueOrReference::Reference(
494 DIDURLReferenceBuf::Relative(
495 RelativeDIDURLBuf::new(
496 ["#key-", &key_count.to_string()]
497 .concat()
498 .as_bytes()
499 .to_vec(),
500 )
501 .unwrap(),
502 ),
503 ),
504 );
505 verification_relationships.assertion_method.push(
506 verification_method::ValueOrReference::Reference(
507 DIDURLReferenceBuf::Relative(
508 RelativeDIDURLBuf::new(
509 ["#key-", &key_count.to_string()]
510 .concat()
511 .as_bytes()
512 .to_vec(),
513 )
514 .unwrap(),
515 ),
516 ),
517 );
518
519 key_count += 1;
520 }
521 'S' => {
522 let service = convert_service(&did, part, service_idx)
524 .map_err(|e| Error::Internal(e.to_string()))?;
525 services.push(service);
526 service_idx += 1;
527 }
528 other => {
529 return Err(Error::RepresentationNotSupported(format!(
530 "An invalid Purpose Code ({other}) was found in the DID",
531 )));
532 }
533 }
534 }
535 None => {
536 }
539 }
540 }
541
542 let vm_type = match options.parameters.public_key_format {
543 Some(name) => VerificationMethodType::from_name(&name).ok_or_else(|| {
544 Error::Internal(format!(
545 "verification method type `{name}` unsupported by did:peer"
546 ))
547 })?,
548 None => VerificationMethodType::Multikey,
549 };
550
551 let mut doc =
552 Document::new(DIDBuf::from_string(["did:peer:", method_specific_id].concat()).unwrap());
553 doc.verification_method = verification_methods;
554 doc.verification_relationships = verification_relationships;
555 doc.service = services;
556
557 let mut json_ld_context = Vec::new();
558 if let Some(context) = vm_type.context_entry() {
559 json_ld_context.push(context)
560 }
561
562 let content_type = options.accept.unwrap_or(MediaType::JsonLd);
563
564 let represented = doc.into_representation(representation::Options::from_media_type(
565 content_type,
566 move || representation::json_ld::Options {
567 context: representation::json_ld::Context::array(
568 representation::json_ld::DIDContext::V1,
569 json_ld_context,
570 ),
571 },
572 ));
573
574 Ok(resolution::Output::new(
575 represented.to_bytes(),
576 document::Metadata::default(),
577 resolution::Metadata::from_content_type(Some(content_type.to_string())),
578 ))
579 }
580}
581
582impl DIDMethod for DIDPeer {
583 const DID_METHOD_NAME: &'static str = "peer";
584}
585
586impl DIDPeer {
587 pub fn create_peer_did(
634 keys: &Vec<DIDPeerCreateKeys>,
635 services: Option<&Vec<DIDPeerService>>,
636 ) -> Result<(String, Vec<DIDPeerCreatedKeys>), DIDPeerError> {
637 let mut result = String::from("did:peer:2");
638
639 let mut private_keys: Vec<DIDPeerCreatedKeys> = vec![];
640 for key in keys {
641 let public_key = if let Some(key) = key.public_key_multibase.as_ref() {
643 key.clone()
644 } else {
645 let jwk = match &key.type_ {
646 Some(type_) => match type_ {
647 DIDPeerKeyType::Ed25519 => match JWK::generate_ed25519() {
648 Ok(k) => k,
649 Err(e) => {
650 return Err(DIDPeerError::InternalError(format!(
651 "Failed to generate ed25519 key. Reason: {e}",
652 )));
653 }
654 },
655 DIDPeerKeyType::Secp256k1 => JWK::generate_secp256k1(),
656 DIDPeerKeyType::P256 => JWK::generate_p256(),
657 },
658 None => return Err(DIDPeerError::UnsupportedKeyType),
659 };
660 let did = if let Ok(output) = ssi::dids::DIDKey::generate(&jwk) {
661 output.to_string()
662 } else {
663 return Err(DIDPeerError::InternalError(
664 "Couldn't create did:key".to_string(),
665 ));
666 };
667
668 match jwk.params {
669 Params::OKP(map) => {
670 let d = if let Some(d) = &map.private_key {
671 d
672 } else {
673 return Err(DIDPeerError::KeyParsingError(
674 "Missing private key".to_string(),
675 ));
676 };
677 private_keys.push(DIDPeerCreatedKeys {
678 key_multibase: did[8..].to_string(),
679 curve: map.curve.clone(),
680 d: String::from(d),
681 x: String::from(map.public_key.clone()),
682 y: None,
683 })
684 }
685 Params::EC(map) => {
686 let curve = if let Some(curve) = &map.curve {
687 curve
688 } else {
689 return Err(DIDPeerError::KeyParsingError("Missing curve".to_string()));
690 };
691 let d = if let Some(d) = &map.ecc_private_key {
692 d
693 } else {
694 return Err(DIDPeerError::KeyParsingError(
695 "Missing private key".to_string(),
696 ));
697 };
698
699 let x = if let Some(x) = &map.x_coordinate {
700 x
701 } else {
702 return Err(DIDPeerError::KeyParsingError(
703 "Missing public key (x)".to_string(),
704 ));
705 };
706 let y = if let Some(y) = &map.y_coordinate {
707 y
708 } else {
709 return Err(DIDPeerError::KeyParsingError(
710 "Missing public key (y)".to_string(),
711 ));
712 };
713
714 private_keys.push(DIDPeerCreatedKeys {
715 key_multibase: did[8..].to_string(),
716 curve: curve.into(),
717 d: String::from(d),
718 x: String::from(x),
719 y: Some(String::from(y)),
720 })
721 }
722 _ => return Err(DIDPeerError::UnsupportedKeyType),
723 }
724
725 did[8..].to_string()
726 };
727
728 match key.purpose {
730 DIDPeerKeys::Verification => {
731 result.push_str(&format!(".V{public_key}",));
732 }
733 DIDPeerKeys::Encryption => {
734 result.push_str(&format!(".E{public_key}",));
735 }
736 }
737 }
738
739 if let Some(services) = services {
740 for service in services {
741 let service = serde_json::to_string(&service).map_err(|e| {
742 DIDPeerError::SyntaxErrorServiceDefinition(format!(
743 "Error parsing service: {e}",
744 ))
745 })?;
746 result.push_str(&format!(".S{}", BASE64_URL_SAFE_NO_PAD.encode(service)));
747 }
748 }
749
750 Ok((result, private_keys))
751 }
752
753 pub async fn expand_keys(doc: &Document) -> Result<Document, DIDPeerError> {
757 let mut new_doc = doc.clone();
758
759 let mut new_vms: Vec<DIDVerificationMethod> = vec![];
760 for v_method in &doc.verification_method {
761 new_vms.push(Self::_convert_vm(v_method).await?);
762 }
763
764 new_doc.verification_method = new_vms;
765 Ok(new_doc)
766 }
767
768 async fn _convert_vm(
770 method: &DIDVerificationMethod,
771 ) -> Result<DIDVerificationMethod, DIDPeerError> {
772 let current_controller = method.controller.clone();
773 let current_id = method.id.clone();
774 let did_key = if let Some(key) = method.properties.get("publicKeyBase58") {
775 ["did:key:", key.as_str().unwrap()].concat()
776 } else if let Some(key) = method.properties.get("publicKeyMultibase") {
777 ["did:key:", key.as_str().unwrap()].concat()
778 } else {
779 return Err(DIDPeerError::KeyParsingError(
780 "Failed to convert verification_method. Reason: Missing publicKeyBase58"
781 .to_string(),
782 ));
783 };
784
785 let key_method = DIDKey;
786
787 let output = match key_method
788 .dereference_with(
789 DIDURL::new::<String>(&did_key.clone()).unwrap(),
790 Options {
791 accept: None,
792 parameters: Parameters {
793 public_key_format: Some("JsonWebKey2020".to_string()),
794 ..Default::default()
795 },
796 },
797 )
798 .await
799 {
800 Ok(output) => output.content,
801 Err(e) => {
802 return Err(DIDPeerError::KeyParsingError(format!(
803 "Failed to resolve key ({did_key}). Reason: {e}",
804 )));
805 }
806 };
807
808 if let Content::Resource(Resource::Document(doc)) = output
809 && let Some(vm) = doc.into_any_verification_method()
810 {
811 let mut new_vm = vm.clone();
812 new_vm.controller = current_controller;
813 new_vm.id = current_id;
814 return Ok(new_vm);
815 }
816
817 Err(DIDPeerError::KeyParsingError(
818 "Failed to convert verification_method. Reason: Missing verification_method"
819 .to_string(),
820 ))
821 }
822}
823
824#[cfg(test)]
825mod test {
826 use crate::{
827 DIDPeer, DIDPeerCreateKeys, DIDPeerKeyType, DIDPeerKeys, DIDPeerService,
828 PeerServiceEndPoint, PeerServiceEndPointLong, PeerServiceEndPointLongMap,
829 };
830
831 use ssi::{
832 JWK,
833 dids::{DID, DIDBuf, DIDResolver, document::DIDVerificationMethod},
834 verification_methods::ssi_core::OneOrMany,
835 };
836
837 const DID_PEER: &str = "did:peer:2.Vz6MkiToqovww7vYtxm1xNM15u9JzqzUFZ1k7s7MazYJUyAxv.EzQ3shQLqRUza6AMJFbPuMdvFRFWm1wKviQRnQSC1fScovJN4s.SeyJ0IjoiRElEQ29tbU1lc3NhZ2luZyIsInMiOnsidXJpIjoiaHR0cHM6Ly8xMjcuMC4wLjE6NzAzNyIsImEiOlsiZGlkY29tbS92MiJdLCJyIjpbXX19";
838
839 #[should_panic(
840 expected = "Failed to convert verification_method. Reason: Missing publicKeyBase58"
841 )]
842 #[tokio::test]
843 async fn expand_keys_throws_key_parsing_missing_pbk58_error() {
844 let peer = DIDPeer;
845 let output = peer
846 .resolve(DID::new::<String>(&DID_PEER.to_string()).unwrap())
847 .await
848 .unwrap();
849
850 let mut document = output.document.document().clone();
851 let mut new_vms: Vec<DIDVerificationMethod> = vec![];
852 for mut vm in document.verification_method {
853 vm.properties.remove("publicKeyMultibase");
854 new_vms.push(vm);
855 }
856
857 document.verification_method = new_vms;
858 let _expanded_doc = DIDPeer::expand_keys(&document).await.unwrap();
859 }
860
861 #[tokio::test]
862 async fn expand_keys_works() {
863 let peer = DIDPeer;
864 let document = peer
865 .resolve(DID::new::<String>(&DID_PEER.to_string()).unwrap())
866 .await
867 .expect("Couldn't resolve DID");
868
869 let vm_before_expansion = document.clone().document.verification_method.clone();
870 let expanded_doc = DIDPeer::expand_keys(&document.document).await.unwrap();
871 let vms_after_expansion = expanded_doc.verification_method;
872
873 for vm in vms_after_expansion.clone() {
874 assert!(vm.id.starts_with("did:peer"));
875 }
876 assert_eq!(vm_before_expansion.len(), vms_after_expansion.len())
877 }
878
879 #[tokio::test]
880 async fn create_peer_did_without_keys_and_services() {
881 let keys: Vec<DIDPeerCreateKeys> = vec![];
882 let services: Vec<DIDPeerService> = vec![];
883
884 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
885 let parts: Vec<&str> = did.split(":").collect();
886
887 assert_eq!(parts.len(), 3);
888 assert_eq!(parts[1], "peer");
889 assert!(parts[2].len() == 1);
890 }
891
892 #[tokio::test]
893 async fn create_peer_did_without_keys() {
894 let keys: Vec<DIDPeerCreateKeys> = vec![];
895 let services = vec![DIDPeerService {
896 _type: "dm".into(),
897 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
898 OneOrMany::One(PeerServiceEndPointLongMap {
899 uri: "https://localhost:7037".into(),
900 accept: vec!["didcomm/v2".into()],
901 routing_keys: vec![],
902 }),
903 )),
904 id: None,
905 }];
906
907 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
908 let parts: Vec<&str> = did.split(":").collect();
909 let method_ids: Vec<&str> = parts[2].split(".").collect();
910
911 assert_eq!(parts.len(), 3);
912 assert_eq!(parts[1], "peer");
913 assert!(method_ids.len() > 1);
914 assert!(method_ids[1].len() > 1);
915 }
916
917 #[tokio::test]
918 async fn create_peer_did_without_services() {
919 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::Ed25519), true);
920 let services: Vec<DIDPeerService> = vec![];
921
922 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
923 let parts: Vec<&str> = did.split(":").collect();
924 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
925 method_ids = method_ids[1..].to_vec();
926 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
927
928 method_ids.iter().take(2).for_each(|id| {
929 assert!(keys_multibase.contains(&id[1..].to_string()));
930 });
931 assert_eq!(parts.len(), 3);
932 assert_eq!(parts[1], "peer");
933 }
934
935 #[should_panic(expected = "UnsupportedKeyType")]
936 #[tokio::test]
937 async fn create_peer_did_should_throw_unsupported_key_error_p384() {
938 let (_, _, keys) = _get_keys(None, false);
939 let services = vec![DIDPeerService {
941 _type: "dm".into(),
942 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
943 OneOrMany::One(PeerServiceEndPointLongMap {
944 uri: "https://localhost:7037".into(),
945 accept: vec!["didcomm/v2".into()],
946 routing_keys: vec![],
947 }),
948 )),
949 id: None,
950 }];
951
952 DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
953 }
954
955 #[tokio::test]
956 async fn create_peer_did_works_ed25519_without_passing_pub_key() {
957 let (_, _, keys) = _get_keys(Some(DIDPeerKeyType::Ed25519), false);
958
959 let services = vec![DIDPeerService {
961 _type: "dm".into(),
962 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
963 OneOrMany::One(PeerServiceEndPointLongMap {
964 uri: "https://localhost:7037".into(),
965 accept: vec!["didcomm/v2".into()],
966 routing_keys: vec![],
967 }),
968 )),
969 id: None,
970 }];
971
972 let (did, keys) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
973 let parts: Vec<&str> = did.split(":").collect();
974 let method_ids: Vec<&str> = parts[2].split(".").collect();
975
976 assert_eq!(keys.len(), 2);
977 assert_eq!(parts.len(), 3);
978 assert_eq!(parts[1], "peer");
979 assert_eq!(method_ids.first().unwrap().parse::<i32>().unwrap(), 2);
980 assert_eq!(method_ids.len(), 4);
981 }
982
983 #[tokio::test]
984 async fn create_peer_did_works_p256_without_passing_pub_key() {
985 let (_, _, keys) = _get_keys(Some(DIDPeerKeyType::P256), false);
986
987 let services = vec![DIDPeerService {
989 _type: "dm".into(),
990 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
991 OneOrMany::One(PeerServiceEndPointLongMap {
992 uri: "https://localhost:7037".into(),
993 accept: vec!["didcomm/v2".into()],
994 routing_keys: vec![],
995 }),
996 )),
997 id: None,
998 }];
999
1000 let (did, keys) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
1001 let parts: Vec<&str> = did.split(":").collect();
1002 let method_ids: Vec<&str> = parts[2].split(".").collect();
1003
1004 assert_eq!(keys.len(), 2);
1005 assert_eq!(parts.len(), 3);
1006 assert_eq!(parts[1], "peer");
1007 assert_eq!(method_ids.first().unwrap().parse::<i32>().unwrap(), 2);
1008 assert_eq!(method_ids.len(), 4);
1009 }
1010
1011 #[tokio::test]
1012 async fn create_peer_did_works_secp256k1_without_passing_pub_key() {
1013 let (_, _, keys) = _get_keys(Some(DIDPeerKeyType::Secp256k1), false);
1014
1015 let services = vec![DIDPeerService {
1017 _type: "dm".into(),
1018 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
1019 OneOrMany::One(PeerServiceEndPointLongMap {
1020 uri: "https://localhost:7037".into(),
1021 accept: vec!["didcomm/v2".into()],
1022 routing_keys: vec![],
1023 }),
1024 )),
1025 id: None,
1026 }];
1027
1028 let (did, keys) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
1029
1030 let parts: Vec<&str> = did.split(":").collect();
1031 let method_ids: Vec<&str> = parts[2].split(".").collect();
1032
1033 assert_eq!(keys.len(), 2);
1034 assert_eq!(parts.len(), 3);
1035 assert_eq!(parts[1], "peer");
1036 assert_eq!(method_ids.first().unwrap().parse::<i32>().unwrap(), 2);
1037 assert_eq!(method_ids.len(), 4);
1038 }
1039
1040 #[tokio::test]
1041 async fn create_peer_did_works_ed25519() {
1042 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::Ed25519), true);
1043
1044 let services = vec![DIDPeerService {
1046 _type: "dm".into(),
1047 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
1048 OneOrMany::One(PeerServiceEndPointLongMap {
1049 uri: "https://localhost:7037".into(),
1050 accept: vec!["didcomm/v2".into()],
1051 routing_keys: vec![],
1052 }),
1053 )),
1054 id: None,
1055 }];
1056
1057 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
1058 let parts: Vec<&str> = did.split(":").collect();
1059 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
1060 method_ids = method_ids[1..].to_vec();
1061 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
1062
1063 method_ids.iter().take(2).for_each(|id| {
1064 assert!(keys_multibase.contains(&id[1..].to_string()));
1065 });
1066
1067 assert_eq!(parts.len(), 3);
1068 assert_eq!(parts[1], "peer");
1069 }
1070
1071 #[tokio::test]
1072 async fn create_peer_did_works_p256() {
1073 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::P256), true);
1074 let services = vec![DIDPeerService {
1076 _type: "dm".into(),
1077 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
1078 OneOrMany::One(PeerServiceEndPointLongMap {
1079 uri: "https://localhost:7037".into(),
1080 accept: vec!["didcomm/v2".into()],
1081 routing_keys: vec![],
1082 }),
1083 )),
1084 id: None,
1085 }];
1086
1087 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
1088 let parts: Vec<&str> = did.split(":").collect();
1089 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
1090 method_ids = method_ids[1..].to_vec();
1091 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
1092
1093 method_ids.iter().take(2).for_each(|id| {
1094 assert!(keys_multibase.contains(&id[1..].to_string()));
1095 });
1096 assert_eq!(parts.len(), 3);
1097 assert_eq!(parts[1], "peer");
1098 }
1099
1100 #[tokio::test]
1101 async fn create_peer_did_works_secp256k1() {
1102 let (e_did_key, v_did_key, keys) = _get_keys(Some(DIDPeerKeyType::Secp256k1), true);
1103 let services = vec![DIDPeerService {
1105 _type: "dm".into(),
1106 service_end_point: PeerServiceEndPoint::Long(PeerServiceEndPointLong::Map(
1107 OneOrMany::One(PeerServiceEndPointLongMap {
1108 uri: "https://localhost:7037".into(),
1109 accept: vec!["didcomm/v2".into()],
1110 routing_keys: vec![],
1111 }),
1112 )),
1113 id: None,
1114 }];
1115
1116 let (did, _) = DIDPeer::create_peer_did(&keys, Some(&services)).unwrap();
1117 let parts: Vec<&str> = did.split(":").collect();
1118 let mut method_ids: Vec<&str> = parts[2].split(".").collect();
1119 method_ids = method_ids[1..].to_vec();
1120 let keys_multibase = [v_did_key[8..].to_string(), e_did_key[8..].to_string()];
1121
1122 method_ids.iter().take(2).for_each(|id| {
1123 assert!(keys_multibase.contains(&id[1..].to_string()));
1124 });
1125 assert_eq!(parts.len(), 3);
1126 assert_eq!(parts[1], "peer");
1127 }
1128
1129 fn _get_keys(
1130 key_type: Option<DIDPeerKeyType>,
1131 with_pub_key: bool,
1132 ) -> (DIDBuf, DIDBuf, Vec<DIDPeerCreateKeys>) {
1133 let encryption_key = match key_type {
1134 Some(DIDPeerKeyType::Ed25519) => JWK::generate_ed25519().unwrap(),
1135 Some(DIDPeerKeyType::P256) => JWK::generate_p256(),
1136 Some(DIDPeerKeyType::Secp256k1) => JWK::generate_secp256k1(),
1137 None => JWK::generate_p384(),
1138 };
1139 let verification_key = match key_type {
1140 Some(DIDPeerKeyType::Ed25519) => JWK::generate_ed25519().unwrap(),
1141 Some(DIDPeerKeyType::P256) => JWK::generate_p256(),
1142 Some(DIDPeerKeyType::Secp256k1) => JWK::generate_secp256k1(),
1143 None => JWK::generate_p384(),
1144 };
1145 let e_did_key = ssi::dids::DIDKey::generate(&encryption_key).unwrap();
1147 let v_did_key = ssi::dids::DIDKey::generate(&verification_key).unwrap();
1148
1149 let keys = vec![
1151 DIDPeerCreateKeys {
1152 purpose: DIDPeerKeys::Verification,
1153 type_: key_type.clone(),
1154 public_key_multibase: if with_pub_key {
1155 Some(v_did_key[8..].to_string())
1156 } else {
1157 None
1158 },
1159 },
1160 DIDPeerCreateKeys {
1161 purpose: DIDPeerKeys::Encryption,
1162 type_: key_type.clone(),
1163 public_key_multibase: if with_pub_key {
1164 Some(e_did_key[8..].to_string())
1165 } else {
1166 None
1167 },
1168 },
1169 ];
1170
1171 (e_did_key, v_did_key, keys)
1172 }
1173}
1174
1175#[wasm_bindgen(getter_with_clone)]
1189#[derive(Clone, Serialize, Deserialize)]
1190pub struct DIDService {
1191 pub _type: Option<String>,
1192 pub uri: String,
1193 pub accept: Vec<String>,
1194 pub routing_keys: Vec<String>,
1195 pub id: Option<String>,
1196}
1197
1198#[wasm_bindgen]
1199impl DIDService {
1200 #[wasm_bindgen(constructor)]
1201 pub fn new(
1202 uri: String,
1203 accept: Vec<String>,
1204 routing_keys: Vec<String>,
1205 id: Option<String>,
1206 ) -> Self {
1207 DIDService {
1208 _type: None,
1209 uri,
1210 accept,
1211 routing_keys,
1212 id,
1213 }
1214 }
1215}
1216
1217impl From<DIDService> for DIDPeerService {
1218 fn from(service: DIDService) -> Self {
1219 DIDPeerService {
1220 _type: service._type.unwrap_or("DIDCommMessaging".into()),
1221 service_end_point: PeerServiceEndPoint::Short(PeerServiceEndPointShort::Map(
1222 OneOrMany::One(PeerServiceEndPointShortMap {
1223 uri: service.uri,
1224 a: service.accept,
1225 r: service.routing_keys,
1226 }),
1227 )),
1228 id: service.id,
1229 }
1230 }
1231}
1232
1233impl From<&DIDService> for DIDPeerService {
1234 fn from(service: &DIDService) -> Self {
1235 service.clone().into()
1236 }
1237}
1238
1239#[derive(Clone)]
1247#[wasm_bindgen(getter_with_clone)]
1248pub struct DidPeerCreate {
1249 pub keys: Vec<DIDPeerCreateKeys>,
1250 pub services: Option<Vec<DIDService>>,
1251}
1252
1253#[wasm_bindgen]
1254impl DidPeerCreate {
1255 #[wasm_bindgen(constructor)]
1256 pub fn new(keys: Vec<DIDPeerCreateKeys>, services: Option<Vec<DIDService>>) -> Self {
1257 DidPeerCreate { keys, services }
1258 }
1259}
1260
1261#[derive(Serialize, Deserialize)]
1262#[wasm_bindgen(getter_with_clone)]
1263pub struct DIDPeerResult {
1264 pub did: String,
1265 pub keys: Vec<DIDPeerCreatedKeys>,
1266}
1267
1268#[wasm_bindgen]
1269pub fn create_did_peer(input: &DidPeerCreate) -> Result<DIDPeerResult, DIDPeerError> {
1279 let mut new_services: Vec<DIDPeerService> = vec![];
1281 if let Some(services) = input.services.as_ref() {
1282 for service in services {
1283 new_services.push(service.into());
1284 }
1285 }
1286
1287 let response = DIDPeer::create_peer_did(&input.keys, Some(&new_services));
1289
1290 if let Ok((did, keys)) = response {
1291 Ok(DIDPeerResult { did, keys })
1292 } else {
1293 Err(response.unwrap_err())
1294 }
1295}
1296
1297#[wasm_bindgen]
1298pub async fn resolve_did_peer(did: &str) -> Result<String, DIDPeerError> {
1304 let peer = DIDPeer;
1305
1306 match peer
1307 .resolve(DID::new::<String>(&did.to_string()).unwrap())
1308 .await
1309 {
1310 Ok(output) => match serde_json::to_string_pretty(&output.document) {
1311 Ok(json) => Ok(json),
1312 Err(e) => Err(DIDPeerError::JsonParsingError(format!(
1313 "Couldn't convert DID Document to JSON. Reason: {e}",
1314 ))),
1315 },
1316 Err(e) => Err(DIDPeerError::KeyParsingError(format!(
1317 "Failed to resolve key ({did}). Reason: {e}",
1318 ))),
1319 }
1320}