Skip to content

Commit 196456a

Browse files
committed
refactor Metadata decoding
1 parent 40acd23 commit 196456a

File tree

5 files changed

+105
-121
lines changed

5 files changed

+105
-121
lines changed

rust/signed_doc/src/metadata/content_type.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@ pub enum ContentType {
1717
Json,
1818
}
1919

20-
impl Default for ContentType {
21-
fn default() -> Self {
22-
Self::Json
23-
}
24-
}
25-
2620
impl Display for ContentType {
2721
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
2822
match self {

rust/signed_doc/src/metadata/document_id.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ use super::UuidV7;
99
pub struct DocumentId(UuidV7);
1010

1111
impl DocumentId {
12-
/// Generates a zeroed out `UUIDv7` that can never be valid.
13-
pub fn invalid() -> Self {
14-
Self(UuidV7::invalid())
15-
}
16-
1712
/// Returns the `uuid::Uuid` type.
1813
#[must_use]
1914
pub fn uuid(&self) -> uuid::Uuid {

rust/signed_doc/src/metadata/document_type.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ use super::UuidV4;
99
pub struct DocumentType(UuidV4);
1010

1111
impl DocumentType {
12-
/// Generates a zeroed out `UUIDv4` that can never be valid.
13-
pub fn invalid() -> Self {
14-
Self(UuidV4::invalid())
15-
}
16-
1712
/// Returns the `uuid::Uuid` type.
1813
#[must_use]
1914
pub fn uuid(&self) -> uuid::Uuid {

rust/signed_doc/src/metadata/document_version.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@ use super::UuidV7;
88
pub struct DocumentVersion(UuidV7);
99

1010
impl DocumentVersion {
11-
/// Generates a zeroed out `UUIDv7` that can never be valid.
12-
pub fn invalid() -> Self {
13-
Self(UuidV7::invalid())
14-
}
15-
1611
/// Returns the `uuid::Uuid` type.
1712
#[must_use]
1813
pub fn uuid(&self) -> uuid::Uuid {

rust/signed_doc/src/metadata/mod.rs

Lines changed: 105 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ pub struct Metadata {
3535
/// Document Version `UUIDv7`.
3636
ver: DocumentVersion,
3737
/// Document Payload Content Type.
38-
#[serde(default, rename = "content-type")]
38+
#[serde(rename = "content-type")]
3939
content_type: ContentType,
4040
/// Document Payload Content Encoding.
41-
#[serde(default, rename = "content-encoding")]
41+
#[serde(rename = "content-encoding")]
4242
content_encoding: Option<ContentEncoding>,
4343
/// Additional Metadata Fields.
4444
#[serde(flatten)]
@@ -90,131 +90,136 @@ impl Display for Metadata {
9090
}
9191
}
9292

93-
impl Default for Metadata {
94-
fn default() -> Self {
95-
Self {
96-
doc_type: DocumentType::invalid(),
97-
id: DocumentId::invalid(),
98-
ver: DocumentVersion::invalid(),
99-
content_type: ContentType::default(),
100-
content_encoding: None,
101-
extra: AdditionalFields::default(),
102-
}
103-
}
104-
}
105-
10693
impl TryFrom<&coset::ProtectedHeader> for Metadata {
10794
type Error = crate::error::Error;
10895

10996
#[allow(clippy::too_many_lines)]
11097
fn try_from(protected: &coset::ProtectedHeader) -> Result<Self, Self::Error> {
111-
let mut metadata = Metadata::default();
11298
let mut errors = Vec::new();
11399

114-
match protected.header.content_type.as_ref() {
115-
Some(iana_content_type) => {
116-
match ContentType::try_from(iana_content_type) {
117-
Ok(content_type) => metadata.content_type = content_type,
118-
Err(e) => {
119-
errors.push(anyhow!("Invalid Document Content-Type: {e}"));
120-
},
121-
}
122-
},
123-
None => {
124-
errors.push(anyhow!(
125-
"COSE document protected header `content-type` field is missing"
126-
));
127-
},
100+
let content_type = protected.header.content_type.as_ref().and_then(|value| {
101+
ContentType::try_from(value).map_or_else(
102+
|e| {
103+
errors.push(anyhow!("Invalid Document Content-Type: {e}"));
104+
None
105+
},
106+
Some,
107+
)
108+
});
109+
110+
if content_type.is_none() {
111+
errors.push(anyhow!(
112+
"Invalid COSE protected header, missing Content-Type field"
113+
));
128114
}
129115

130-
if let Some(value) = cose_protected_header_find(
131-
protected,
132-
|key| matches!(key, coset::Label::Text(label) if label.eq_ignore_ascii_case(CONTENT_ENCODING_KEY)),
133-
) {
134-
match ContentEncoding::try_from(value) {
135-
Ok(encoding) => {
136-
metadata.content_encoding = Some(encoding);
137-
},
138-
Err(e) => {
139-
errors.push(anyhow!("Invalid Document Content Encoding: {e}"));
140-
},
141-
}
142-
} else {
116+
let content_encoding = cose_protected_header_find(protected, |key| matches!(key, coset::Label::Text(label) if label.eq_ignore_ascii_case(CONTENT_ENCODING_KEY)),
117+
)
118+
.and_then(|value| {
119+
ContentEncoding::try_from(value).map_or_else(
120+
|e| {
121+
errors.push(anyhow!("Invalid Document Content Encoding: {e}"));
122+
None
123+
},
124+
Some,
125+
)
126+
});
127+
128+
if content_encoding.is_none() {
143129
errors.push(anyhow!(
144-
"Invalid COSE document protected header '{CONTENT_ENCODING_KEY}' is missing"
130+
"Invalid COSE protected header, missing Content-Encoding field"
145131
));
146132
}
147133

148-
if let Some(doc_type) = cose_protected_header_find(protected, |key| {
134+
let doc_type = cose_protected_header_find(protected, |key| {
149135
key == &coset::Label::Text("type".to_string())
150-
}) {
151-
match UuidV4::try_from(doc_type) {
152-
Ok(doc_type_uuid) => {
153-
metadata.doc_type = doc_type_uuid.into();
154-
},
155-
Err(e) => {
136+
})
137+
.and_then(|value| {
138+
UuidV4::try_from(value).map_or_else(
139+
|e| {
156140
errors.push(anyhow!("Document `type` is invalid: {e}"));
141+
None
157142
},
158-
}
159-
} else {
143+
Some,
144+
)
145+
});
146+
147+
if doc_type.is_none() {
160148
errors.push(anyhow!(
161149
"Invalid COSE protected header, missing `type` field"
162150
));
163151
}
164152

165-
match cose_protected_header_find(protected, |key| {
153+
let id = cose_protected_header_find(protected, |key| {
166154
key == &coset::Label::Text("id".to_string())
167-
}) {
168-
Some(doc_id) => {
169-
match UuidV7::try_from(doc_id) {
170-
Ok(doc_id_uuid) => {
171-
metadata.id = doc_id_uuid.into();
172-
},
173-
Err(e) => {
174-
errors.push(anyhow!("Document `id` is invalid: {e}"));
175-
},
176-
}
177-
},
178-
None => errors.push(anyhow!("Invalid COSE protected header, missing `id` field")),
179-
};
155+
})
156+
.and_then(|value| {
157+
UuidV7::try_from(value).map_or_else(
158+
|e| {
159+
errors.push(anyhow!("Document `id` is invalid: {e}"));
160+
None
161+
},
162+
Some,
163+
)
164+
});
180165

181-
match cose_protected_header_find(protected, |key| {
166+
if id.is_none() {
167+
errors.push(anyhow!("Invalid COSE protected header, missing `id` field"));
168+
}
169+
170+
let ver = cose_protected_header_find(protected, |key| {
182171
key == &coset::Label::Text("ver".to_string())
183-
}) {
184-
Some(doc_ver) => {
185-
match UuidV7::try_from(doc_ver) {
186-
Ok(doc_ver_uuid) => {
187-
if doc_ver_uuid.uuid() < metadata.id.uuid() {
188-
errors.push(anyhow!(
189-
"Document Version {doc_ver_uuid} cannot be smaller than Document ID {}", metadata.id
190-
));
191-
} else {
192-
metadata.ver = doc_ver_uuid.into();
193-
}
194-
},
195-
Err(e) => {
196-
errors.push(anyhow!(
197-
"Invalid COSE protected header `ver` field, err: {e}"
198-
));
199-
},
200-
}
201-
},
202-
None => {
203-
errors.push(anyhow!(
204-
"Invalid COSE protected header, missing `ver` field"
205-
));
206-
},
172+
})
173+
.and_then(|value| {
174+
UuidV7::try_from(value).map_or_else(
175+
|e| {
176+
errors.push(anyhow!("Document `ver` is invalid: {e}"));
177+
None
178+
},
179+
Some,
180+
)
181+
});
182+
183+
if ver.is_none() {
184+
errors.push(anyhow!(
185+
"Invalid COSE protected header, missing `ver` field"
186+
));
207187
}
208188

209-
match AdditionalFields::try_from(protected) {
210-
Ok(extra) => metadata.extra = extra,
211-
Err(e) => errors.extend(e),
212-
};
189+
let extra = AdditionalFields::try_from(protected).map_or_else(
190+
|e| {
191+
errors.extend(e);
192+
None
193+
},
194+
Some,
195+
);
196+
197+
match (content_type, content_encoding, id, doc_type, ver, extra) {
198+
(
199+
Some(content_type),
200+
content_encoding,
201+
Some(id),
202+
Some(doc_type),
203+
Some(ver),
204+
Some(extra),
205+
) => {
206+
if ver < id {
207+
errors.push(anyhow!(
208+
"Document Version {ver} cannot be smaller than Document ID {id}",
209+
));
210+
return Err(crate::error::Error(errors));
211+
}
213212

214-
if errors.is_empty() {
215-
Ok(metadata)
216-
} else {
217-
Err(errors.into())
213+
Ok(Self {
214+
doc_type: doc_type.into(),
215+
id: id.into(),
216+
ver: ver.into(),
217+
content_encoding,
218+
content_type,
219+
extra,
220+
})
221+
},
222+
_ => Err(crate::error::Error(errors)),
218223
}
219224
}
220225
}

0 commit comments

Comments
 (0)