ssi_vc/v1/data_model/
credential.rs1use iref::{Iri, Uri};
2use ssi_claims_core::{ClaimsValidity, DateTimeProvider, InvalidClaims, VerifiableClaims};
3use ssi_data_integrity::{CryptographicSuite, DataIntegrity};
4use static_iref::iri;
5use xsd_types::DateTime;
6
7use crate::{v1::syntax::VERIFIABLE_CREDENTIAL_TYPE, Identified, MaybeIdentified, Typed};
8
9pub const VERIFIABLE_CREDENTIAL: &Iri =
10 iri!("https://www.w3.org/2018/credentials#VerifiableCredential");
11
12pub trait Credential {
14 type Subject;
16
17 type Issuer: ?Sized + Identified;
19
20 type Status: Identified + Typed;
22
23 type RefreshService: Identified + Typed;
27
28 type TermsOfUse: MaybeIdentified + Typed;
34
35 type Evidence: MaybeIdentified + Typed;
40
41 type Schema: Identified + Typed;
45
46 fn id(&self) -> Option<&Uri> {
48 None
49 }
50
51 fn additional_types(&self) -> &[String] {
58 &[]
59 }
60
61 fn types(&self) -> CredentialTypes {
62 CredentialTypes::from_additional_types(self.additional_types())
63 }
64
65 fn credential_subjects(&self) -> &[Self::Subject] {
67 &[]
68 }
69
70 fn issuer(&self) -> &Self::Issuer;
74
75 fn issuance_date(&self) -> Option<DateTime>;
79
80 fn expiration_date(&self) -> Option<DateTime> {
82 None
83 }
84
85 fn credential_status(&self) -> &[Self::Status] {
90 &[]
91 }
92
93 fn refresh_services(&self) -> &[Self::RefreshService] {
97 &[]
98 }
99
100 fn terms_of_use(&self) -> &[Self::TermsOfUse] {
106 &[]
107 }
108
109 fn evidence(&self) -> &[Self::Evidence] {
114 &[]
115 }
116
117 fn credential_schemas(&self) -> &[Self::Schema] {
121 &[]
122 }
123
124 fn validate_credential<E>(&self, env: &E) -> ClaimsValidity
134 where
135 E: DateTimeProvider,
136 {
137 let now = env.date_time();
138
139 let issuance_date = self
140 .issuance_date()
141 .ok_or(InvalidClaims::MissingIssuanceDate)?;
142
143 let valid_from = issuance_date.earliest().to_utc();
144 if valid_from > now {
145 return Err(InvalidClaims::Premature { now, valid_from });
147 }
148
149 if let Some(t) = self.expiration_date() {
150 let valid_until = t.latest().to_utc();
151 if now >= valid_until {
152 return Err(InvalidClaims::Expired { now, valid_until });
154 }
155 }
156
157 Ok(())
158 }
159}
160
161pub trait VerifiableCredential: Credential + VerifiableClaims {}
162
163impl<T: Credential + VerifiableClaims> VerifiableCredential for T {}
164
165impl<T: Credential, S: CryptographicSuite> Credential for DataIntegrity<T, S> {
166 type Subject = T::Subject;
167 type Issuer = T::Issuer;
168 type Status = T::Status;
169 type RefreshService = T::RefreshService;
170 type TermsOfUse = T::TermsOfUse;
171 type Evidence = T::Evidence;
172 type Schema = T::Schema;
173
174 fn id(&self) -> Option<&Uri> {
175 T::id(&self.claims)
176 }
177
178 fn additional_types(&self) -> &[String] {
179 T::additional_types(&self.claims)
180 }
181
182 fn credential_subjects(&self) -> &[Self::Subject] {
183 T::credential_subjects(&self.claims)
184 }
185
186 fn issuer(&self) -> &Self::Issuer {
187 T::issuer(&self.claims)
188 }
189
190 fn issuance_date(&self) -> Option<DateTime> {
191 T::issuance_date(&self.claims)
192 }
193
194 fn expiration_date(&self) -> Option<DateTime> {
195 T::expiration_date(&self.claims)
196 }
197
198 fn credential_status(&self) -> &[Self::Status] {
199 T::credential_status(&self.claims)
200 }
201
202 fn refresh_services(&self) -> &[Self::RefreshService] {
203 T::refresh_services(&self.claims)
204 }
205
206 fn terms_of_use(&self) -> &[Self::TermsOfUse] {
207 T::terms_of_use(&self.claims)
208 }
209
210 fn evidence(&self) -> &[Self::Evidence] {
211 T::evidence(&self.claims)
212 }
213
214 fn credential_schemas(&self) -> &[Self::Schema] {
215 T::credential_schemas(&self.claims)
216 }
217}
218
219pub struct CredentialTypes<'a> {
220 base_type: bool,
221 additional_types: std::slice::Iter<'a, String>,
222}
223
224impl<'a> CredentialTypes<'a> {
225 pub fn from_additional_types(additional_types: &'a [String]) -> Self {
226 Self {
227 base_type: true,
228 additional_types: additional_types.iter(),
229 }
230 }
231}
232
233impl<'a> Iterator for CredentialTypes<'a> {
234 type Item = &'a str;
235
236 fn next(&mut self) -> Option<Self::Item> {
237 if self.base_type {
238 self.base_type = false;
239 Some(VERIFIABLE_CREDENTIAL_TYPE)
240 } else {
241 self.additional_types.next().map(String::as_str)
242 }
243 }
244}