1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//! Runtime JSON Schema validation for Trust Task payloads.
//!
//! Available behind the `validate` Cargo feature. The codegen inlines each
//! spec's `payload.schema.json` as a string constant and emits a
//! [`ValidatedPayload`] impl so callers can validate any inbound value
//! against the on-the-wire schema, not just the structural shape serde
//! recovers.
//!
//! ```ignore
//! # #[cfg(feature = "validate")]
//! # fn demo() -> Result<(), trust_tasks_rs::validate::ValidationError> {
//! use trust_tasks_rs::{specs::acl::grant::v0_2, validate::ValidatedPayload};
//!
//! let value: serde_json::Value = serde_json::json!({
//! "entry": {
//! "subject": "did:web:alice.example",
//! "role": "admin",
//! "act": { "scope": "all" },
//! "keys": { "scope": "all" },
//! "capabilities": { "scope": "ceiling" }
//! }
//! });
//! v0_2::Payload::validate_value(&value)?;
//! # Ok(())
//! # }
//! ```
//!
//! This is belt-and-suspenders: most schema constraints fall out of typify's
//! generated struct shapes, but cross-cutting checks (regex `pattern`,
//! `minItems` on optional arrays, conditional schemas) only hold up under a
//! true schema validator.
use fmt;
use Value;
use Error;
use cratePayload;
/// A payload type whose original JSON Schema is embedded at compile time and
/// available for runtime validation.
///
/// Implemented automatically by the codegen for every generated request and
/// response payload type.
/// Every [`Payload`] is validatable, because every `Payload` carries its
/// schema (or states that it has none).
///
/// Before 0.9.0 this trait declared its own `SCHEMA_JSON` const and the
/// codegen emitted one impl per generated type. The schema now lives on
/// `Payload` itself — reachable without the `validate` feature, since a
/// `&'static str` costs nothing — and this blanket impl replaces roughly
/// three hundred generated impl blocks.
/// Compile `schema_json` as a JSON Schema and validate `value` against it.
///
/// Compilation is performed every call. Callers in a hot path should keep a
/// compiled schema around themselves; this helper is intended for the
/// once-per-request pattern that consumer pipelines use.
///
/// # ⚠ Schema-validation DoS surface (SPEC §12.3)
///
/// `schema_json` MUST be trusted by the caller. The underlying
/// `jsonschema` crate compiles `pattern` keywords through a regex engine
/// that supports backtracking, so a malicious schema can carry a
/// `pattern` such as `"^(a+)+$"` and validation will consume unbounded
/// CPU on otherwise-innocuous strings.
///
/// The codegen-emitted [`ValidatedPayload`] impls satisfy this rule
/// trivially because the schemas are inlined as string constants from the
/// repo at codegen time and frozen at build time. If you call this function directly
/// with a schema obtained from any other source — content-negotiating
/// a URI over the network, accepting a private-spec submission per
/// SPEC §6.5, etc. — you MUST authenticate the schema's source and
/// SHOULD apply a per-validation timeout outside this call.
/// One or more schema-validation problems encountered while checking a value.