Skip to content

Commit 022330a

Browse files
committed
initial
1 parent 57f314c commit 022330a

File tree

2 files changed

+68
-62
lines changed

2 files changed

+68
-62
lines changed

rust/signed_doc/src/validator/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fn proposal_rule() -> Rules {
4141
Rules {
4242
id: IdRule,
4343
ver: VerRule,
44-
content_type: ContentTypeRule {
44+
content_type: ContentTypeRule::Specified {
4545
exp: ContentType::Json,
4646
},
4747
content_encoding: ContentEncodingRule {
@@ -79,7 +79,7 @@ fn proposal_comment_rule() -> Rules {
7979
Rules {
8080
id: IdRule,
8181
ver: VerRule,
82-
content_type: ContentTypeRule {
82+
content_type: ContentTypeRule::Specified {
8383
exp: ContentType::Json,
8484
},
8585
content_encoding: ContentEncodingRule {
@@ -135,7 +135,7 @@ fn proposal_submission_action_rule() -> Rules {
135135
Rules {
136136
id: IdRule,
137137
ver: VerRule,
138-
content_type: ContentTypeRule {
138+
content_type: ContentTypeRule::Specified {
139139
exp: ContentType::Json,
140140
},
141141
content_encoding: ContentEncodingRule {

rust/signed_doc/src/validator/rules/content_type.rs

Lines changed: 65 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ use crate::{metadata::ContentType, CatalystSignedDocument};
44

55
/// `content-type` field validation rule
66
#[derive(Debug)]
7-
pub(crate) struct ContentTypeRule {
8-
/// expected `content-type` field
9-
pub(crate) exp: ContentType,
7+
pub(crate) enum ContentTypeRule {
8+
Specified {
9+
/// expected `content-type` field
10+
exp: ContentType,
11+
},
12+
NotSpecified,
1013
}
1114

1215
impl ContentTypeRule {
@@ -23,14 +26,16 @@ impl ContentTypeRule {
2326
);
2427
return Ok(false);
2528
};
26-
if content_type != self.exp {
27-
doc.report().invalid_value(
28-
"content-type",
29-
content_type.to_string().as_str(),
30-
self.exp.to_string().as_str(),
31-
"Invalid Document content-type value",
32-
);
33-
return Ok(false);
29+
if let Self::Specified { exp } = &self {
30+
if content_type != *exp {
31+
doc.report().invalid_value(
32+
"content-type",
33+
content_type.to_string().as_str(),
34+
exp.to_string().as_str(),
35+
"Invalid Document content-type value",
36+
);
37+
return Ok(false);
38+
}
3439
}
3540
let Ok(content) = doc.decoded_content() else {
3641
doc.report().functional_validation(
@@ -57,34 +62,37 @@ impl ContentTypeRule {
5762
&self,
5863
content: &[u8],
5964
) -> anyhow::Result<()> {
60-
match self.exp {
61-
ContentType::Json => {
62-
if let Err(e) = serde_json::from_slice::<&serde_json::value::RawValue>(content) {
63-
anyhow::bail!("Invalid {} content: {e}", self.exp)
64-
}
65-
},
66-
ContentType::Cbor => {
67-
let mut decoder = minicbor::Decoder::new(content);
68-
69-
decoder.skip()?;
70-
71-
if decoder.position() != content.len() {
72-
anyhow::bail!("Unused bytes remain in the input after decoding")
73-
}
74-
},
75-
ContentType::Cddl
76-
| ContentType::JsonSchema
77-
| ContentType::Css
78-
| ContentType::CssHandlebars
79-
| ContentType::Html
80-
| ContentType::HtmlHandlebars
81-
| ContentType::Markdown
82-
| ContentType::MarkdownHandlebars
83-
| ContentType::Plain
84-
| ContentType::PlainHandlebars => {
85-
// TODO: not implemented yet
86-
anyhow::bail!("`{}` is valid but unavailable yet", self.exp)
87-
},
65+
if let Self::Specified { exp } = self {
66+
match exp {
67+
ContentType::Json => {
68+
if let Err(e) = serde_json::from_slice::<&serde_json::value::RawValue>(content)
69+
{
70+
anyhow::bail!("Invalid {} content: {e}", exp)
71+
}
72+
},
73+
ContentType::Cbor => {
74+
let mut decoder = minicbor::Decoder::new(content);
75+
76+
decoder.skip()?;
77+
78+
if decoder.position() != content.len() {
79+
anyhow::bail!("Unused bytes remain in the input after decoding")
80+
}
81+
},
82+
ContentType::Cddl
83+
| ContentType::JsonSchema
84+
| ContentType::Css
85+
| ContentType::CssHandlebars
86+
| ContentType::Html
87+
| ContentType::HtmlHandlebars
88+
| ContentType::Markdown
89+
| ContentType::MarkdownHandlebars
90+
| ContentType::Plain
91+
| ContentType::PlainHandlebars => {
92+
// TODO: not implemented yet
93+
anyhow::bail!("`{}` is valid but unavailable yet", exp)
94+
},
95+
}
8896
}
8997
Ok(())
9098
}
@@ -103,12 +111,11 @@ mod tests {
103111
enc.map(1).unwrap().u8(1).unwrap().u8(2).unwrap();
104112
buf.push(0xFF); // extra byte
105113

106-
let cbor_rule = ContentTypeRule {
107-
exp: ContentType::Cbor,
108-
};
114+
let content_type = ContentType::Cbor;
115+
let cbor_rule = ContentTypeRule::Specified { exp: content_type };
109116

110117
let doc = Builder::new()
111-
.with_metadata_field(SupportedField::ContentType(cbor_rule.exp))
118+
.with_metadata_field(SupportedField::ContentType(content_type))
112119
.with_content(buf)
113120
.build();
114121

@@ -120,12 +127,11 @@ mod tests {
120127
// 0xa2 means a map with 2 key-value pairs, but we only give 1 key
121128
let invalid_bytes = &[0xA2, 0x01];
122129

123-
let cbor_rule = ContentTypeRule {
124-
exp: ContentType::Cbor,
125-
};
130+
let content_type = ContentType::Cbor;
131+
let cbor_rule = ContentTypeRule::Specified { exp: content_type };
126132

127133
let doc = Builder::new()
128-
.with_metadata_field(SupportedField::ContentType(cbor_rule.exp))
134+
.with_metadata_field(SupportedField::ContentType(content_type))
129135
.with_content(invalid_bytes.into())
130136
.build();
131137

@@ -134,66 +140,66 @@ mod tests {
134140

135141
#[tokio::test]
136142
async fn content_type_cbor_rule_test() {
137-
let cbor_rule = ContentTypeRule {
138-
exp: ContentType::Cbor,
139-
};
143+
let content_type = ContentType::Cbor;
144+
let cbor_rule = ContentTypeRule::Specified { exp: content_type };
140145

141146
// with json bytes
142147
let doc = Builder::new()
143-
.with_metadata_field(SupportedField::ContentType(cbor_rule.exp))
148+
.with_metadata_field(SupportedField::ContentType(content_type))
144149
.with_content(serde_json::to_vec(&serde_json::json!({})).unwrap())
145150
.build();
146151
assert!(matches!(cbor_rule.check(&doc).await, Ok(false)));
147152

148153
// with cbor bytes
149154
let doc = Builder::new()
150-
.with_metadata_field(SupportedField::ContentType(cbor_rule.exp))
155+
.with_metadata_field(SupportedField::ContentType(content_type))
151156
.with_content(minicbor::to_vec(minicbor::data::Token::Null).unwrap())
152157
.build();
153158
assert!(matches!(cbor_rule.check(&doc).await, Ok(true)));
154159

155160
// without content
156161
let doc = Builder::new()
157-
.with_metadata_field(SupportedField::ContentType(cbor_rule.exp))
162+
.with_metadata_field(SupportedField::ContentType(content_type))
158163
.build();
159164
assert!(matches!(cbor_rule.check(&doc).await, Ok(false)));
160165

161166
// with empty content
162167
let doc = Builder::new()
163-
.with_metadata_field(SupportedField::ContentType(cbor_rule.exp))
168+
.with_metadata_field(SupportedField::ContentType(content_type))
164169
.build();
165170
assert!(matches!(cbor_rule.check(&doc).await, Ok(false)));
166171
}
167172

168173
#[tokio::test]
169174
async fn content_type_json_rule_test() {
170-
let json_rule = ContentTypeRule {
175+
let content_type = ContentType::Json;
176+
let json_rule = ContentTypeRule::Specified {
171177
exp: ContentType::Json,
172178
};
173179

174180
// with json bytes
175181
let doc = Builder::new()
176-
.with_metadata_field(SupportedField::ContentType(json_rule.exp))
182+
.with_metadata_field(SupportedField::ContentType(content_type))
177183
.with_content(serde_json::to_vec(&serde_json::json!({})).unwrap())
178184
.build();
179185
assert!(matches!(json_rule.check(&doc).await, Ok(true)));
180186

181187
// with cbor bytes
182188
let doc = Builder::new()
183-
.with_metadata_field(SupportedField::ContentType(json_rule.exp))
189+
.with_metadata_field(SupportedField::ContentType(content_type))
184190
.with_content(minicbor::to_vec(minicbor::data::Token::Null).unwrap())
185191
.build();
186192
assert!(matches!(json_rule.check(&doc).await, Ok(false)));
187193

188194
// without content
189195
let doc = Builder::new()
190-
.with_metadata_field(SupportedField::ContentType(json_rule.exp))
196+
.with_metadata_field(SupportedField::ContentType(content_type))
191197
.build();
192198
assert!(matches!(json_rule.check(&doc).await, Ok(false)));
193199

194200
// with empty content
195201
let doc = Builder::new()
196-
.with_metadata_field(SupportedField::ContentType(json_rule.exp))
202+
.with_metadata_field(SupportedField::ContentType(content_type))
197203
.build();
198204
assert!(matches!(json_rule.check(&doc).await, Ok(false)));
199205

0 commit comments

Comments
 (0)