1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Serialize, Deserialize)]
4#[serde(rename_all = "camelCase")]
5pub struct ValidationReport {
6 pub schema_valid: bool,
7 pub schema_errors: Vec<String>,
8 pub ttl_valid: bool,
9 pub ttl_errors: Vec<String>,
10 pub inspector_valid: bool,
11 pub inspector_errors: Vec<String>,
12 pub crypto_valid: bool,
13 pub crypto_errors: Vec<String>,
14 pub crypto_report: Option<CryptoReport>,
15 pub policy_valid: bool,
16 pub policy_errors: Vec<String>,
17}
18
19impl ValidationReport {
20 pub fn ok() -> Self {
21 Self {
22 schema_valid: true,
23 schema_errors: Vec::new(),
24 ttl_valid: true,
25 ttl_errors: Vec::new(),
26 inspector_valid: true,
27 inspector_errors: Vec::new(),
28 crypto_valid: true,
29 crypto_errors: Vec::new(),
30 crypto_report: None,
31 policy_valid: true,
32 policy_errors: Vec::new(),
33 }
34 }
35
36 pub fn is_valid(&self) -> bool {
38 self.schema_valid
39 && self.ttl_valid
40 && self.inspector_valid
41 && self.crypto_valid
42 && self.policy_valid
43 }
44
45 pub fn errors(&self) -> Vec<String> {
47 let mut all = Vec::new();
48 all.extend(self.schema_errors.clone());
49 all.extend(self.ttl_errors.clone());
50 all.extend(self.inspector_errors.clone());
51 all.extend(self.crypto_errors.clone());
52 all.extend(self.policy_errors.clone());
53 all
54 }
55
56 pub fn warnings(&self) -> Vec<String> {
58 Vec::new()
59 }
60}
61
62#[derive(Debug, Serialize, Deserialize, Clone)]
63#[serde(rename_all = "camelCase")]
64pub struct VerificationMethod {
65 pub id: String,
66 #[serde(rename = "type")]
67 pub method_type: String,
68 pub controller: String,
69 pub public_key_multibase: Option<String>,
70}
71
72#[derive(Debug, Serialize, Deserialize)]
73#[serde(rename_all = "camelCase")]
74pub struct ManifestProof {
75 #[serde(rename = "type")]
76 pub proof_type: String,
77 pub cryptosuite: Option<String>,
78 pub verification_method: String,
79 pub proof_purpose: String,
80 pub proof_value: String,
81}
82
83#[derive(Debug, Serialize, Deserialize)]
84#[serde(rename_all = "camelCase")]
85pub struct Manifest {
86 pub kya_version: String,
87 pub agent_id: String,
88 pub verification_method: Option<Vec<VerificationMethod>>,
89 pub proof: Vec<ManifestProof>,
90 pub max_transaction_value: Option<i64>,
91 pub permitted_regions: Option<Vec<String>>,
92 pub forbidden_regions: Option<Vec<String>>,
93}
94
95impl Manifest {
96 pub fn from_value(value: &serde_json::Value) -> Result<Self, String> {
97 serde_json::from_value(value.clone()).map_err(|err| err.to_string())
98 }
99}
100
101#[derive(Debug, Default, Clone)]
102pub struct ValidationOptions {
103 pub allowed_kya_versions: Vec<String>,
104 pub enforce_schema_url: bool,
105}
106
107#[derive(Debug, Default, Clone)]
108pub struct PolicyContext {
109 pub requested_region: Option<String>,
110 pub transaction_value: Option<i64>,
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
114#[serde(rename_all = "camelCase")]
115pub enum ValidationMode {
116 SelfAudit,
117 ClientAudit,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct TlsPinConfig {
123 pub expected_certificate_hash: Option<String>,
124 pub expected_certificate_pem: Option<String>,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
128#[serde(rename_all = "camelCase")]
129pub struct ContentCheck {
130 #[serde(rename = "type")]
131 pub check_type: ContentCheckType,
132 pub expected_value: String,
133 pub json_pointer: Option<String>,
134}
135
136#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
137#[serde(rename_all = "camelCase")]
138pub enum ContentCheckType {
139 StringContains,
140 StringEquals,
141 StringMatchesRegex,
142 JsonPointerEquals,
143 JsonPointerMatchesRegex,
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148pub enum HashAlgorithm {
149 Sha256,
150 Sha384,
151 Sha512,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
155#[serde(rename_all = "camelCase")]
156pub struct DigestConfig {
157 pub algorithm: HashAlgorithm,
158 pub expected_hash: String,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
162#[serde(rename_all = "camelCase")]
163pub struct LinkCheckConfig {
164 pub json_pointer: String,
165 pub required_contains: Option<String>,
166 pub tls_pin: Option<TlsPinConfig>,
167 pub allowed_domains: Option<Vec<String>>,
168 pub content_check: Option<ContentCheck>,
169 pub verify_digest: Option<DigestConfig>,
170 pub timeout_secs: Option<u64>,
171 pub max_retries: Option<u32>,
172 pub cache_ttl_secs: Option<u64>,
173}
174
175#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
176#[serde(rename_all = "camelCase")]
177pub enum TEEType {
178 SGX,
179 Nitro,
180 SevSnp,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
184#[serde(rename_all = "camelCase")]
185pub struct AttestationCheckConfig {
186 pub json_pointer: String,
187 pub tee_type: TEEType,
188 pub require_root_certificate: bool,
189 pub expected_tcb_info: Option<TcbInfo>,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
193#[serde(rename_all = "camelCase")]
194pub struct TcbInfo {
195 pub version: Option<String>,
196 pub svn: Option<u64>,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
200#[serde(rename_all = "camelCase", default)]
201pub struct ValidationConfig {
202 pub mode: ValidationMode,
203 pub allowed_kya_versions: Vec<String>,
204 pub required_fields: Vec<String>,
205 pub enforce_controller_match: bool,
206 pub check_external_links: bool,
207 pub link_checks: Vec<LinkCheckConfig>,
208 pub require_all_proofs: bool,
209 pub required_field_pairs: Vec<(String, String)>,
210 pub allowed_controllers: Vec<String>,
211 pub required_vc_types: Vec<String>,
212 pub attestation_checks: Vec<AttestationCheckConfig>,
213}
214
215impl Default for ValidationConfig {
216 fn default() -> Self {
217 Self {
218 mode: ValidationMode::SelfAudit,
219 allowed_kya_versions: vec!["1.0".to_string(), "1.1".to_string()],
220 required_fields: Vec::new(),
221 enforce_controller_match: true,
222 check_external_links: false,
223 link_checks: Vec::new(),
224 require_all_proofs: false,
225 required_field_pairs: Vec::new(),
226 allowed_controllers: Vec::new(),
227 required_vc_types: Vec::new(),
228 attestation_checks: Vec::new(),
229 }
230 }
231}
232
233impl ValidationConfig {
234 pub fn self_audit() -> Self {
235 Self {
236 mode: ValidationMode::SelfAudit,
237 allowed_kya_versions: vec!["1.0".to_string(), "1.1".to_string()],
238 required_fields: vec!["/agentId".to_string(), "/proof".to_string()],
239 enforce_controller_match: true,
240 check_external_links: true,
241 link_checks: Vec::new(),
242 require_all_proofs: true,
243 required_field_pairs: Vec::new(),
244 allowed_controllers: Vec::new(),
245 required_vc_types: Vec::new(),
246 attestation_checks: Vec::new(),
247 }
248 }
249
250 pub fn lenient() -> Self {
251 Self {
252 mode: ValidationMode::ClientAudit,
253 allowed_kya_versions: vec!["1.0".to_string(), "1.1".to_string()],
254 required_fields: Vec::new(),
255 enforce_controller_match: false,
256 check_external_links: false,
257 link_checks: Vec::new(),
258 require_all_proofs: false,
259 required_field_pairs: Vec::new(),
260 allowed_controllers: Vec::new(),
261 required_vc_types: Vec::new(),
262 attestation_checks: Vec::new(),
263 }
264 }
265
266 pub fn strict() -> Self {
267 Self {
268 mode: ValidationMode::SelfAudit,
269 allowed_kya_versions: vec!["1.0".to_string(), "1.1".to_string()],
270 required_fields: vec![
271 "/agentId".to_string(),
272 "/name".to_string(),
273 "/proof".to_string(),
274 ],
275 enforce_controller_match: true,
276 check_external_links: true,
277 link_checks: Vec::new(),
278 require_all_proofs: true,
279 required_field_pairs: Vec::new(),
280 allowed_controllers: Vec::new(),
281 required_vc_types: Vec::new(),
282 attestation_checks: Vec::new(),
283 }
284 }
285
286 pub fn client_audit() -> Self {
287 Self {
288 mode: ValidationMode::ClientAudit,
289 allowed_kya_versions: vec!["1.0".to_string(), "1.1".to_string()],
290 required_fields: vec!["/agentId".to_string(), "/proof".to_string()],
291 enforce_controller_match: true,
292 check_external_links: false,
293 link_checks: Vec::new(),
294 require_all_proofs: true,
295 required_field_pairs: Vec::new(),
296 allowed_controllers: Vec::new(),
297 required_vc_types: Vec::new(),
298 attestation_checks: Vec::new(),
299 }
300 }
301}
302
303#[derive(Debug, Serialize, Deserialize)]
304#[serde(rename_all = "camelCase")]
305pub struct DidDocument {
306 pub id: Option<String>,
307 #[serde(rename = "verificationMethod")]
308 pub verification_method: Option<Vec<VerificationMethod>>,
309}
310
311#[derive(Debug, Serialize, Deserialize)]
312#[serde(rename_all = "camelCase")]
313pub struct CryptoReport {
314 pub resolved_keys: Vec<String>,
315 pub invalid_signatures: Vec<String>,
316 pub missing_verification_methods: Vec<String>,
317}
318
319impl CryptoReport {
320 pub fn ok() -> Self {
321 Self {
322 resolved_keys: Vec::new(),
323 invalid_signatures: Vec::new(),
324 missing_verification_methods: Vec::new(),
325 }
326 }
327}
328
329#[derive(Debug, Clone, Copy, PartialEq, Eq)]
330pub(crate) enum KeyType {
331 Ed25519,
332 Secp256k1,
333}
334
335#[derive(Debug, Clone)]
336pub(crate) struct ResolvedKey {
337 pub id: String,
338 pub controller: String,
339 pub key_type: KeyType,
340 pub public_key: Vec<u8>,
341}