prople_did_core/verifiable/
vc.rs1use rst_common::standard::serde::{self, Deserialize, Serialize};
2use rst_common::standard::serde_json::{self, Value};
3
4use crate::types::DIDError;
5use crate::types::{JSONValue, ToJCS, ToJSON, Validator};
6
7use crate::verifiable::proof::types::{ProofError, Proofable};
8use crate::verifiable::proof::Proof;
9
10pub type Context = String;
11pub type ID = String;
12pub type Type = String;
13pub type SRI = String;
14pub type Issuer = String;
15
16#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
20#[serde(crate = "self::serde")]
21pub struct VC {
22 #[serde(rename = "@context")]
23 pub contexts: Vec<Context>,
24
25 #[serde(rename = "type")]
26 pub types: Vec<Type>,
27
28 #[serde(rename = "credentialSubject")]
29 pub credential_subject: Value,
30
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub proof: Option<Proof>,
33
34 pub id: ID,
35 pub issuer: String,
36}
37
38impl VC {
39 pub fn new(id: ID, issuer: Issuer) -> Self {
40 Self {
41 id,
42 issuer,
43 contexts: Vec::new(),
44 types: Vec::new(),
45 credential_subject: Value::Null,
46 proof: None,
47 }
48 }
49
50 pub fn add_context(&mut self, context: Context) -> &mut Self {
51 self.contexts.push(context);
52 self
53 }
54
55 pub fn add_type(&mut self, t: Type) -> &mut Self {
56 self.types.push(t);
57 self
58 }
59
60 pub fn set_credential(&mut self, credential: Value) -> &mut Self {
61 self.credential_subject = credential;
62 self
63 }
64
65 pub fn proof(&mut self, proof: Proof) -> &mut Self {
66 self.proof = Some(proof);
67 self
68 }
69}
70
71impl ToJSON for VC {
72 fn to_json(&self) -> Result<JSONValue, DIDError> {
73 let validation = self.validate();
74 match validation {
75 Ok(_) => {
76 let jsonstr = serde_json::to_string(self)
77 .map_err(|err| DIDError::GenerateJSONError(err.to_string()))?;
78
79 Ok(JSONValue::from(jsonstr))
80 }
81 Err(err) => Err(err),
82 }
83 }
84}
85
86impl ToJCS for VC {
87 fn to_jcs(&self) -> Result<String, DIDError> {
88 let validation = self.validate();
89 match validation {
90 Ok(_) => serde_jcs::to_string(self)
91 .map_err(|err| DIDError::GenerateJSONError(err.to_string())),
92 Err(err) => Err(err),
93 }
94 }
95}
96
97impl Validator for VC {
98 fn validate(&self) -> Result<(), DIDError> {
99 if self.contexts.is_empty() {
100 return Err(DIDError::GenerateVCError(String::from(
101 "vc_error: empty context",
102 )));
103 }
104
105 if self.types.is_empty() {
106 return Err(DIDError::GenerateVCError(String::from(
107 "vc_error: empty types",
108 )));
109 }
110
111 if self.credential_subject == Value::Null {
112 return Err(DIDError::GenerateVCError(String::from(
113 "vc_error: credential should not be null",
114 )));
115 }
116
117 Ok(())
118 }
119}
120
121impl Proofable for VC {
122 fn get_proof(&self) -> Option<Proof> {
123 self.proof.to_owned()
124 }
125
126 fn setup_proof(&mut self, proof: Proof) -> &mut Self {
127 self.proof(proof);
128 self
129 }
130
131 fn parse_json_bytes(bytes: Vec<u8>) -> Result<Self, ProofError> {
132 let parsed: Self = serde_json::from_slice(bytes.as_slice())
133 .map_err(|err| ProofError::ProofGenerationError(err.to_string()))?;
134
135 Ok(parsed)
136 }
137
138 fn remove_proof(&self) -> Self {
139 let mut vc = self.clone();
140 vc.proof = None;
141 vc
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[derive(Serialize, Deserialize)]
150 #[serde(crate = "self::serde")]
151 struct FakeCredentialProperties {
152 pub user_agent: String,
153 pub user_did: String,
154 }
155
156 #[derive(Serialize, Deserialize)]
157 #[serde(crate = "self::serde")]
158 struct FakeCredentialSubject {
159 id: String,
160 connection: FakeCredentialProperties,
161 }
162
163 #[test]
164 fn test_generate_credential() {
165 let mut vc = VC::new(String::from("id"), String::from("issuer"));
166 vc.add_context(String::from("context1"))
167 .add_context("context2".to_string())
168 .add_type("VerifiableCredential".to_string());
169
170 let credential_props = FakeCredentialProperties {
171 user_agent: String::from("test_agent"),
172 user_did: String::from("test_did"),
173 };
174
175 let credential = FakeCredentialSubject {
176 id: String::from("id"),
177 connection: credential_props,
178 };
179
180 let credential_value = serde_json::to_value(credential);
181 assert!(!credential_value.is_err());
182
183 vc.set_credential(credential_value.unwrap());
184 let json_str = vc.to_json();
185 assert!(!json_str.is_err());
186
187 let expected_json = r#"{"@context":["context1","context2"],"type":["VerifiableCredential"],"credentialSubject":{"connection":{"user_agent":"test_agent","user_did":"test_did"},"id":"id"},"id":"id","issuer":"issuer"}"#;
188 assert_eq!(json_str.unwrap(), JSONValue::from(expected_json))
189 }
190
191 #[test]
192 fn test_generate_credential_jcs() {
193 let mut vc = VC::new(String::from("id"), String::from("issuer"));
194 vc.add_context(String::from("context1"))
195 .add_context("context2".to_string())
196 .add_type("VerifiableCredential".to_string());
197
198 let credential_props = FakeCredentialProperties {
199 user_agent: String::from("test_agent"),
200 user_did: String::from("test_did"),
201 };
202
203 let credential = FakeCredentialSubject {
204 id: String::from("id"),
205 connection: credential_props,
206 };
207
208 let credential_value = serde_json::to_value(credential);
209 assert!(!credential_value.is_err());
210
211 vc.set_credential(credential_value.unwrap());
212 let json_str = vc.to_jcs();
213 assert!(!json_str.is_err());
214 }
215
216 #[test]
217 fn test_generate_empty_context() {
218 let vc = VC::new(String::from("id"), String::from("issuer"));
219 let try_json = vc.to_json();
220 assert!(try_json.is_err());
221
222 assert_eq!(
223 DIDError::GenerateVCError(String::from("vc_error: empty context")),
224 try_json.unwrap_err()
225 )
226 }
227
228 #[test]
229 fn test_generate_empty_types() {
230 let mut vc = VC::new(String::from("id"), String::from("issuer"));
231 vc.add_context(String::from("context1"));
232 vc.add_context(String::from("context2"));
233
234 let try_json = vc.to_json();
235 assert!(try_json.is_err());
236
237 assert_eq!(
238 DIDError::GenerateVCError(String::from("vc_error: empty types")),
239 try_json.unwrap_err()
240 )
241 }
242
243 #[test]
244 fn test_generate_empty_credential() {
245 let mut vc = VC::new(String::from("id"), String::from("issuer"));
246 vc.add_context(String::from("context1"))
247 .add_context("context2".to_string())
248 .add_type("VerifiableCredential".to_string());
249
250 let try_json = vc.to_json();
251 assert!(try_json.is_err());
252
253 assert_eq!(
254 DIDError::GenerateVCError(String::from("vc_error: credential should not be null")),
255 try_json.unwrap_err()
256 )
257 }
258}