22
33mod builder;
44mod content;
5- mod error;
65mod metadata;
76mod signature;
7+ mod utils;
88
99use std:: {
1010 convert:: TryFrom ,
11- fmt:: { Display , Formatter } ,
11+ fmt:: { self , Display , Formatter } ,
1212 sync:: Arc ,
1313} ;
1414
15- use anyhow:: anyhow;
1615pub use builder:: Builder ;
16+ use catalyst_types:: problem_report:: ProblemReport ;
1717pub use content:: Content ;
1818use coset:: { CborSerializable , Header } ;
1919pub use metadata:: { DocumentRef , ExtraFields , Metadata , UuidV4 , UuidV7 } ;
2020pub use minicbor:: { decode, encode, Decode , Decoder , Encode } ;
2121pub use signature:: { KidUri , Signatures } ;
22+ use utils:: context:: SignDocContext ;
2223
2324/// Inner type that holds the Catalyst Signed Document with parsing errors.
2425#[ derive( Debug , Clone ) ]
@@ -64,7 +65,55 @@ impl From<InnerCatalystSignedDocument> for CatalystSignedDocument {
6465 }
6566}
6667
68+ /// Catalyst Signed Document Error
69+ #[ derive( Debug ) ]
70+ pub struct CatalystSignedDocError {
71+ /// List of errors during processing.
72+ report : ProblemReport ,
73+ /// Actual error.
74+ error : anyhow:: Error ,
75+ }
76+
77+ impl fmt:: Display for CatalystSignedDocError {
78+ fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
79+ let report_json = serde_json:: to_string ( & self . report )
80+ . unwrap_or_else ( |_| String :: from ( "Failed to serialize ProblemReport" ) ) ;
81+
82+ write ! (
83+ fmt,
84+ "CatalystSignedDocError {{ error: {}, report: {} }}" ,
85+ self . error, report_json
86+ )
87+ }
88+ }
89+
6790impl CatalystSignedDocument {
91+ /// Create a new Catalyst Signed Document from a COSE Sign document bytes.
92+ ///
93+ /// # Arguments
94+ ///
95+ /// * `cose_bytes` - COSE Sign document bytes.
96+ ///
97+ /// # Returns
98+ ///
99+ /// A new Catalyst Signed Document.
100+ ///
101+ /// # Errors
102+ ///
103+ /// Returns an error if the COSE Sign document bytes are invalid or decode error.
104+ pub fn new ( cose_bytes : & [ u8 ] ) -> anyhow:: Result < Self , CatalystSignedDocError > {
105+ let error_report = ProblemReport :: new ( "Catalyst Signed Document" ) ;
106+ let mut ctx = SignDocContext { error_report } ;
107+ let decoded: CatalystSignedDocument =
108+ minicbor:: decode_with ( cose_bytes, & mut ctx) . map_err ( |e| {
109+ CatalystSignedDocError {
110+ report : ctx. error_report ,
111+ error : e. into ( ) ,
112+ }
113+ } ) ?;
114+ Ok ( decoded)
115+ }
116+
68117 // A bunch of getters to access the contents, or reason through the document, such as.
69118
70119 /// Return Document Type `UUIDv4`.
@@ -104,8 +153,8 @@ impl CatalystSignedDocument {
104153 }
105154}
106155
107- impl Decode < ' _ , ( ) > for CatalystSignedDocument {
108- fn decode ( d : & mut Decoder < ' _ > , ( ) : & mut ( ) ) -> Result < Self , decode:: Error > {
156+ impl Decode < ' _ , SignDocContext > for CatalystSignedDocument {
157+ fn decode ( d : & mut Decoder < ' _ > , ctx : & mut SignDocContext ) -> Result < Self , decode:: Error > {
109158 let start = d. position ( ) ;
110159 d. skip ( ) ?;
111160 let end = d. position ( ) ;
@@ -115,40 +164,67 @@ impl Decode<'_, ()> for CatalystSignedDocument {
115164 . ok_or ( minicbor:: decode:: Error :: end_of_input ( ) ) ?;
116165
117166 let cose_sign = coset:: CoseSign :: from_slice ( cose_bytes) . map_err ( |e| {
167+ ctx. error_report . invalid_value (
168+ "COSE sign document bytes" ,
169+ & format ! ( "{:?}" , & cose_bytes) ,
170+ & format ! ( "Cannot convert bytes to CoseSign {e:?}" ) ,
171+ "Creating COSE Sign document" ,
172+ ) ;
118173 minicbor:: decode:: Error :: message ( format ! ( "Invalid COSE Sign document: {e}" ) )
119174 } ) ?;
120175
121- let mut errors = Vec :: new ( ) ;
122-
123- let metadata = Metadata :: try_from ( & cose_sign. protected ) . map_or_else (
124- |e| {
125- errors. extend ( e. 0 . 0 ) ;
126- None
127- } ,
128- Some ,
129- ) ;
130- let signatures = Signatures :: try_from ( & cose_sign. signatures ) . map_or_else (
131- |e| {
132- errors. extend ( e. 0 . 0 ) ;
133- None
134- } ,
135- Some ,
136- ) ;
176+ let metadata = Metadata :: from_protected_header ( & cose_sign. protected , & ctx. error_report )
177+ . map_or_else (
178+ |e| {
179+ ctx. error_report . conversion_error (
180+ "COSE sign protected header" ,
181+ & format ! ( "{:?}" , & cose_sign. protected) ,
182+ & format ! ( "Expected Metadata: {e:?}" ) ,
183+ "Converting COSE Sign protected header to Metadata" ,
184+ ) ;
185+ None
186+ } ,
187+ Some ,
188+ ) ;
189+ let signatures = Signatures :: from_cose_sig ( & cose_sign. signatures , & ctx. error_report )
190+ . map_or_else (
191+ |e| {
192+ ctx. error_report . conversion_error (
193+ "COSE sign signatures" ,
194+ & format ! ( "{:?}" , & cose_sign. signatures) ,
195+ & format ! ( "Expected Signatures {e:?}" ) ,
196+ "Converting COSE Sign signatures to Signatures" ,
197+ ) ;
198+ None
199+ } ,
200+ Some ,
201+ ) ;
137202
138203 if cose_sign. payload . is_none ( ) {
139- errors. push ( anyhow ! ( "Document Content is missing" ) ) ;
204+ ctx. error_report
205+ . missing_field ( "COSE Sign Payload" , "Missing document content (payload)" ) ;
140206 }
141207
142208 match ( cose_sign. payload , metadata, signatures) {
143209 ( Some ( payload) , Some ( metadata) , Some ( signatures) ) => {
144210 let content = Content :: from_encoded (
145- payload,
211+ payload. clone ( ) ,
146212 metadata. content_type ( ) ,
147213 metadata. content_encoding ( ) ,
148214 )
149215 . map_err ( |e| {
150- errors. push ( anyhow ! ( "Invalid Document Content: {e}" ) ) ;
151- minicbor:: decode:: Error :: message ( error:: Error :: from ( errors) )
216+ ctx. error_report . invalid_value (
217+ "Document Content" ,
218+ & format ! (
219+ "Given value {:?}, {:?}, {:?}" ,
220+ payload,
221+ metadata. content_type( ) ,
222+ metadata. content_encoding( )
223+ ) ,
224+ & format ! ( "{e:?}" ) ,
225+ "Creating document content" ,
226+ ) ;
227+ minicbor:: decode:: Error :: message ( "Failed to create Document Content" )
152228 } ) ?;
153229
154230 Ok ( InnerCatalystSignedDocument {
@@ -158,7 +234,11 @@ impl Decode<'_, ()> for CatalystSignedDocument {
158234 }
159235 . into ( ) )
160236 } ,
161- _ => Err ( minicbor:: decode:: Error :: message ( error:: Error :: from ( errors) ) ) ,
237+ _ => {
238+ Err ( minicbor:: decode:: Error :: message (
239+ "Failed to decode Catalyst Signed Document" ,
240+ ) )
241+ } ,
162242 }
163243 }
164244}
@@ -238,8 +318,8 @@ mod tests {
238318
239319 let mut bytes = Vec :: new ( ) ;
240320 minicbor:: encode_with ( doc, & mut bytes, & mut ( ) ) . unwrap ( ) ;
241- let decoded : CatalystSignedDocument =
242- minicbor :: decode_with ( bytes . as_slice ( ) , & mut ( ) ) . unwrap ( ) ;
321+
322+ let decoded = CatalystSignedDocument :: new ( & bytes ) . unwrap ( ) ;
243323
244324 assert_eq ! ( decoded. doc_type( ) , uuid_v4) ;
245325 assert_eq ! ( decoded. doc_id( ) , uuid_v7) ;
0 commit comments