prople_did_core/doc/
mod.rs

1//! `doc` module take responsibility to generate the `DID Documents`
2//!
3//! The data structure will follow the standard from `W3C DID CORE`
4//! Ref: <https://www.w3.org/TR/did-core/#core-properties>
5//!
6//! Simple document:
7//! ```json
8//! {
9//!     "@context": [
10//!       "https://www.w3.org/ns/did/v1",
11//!       "https://w3id.org/security/suites/ed25519-2020/v1"
12//!     ]
13//!     "id": "did:example:123456789abcdefghi",
14//!     "authentication": [{
15//!       "id": "did:example:123456789abcdefghi#keys-1",
16//!       "type": "Ed25519VerificationKey2020",
17//!       "controller": "did:example:123456789abcdefghi",
18//!       "publicKeyMultibase": "zH3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
19//!     }]
20//!   }
21//! ````
22use multibase;
23
24use rst_common::standard::serde::{self, Deserialize, Serialize};
25use rst_common::standard::serde_json;
26
27use prople_crypto::ecdh::pubkey::PublicKey as ECDHPubKey;
28use prople_crypto::eddsa::pubkey::PubKey as EdDSAPubKey;
29use prople_crypto::types::ByteHex;
30
31use crate::types::*;
32
33pub trait ToDoc {
34    fn to_doc(&self) -> Doc;
35}
36
37#[derive(Debug)]
38pub enum PublicKeyDecoded {
39    EdDSA(EdDSAPubKey),
40    ECDH(ECDHPubKey),
41}
42
43/// `Primary` is a main data structure used for `authentication`, `assertion`
44/// `capabilityInvocation` and `capabilityDelegation`
45#[derive(Debug, Clone, Serialize, Deserialize)]
46#[serde(crate = "self::serde")]
47pub struct Primary {
48    pub id: DIDSyntax,
49    pub controller: DIDController,
50
51    #[serde(rename = "type")]
52    pub verification_type: DIDVerificationKeyType,
53
54    #[serde(rename = "publicKeyMultibase")]
55    pub multibase: DIDMultibase,
56}
57
58impl Primary {
59    pub fn decode_pub_key(&self) -> Result<PublicKeyDecoded, DIDError> {
60        match self.verification_type.to_owned().as_str() {
61            VERIFICATION_TYPE_ED25519 => {
62                let public_key = self.decode_pub_key_verificaiton()?;
63                Ok(PublicKeyDecoded::EdDSA(public_key))
64            }
65            VERIFICATION_TYPE_X25519 => {
66                let public_key = self.decode_pub_key_agreement()?;
67                Ok(PublicKeyDecoded::ECDH(public_key))
68            }
69            _ => Err(DIDError::DecodePubKeyError(
70                "unknown verification type".to_string(),
71            )),
72        }
73    }
74
75    fn decode_pub_key_verificaiton(&self) -> Result<EdDSAPubKey, DIDError> {
76        let (_, pubkey_bytes) = multibase::decode(&self.multibase).map_err(|_| {
77            DIDError::DecodePubKeyError(
78                "unable to decode encoded multibase to EDDSA public key".to_string(),
79            )
80        })?;
81
82        let pubkey_string = String::from_utf8(pubkey_bytes).map_err(|_| {
83            DIDError::DecodePubKeyError("unable convert public key to string".to_string())
84        })?;
85
86        let pubkey = EdDSAPubKey::from_hex(ByteHex::from(pubkey_string))
87            .map_err(|_| DIDError::DecodePubKeyError("unable to restore public key".to_string()))?;
88        Ok(pubkey)
89    }
90
91    fn decode_pub_key_agreement(&self) -> Result<ECDHPubKey, DIDError> {
92        let (_, pubkey_bytes) = multibase::decode(&self.multibase).map_err(|_| {
93            DIDError::DecodePubKeyError(
94                "unable to decode encoded multibase to ECDH public key".to_string(),
95            )
96        })?;
97
98        let pubkey_string = String::from_utf8(pubkey_bytes).map_err(|_| {
99            DIDError::DecodePubKeyError("unable convert public key to string".to_string())
100        })?;
101
102        let pubkey = ECDHPubKey::from_hex(ByteHex::from(pubkey_string))
103            .map_err(|_| DIDError::DecodePubKeyError("unable to restore public key".to_string()))?;
104
105        Ok(pubkey)
106    }
107}
108
109/// `Doc` is a main data structure modeling the core properties
110/// from the `DID Document`
111///
112/// Ref: <https://www.w3.org/TR/did-core/#core-properties>
113#[derive(Debug, Clone, Serialize, Deserialize)]
114#[serde(crate = "self::serde")]
115pub struct Doc {
116    #[serde(rename = "@context")]
117    pub context: Vec<DIDContext>,
118
119    pub id: DIDSyntax,
120
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub authentication: Option<Vec<Primary>>,
123
124    #[serde(skip_serializing_if = "Option::is_none")]
125    #[serde(rename = "capabilityInvocation")]
126    pub cap_invoke: Option<Vec<Primary>>,
127
128    #[serde(skip_serializing_if = "Option::is_none")]
129    #[serde(rename = "capabilityDelegation")]
130    pub cap_delegate: Option<Vec<Primary>>,
131
132    #[serde(skip_serializing_if = "Option::is_none")]
133    #[serde(rename = "assertionMethod")]
134    pub assertion: Option<Vec<Primary>>,
135}
136
137impl Doc {
138    pub fn generate(did: String) -> Self {
139        let context = vec![CONTEXT_DEFAULT.to_string()];
140        Self {
141            context,
142            id: did,
143            authentication: None,
144            cap_delegate: None,
145            cap_invoke: None,
146            assertion: None,
147        }
148    }
149
150    pub fn add_context(&mut self, context: DIDContext) -> &mut Self {
151        self.context.push(context);
152        self
153    }
154
155    pub fn add_assertion(&mut self, assertion: Primary) -> &mut Self {
156        if let Some(ref mut assertions) = self.assertion {
157            assertions.push(assertion.clone())
158        }
159
160        if self.assertion.is_none() {
161            self.assertion = Some(vec![assertion.clone()]);
162        }
163
164        self
165    }
166
167    pub fn add_authentication(&mut self, auth: Primary) -> &mut Self {
168        if let Some(ref mut authentication) = self.authentication {
169            authentication.push(auth.clone())
170        }
171
172        if self.authentication.is_none() {
173            self.authentication = Some(vec![auth.clone()]);
174        }
175
176        self
177    }
178
179    pub fn add_cap_delegate(&mut self, delegate: Primary) -> &mut Self {
180        if let Some(ref mut cap_delegate) = self.cap_delegate {
181            cap_delegate.push(delegate.clone())
182        }
183
184        if self.cap_delegate.is_none() {
185            self.cap_delegate = Some(vec![delegate.clone()]);
186        }
187
188        self
189    }
190
191    pub fn add_cap_invoke(&mut self, invoke: Primary) -> &mut Self {
192        if let Some(ref mut cap_invoke) = self.cap_invoke {
193            cap_invoke.push(invoke.clone())
194        }
195
196        if self.cap_invoke.is_none() {
197            self.cap_invoke = Some(vec![invoke.clone()]);
198        }
199
200        self
201    }
202}
203
204impl ToJSON for Doc {
205    fn to_json(&self) -> Result<JSONValue, DIDError> {
206        let jsonstr = serde_json::to_string(self)
207            .map_err(|err| DIDError::GenerateDocError(err.to_string()))?;
208        Ok(JSONValue::from(jsonstr))
209    }
210}
211
212impl Validator for Doc {
213    fn validate(&self) -> Result<(), DIDError> {
214        if self.id.is_empty() {
215            return Err(DIDError::ValidateError("[doc]: missing id".to_string()));
216        }
217
218        if self.context.is_empty() {
219            return Err(DIDError::ValidateError(
220                "[doc]: at least one context must be filled".to_string(),
221            ));
222        }
223
224        Ok(())
225    }
226}
227
228#[cfg(test)]
229mod tests {
230    use super::*;
231
232    use prople_crypto::eddsa::keypair::KeyPair;
233
234    use crate::keys::{AgreementKey, VerificationKey};
235
236    #[test]
237    fn test_add_assertion() {
238        let primary = Primary {
239            id: "id".to_string(),
240            controller: "controller".to_string(),
241            verification_type: "verification".to_string(),
242            multibase: "multibase".to_string(),
243        };
244
245        let mut doc = Doc::generate("test".to_string());
246        let json = doc
247            .add_assertion(primary.clone())
248            .add_assertion(primary.clone())
249            .to_json();
250
251        assert!(!json.is_err());
252
253        let fromjson: Result<Doc, _> =
254            serde_json::from_str(json.as_ref().unwrap().to_string().as_str());
255        assert!(!fromjson.as_ref().is_err());
256
257        let doc = fromjson.unwrap();
258        assert!(doc.authentication.is_none());
259        assert!(doc.cap_delegate.is_none());
260        assert!(doc.cap_invoke.is_none());
261        assert_eq!(doc.assertion.unwrap().len(), 2);
262    }
263
264    #[test]
265    fn test_validation_error() {
266        let mut doc = Doc::generate("test".to_string());
267        doc.context = vec![];
268
269        let validation = doc.validate();
270        assert!(validation.is_err());
271    }
272
273    #[test]
274    fn test_validation_success() {
275        let doc = Doc::generate("test".to_string());
276        let validation = doc.validate();
277        assert!(validation.is_ok());
278    }
279
280    #[test]
281    fn test_decode_public_key_eddsa() {
282        let key = VerificationKey::new();
283        let pairs = key.generate();
284
285        let primary = Primary {
286            id: "id".to_string(),
287            controller: "controller".to_string(),
288            verification_type: VERIFICATION_TYPE_ED25519.to_string(),
289            multibase: pairs.clone().pub_key,
290        };
291
292        let decoded = primary.decode_pub_key();
293        assert!(!decoded.is_err());
294
295        let decoded_pub_key = decoded.unwrap();
296        assert!(matches!(decoded_pub_key, PublicKeyDecoded::EdDSA(_)));
297
298        match decoded_pub_key {
299            PublicKeyDecoded::EdDSA(pubkey) => {
300                let privkey_pem = pairs.priv_key.to_pem().unwrap();
301                let keypair_regenerated = KeyPair::from_pem(privkey_pem).unwrap();
302                let pubkey_regenerated = keypair_regenerated.pub_key();
303                assert_eq!(pubkey.to_hex(), pubkey_regenerated.to_hex())
304            }
305            _ => panic!("unknown"),
306        }
307    }
308
309    #[test]
310    fn test_decode_public_key_ecdh() {
311        let key = AgreementKey::new();
312        let pairs = key.generate();
313
314        let primary = Primary {
315            id: "id".to_string(),
316            controller: "controller".to_string(),
317            verification_type: VERIFICATION_TYPE_X25519.to_string(),
318            multibase: pairs.clone().pub_key,
319        };
320
321        let decoded = primary.decode_pub_key();
322        assert!(!decoded.is_err());
323
324        let decoded_pub_key = decoded.unwrap();
325        assert!(matches!(decoded_pub_key, PublicKeyDecoded::ECDH(_)));
326
327        match decoded_pub_key {
328            PublicKeyDecoded::ECDH(pubkey) => {
329                let keypair = pairs.priv_key;
330                assert_eq!(keypair.pub_key().to_hex(), pubkey.to_hex());
331            }
332            _ => panic!("unknown"),
333        }
334    }
335
336    #[test]
337    fn test_decode_public_key_invalid_type() {
338        let primary = Primary {
339            id: "id".to_string(),
340            controller: "controller".to_string(),
341            verification_type: "unknown".to_string(),
342            multibase: "".to_string(),
343        };
344
345        let decoded = primary.decode_pub_key();
346        assert!(decoded.is_err());
347        assert!(matches!(
348            decoded.unwrap_err(),
349            DIDError::DecodePubKeyError(_)
350        ))
351    }
352}