ssi_vc/v2/syntax/
presentation.rs

1use std::{borrow::Cow, collections::BTreeMap, hash::Hash};
2
3use crate::syntax::{not_null, value_or_array, IdOr, IdentifiedObject};
4use crate::v2::{Context, Credential};
5use iref::{Uri, UriBuf};
6use rdf_types::VocabularyMut;
7use serde::{Deserialize, Serialize};
8use ssi_claims_core::{ClaimsValidity, ValidateClaims};
9use ssi_json_ld::{JsonLdError, JsonLdNodeObject, JsonLdObject, JsonLdTypes, Loader};
10use ssi_rdf::{Interpretation, LdEnvironment, LinkedDataResource, LinkedDataSubject};
11
12use super::JsonCredential;
13
14pub use crate::v1::syntax::{
15    JsonPresentationTypes, PresentationType, VERIFIABLE_PRESENTATION_TYPE,
16};
17
18/// JSON Presentation.
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(bound(
21    serialize = "C: serde::Serialize",
22    deserialize = "C: serde::Deserialize<'de>"
23))]
24pub struct JsonPresentation<C = JsonCredential> {
25    /// JSON-LD context.
26    #[serde(rename = "@context")]
27    pub context: Context,
28
29    /// Presentation identifier.
30    #[serde(
31        default,
32        deserialize_with = "not_null",
33        skip_serializing_if = "Option::is_none"
34    )]
35    pub id: Option<UriBuf>,
36
37    /// Presentation type.
38    #[serde(rename = "type")]
39    pub types: JsonPresentationTypes,
40
41    /// Holders.
42    #[serde(rename = "holder")]
43    #[serde(
44        with = "value_or_array",
45        default,
46        skip_serializing_if = "Vec::is_empty"
47    )]
48    pub holders: Vec<IdOr<IdentifiedObject>>,
49
50    /// Verifiable credentials.
51    #[serde(rename = "verifiableCredential")]
52    #[serde(
53        with = "value_or_array",
54        default,
55        skip_serializing_if = "Vec::is_empty"
56    )]
57    pub verifiable_credentials: Vec<C>,
58
59    #[serde(flatten)]
60    pub additional_properties: BTreeMap<String, json_syntax::Value>,
61}
62
63impl Default for JsonPresentation {
64    fn default() -> Self {
65        Self {
66            context: Context::default(),
67            id: None,
68            types: JsonPresentationTypes::default(),
69            verifiable_credentials: Vec::new(),
70            holders: Vec::new(),
71            additional_properties: BTreeMap::new(),
72        }
73    }
74}
75
76impl<C> JsonPresentation<C> {
77    pub fn new(
78        id: Option<UriBuf>,
79        holders: Vec<IdOr<IdentifiedObject>>,
80        verifiable_credentials: Vec<C>,
81    ) -> Self {
82        Self {
83            context: Context::default(),
84            id,
85            types: JsonPresentationTypes::default(),
86            holders,
87            verifiable_credentials,
88            additional_properties: BTreeMap::new(),
89        }
90    }
91}
92
93impl<C> JsonLdObject for JsonPresentation<C> {
94    fn json_ld_context(&self) -> Option<Cow<ssi_json_ld::syntax::Context>> {
95        Some(Cow::Borrowed(self.context.as_ref()))
96    }
97}
98
99impl<C> JsonLdNodeObject for JsonPresentation<C> {
100    fn json_ld_type(&self) -> JsonLdTypes {
101        self.types.to_json_ld_types()
102    }
103}
104
105impl<C, E, P> ValidateClaims<E, P> for JsonPresentation<C> {
106    fn validate_claims(&self, _: &E, _: &P) -> ClaimsValidity {
107        Ok(())
108    }
109}
110
111impl<C: Credential> crate::MaybeIdentified for JsonPresentation<C> {
112    fn id(&self) -> Option<&Uri> {
113        self.id.as_deref()
114    }
115}
116
117impl<C: Credential> crate::v2::Presentation for JsonPresentation<C> {
118    /// Verifiable credential type.
119    type Credential = C;
120
121    type Holder = IdOr<IdentifiedObject>;
122
123    /// Types, without the `VerifiablePresentation` type.
124    fn additional_types(&self) -> &[String] {
125        self.types.additional_types()
126    }
127
128    fn verifiable_credentials(&self) -> &[Self::Credential] {
129        &self.verifiable_credentials
130    }
131
132    fn holders(&self) -> &[Self::Holder] {
133        &self.holders
134    }
135}
136
137impl<C> ssi_json_ld::Expandable for JsonPresentation<C>
138where
139    C: Serialize,
140{
141    type Error = JsonLdError;
142
143    type Expanded<I, V>
144        = ssi_json_ld::ExpandedDocument<V::Iri, V::BlankId>
145    where
146        I: Interpretation,
147        V: VocabularyMut,
148        V::Iri: LinkedDataResource<I, V> + LinkedDataSubject<I, V>,
149        V::BlankId: LinkedDataResource<I, V> + LinkedDataSubject<I, V>;
150
151    async fn expand_with<I, V>(
152        &self,
153        ld: &mut LdEnvironment<V, I>,
154        loader: &impl Loader,
155    ) -> Result<Self::Expanded<I, V>, Self::Error>
156    where
157        I: Interpretation,
158        V: VocabularyMut,
159        V::Iri: Clone + Eq + Hash + LinkedDataResource<I, V> + LinkedDataSubject<I, V>,
160        V::BlankId: Clone + Eq + Hash + LinkedDataResource<I, V> + LinkedDataSubject<I, V>,
161    {
162        let json = ssi_json_ld::CompactJsonLd(json_syntax::to_value(self).unwrap());
163        json.expand_with(ld, loader).await
164    }
165}