• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! This module defines a helper for parsing fields in a CBOR map.
2 
3 use coset::{cbor::value::Value, AsCborValue, CoseEncrypt, CoseError, CoseMac0, CoseSign1};
4 use thiserror::Error;
5 
6 #[derive(Error, Debug)]
7 pub enum FieldValueError {
8     #[error("expected a value for field {0}, but none was found")]
9     Missing(&'static str),
10     #[error("expected bytes for field {0}, but found `{1:?}`")]
11     NotBytes(&'static str, Value),
12     #[error("expected string for field {0}, but found `{1:?}`")]
13     NotString(&'static str, Value),
14     #[error("expected null for field {0}, but found `{1:?}`")]
15     NotNull(&'static str, Value),
16     #[error("expected u32 for field {0}, but found `{1:?}`")]
17     NotU32(&'static str, Value),
18     #[error("expected i64 for field {0}, but found `{1:?}`")]
19     NotI64(&'static str, Value),
20     #[error("expected u64 for field {0}, but found `{1:?}`")]
21     NotU64(&'static str, Value),
22     #[error("expected map for field {0}, but found `{1:?}`")]
23     NotMap(&'static str, Value),
24     #[error("expected array for field {0}, but found `{1:?}`")]
25     NotArray(&'static str, Value),
26     #[error("unable to parse field {0} as COSE_Sign1: `{1:?}`")]
27     CoseSign1ParseError(&'static str, CoseError),
28     #[error("unable to parse field {0} as COSE_Encrypt: `{1:?}`")]
29     CoseEncryptParseError(&'static str, CoseError),
30     #[error("unable to parse field {0} as COSE_Mac0: `{1:?}`")]
31     CoseMac0ParseError(&'static str, CoseError),
32     #[error("field {0} may be set only once; encountered multiple values: `{1:?}`, `{2:?}`")]
33     DuplicateField(&'static str, Value, Value),
34 }
35 
36 pub(super) struct FieldValue {
37     name: &'static str,
38     value: Option<Value>,
39 }
40 
41 impl FieldValue {
new(name: &'static str) -> Self42     pub fn new(name: &'static str) -> Self {
43         Self { name, value: None }
44     }
45 
from_value(name: &'static str, value: Value) -> Self46     pub fn from_value(name: &'static str, value: Value) -> Self {
47         Self { name, value: Some(value) }
48     }
49 
from_optional_value(name: &'static str, value: Option<Value>) -> Self50     pub fn from_optional_value(name: &'static str, value: Option<Value>) -> Self {
51         Self { name, value }
52     }
53 
set_once(&mut self, value: Value) -> Result<(), FieldValueError>54     pub fn set_once(&mut self, value: Value) -> Result<(), FieldValueError> {
55         match &self.value {
56             None => {
57                 self.value = Some(value);
58                 Ok(())
59             }
60             Some(previous) => {
61                 Err(FieldValueError::DuplicateField(self.name, previous.clone(), value))
62             }
63         }
64     }
65 
is_bytes(&self) -> bool66     pub fn is_bytes(&self) -> bool {
67         self.value.as_ref().map_or(false, |v| v.is_bytes())
68     }
69 
into_optional_bytes(self) -> Result<Option<Vec<u8>>, FieldValueError>70     pub fn into_optional_bytes(self) -> Result<Option<Vec<u8>>, FieldValueError> {
71         self.value
72             .map(|v| match v {
73                 Value::Bytes(b) => Ok(b),
74                 _ => Err(FieldValueError::NotBytes(self.name, v)),
75             })
76             .transpose()
77     }
78 
into_bytes(self) -> Result<Vec<u8>, FieldValueError>79     pub fn into_bytes(self) -> Result<Vec<u8>, FieldValueError> {
80         require_present(self.name, self.into_optional_bytes())
81     }
82 
into_optional_string(self) -> Result<Option<String>, FieldValueError>83     pub fn into_optional_string(self) -> Result<Option<String>, FieldValueError> {
84         self.value
85             .map(|v| match v {
86                 Value::Text(s) => Ok(s),
87                 _ => Err(FieldValueError::NotString(self.name, v)),
88             })
89             .transpose()
90     }
91 
into_string(self) -> Result<String, FieldValueError>92     pub fn into_string(self) -> Result<String, FieldValueError> {
93         require_present(self.name, self.into_optional_string())
94     }
95 
into_cose_encrypt(self) -> Result<CoseEncrypt, FieldValueError>96     pub fn into_cose_encrypt(self) -> Result<CoseEncrypt, FieldValueError> {
97         require_present(self.name, self.into_optional_cose_encrypt())
98     }
99 
into_optional_cose_encrypt(self) -> Result<Option<CoseEncrypt>, FieldValueError>100     pub fn into_optional_cose_encrypt(self) -> Result<Option<CoseEncrypt>, FieldValueError> {
101         self.value
102             .map(|v| match v {
103                 Value::Array(_) => CoseEncrypt::from_cbor_value(v)
104                     .map_err(|e| FieldValueError::CoseEncryptParseError(self.name, e)),
105                 _ => Err(FieldValueError::NotArray(self.name, v)),
106             })
107             .transpose()
108     }
109 
into_cose_mac0(self) -> Result<CoseMac0, FieldValueError>110     pub fn into_cose_mac0(self) -> Result<CoseMac0, FieldValueError> {
111         require_present(self.name, self.into_optional_cose_mac0())
112     }
113 
into_optional_cose_mac0(self) -> Result<Option<CoseMac0>, FieldValueError>114     pub fn into_optional_cose_mac0(self) -> Result<Option<CoseMac0>, FieldValueError> {
115         self.value
116             .map(|v| match v {
117                 Value::Array(_) => CoseMac0::from_cbor_value(v)
118                     .map_err(|e| FieldValueError::CoseMac0ParseError(self.name, e)),
119                 _ => Err(FieldValueError::NotArray(self.name, v)),
120             })
121             .transpose()
122     }
123 
into_cose_sign1(self) -> Result<CoseSign1, FieldValueError>124     pub fn into_cose_sign1(self) -> Result<CoseSign1, FieldValueError> {
125         require_present(self.name, self.into_optional_cose_sign1())
126     }
127 
into_optional_cose_sign1(self) -> Result<Option<CoseSign1>, FieldValueError>128     pub fn into_optional_cose_sign1(self) -> Result<Option<CoseSign1>, FieldValueError> {
129         self.value
130             .map(|v| match v {
131                 Value::Array(_) => CoseSign1::from_cbor_value(v)
132                     .map_err(|e| FieldValueError::CoseSign1ParseError(self.name, e)),
133                 _ => Err(FieldValueError::NotArray(self.name, v)),
134             })
135             .transpose()
136     }
137 
into_array(self) -> Result<Vec<Value>, FieldValueError>138     pub fn into_array(self) -> Result<Vec<Value>, FieldValueError> {
139         require_present(self.name, self.into_optional_array())
140     }
141 
into_optional_array(self) -> Result<Option<Vec<Value>>, FieldValueError>142     pub fn into_optional_array(self) -> Result<Option<Vec<Value>>, FieldValueError> {
143         self.value
144             .map(|v| match v {
145                 Value::Array(v) => Ok(v),
146                 _ => Err(FieldValueError::NotArray(self.name, v)),
147             })
148             .transpose()
149     }
150 
into_map(self) -> Result<Vec<(Value, Value)>, FieldValueError>151     pub fn into_map(self) -> Result<Vec<(Value, Value)>, FieldValueError> {
152         require_present(self.name, self.into_optional_map())
153     }
154 
into_optional_map(self) -> Result<Option<Vec<(Value, Value)>>, FieldValueError>155     pub fn into_optional_map(self) -> Result<Option<Vec<(Value, Value)>>, FieldValueError> {
156         self.value
157             .map(|v| match v {
158                 Value::Map(v) => Ok(v),
159                 _ => Err(FieldValueError::NotMap(self.name, v)),
160             })
161             .transpose()
162     }
163 
is_null(&self) -> Result<bool, FieldValueError>164     pub fn is_null(&self) -> Result<bool, FieldValueError> {
165         // If there's no value, return false; if there is a null value, return true; anything else
166         // is an error.
167         self.value
168             .as_ref()
169             .map(|v| match *v {
170                 Value::Null => Ok(true),
171                 _ => Err(FieldValueError::NotNull(self.name, v.clone())),
172             })
173             .unwrap_or(Ok(false))
174     }
175 
is_integer(&self) -> bool176     pub fn is_integer(&self) -> bool {
177         self.value.as_ref().map_or(false, |v| v.is_integer())
178     }
179 
into_u32(self) -> Result<u32, FieldValueError>180     pub fn into_u32(self) -> Result<u32, FieldValueError> {
181         require_present(self.name, self.into_optional_u32())
182     }
183 
into_optional_u32(self) -> Result<Option<u32>, FieldValueError>184     pub fn into_optional_u32(self) -> Result<Option<u32>, FieldValueError> {
185         self.value
186             .map(|v| {
187                 let value =
188                     if let Value::Integer(i) = v { i128::from(i).try_into().ok() } else { None };
189                 value.ok_or(FieldValueError::NotU32(self.name, v))
190             })
191             .transpose()
192     }
193 
into_optional_i64(self) -> Result<Option<i64>, FieldValueError>194     pub fn into_optional_i64(self) -> Result<Option<i64>, FieldValueError> {
195         self.value
196             .map(|v| {
197                 let value =
198                     if let Value::Integer(i) = v { i128::from(i).try_into().ok() } else { None };
199                 value.ok_or(FieldValueError::NotI64(self.name, v))
200             })
201             .transpose()
202     }
203 
into_u64(self) -> Result<u64, FieldValueError>204     pub fn into_u64(self) -> Result<u64, FieldValueError> {
205         require_present(self.name, self.into_optional_u64())
206     }
207 
into_optional_u64(self) -> Result<Option<u64>, FieldValueError>208     pub fn into_optional_u64(self) -> Result<Option<u64>, FieldValueError> {
209         self.value
210             .map(|v| {
211                 let value =
212                     if let Value::Integer(i) = v { i128::from(i).try_into().ok() } else { None };
213                 value.ok_or(FieldValueError::NotU64(self.name, v))
214             })
215             .transpose()
216     }
217 }
218 
require_present<T>( name: &'static str, value: Result<Option<T>, FieldValueError>, ) -> Result<T, FieldValueError>219 fn require_present<T>(
220     name: &'static str,
221     value: Result<Option<T>, FieldValueError>,
222 ) -> Result<T, FieldValueError> {
223     value.and_then(|opt| opt.ok_or(FieldValueError::Missing(name)))
224 }
225