Skip to content

Commit 320be58

Browse files
authored
fix(rust/signed-doc): Apply new document ref and fix validation rules (#368)
* fix(signed-doc): wip apply new doc ref Signed-off-by: bkioshn <bkioshn@gmail.com> * fix(signed-doc): apply new doc ref and implement validation rule for doc ref Signed-off-by: bkioshn <bkioshn@gmail.com> * fix(signed-doc): revert doc type change Signed-off-by: bkioshn <bkioshn@gmail.com> * fix(signed-doc): remove problem report in encoder Signed-off-by: bkioshn <bkioshn@gmail.com> * fix(signed-doc): metadata decode Signed-off-by: bkioshn <bkioshn@gmail.com> * chore(signed-doc): revert change Signed-off-by: bkioshn <bkioshn@gmail.com> * test(signed-doc): add docref to decoding test Signed-off-by: bkioshn <bkioshn@gmail.com> * fix(signed-doc): format Signed-off-by: bkioshn <bkioshn@gmail.com> * fix(signed-doc): refactor and improvement Signed-off-by: bkioshn <bkioshn@gmail.com> * fix(signed-doc): refactor Signed-off-by: bkioshn <bkioshn@gmail.com> * test(signed-doc): fix content test Signed-off-by: bkioshn <bkioshn@gmail.com> * test(signed-doc): fix content test Signed-off-by: bkioshn <bkioshn@gmail.com> --------- Signed-off-by: bkioshn <bkioshn@gmail.com>
1 parent 8460d78 commit 320be58

File tree

21 files changed

+999
-400
lines changed

21 files changed

+999
-400
lines changed

rust/signed_doc/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub use content::Content;
2424
use coset::{CborSerializable, TaggedCborSerializable};
2525
use decode_context::{CompatibilityPolicy, DecodeContext};
2626
pub use metadata::{
27-
ContentEncoding, ContentType, DocLocator, DocType, DocumentRef, Metadata, Section,
27+
ContentEncoding, ContentType, DocLocator, DocType, DocumentRef, DocumentRefs, Metadata, Section,
2828
};
2929
use minicbor::{decode, encode, Decode, Decoder, Encode};
3030
pub use signature::{CatalystId, Signatures};

rust/signed_doc/src/metadata/document_refs/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ mod doc_locator;
44
mod doc_ref;
55
use std::{fmt::Display, str::FromStr};
66

7-
use catalyst_types::{
8-
problem_report::ProblemReport,
9-
uuid::{CborContext, UuidV7},
10-
};
7+
use catalyst_types::uuid::{CborContext, UuidV7};
118
use coset::cbor::Value;
129
pub use doc_locator::DocLocator;
1310
pub use doc_ref::DocumentRef;
@@ -267,6 +264,7 @@ impl<'de> Deserialize<'de> for DocumentRefs {
267264
#[cfg(test)]
268265
mod tests {
269266

267+
use catalyst_types::problem_report::ProblemReport;
270268
use minicbor::Encoder;
271269
use serde_json::json;
272270

@@ -352,11 +350,11 @@ mod tests {
352350
let doc_refs = DocumentRefs(vec![doc_ref.clone(), doc_ref]);
353351
let mut buffer = Vec::new();
354352
let mut encoder = Encoder::new(&mut buffer);
355-
doc_refs.encode(&mut encoder, &mut report).unwrap();
353+
doc_refs.encode(&mut encoder, &mut ()).unwrap();
356354
let mut decoder = Decoder::new(&buffer);
357355
let mut decoded_context = DecodeContext {
358356
compatibility_policy: CompatibilityPolicy::Accept,
359-
report: &mut report.clone(),
357+
report: &mut report,
360358
};
361359
let decoded_doc_refs = DocumentRefs::decode(&mut decoder, &mut decoded_context).unwrap();
362360
assert_eq!(decoded_doc_refs, doc_refs);

rust/signed_doc/src/metadata/mod.rs

Lines changed: 28 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,19 @@ pub(crate) mod utils;
1616
use catalyst_types::{problem_report::ProblemReport, uuid::UuidV7};
1717
pub use content_encoding::ContentEncoding;
1818
pub use content_type::ContentType;
19-
use coset::CborSerializable;
2019
pub use doc_type::DocType;
2120
pub use document_refs::{DocLocator, DocumentRef, DocumentRefs};
22-
use minicbor::{Decode, Decoder};
21+
use minicbor::Decoder;
2322
pub use section::Section;
2423
use strum::IntoDiscriminant as _;
2524
use utils::{cose_protected_header_find, decode_document_field_from_protected_header, CborUuidV7};
2625

2726
use crate::{
2827
decode_context::DecodeContext,
29-
metadata::supported_field::{SupportedField, SupportedLabel},
28+
metadata::{
29+
supported_field::{SupportedField, SupportedLabel},
30+
utils::decode_cose_protected_header_value,
31+
},
3032
};
3133

3234
/// `content_encoding` field COSE key value
@@ -122,29 +124,26 @@ impl Metadata {
122124

123125
/// Return `ref` field.
124126
#[must_use]
125-
pub fn doc_ref(&self) -> Option<DocumentRef> {
127+
pub fn doc_ref(&self) -> Option<&DocumentRefs> {
126128
self.0
127129
.get(&SupportedLabel::Ref)
128130
.and_then(SupportedField::try_as_ref_ref)
129-
.copied()
130131
}
131132

132133
/// Return `template` field.
133134
#[must_use]
134-
pub fn template(&self) -> Option<DocumentRef> {
135+
pub fn template(&self) -> Option<&DocumentRefs> {
135136
self.0
136137
.get(&SupportedLabel::Template)
137138
.and_then(SupportedField::try_as_template_ref)
138-
.copied()
139139
}
140140

141141
/// Return `reply` field.
142142
#[must_use]
143-
pub fn reply(&self) -> Option<DocumentRef> {
143+
pub fn reply(&self) -> Option<&DocumentRefs> {
144144
self.0
145145
.get(&SupportedLabel::Reply)
146146
.and_then(SupportedField::try_as_reply_ref)
147-
.copied()
148147
}
149148

150149
/// Return `section` field.
@@ -166,11 +165,10 @@ impl Metadata {
166165

167166
/// Return `parameters` field.
168167
#[must_use]
169-
pub fn parameters(&self) -> Option<DocumentRef> {
168+
pub fn parameters(&self) -> Option<&DocumentRefs> {
170169
self.0
171170
.get(&SupportedLabel::Parameters)
172171
.and_then(SupportedField::try_as_parameters_ref)
173-
.copied()
174172
}
175173

176174
/// Build `Metadata` object from the metadata fields, doing all necessary validation.
@@ -266,20 +264,6 @@ impl Metadata {
266264
}
267265
}
268266

269-
if let Some(value) = cose_protected_header_find(
270-
protected,
271-
|key| matches!(key, coset::Label::Text(label) if label.eq_ignore_ascii_case(TYPE_KEY)),
272-
)
273-
.and_then(|value| {
274-
DocType::decode(
275-
&mut Decoder::new(&value.clone().to_vec().unwrap_or_default()),
276-
context,
277-
)
278-
.ok()
279-
}) {
280-
metadata_fields.push(SupportedField::Type(value));
281-
}
282-
283267
if let Some(value) = decode_document_field_from_protected_header::<CborUuidV7>(
284268
protected,
285269
ID_KEY,
@@ -302,30 +286,30 @@ impl Metadata {
302286
metadata_fields.push(SupportedField::Ver(value));
303287
}
304288

305-
if let Some(value) = decode_document_field_from_protected_header(
306-
protected,
307-
REF_KEY,
308-
COSE_DECODING_CONTEXT,
309-
context.report,
289+
// DocType and DocRef now using minicbor decoding.
290+
if let Some(value) = decode_cose_protected_header_value::<DecodeContext, DocType>(
291+
protected, context, TYPE_KEY,
292+
) {
293+
metadata_fields.push(SupportedField::Type(value));
294+
};
295+
if let Some(value) = decode_cose_protected_header_value::<DecodeContext, DocumentRefs>(
296+
protected, context, REF_KEY,
310297
) {
311298
metadata_fields.push(SupportedField::Ref(value));
312-
}
313-
if let Some(value) = decode_document_field_from_protected_header(
299+
};
300+
if let Some(value) = decode_cose_protected_header_value::<DecodeContext, DocumentRefs>(
314301
protected,
302+
context,
315303
TEMPLATE_KEY,
316-
COSE_DECODING_CONTEXT,
317-
context.report,
318304
) {
319305
metadata_fields.push(SupportedField::Template(value));
320306
}
321-
if let Some(value) = decode_document_field_from_protected_header(
322-
protected,
323-
REPLY_KEY,
324-
COSE_DECODING_CONTEXT,
325-
context.report,
307+
if let Some(value) = decode_cose_protected_header_value::<DecodeContext, DocumentRefs>(
308+
protected, context, REPLY_KEY,
326309
) {
327310
metadata_fields.push(SupportedField::Reply(value));
328311
}
312+
329313
if let Some(value) = decode_document_field_from_protected_header(
330314
protected,
331315
SECTION_KEY,
@@ -343,20 +327,15 @@ impl Metadata {
343327
CATEGORY_ID_KEY,
344328
]
345329
.iter()
346-
.filter_map(|field_name| -> Option<DocumentRef> {
347-
decode_document_field_from_protected_header(
348-
protected,
349-
field_name,
350-
COSE_DECODING_CONTEXT,
351-
context.report,
352-
)
330+
.filter_map(|field_name| -> Option<DocumentRefs> {
331+
decode_cose_protected_header_value(protected, context, field_name)
353332
})
354333
.fold((None, false), |(res, _), v| (Some(v), res.is_some()));
355334
if has_multiple_fields {
356335
context.report.duplicate_field(
357-
"brand_id, campaign_id, category_id",
358-
"Only value at the same time is allowed parameters, brand_id, campaign_id, category_id",
359-
"Validation of parameters field aliases"
336+
"Parameters field",
337+
"Only one parameter can be used at a time: either brand_id, campaign_id, category_id",
338+
COSE_DECODING_CONTEXT
360339
);
361340
}
362341
if let Some(value) = parameters {

rust/signed_doc/src/metadata/supported_field.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use serde::Deserialize;
99
use strum::{EnumDiscriminants, EnumTryAs, IntoDiscriminant as _};
1010

1111
use crate::{
12-
metadata::custom_transient_decode_error, ContentEncoding, ContentType, DocType, DocumentRef,
12+
metadata::custom_transient_decode_error, ContentEncoding, ContentType, DocType, DocumentRefs,
1313
Section,
1414
};
1515

@@ -104,21 +104,21 @@ pub enum SupportedField {
104104
/// `id` field.
105105
Id(UuidV7) = 1,
106106
/// `ref` field.
107-
Ref(DocumentRef) = 2,
107+
Ref(DocumentRefs) = 2,
108108
/// `ver` field.
109109
Ver(UuidV7) = 3,
110110
/// `type` field.
111111
Type(DocType) = 4,
112112
/// `reply` field.
113-
Reply(DocumentRef) = 5,
113+
Reply(DocumentRefs) = 5,
114114
/// `collabs` field.
115115
Collabs(Vec<String>) = 7,
116116
/// `section` field.
117117
Section(Section) = 8,
118118
/// `template` field.
119-
Template(DocumentRef) = 9,
119+
Template(DocumentRefs) = 9,
120120
/// `parameters` field.
121-
Parameters(DocumentRef) = 10,
121+
Parameters(DocumentRefs) = 10,
122122
/// `Content-Encoding` field.
123123
ContentEncoding(ContentEncoding) = 11,
124124
}
@@ -230,17 +230,17 @@ impl minicbor::Decode<'_, crate::decode_context::DecodeContext<'_>> for Supporte
230230
d.decode_with(&mut catalyst_types::uuid::CborContext::Tagged)
231231
.map(Self::Id)
232232
},
233-
SupportedLabel::Ref => todo!(),
233+
SupportedLabel::Ref => d.decode_with(ctx).map(Self::Ref),
234234
SupportedLabel::Ver => {
235235
d.decode_with(&mut catalyst_types::uuid::CborContext::Tagged)
236236
.map(Self::Ver)
237237
},
238238
SupportedLabel::Type => d.decode_with(ctx).map(Self::Type),
239-
SupportedLabel::Reply => todo!(),
239+
SupportedLabel::Reply => d.decode_with(ctx).map(Self::Reply),
240240
SupportedLabel::Collabs => todo!(),
241241
SupportedLabel::Section => todo!(),
242-
SupportedLabel::Template => todo!(),
243-
SupportedLabel::Parameters => todo!(),
242+
SupportedLabel::Template => d.decode_with(ctx).map(Self::Template),
243+
SupportedLabel::Parameters => d.decode_with(ctx).map(Self::Parameters),
244244
SupportedLabel::ContentEncoding => todo!(),
245245
}?;
246246

rust/signed_doc/src/metadata/utils.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ use catalyst_types::{
55
uuid::{CborContext, UuidV7},
66
};
77
use coset::{CborSerializable, Label, ProtectedHeader};
8+
use minicbor::{Decode, Decoder};
9+
10+
/// Decode cose protected header value using minicbor decoder.
11+
pub(crate) fn decode_cose_protected_header_value<C, T>(
12+
protected: &ProtectedHeader, context: &mut C, label: &str,
13+
) -> Option<T>
14+
where T: for<'a> Decode<'a, C> {
15+
cose_protected_header_find(protected, |key| matches!(key, Label::Text(l) if l == label))
16+
.and_then(|value| {
17+
let bytes = value.clone().to_vec().unwrap_or_default();
18+
Decoder::new(&bytes).decode_with(context).ok()
19+
})
20+
}
821

922
/// Find a value for a predicate in the protected header.
1023
pub(crate) fn cose_protected_header_find(

rust/signed_doc/src/providers.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub trait VerifyingKeyProvider {
1717

1818
/// `CatalystSignedDocument` Provider trait
1919
pub trait CatalystSignedDocumentProvider: Send + Sync {
20-
/// Try to get `CatalystSignedDocument`
20+
/// Try to get `CatalystSignedDocument`from document reference
2121
fn try_get_doc(
2222
&self, doc_ref: &DocumentRef,
2323
) -> impl Future<Output = anyhow::Result<Option<CatalystSignedDocument>>> + Send;
@@ -38,24 +38,34 @@ pub mod tests {
3838
3939
use std::{collections::HashMap, time::Duration};
4040

41-
use catalyst_types::uuid::Uuid;
42-
4341
use super::{
44-
CatalystId, CatalystSignedDocument, CatalystSignedDocumentProvider, DocumentRef,
45-
VerifyingKey, VerifyingKeyProvider,
42+
CatalystId, CatalystSignedDocument, CatalystSignedDocumentProvider, VerifyingKey,
43+
VerifyingKeyProvider,
4644
};
45+
use crate::{DocLocator, DocumentRef};
4746

4847
/// Simple testing implementation of `CatalystSignedDocumentProvider`
49-
#[derive(Default)]
50-
pub struct TestCatalystSignedDocumentProvider(HashMap<Uuid, CatalystSignedDocument>);
48+
#[derive(Default, Debug)]
49+
50+
pub struct TestCatalystSignedDocumentProvider(HashMap<DocumentRef, CatalystSignedDocument>);
5151

5252
impl TestCatalystSignedDocumentProvider {
53-
/// Inserts document into the `TestCatalystSignedDocumentProvider`
53+
/// Inserts document into the `TestCatalystSignedDocumentProvider` where
54+
/// if document reference is provided use that value.
55+
/// if not use the id and version of the provided doc.
5456
///
5557
/// # Errors
56-
/// - Missing document id
57-
pub fn add_document(&mut self, doc: CatalystSignedDocument) -> anyhow::Result<()> {
58-
self.0.insert(doc.doc_id()?.uuid(), doc);
58+
/// Returns error if document reference is not provided and its fail to create one
59+
/// from the given doc.
60+
pub fn add_document(
61+
&mut self, doc_ref: Option<DocumentRef>, doc: &CatalystSignedDocument,
62+
) -> anyhow::Result<()> {
63+
if let Some(dr) = doc_ref {
64+
self.0.insert(dr, doc.clone());
65+
} else {
66+
let dr = DocumentRef::new(doc.doc_id()?, doc.doc_ver()?, DocLocator::default());
67+
self.0.insert(dr, doc.clone());
68+
}
5969
Ok(())
6070
}
6171
}
@@ -64,7 +74,7 @@ pub mod tests {
6474
async fn try_get_doc(
6575
&self, doc_ref: &DocumentRef,
6676
) -> anyhow::Result<Option<CatalystSignedDocument>> {
67-
Ok(self.0.get(&doc_ref.id.uuid()).cloned())
77+
Ok(self.0.get(doc_ref).cloned())
6878
}
6979

7080
fn future_threshold(&self) -> Option<std::time::Duration> {

0 commit comments

Comments
 (0)