1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use ssi_core::Lexical;
5use ssi_verification_methods::{ProofPurpose, ReferenceOrOwned};
6
7use crate::{suite::ConfigurationError, CryptographicSuite, ProofConfiguration};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct ProofOptions<M, T> {
13 #[serde(rename = "@context", skip_serializing_if = "Option::is_none")]
14 pub context: Option<ssi_json_ld::syntax::Context>,
15
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub created: Option<Lexical<xsd_types::DateTimeStamp>>,
19
20 pub verification_method: Option<ReferenceOrOwned<M>>,
22
23 #[serde(default)]
25 pub proof_purpose: ProofPurpose,
26
27 #[serde(default, skip_serializing_if = "Option::is_none")]
29 pub expires: Option<Lexical<xsd_types::DateTimeStamp>>,
30
31 #[allow(rustdoc::bare_urls)]
32 #[serde(
45 default,
46 with = "crate::value_or_array",
47 skip_serializing_if = "Vec::is_empty",
48 rename = "domain"
49 )]
50 pub domains: Vec<String>,
51
52 #[serde(default, skip_serializing_if = "Option::is_none")]
58 pub challenge: Option<String>,
59
60 #[serde(default, skip_serializing_if = "Option::is_none")]
65 pub nonce: Option<String>,
66
67 #[serde(flatten)]
72 pub options: T,
73
74 #[serde(flatten)]
76 pub extra_properties: BTreeMap<String, json_syntax::Value>,
77}
78
79impl<M, T: Default> Default for ProofOptions<M, T> {
80 fn default() -> Self {
81 Self {
82 context: None,
83 created: Some(xsd_types::DateTimeStamp::now_ms().into()),
84 verification_method: None,
85 proof_purpose: ProofPurpose::default(),
86 expires: None,
87 domains: Vec::new(),
88 challenge: None,
89 nonce: None,
90 options: Default::default(),
91 extra_properties: BTreeMap::new(),
92 }
93 }
94}
95
96impl<M, T> ProofOptions<M, T> {
97 pub fn new(
98 created: Lexical<xsd_types::DateTimeStamp>,
99 verification_method: ReferenceOrOwned<M>,
100 proof_purpose: ProofPurpose,
101 options: T,
102 ) -> Self {
103 Self {
104 context: None,
105 created: Some(created),
106 verification_method: Some(verification_method),
107 proof_purpose,
108 expires: None,
109 domains: Vec::new(),
110 challenge: None,
111 nonce: None,
112 options,
113 extra_properties: BTreeMap::new(),
114 }
115 }
116
117 pub fn from_method_and_options(verification_method: ReferenceOrOwned<M>, options: T) -> Self {
118 Self {
119 context: None,
120 created: Some(xsd_types::DateTimeStamp::now_ms().into()),
121 verification_method: Some(verification_method),
122 proof_purpose: ProofPurpose::default(),
123 expires: None,
124 domains: Vec::new(),
125 challenge: None,
126 nonce: None,
127 options,
128 extra_properties: BTreeMap::new(),
129 }
130 }
131
132 pub fn from_method(verification_method: ReferenceOrOwned<M>) -> Self
133 where
134 T: Default,
135 {
136 Self::from_method_and_options(verification_method, Default::default())
137 }
138
139 pub fn map<N, U>(
140 self,
141 map_verification_method: impl FnOnce(M) -> N,
142 map_options: impl FnOnce(T) -> U,
143 ) -> ProofOptions<N, U> {
144 ProofOptions {
145 context: self.context,
146 created: self.created,
147 verification_method: self
148 .verification_method
149 .map(|m| m.map(map_verification_method)),
150 proof_purpose: self.proof_purpose,
151 expires: self.expires,
152 domains: self.domains,
153 challenge: self.challenge,
154 nonce: self.nonce,
155 options: map_options(self.options),
156 extra_properties: self.extra_properties,
157 }
158 }
159
160 pub fn cast<N, U>(self) -> ProofOptions<N, U>
161 where
162 M: Into<N>,
163 T: Into<U>,
164 {
165 self.map(Into::into, Into::into)
166 }
167
168 pub fn try_map<N, U, E>(
169 self,
170 map_verification_method: impl FnOnce(M) -> Result<N, E>,
171 map_options: impl FnOnce(T) -> Result<U, E>,
172 ) -> Result<ProofOptions<N, U>, E> {
173 Ok(ProofOptions {
174 context: self.context,
175 created: self.created,
176 verification_method: self
177 .verification_method
178 .map(|m| m.try_map(map_verification_method))
179 .transpose()?,
180 proof_purpose: self.proof_purpose,
181 expires: self.expires,
182 domains: self.domains,
183 challenge: self.challenge,
184 nonce: self.nonce,
185 options: map_options(self.options)?,
186 extra_properties: self.extra_properties,
187 })
188 }
189
190 pub fn into_configuration_with<S>(
191 self,
192 type_: S,
193 f: impl FnOnce(T) -> S::ProofOptions,
194 ) -> Result<ProofConfiguration<S>, ConfigurationError>
195 where
196 S: CryptographicSuite<VerificationMethod = M>,
197 {
198 Ok(ProofConfiguration {
199 context: self.context,
200 type_,
201 created: self.created,
202 verification_method: self
203 .verification_method
204 .ok_or(ConfigurationError::MissingVerificationMethod)?,
205 proof_purpose: self.proof_purpose,
206 expires: self.expires,
207 domains: self.domains,
208 challenge: self.challenge,
209 nonce: self.nonce,
210 options: f(self.options),
211 extra_properties: self.extra_properties,
212 })
213 }
214
215 pub fn into_configuration<S>(
216 self,
217 type_: S,
218 ) -> Result<ProofConfiguration<S>, ConfigurationError>
219 where
220 S: CryptographicSuite<VerificationMethod = M, ProofOptions = T>,
221 {
222 self.into_configuration_with(type_, |o| o)
223 }
224}