prople_did_core/verifiable/
vp.rs

1use rst_common::standard::serde::{self, Deserialize, Serialize};
2use rst_common::standard::serde_json;
3
4use crate::types::{DIDError, JSONValue, ToJCS, ToJSON, Validator};
5use crate::verifiable::objects::VC;
6use crate::verifiable::types::{Context, Type};
7
8use crate::verifiable::proof::types::{ProofError, Proofable};
9use crate::verifiable::proof::Proof;
10
11/// `VP` a main object used to generate `DID VP`. The `VP` object MUST contains
12/// a [`VC`] object, it may be a single `VC` or multiple
13///
14/// Ref: <https://www.w3.org/TR/vc-data-model-2.0/#presentations>
15#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
16#[serde(crate = "self::serde")]
17pub struct VP {
18    #[serde(rename = "@context")]
19    pub contexts: Vec<Context>,
20
21    #[serde(rename = "type")]
22    pub types: Vec<Type>,
23
24    #[serde(rename = "verifiableCredential")]
25    pub verifiable_credential: Vec<VC>,
26
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub proof: Option<Proof>,
29
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub holder: Option<String>,
32}
33
34impl Default for VP {
35    fn default() -> Self {
36        Self::new()
37    }
38}
39
40impl VP {
41    pub fn new() -> Self {
42        Self {
43            contexts: Vec::new(),
44            types: Vec::new(),
45            verifiable_credential: Vec::new(),
46            proof: None,
47            holder: None,
48        }
49    }
50
51    pub fn add_context(&mut self, context: Context) -> &mut Self {
52        self.contexts.push(context);
53        self
54    }
55
56    pub fn add_type(&mut self, t: Type) -> &mut Self {
57        self.types.push(t);
58        self
59    }
60
61    pub fn add_credential(&mut self, cred: VC) -> &mut Self {
62        self.verifiable_credential.push(cred);
63        self
64    }
65
66    pub fn add_proof(&mut self, proof: Proof) -> &mut Self {
67        self.proof = Some(proof);
68        self
69    }
70
71    pub fn set_holder(&mut self, holder: String) -> &mut Self {
72        self.holder = Some(holder);
73        self
74    }
75}
76
77impl ToJSON for VP {
78    fn to_json(&self) -> Result<JSONValue, DIDError> {
79        match self.validate() {
80            Ok(_) => {
81                let jsonstr = serde_json::to_string(self)
82                    .map_err(|err| DIDError::GenerateJSONError(err.to_string()))?;
83
84                Ok(JSONValue::from(jsonstr))
85            }
86            Err(err) => Err(err),
87        }
88    }
89}
90
91impl ToJCS for VP {
92    fn to_jcs(&self) -> Result<String, DIDError> {
93        match self.validate() {
94            Ok(_) => serde_jcs::to_string(self)
95                .map_err(|err| DIDError::GenerateJSONError(err.to_string())),
96            Err(err) => Err(err),
97        }
98    }
99}
100
101impl Validator for VP {
102    fn validate(&self) -> Result<(), DIDError> {
103        if self.contexts.is_empty() {
104            return Err(DIDError::GenerateJSONError(String::from(
105                "vp: empty context",
106            )));
107        }
108
109        if self.types.is_empty() {
110            return Err(DIDError::GenerateJSONError(String::from("vp: empty types")));
111        }
112
113        if self.verifiable_credential.is_empty() {
114            return Err(DIDError::GenerateJSONError(String::from(
115                "vp: empty credentials",
116            )));
117        }
118
119        Ok(())
120    }
121}
122
123impl Proofable for VP {
124    fn get_proof(&self) -> Option<Proof> {
125        self.proof.to_owned()
126    }
127
128    fn setup_proof(&mut self, proof: Proof) -> &mut Self {
129        self.add_proof(proof);
130        self
131    }
132
133    fn parse_json_bytes(bytes: Vec<u8>) -> Result<Self, ProofError> {
134        let parsed: Self = serde_json::from_slice(bytes.as_slice())
135            .map_err(|err| ProofError::ProofGenerationError(err.to_string()))?;
136
137        Ok(parsed)
138    }
139
140    fn remove_proof(&self) -> Self {
141        let mut vp = self.clone();
142        vp.proof = None;
143        vp
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn test_generate_json() {
153        let vc = VC::new("id1".to_string(), "issuer".to_string());
154        let mut vp = VP::new();
155
156        vp.add_context("context1".to_string())
157            .add_context("context2".to_string())
158            .add_type("type".to_string())
159            .add_credential(vc);
160
161        let try_json = vp.to_json();
162        assert!(!try_json.is_err());
163
164        let expected_json = r#"{"@context":["context1","context2"],"type":["type"],"verifiableCredential":[{"@context":[],"type":[],"credentialSubject":null,"id":"id1","issuer":"issuer"}]}"#;
165        assert_eq!(JSONValue::from(expected_json), try_json.unwrap())
166    }
167
168    #[test]
169    fn test_generate_jcs() {
170        let vc = VC::new("id1".to_string(), "issuer".to_string());
171        let mut vp = VP::new();
172
173        vp.add_context("context1".to_string())
174            .add_context("context2".to_string())
175            .add_type("type".to_string())
176            .add_credential(vc);
177
178        let try_json = vp.to_jcs();
179        assert!(!try_json.is_err());
180    }
181
182    #[test]
183    fn test_validate_failed_context_empty() {
184        let vp = VP::new();
185        let try_json = vp.to_json();
186        assert!(try_json.is_err());
187        assert_eq!(
188            DIDError::GenerateJSONError("vp: empty context".to_string()),
189            try_json.unwrap_err()
190        )
191    }
192
193    #[test]
194    fn test_validate_failed_types_empty() {
195        let mut vp = VP::new();
196        vp.add_context("context1".to_string());
197
198        let try_json = vp.to_json();
199        assert!(try_json.is_err());
200        assert_eq!(
201            DIDError::GenerateJSONError("vp: empty types".to_string()),
202            try_json.unwrap_err()
203        )
204    }
205
206    #[test]
207    fn test_validate_failed_credential_empty() {
208        let mut vp = VP::new();
209        vp.add_context("context1".to_string());
210        vp.add_type("type".to_string());
211
212        let try_json = vp.to_json();
213        assert!(try_json.is_err());
214        assert_eq!(
215            DIDError::GenerateJSONError("vp: empty credentials".to_string()),
216            try_json.unwrap_err()
217        )
218    }
219}