Skip to content

Commit 782c7b9

Browse files
committed
move additional_fields into another mod
1 parent bb0e29a commit 782c7b9

File tree

3 files changed

+125
-100
lines changed

3 files changed

+125
-100
lines changed

rust/signed_doc/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ impl Display for CatalystSignedDocument {
5959
}
6060
}
6161

62-
impl TryFrom<Vec<u8>> for CatalystSignedDocument {
62+
impl TryFrom<&[u8]> for CatalystSignedDocument {
6363
type Error = anyhow::Error;
6464

65-
fn try_from(cose_bytes: Vec<u8>) -> Result<Self, Self::Error> {
65+
fn try_from(cose_bytes: &[u8]) -> Result<Self, Self::Error> {
6666
// Try reading as a tagged COSE SIGN, otherwise try reading as untagged.
67-
let cose_sign = coset::CoseSign::from_slice(&cose_bytes)
67+
let cose_sign = coset::CoseSign::from_slice(cose_bytes)
6868
.map_err(|e| anyhow::anyhow!("Invalid COSE Sign document: {e}"))?;
6969

7070
let mut content_errors = Vec::new();
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//! Catalyst Signed Document Additional Fields.
2+
3+
use anyhow::anyhow;
4+
5+
use super::{cose_protected_header_find, DocumentRef};
6+
7+
/// Additional Metadata Fields.
8+
///
9+
/// These values are extracted from the COSE Sign protected header labels.
10+
#[derive(Default, Debug, serde::Deserialize)]
11+
pub(super) struct AdditionalFields {
12+
/// Reference to the latest document.
13+
#[serde(rename = "ref")]
14+
pub(super) doc_ref: Option<DocumentRef>,
15+
/// Reference to the document template.
16+
pub(super) template: Option<DocumentRef>,
17+
/// Reference to the document reply.
18+
pub(super) reply: Option<DocumentRef>,
19+
/// Reference to the document section.
20+
pub(super) section: Option<String>,
21+
}
22+
23+
impl TryFrom<&coset::ProtectedHeader> for AdditionalFields {
24+
type Error = Vec<anyhow::Error>;
25+
26+
fn try_from(protected: &coset::ProtectedHeader) -> Result<Self, Self::Error> {
27+
let mut extra = AdditionalFields::default();
28+
let mut errors = Vec::new();
29+
30+
if let Some(cbor_doc_ref) = cose_protected_header_find(protected, |key| {
31+
key == &coset::Label::Text("ref".to_string())
32+
}) {
33+
match DocumentRef::try_from(cbor_doc_ref) {
34+
Ok(doc_ref) => {
35+
extra.doc_ref = Some(doc_ref);
36+
},
37+
Err(e) => {
38+
errors.push(anyhow!(
39+
"Invalid COSE protected header `ref` field, err: {e}"
40+
));
41+
},
42+
}
43+
}
44+
45+
if let Some(cbor_doc_template) = cose_protected_header_find(protected, |key| {
46+
key == &coset::Label::Text("template".to_string())
47+
}) {
48+
match DocumentRef::try_from(cbor_doc_template) {
49+
Ok(doc_template) => {
50+
extra.template = Some(doc_template);
51+
},
52+
Err(e) => {
53+
errors.push(anyhow!(
54+
"Invalid COSE protected header `template` field, err: {e}"
55+
));
56+
},
57+
}
58+
}
59+
60+
if let Some(cbor_doc_reply) = cose_protected_header_find(protected, |key| {
61+
key == &coset::Label::Text("reply".to_string())
62+
}) {
63+
match DocumentRef::try_from(cbor_doc_reply) {
64+
Ok(doc_reply) => {
65+
extra.reply = Some(doc_reply);
66+
},
67+
Err(e) => {
68+
errors.push(anyhow!(
69+
"Invalid COSE protected header `reply` field, err: {e}"
70+
));
71+
},
72+
}
73+
}
74+
75+
if let Some(cbor_doc_section) = cose_protected_header_find(protected, |key| {
76+
key == &coset::Label::Text("section".to_string())
77+
}) {
78+
match cbor_doc_section.clone().into_text() {
79+
Ok(doc_section) => {
80+
extra.section = Some(doc_section);
81+
},
82+
Err(e) => {
83+
errors.push(anyhow!(
84+
"Invalid COSE protected header `section` field, err: {e:?}"
85+
));
86+
},
87+
}
88+
}
89+
90+
if errors.is_empty() {
91+
Ok(extra)
92+
} else {
93+
Err(errors)
94+
}
95+
}
96+
}

rust/signed_doc/src/metadata/mod.rs

Lines changed: 26 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
//! Catalyst Signed Document Metadata.
22
use std::fmt::{Display, Formatter};
33

4+
mod additional_fields;
45
mod content_encoding;
56
mod content_type;
67
mod document_id;
78
mod document_ref;
89
mod document_type;
910
mod document_version;
1011

12+
use additional_fields::AdditionalFields;
13+
use anyhow::anyhow;
1114
pub use catalyst_types::uuid::{V4 as UuidV4, V7 as UuidV7};
1215
pub use content_encoding::ContentEncoding;
1316
pub use content_type::ContentType;
@@ -45,24 +48,6 @@ pub struct Metadata {
4548
content_errors: Vec<String>,
4649
}
4750

48-
/// Additional Metadata Fields.
49-
///
50-
/// These values are extracted from the COSE Sign protected header labels.
51-
#[derive(Default, Debug, serde::Deserialize)]
52-
struct AdditionalFields {
53-
/// Reference to the latest document.
54-
#[serde(rename = "ref")]
55-
doc_ref: Option<DocumentRef>,
56-
/// Hash of the referenced document bytes.
57-
ref_hash: Option<Vec<u8>>,
58-
/// Reference to the document template.
59-
template: Option<DocumentRef>,
60-
/// Reference to the document reply.
61-
reply: Option<DocumentRef>,
62-
/// Reference to the document section.
63-
section: Option<String>,
64-
}
65-
6651
impl Metadata {
6752
/// Are there any validation errors (as opposed to structural errors).
6853
#[must_use]
@@ -100,12 +85,6 @@ impl Metadata {
10085
self.content_encoding
10186
}
10287

103-
/// Return Last Document Reference `Option<Vec<u8>>`.
104-
#[must_use]
105-
pub fn doc_ref_hash(&self) -> Option<Vec<u8>> {
106-
self.extra.ref_hash.clone()
107-
}
108-
10988
/// Return Last Document Reference `Option<DocumentRef>`.
11089
#[must_use]
11190
pub fn doc_ref(&self) -> Option<DocumentRef> {
@@ -165,7 +144,6 @@ impl Default for Metadata {
165144
}
166145

167146
impl From<&coset::ProtectedHeader> for Metadata {
168-
#[allow(clippy::too_many_lines)]
169147
fn from(protected: &coset::ProtectedHeader) -> Self {
170148
let mut metadata = Metadata::default();
171149
let mut errors = Vec::new();
@@ -175,14 +153,14 @@ impl From<&coset::ProtectedHeader> for Metadata {
175153
match ContentType::try_from(iana_content_type) {
176154
Ok(content_type) => metadata.content_type = content_type,
177155
Err(e) => {
178-
errors.push(format!("Invalid Document Content-Type: {e}"));
156+
errors.push(anyhow!("Invalid Document Content-Type: {e}"));
179157
},
180158
}
181159
},
182160
None => {
183-
errors.push(
184-
"COSE document protected header `content-type` field is missing".to_string(),
185-
);
161+
errors.push(anyhow!(
162+
"COSE document protected header `content-type` field is missing"
163+
));
186164
},
187165
}
188166

@@ -195,11 +173,11 @@ impl From<&coset::ProtectedHeader> for Metadata {
195173
metadata.content_encoding = Some(encoding);
196174
},
197175
Err(e) => {
198-
errors.push(format!("Invalid Document Content Encoding: {e}"));
176+
errors.push(anyhow!("Invalid Document Content Encoding: {e}"));
199177
},
200178
}
201179
} else {
202-
errors.push(format!(
180+
errors.push(anyhow!(
203181
"Invalid COSE document protected header '{CONTENT_ENCODING_KEY}' is missing"
204182
));
205183
}
@@ -212,11 +190,13 @@ impl From<&coset::ProtectedHeader> for Metadata {
212190
metadata.doc_type = doc_type_uuid.into();
213191
},
214192
Err(e) => {
215-
errors.push(format!("Document `type` is invalid: {e}"));
193+
errors.push(anyhow!("Document `type` is invalid: {e}"));
216194
},
217195
}
218196
} else {
219-
errors.push("Invalid COSE protected header, missing `type` field".to_string());
197+
errors.push(anyhow!(
198+
"Invalid COSE protected header, missing `type` field"
199+
));
220200
}
221201

222202
match cose_protected_header_find(protected, |key| {
@@ -228,11 +208,11 @@ impl From<&coset::ProtectedHeader> for Metadata {
228208
metadata.id = doc_id_uuid.into();
229209
},
230210
Err(e) => {
231-
errors.push(format!("Document `id` is invalid: {e}"));
211+
errors.push(anyhow!("Document `id` is invalid: {e}"));
232212
},
233213
}
234214
},
235-
None => errors.push("Invalid COSE protected header, missing `id` field".to_string()),
215+
None => errors.push(anyhow!("Invalid COSE protected header, missing `id` field")),
236216
};
237217

238218
match cose_protected_header_find(protected, |key| {
@@ -242,83 +222,32 @@ impl From<&coset::ProtectedHeader> for Metadata {
242222
match UuidV7::try_from(doc_ver) {
243223
Ok(doc_ver_uuid) => {
244224
if doc_ver_uuid.uuid() < metadata.id.uuid() {
245-
errors.push(format!(
225+
errors.push(anyhow!(
246226
"Document Version {doc_ver_uuid} cannot be smaller than Document ID {}", metadata.id
247227
));
248228
} else {
249229
metadata.ver = doc_ver_uuid.into();
250230
}
251231
},
252232
Err(e) => {
253-
errors.push(format!(
233+
errors.push(anyhow!(
254234
"Invalid COSE protected header `ver` field, err: {e}"
255235
));
256236
},
257237
}
258238
},
259-
None => errors.push("Invalid COSE protected header, missing `ver` field".to_string()),
260-
}
261-
262-
if let Some(cbor_doc_ref) = cose_protected_header_find(protected, |key| {
263-
key == &coset::Label::Text("ref".to_string())
264-
}) {
265-
match DocumentRef::try_from(cbor_doc_ref) {
266-
Ok(doc_ref) => {
267-
metadata.extra.doc_ref = Some(doc_ref);
268-
},
269-
Err(e) => {
270-
errors.push(format!(
271-
"Invalid COSE protected header `ref` field, err: {e}"
272-
));
273-
},
274-
}
275-
}
276-
277-
if let Some(cbor_doc_template) = cose_protected_header_find(protected, |key| {
278-
key == &coset::Label::Text("template".to_string())
279-
}) {
280-
match DocumentRef::try_from(cbor_doc_template) {
281-
Ok(doc_template) => {
282-
metadata.extra.template = Some(doc_template);
283-
},
284-
Err(e) => {
285-
errors.push(format!(
286-
"Invalid COSE protected header `template` field, err: {e}"
287-
));
288-
},
289-
}
239+
None => {
240+
errors.push(anyhow!(
241+
"Invalid COSE protected header, missing `ver` field"
242+
));
243+
},
290244
}
291245

292-
if let Some(cbor_doc_reply) = cose_protected_header_find(protected, |key| {
293-
key == &coset::Label::Text("reply".to_string())
294-
}) {
295-
match DocumentRef::try_from(cbor_doc_reply) {
296-
Ok(doc_reply) => {
297-
metadata.extra.reply = Some(doc_reply);
298-
},
299-
Err(e) => {
300-
errors.push(format!(
301-
"Invalid COSE protected header `reply` field, err: {e}"
302-
));
303-
},
304-
}
305-
}
246+
match AdditionalFields::try_from(protected) {
247+
Ok(extra) => metadata.extra = extra,
248+
Err(e) => errors.extend(e),
249+
};
306250

307-
if let Some(cbor_doc_section) = cose_protected_header_find(protected, |key| {
308-
key == &coset::Label::Text("section".to_string())
309-
}) {
310-
match cbor_doc_section.clone().into_text() {
311-
Ok(doc_section) => {
312-
metadata.extra.section = Some(doc_section);
313-
},
314-
Err(e) => {
315-
errors.push(format!(
316-
"Invalid COSE protected header `section` field, err: {e:?}"
317-
));
318-
},
319-
}
320-
}
321-
metadata.content_errors = errors;
322251
metadata
323252
}
324253
}

0 commit comments

Comments
 (0)