Skip to main content

kya_validator/
types.rs

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    /// Returns true if all validations passed
37    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    /// Collects all errors into a single vector
46    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    /// Returns warnings (currently empty, can be extended)
57    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}