Skip to content

Commit cd4301c

Browse files
committed
wip
1 parent 2182445 commit cd4301c

File tree

4 files changed

+74
-45
lines changed

4 files changed

+74
-45
lines changed

rust/signed_doc/src/doc_types/comment_document.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ pub struct CommentDocument {
3232

3333
impl StatelessValidation for CommentDocument {
3434
const STATELESS_RULES: &[crate::validator::StatelessRule] = &[
35-
type_check,
36-
content_type_check,
37-
content_encoding_check,
38-
template_check,
39-
reply_check,
35+
type_stateless_check,
36+
content_type_stateless_check,
37+
content_encoding_stateless_check,
38+
template_stateless_check,
39+
reply_stateless_check,
4040
];
4141
}
4242

@@ -48,7 +48,7 @@ where DocProvider: 'static + Fn(&DocumentRef) -> Option<CatalystSignedDocument>
4848
}
4949

5050
/// `type` field validation
51-
fn type_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
51+
fn type_stateless_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
5252
if doc.doc_type().uuid() != COMMENT_DOCUMENT_UUID_TYPE {
5353
report.invalid_value(
5454
"type",
@@ -62,7 +62,7 @@ fn type_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
6262
}
6363

6464
/// `content-type` validation
65-
fn content_type_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
65+
fn content_type_stateless_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
6666
if doc.doc_content_type() != ContentType::Json {
6767
report.invalid_value(
6868
"content-type",
@@ -76,7 +76,7 @@ fn content_type_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> b
7676
}
7777

7878
/// `content-encoding` validation
79-
fn content_encoding_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
79+
fn content_encoding_stateless_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
8080
if let Some(content_encoding) = doc.doc_content_encoding() {
8181
if content_encoding != ContentEncoding::Brotli {
8282
report.invalid_value(
@@ -98,7 +98,7 @@ fn content_encoding_check(doc: &CatalystSignedDocument, report: &ProblemReport)
9898
}
9999

100100
/// `template` validation
101-
fn template_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
101+
fn template_stateless_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
102102
if doc.doc_meta().template().is_none() {
103103
report.missing_field("template", "Comment Document must have a template field");
104104
return false;
@@ -107,7 +107,7 @@ fn template_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool
107107
}
108108

109109
/// `reply` validation
110-
fn reply_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
110+
fn reply_stateless_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
111111
if doc.doc_meta().doc_ref().is_none() {
112112
report.missing_field("ref", "Comment Document must have a ref field");
113113
return false;

rust/signed_doc/src/doc_types/proposal_document.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ pub struct ProposalDocument {
3030

3131
impl StatelessValidation for ProposalDocument {
3232
const STATELESS_RULES: &[StatelessRule] = &[
33-
type_check,
34-
content_type_check,
35-
content_encoding_check,
36-
template_check,
33+
type_stateless_check,
34+
content_type_stateless_check,
35+
content_encoding_stateless_check,
36+
template_stateless_check,
3737
];
3838
}
3939

@@ -45,7 +45,7 @@ where DocProvider: 'static + Fn(&DocumentRef) -> Option<CatalystSignedDocument>
4545
}
4646

4747
/// `type` field validation
48-
fn type_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
48+
fn type_stateless_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
4949
if doc.doc_type().uuid() != PROPOSAL_DOCUMENT_UUID_TYPE {
5050
report.invalid_value(
5151
"type",
@@ -59,7 +59,7 @@ fn type_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
5959
}
6060

6161
/// `content-type` validation
62-
fn content_type_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
62+
fn content_type_stateless_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
6363
if doc.doc_content_type() != ContentType::Json {
6464
report.invalid_value(
6565
"content-type",
@@ -73,7 +73,7 @@ fn content_type_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> b
7373
}
7474

7575
/// `content-encoding` validation
76-
fn content_encoding_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
76+
fn content_encoding_stateless_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
7777
if let Some(content_encoding) = doc.doc_content_encoding() {
7878
if content_encoding != ContentEncoding::Brotli {
7979
report.invalid_value(
@@ -95,7 +95,7 @@ fn content_encoding_check(doc: &CatalystSignedDocument, report: &ProblemReport)
9595
}
9696

9797
/// `template` validation
98-
fn template_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
98+
fn template_stateless_check(doc: &CatalystSignedDocument, report: &ProblemReport) -> bool {
9999
if doc.doc_meta().template().is_none() {
100100
report.missing_field("template", "Proposal Document must have a template field");
101101
return false;

rust/signed_doc/src/lib.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,10 @@ impl CatalystSignedDocument {
141141
/// # Errors
142142
///
143143
/// Returns a report of verification failures and the source error.
144-
pub fn verify<P>(&self, pk_getter: P) -> Result<(), CatalystSignedDocError>
145-
where P: Fn(&IdUri) -> Option<VerifyingKey> {
144+
/// If `provider` returns error, fails fast and placed this error into
145+
/// `CatalystSignedDocError::error`.
146+
pub fn verify<P>(&self, provider: P) -> Result<(), CatalystSignedDocError>
147+
where P: Fn(&IdUri) -> anyhow::Result<Option<VerifyingKey>> {
146148
let report = ProblemReport::new("Catalyst Signed Document Verification");
147149

148150
let cose_sign = match self.as_cose_sign() {
@@ -157,8 +159,8 @@ impl CatalystSignedDocument {
157159
};
158160

159161
for (signature, kid) in self.signatures().cose_signatures_with_kids() {
160-
match pk_getter(kid) {
161-
Some(pk) => {
162+
match provider(kid) {
163+
Ok(Some(pk)) => {
162164
let tbs_data = cose_sign.tbs_data(&[], signature);
163165
match signature.signature.as_slice().try_into() {
164166
Ok(signature_bytes) => {
@@ -182,19 +184,22 @@ impl CatalystSignedDocument {
182184
},
183185
}
184186
},
185-
None => {
187+
Ok(None) => {
186188
report.other(
187189
&format!("Missing public key for {kid}."),
188190
"During public key extraction",
189191
);
190192
},
193+
Err(e) => {
194+
return Err(CatalystSignedDocError::new(report, e));
195+
},
191196
}
192197
}
193198

194199
if report.is_problematic() {
195200
return Err(CatalystSignedDocError::new(
196201
report,
197-
anyhow::anyhow!("Verification failed for Catalyst Signed Document"),
202+
anyhow::anyhow!("Signature validation for Catalyst Signed Document fails"),
198203
));
199204
}
200205

@@ -426,8 +431,10 @@ mod tests {
426431
.build()
427432
.unwrap();
428433

429-
assert!(signed_doc.verify(|_| Some(pk)).is_ok());
430-
431-
assert!(signed_doc.verify(|_| None).is_err());
434+
assert!(signed_doc.verify(|_| Ok(Some(pk))).is_ok());
435+
assert!(signed_doc.verify(|_| Ok(None)).is_err());
436+
assert!(signed_doc
437+
.verify(|_| Err(anyhow::anyhow!("some error")))
438+
.is_err());
432439
}
433440
}

rust/signed_doc/src/validator/mod.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,15 @@ where
4242
const STATEFULL_RULES: &[StatefullRule<Self, DocProvider>];
4343

4444
/// Perform a statefull validation, collecting a problem report
45-
fn validate(&self, provider: &DocProvider, report: &ProblemReport) -> bool {
46-
Self::STATEFULL_RULES
45+
///
46+
/// # Errors
47+
/// Returns an error if `provider` will return an error, fails fast in this case.
48+
fn validate(&self, provider: &DocProvider, report: &ProblemReport) -> anyhow::Result<bool> {
49+
let res = Self::STATEFULL_RULES
4750
.iter()
4851
.map(|rule| rule(self, provider, report))
49-
.all(|res| res)
52+
.all(|res| res);
53+
Ok(res)
5054
}
5155
}
5256

@@ -56,6 +60,8 @@ where
5660
/// # Errors
5761
///
5862
/// Returns a report of validation failures and the source error.
63+
/// If `provider` returns error, fails fast and placed this error into
64+
/// `CatalystSignedDocError::error`.
5965
pub fn validate<DocProvider>(
6066
doc: &CatalystSignedDocument, provider: &DocProvider,
6167
) -> Result<(), CatalystSignedDocError>
@@ -73,23 +79,47 @@ where DocProvider: 'static + Fn(&DocumentRef) -> Option<CatalystSignedDocument>
7379
);
7480
return Err(CatalystSignedDocError::new(
7581
report,
76-
anyhow::anyhow!("Validation of the Catalyst Signed Document failed"),
82+
anyhow::anyhow!("Validation of the Catalyst Signed Document failed, {e}"),
7783
));
7884
},
7985
};
8086

87+
match validate_inner(doc_type, doc, provider, &report) {
88+
Ok(()) if report.is_problematic() => {
89+
Err(CatalystSignedDocError::new(
90+
report,
91+
anyhow::anyhow!("Validation of the Catalyst Signed Document failed"),
92+
))
93+
},
94+
Err(e) => Err(CatalystSignedDocError::new(report, e)),
95+
Ok(()) => Ok(()),
96+
}
97+
}
98+
99+
/// A comprehensive type based validation of the `CatalystSignedDocument`, collecting a
100+
/// `report`.
101+
///
102+
/// # Errors
103+
///
104+
/// If `provider` returns error, fails fast and placed this error into
105+
/// `CatalystSignedDocError::error`.
106+
fn validate_inner<DocProvider>(
107+
doc_type: DocumentType, doc: &CatalystSignedDocument, provider: &DocProvider,
108+
report: &ProblemReport,
109+
) -> anyhow::Result<()>
110+
where
111+
DocProvider: 'static + Fn(&DocumentRef) -> Option<CatalystSignedDocument>,
112+
{
81113
#[allow(clippy::match_same_arms)]
82114
match doc_type {
83115
DocumentType::ProposalDocument => {
84-
if let Ok(proposal_doc) = ProposalDocument::from_signed_doc(doc, &report) {
85-
proposal_doc.validate(provider, &report);
86-
}
116+
let doc = ProposalDocument::from_signed_doc(doc, report)?;
117+
doc.validate(provider, report)?;
87118
},
88119
DocumentType::ProposalTemplate => {},
89120
DocumentType::CommentDocument => {
90-
if let Ok(comment_doc) = CommentDocument::from_signed_doc(doc, &report) {
91-
comment_doc.validate(provider, &report);
92-
}
121+
let doc = CommentDocument::from_signed_doc(doc, report)?;
122+
doc.validate(provider, report)?;
93123
},
94124
DocumentType::CommentTemplate => {},
95125
DocumentType::ReviewDocument => {},
@@ -105,13 +135,5 @@ where DocProvider: 'static + Fn(&DocumentRef) -> Option<CatalystSignedDocument>
105135
DocumentType::PrivateVoteTxV2 => {},
106136
DocumentType::ImmutableLedgerBlock => {},
107137
}
108-
109-
if report.is_problematic() {
110-
return Err(CatalystSignedDocError::new(
111-
report,
112-
anyhow::anyhow!("Validation of the Catalyst Signed Document failed"),
113-
));
114-
}
115-
116138
Ok(())
117139
}

0 commit comments

Comments
 (0)