Skip to main content

affinidi_did_common/
lib.rs

1/*!
2*   DID Document Definition
3*/
4
5use std::collections::HashMap;
6
7use affinidi_encoding::EncodingError;
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use thiserror::Error;
11use url::Url;
12
13use crate::{
14    service::Service,
15    verification_method::{VerificationMethod, VerificationRelationship},
16};
17
18pub mod builder;
19pub mod did;
20pub mod did_method;
21pub mod document;
22pub mod one_or_many;
23pub mod service;
24pub mod verification_method;
25
26pub use builder::{DocumentBuilder, ServiceBuilder, VerificationMethodBuilder};
27pub use did::{DID, DIDError};
28pub use did_method::DIDMethod;
29pub use did_method::key::{KeyError, KeyMaterial, KeyMaterialFormat, KeyMaterialType};
30pub use did_method::peer::{
31    PeerCreateKey, PeerCreatedKey, PeerError, PeerKeyPurpose, PeerKeyType, PeerNumAlgo,
32    PeerPurpose, PeerService, PeerServiceEndpoint, PeerServiceEndpointLong,
33    PeerServiceEndpointShort,
34};
35pub use document::DocumentExt;
36
37#[derive(Error, Debug)]
38pub enum DocumentError {
39    #[error("URL Error")]
40    URL(#[from] url::ParseError),
41
42    #[error("VerificationMethod Error: {0}")]
43    VM(String),
44
45    #[error("Encoding Error: {0}")]
46    Encoding(#[from] EncodingError),
47
48    #[error("Key expansion error: {0}")]
49    KeyExpansionError(String),
50}
51
52/// A [DID Document]
53///
54/// [DID Document]: https://www.w3.org/TR/did-1.1/
55#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
56#[serde(rename_all = "camelCase")]
57pub struct Document {
58    /// DID Subject Identifier
59    /// <https://www.w3.org/TR/cid-1.0/#subjects>
60    pub id: Url,
61
62    /// https://www.w3.org/TR/cid-1.0/#verification-methods
63    #[serde(skip_serializing_if = "Vec::is_empty", default)]
64    pub verification_method: Vec<VerificationMethod>,
65
66    /// https://www.w3.org/TR/cid-1.0/#authentication
67    #[serde(skip_serializing_if = "Vec::is_empty", default)]
68    pub authentication: Vec<VerificationRelationship>,
69
70    /// https://www.w3.org/TR/cid-1.0/#assertion
71    #[serde(skip_serializing_if = "Vec::is_empty", default)]
72    pub assertion_method: Vec<VerificationRelationship>,
73
74    /// https://www.w3.org/TR/cid-1.0/#key-agreement
75    #[serde(skip_serializing_if = "Vec::is_empty", default)]
76    pub key_agreement: Vec<VerificationRelationship>,
77
78    /// https://www.w3.org/TR/cid-1.0/#capability-invocation
79    #[serde(skip_serializing_if = "Vec::is_empty", default)]
80    pub capability_invocation: Vec<VerificationRelationship>,
81
82    /// https://www.w3.org/TR/cid-1.0/#capability-delegation
83    #[serde(skip_serializing_if = "Vec::is_empty", default)]
84    pub capability_delegation: Vec<VerificationRelationship>,
85
86    /// Set of Services
87    #[serde(skip_serializing_if = "Vec::is_empty", default)]
88    pub service: Vec<Service>,
89
90    /// Other parameters that may be in a DID Document
91    #[serde(flatten)]
92    pub parameters_set: HashMap<String, Value>,
93}
94
95impl Default for Document {
96    /// Creates a default example DID Document that is blank except for the id field
97    fn default() -> Self {
98        Self {
99            id: Url::parse("did:example:123456789abcdefghi").unwrap(),
100            verification_method: Vec::new(),
101            authentication: Vec::new(),
102            assertion_method: Vec::new(),
103            key_agreement: Vec::new(),
104            capability_invocation: Vec::new(),
105            capability_delegation: Vec::new(),
106            service: Vec::new(),
107            parameters_set: HashMap::new(),
108        }
109    }
110}
111
112impl Document {
113    /// Creates a new DID Document with the given identifier
114    /// Rest of the Document is blank
115    pub fn new(id: &str) -> Result<Self, DocumentError> {
116        Ok(Document {
117            id: Url::parse(id)?,
118            ..Default::default()
119        })
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126    use url::Url;
127
128    #[test]
129    fn valid_id() {
130        assert!(Url::parse("did:example:123456789abcdefghi").is_ok());
131        assert!(Url::parse("did:webvh:Qmd1FCL9Vj2vJ433UDfC9MBstK6W6QWSQvYyeNn8va2fai:identity.foundation:didwebvh-implementations:implementations:affinidi-didwebvh-rs").is_ok());
132    }
133
134    #[test]
135    fn document_new_valid() {
136        let doc = Document::new("did:example:123").unwrap();
137        assert_eq!(doc.id.as_str(), "did:example:123");
138        assert!(doc.verification_method.is_empty());
139        assert!(doc.service.is_empty());
140    }
141
142    #[test]
143    fn document_new_invalid() {
144        assert!(Document::new("not a url").is_err());
145    }
146
147    #[test]
148    fn document_default_has_example_id() {
149        let doc = Document::default();
150        assert_eq!(doc.id.as_str(), "did:example:123456789abcdefghi");
151    }
152
153    #[test]
154    fn document_serde_roundtrip_minimal() {
155        let doc = Document::new("did:example:456").unwrap();
156        let json = serde_json::to_string(&doc).unwrap();
157        let back: Document = serde_json::from_str(&json).unwrap();
158        assert_eq!(doc, back);
159    }
160}