identity_credential/credential/
evidence.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use serde::Deserialize;
5use serde::Serialize;
6
7use identity_core::common::Object;
8use identity_core::common::OneOrMany;
9
10/// Information used to increase confidence in the claims of a `Credential`
11///
12/// [More Info](https://www.w3.org/TR/vc-data-model/#evidence)
13#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
14pub struct Evidence {
15  /// A Url that allows retrieval of information about the evidence.
16  #[serde(skip_serializing_if = "Option::is_none")]
17  pub id: Option<String>,
18  /// The type(s) of the credential evidence.
19  #[serde(rename = "type")]
20  pub types: OneOrMany<String>,
21  /// Additional properties of the credential evidence.
22  #[serde(flatten)]
23  pub properties: Object,
24}
25
26impl Evidence {
27  /// Creates a new `Evidence` instance.
28  pub fn new<T>(types: T) -> Self
29  where
30    T: Into<OneOrMany<String>>,
31  {
32    Self::with_properties(types, Object::new())
33  }
34
35  /// Creates a new `Evidence` instance with the given `id`.
36  pub fn with_id<T, U>(types: T, id: U) -> Self
37  where
38    T: Into<OneOrMany<String>>,
39    U: Into<String>,
40  {
41    Self {
42      id: Some(id.into()),
43      types: types.into(),
44      properties: Object::new(),
45    }
46  }
47
48  /// Creates a new `Evidence` instance with the given `properties`.
49  pub fn with_properties<T>(types: T, properties: Object) -> Self
50  where
51    T: Into<OneOrMany<String>>,
52  {
53    Self {
54      id: None,
55      types: types.into(),
56      properties,
57    }
58  }
59
60  /// Creates a new `Evidence` instance with the given `id` and `properties`.
61  pub fn with_id_and_properties<T, U, V>(types: T, id: U, properties: Object) -> Self
62  where
63    T: Into<OneOrMany<String>>,
64    U: Into<String>,
65  {
66    Self {
67      id: Some(id.into()),
68      types: types.into(),
69      properties,
70    }
71  }
72}
73
74#[cfg(test)]
75mod tests {
76  use identity_core::convert::FromJson;
77
78  use crate::credential::Evidence;
79
80  const JSON1: &str = include_str!("../../tests/fixtures/evidence-1.json");
81  const JSON2: &str = include_str!("../../tests/fixtures/evidence-2.json");
82
83  #[test]
84  fn test_from_json() {
85    let evidence: Evidence = Evidence::from_json(JSON1).unwrap();
86    assert_eq!(
87      evidence.id.unwrap(),
88      "https://example.edu/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d4231"
89    );
90    assert_eq!(evidence.types.as_slice(), ["DocumentVerification"]);
91    assert_eq!(evidence.properties["verifier"], "https://example.edu/issuers/14");
92    assert_eq!(evidence.properties["evidenceDocument"], "DriversLicense");
93    assert_eq!(evidence.properties["subjectPresence"], "Physical");
94    assert_eq!(evidence.properties["documentPresence"], "Physical");
95
96    let evidence: Evidence = Evidence::from_json(JSON2).unwrap();
97    assert_eq!(
98      evidence.id.unwrap(),
99      "https://example.edu/evidence/f2aeec97-fc0d-42bf-8ca7-0548192dxyzab"
100    );
101    assert_eq!(evidence.types.as_slice(), ["SupportingActivity"]);
102    assert_eq!(evidence.properties["verifier"], "https://example.edu/issuers/14");
103    assert_eq!(evidence.properties["evidenceDocument"], "Fluid Dynamics Focus");
104    assert_eq!(evidence.properties["subjectPresence"], "Digital");
105    assert_eq!(evidence.properties["documentPresence"], "Digital");
106  }
107}