Skip to main content

ic_response_verification/
error.rs

1//! Various error types for response verification failure scenarios
2
3#[cfg(all(target_arch = "wasm32", feature = "js"))]
4use wasm_bindgen::prelude::*;
5
6use crate::cel;
7
8/// Convenience type that represents the Result of performing response verification
9pub type ResponseVerificationResult<T = ()> = Result<T, ResponseVerificationError>;
10
11/// The primary container for response verification errors
12#[derive(thiserror::Error, Debug, Clone)]
13pub enum ResponseVerificationError {
14    /// Error converting UTF-8 string
15    #[error(r#"IO error: "{0}""#)]
16    IoError(String),
17
18    /// An unsupported verification version was requested
19    #[error(r#"The requested verification version {requested_version:?} is not supported, the current supported range is {min_supported_version:?}-{max_supported_version:?}"#)]
20    UnsupportedVerificationVersion {
21        /// The minimum supported verification version
22        min_supported_version: u8,
23        /// The maximum supported verification version
24        max_supported_version: u8,
25        /// The actual requested verification version
26        requested_version: u8,
27    },
28
29    /// Mismatch between the minimum requested version and the actual requested version
30    #[error(r#"The requested verification version {requested_version:?} is lower than the minimum requested version {min_requested_verification_version:?}"#)]
31    RequestedVerificationVersionMismatch {
32        /// The minimum version that will be requested
33        min_requested_verification_version: u8,
34        /// The actual requested version
35        requested_version: u8,
36    },
37
38    /// Error parsing CEL expression
39    #[error("Cel parser error")]
40    CelError(#[from] cel::CelParserError),
41
42    /// Error decoding base64
43    #[error("Base64 decoding error")]
44    Base64DecodingError(#[from] base64::DecodeError),
45
46    /// Error parsing int
47    #[error("Error parsing int")]
48    ParseIntError(#[from] std::num::ParseIntError),
49
50    /// The tree has different root hash from the expected value in the certified variables
51    #[error("Invalid tree root hash")]
52    InvalidTreeRootHash,
53
54    /// The certificate provided by the "IC-Certificate" response header is missing the
55    /// certified data witness for the canister
56    #[error(r#"The certificate provided by the "IC-Certificate" response header is missing the certified data witness for the canister with ID {canister_id}"#)]
57    CertificateMissingCertifiedData {
58        /// The ID of the canister that returned the response
59        canister_id: String,
60    },
61
62    /// The expression path provided by the "IC-Certificate" response header
63    /// has an unexpected suffix and should end with "<$>" or "<*>"
64    #[error(r#"The expression path provided by the "IC-Certificate" response header ({provided_expr_path:?}) has an unexpected prefix and should start with "http_expr"#)]
65    UnexpectedExpressionPathPrefix {
66        /// The invalid expression path
67        provided_expr_path: Vec<String>,
68    },
69
70    /// The expression path provided by the "IC-Certificate" response header
71    /// has an unexpected suffix and should end with "<$>" or "<*>"
72    #[error(r#"The expression path provided by the "IC-Certificate" response header ({provided_expr_path:?}) has an unexpected suffix and should end with "<$>" or "<*>"#)]
73    UnexpectedExpressionPathSuffix {
74        /// The invalid expression path
75        provided_expr_path: Vec<String>,
76    },
77
78    /// The exact expression path provided by the "IC-Certificate" response header
79    /// was not found in the tree
80    #[error(r#"The exact expression path provided by the "IC-Certificate" response header ({provided_expr_path:?}) was not found in the tree"#)]
81    ExactExpressionPathNotFoundInTree {
82        /// The missing expression path
83        provided_expr_path: Vec<String>,
84    },
85
86    /// The exact expression path provided by the "IC-Certificate" response header
87    /// is not valid for the request path
88    #[error(r#"The exact expression path provided by the "IC-Certificate" response header ({provided_expr_path:?}) is not valid for the request path ({request_path:?})"#)]
89    ExactExpressionPathMismatch {
90        /// The expression path provided by the "IC-Certificate" response header
91        provided_expr_path: Vec<String>,
92        /// The request path
93        request_path: String,
94    },
95
96    /// A wildcard expression path was provided by the "IC-Certificate" response header
97    /// but a potential exact expression path is valid for the request path and might
98    /// exist in the tree
99    #[error(r#"A wildcard expression path was provided by the "IC-Certificate" response header ({provided_expr_path:?}), but a potential exact expression path ({potential_expr_path:?}) is valid for the request path ({request_path:?}) and might exist in the tree"#)]
100    ExactExpressionPathMightExistInTree {
101        /// The expression path provided by the "IC-Certificate" response header
102        provided_expr_path: Vec<String>,
103        /// The expected expression path
104        potential_expr_path: Vec<String>,
105        /// The request path
106        request_path: String,
107    },
108
109    /// The wildcard expression path provided by the "IC-Certificate" response
110    /// was not found in the tree
111    #[error(r#"The wildcard expression path provided by the "IC-Certificate" response header ({provided_expr_path:?}) is valid for the request path ({request_path:?}), but was not found in the tree"#)]
112    WildcardExpressionPathNotFoundInTree {
113        /// The expression path provided by the "IC-Certificate" response header
114        provided_expr_path: Vec<String>,
115        /// The request path
116        request_path: String,
117    },
118
119    /// The wildcard expression path provided by the "IC-Certificate" response
120    /// header is not valid for the request path
121    #[error(r#"The wildcard expression path provided by the "IC-Certificate" response header ({provided_expr_path:?}) is not valid for the request path ({request_path:?})"#)]
122    WildcardExpressionPathMismatch {
123        /// The expression path provided by the "IC-Certificate" response header
124        provided_expr_path: Vec<String>,
125        /// The request path
126        request_path: String,
127    },
128
129    /// A more specific wildcard expression path than the one provided by the
130    /// "IC-Certificate" response header that is valid for the request path might
131    /// exist in the tree
132    #[error(r#"A more specific wildcard expression path ({more_specific_expr_path:?}) than the one provided by the "IC-Certificate" response header ({provided_expr_path:?}) that is valid for the request path ({request_path:?}) might exist in the tree"#)]
133    MoreSpecificWildcardExpressionMightExistInTree {
134        /// The expression path provided by the "IC-Certificate" response header
135        provided_expr_path: Vec<String>,
136        /// The more specific expression path that might exist in the tree
137        more_specific_expr_path: Vec<String>,
138        /// The request path
139        request_path: String,
140    },
141
142    /// The hash of the CEL expression provided by the "IC-Certificate-Expression"
143    /// response header does not exist at the expression path provided by the
144    /// "IC-Certificate" response header
145    #[error(r#"The hash of the CEL expression provided by the "IC-Certificate-Expression" response header does not exist at the path provided by the "IC-Certificate" response header ({provided_expr_path:?})"#)]
146    InvalidExpressionHash {
147        /// The expression path provided by the "IC-Certificate" response header
148        provided_expr_path: Vec<String>,
149    },
150
151    /// The hash of the request and response was not found in the tree at the
152    /// expression path provided by the "IC-Certificate" response header
153    #[error(r#"The hash of the request and response was not found in the tree at the expression path provided by the "IC-Certificate" response header ({provided_expr_path:?})"#)]
154    InvalidRequestAndResponseHashes {
155        /// The expression path provided by the "IC-Certificate" response header
156        provided_expr_path: Vec<String>,
157    },
158
159    /// The required empty leaf node was not found in the tree at the expression
160    /// path provided by the "IC-Certificate" response header
161    #[error(r#"The required empty leaf node was not found in the tree at the expression path provided by the "IC-Certificate" response header ({provided_expr_path:?})"#)]
162    MissingLeafNode {
163        /// The expression path provided by the "IC-Certificate" response header
164        provided_expr_path: Vec<String>,
165    },
166
167    /// The response body was a mismatch from the expected values in the tree
168    #[error("Invalid response body")]
169    InvalidResponseBody,
170
171    /// The certificate was missing from the certification header
172    #[error("Certificate not found")]
173    HeaderMissingCertificate,
174
175    /// The tree was missing from the certification header
176    #[error("Tree not found")]
177    HeaderMissingTree,
178
179    /// The certificate expression path was missing from the certification header
180    #[error("Certificate expression path not found")]
181    HeaderMissingCertificateExpressionPath,
182
183    /// The certificate expression was missing from the response headers
184    #[error("Certificate expression not found")]
185    HeaderMissingCertificateExpression,
186
187    /// The certification values could not be found in the response headers
188    #[error("Certification values not found")]
189    HeaderMissingCertification,
190
191    /// Failed to decode CBOR
192    #[error("CBOR decoding failed")]
193    CborDecodingFailed(#[from] ic_cbor::CborError),
194
195    /// Failed to verify certificate
196    #[error("Certificate verification failed")]
197    CertificateVerificationFailed(
198        #[from] ic_certificate_verification::CertificateVerificationError,
199    ),
200
201    /// HTTP Certification error
202    #[error(r#"HTTP Certification error: "{0}""#)]
203    HttpCertificationError(#[from] ic_http_certification::HttpCertificationError),
204}
205
206impl From<std::io::Error> for ResponseVerificationError {
207    fn from(error: std::io::Error) -> Self {
208        ResponseVerificationError::IoError(error.to_string())
209    }
210}
211
212/// JS Representation of the ResponseVerificationError code
213#[cfg(all(target_arch = "wasm32", feature = "js"))]
214#[wasm_bindgen(js_name = ResponseVerificationErrorCode)]
215#[derive(Debug, Copy, Clone, Eq, PartialEq)]
216pub enum ResponseVerificationJsErrorCode {
217    /// Error converting UTF-8 string
218    IoError,
219    /// An unsupported verification version was requested
220    UnsupportedVerificationVersion,
221    /// Mismatch between the minimum requested version and the actual requested version
222    RequestedVerificationVersionMismatch,
223    /// Error parsing CEL expression
224    CelError,
225    /// Error decoding base64
226    Base64DecodingError,
227    /// Error parsing int
228    ParseIntError,
229    /// The tree has different root hash from the expected value in the certified variables
230    InvalidTreeRootHash,
231    /// The certificate provided by the "IC-Certificate" response header is missing the
232    /// certified data witness for the canister
233    CertificateMissingCertifiedData,
234    /// The expression path provided by the "IC-Certificate" response header
235    /// has an unexpected suffix and should end with "<$>" or "<*>"
236    UnexpectedExpressionPathPrefix,
237    /// The expression path provided by the "IC-Certificate" response header
238    /// has an unexpected suffix and should end with "<$>" or "<*>"
239    UnexpectedExpressionPathSuffix,
240    /// The exact expression path provided by the "IC-Certificate" response header
241    /// was not found in the tree
242    ExactExpressionPathNotFoundInTree,
243    /// The exact expression path provided by the "IC-Certificate" response header
244    /// is not valid for the request path
245    ExactExpressionPathMismatch,
246    /// A wildcard expression path was provided by the "IC-Certificate" response header
247    /// but a potential exact expression path is valid for the request path and might
248    /// exist in the tree
249    ExactExpressionPathMightExistInTree,
250    /// The wildcard expression path provided by the "IC-Certificate" response
251    /// was not found in the tree
252    WildcardExpressionPathNotFoundInTree,
253    /// The wildcard expression path provided by the "IC-Certificate" response
254    /// header is not valid for the request path
255    WildcardExpressionPathMismatch,
256    /// A more specific wildcard expression path than the one provided by the
257    /// "IC-Certificate" response header that is valid for the request path might
258    /// exist in the tree
259    MoreSpecificWildcardExpressionMightExistInTree,
260    /// The hash of the CEL expression provided by the "IC-Certificate-Expression"
261    /// response header does not exist at the expression path provided by the
262    /// "IC-Certificate" response header
263    InvalidExpressionHash,
264    /// The hash of the request and response was not found in the tree at the
265    /// expression path provided by the "IC-Certificate" response header
266    InvalidRequestAndResponseHashes,
267    /// The required empty leaf node was not found in the tree at the expression
268    /// path provided by the "IC-Certificate" response header
269    MissingLeafNode,
270    /// The response body was a mismatch from the expected values in the tree
271    InvalidResponseBody,
272    /// The certificate was missing from the certification header
273    HeaderMissingCertificate,
274    /// The tree was missing from the certification header
275    HeaderMissingTree,
276    /// The certificate expression path was missing from the certification header
277    HeaderMissingCertificateExpression,
278    /// The certificate expression was missing from the response headers
279    MissingCertificateExpression,
280    /// The certification values could not be found in the response headers
281    HeaderMissingCertification,
282    /// Failed to decode CBOR
283    CborDecodingFailed,
284    /// Failed to verify certificate
285    CertificateVerificationFailed,
286    /// HTTP Certification error
287    HttpCertificationError,
288}
289
290/// JS Representation of the ResponseVerificationError
291#[cfg(all(target_arch = "wasm32", feature = "js"))]
292#[wasm_bindgen(inspectable, js_name = ResponseVerificationError)]
293#[derive(Debug, Eq, PartialEq)]
294pub struct ResponseVerificationJsError {
295    /// Error code as an enum
296    #[wasm_bindgen(readonly)]
297    pub code: ResponseVerificationJsErrorCode,
298
299    /// Stringified error message
300    #[wasm_bindgen(getter_with_clone, readonly)]
301    pub message: String,
302}
303
304#[cfg(all(target_arch = "wasm32", feature = "js"))]
305impl From<ResponseVerificationError> for ResponseVerificationJsError {
306    fn from(error: ResponseVerificationError) -> ResponseVerificationJsError {
307        let code = match error {
308            ResponseVerificationError::IoError(_) => ResponseVerificationJsErrorCode::IoError,
309            ResponseVerificationError::UnsupportedVerificationVersion { .. } => {
310                ResponseVerificationJsErrorCode::UnsupportedVerificationVersion
311            }
312            ResponseVerificationError::RequestedVerificationVersionMismatch { .. } => {
313                ResponseVerificationJsErrorCode::RequestedVerificationVersionMismatch
314            }
315            ResponseVerificationError::CelError(_) => ResponseVerificationJsErrorCode::CelError,
316            ResponseVerificationError::Base64DecodingError(_) => {
317                ResponseVerificationJsErrorCode::Base64DecodingError
318            }
319            ResponseVerificationError::ParseIntError(_) => {
320                ResponseVerificationJsErrorCode::ParseIntError
321            }
322            ResponseVerificationError::InvalidTreeRootHash => {
323                ResponseVerificationJsErrorCode::InvalidTreeRootHash
324            }
325            ResponseVerificationError::CertificateMissingCertifiedData { .. } => {
326                ResponseVerificationJsErrorCode::CertificateMissingCertifiedData
327            }
328            ResponseVerificationError::UnexpectedExpressionPathPrefix { .. } => {
329                ResponseVerificationJsErrorCode::UnexpectedExpressionPathPrefix
330            }
331            ResponseVerificationError::UnexpectedExpressionPathSuffix { .. } => {
332                ResponseVerificationJsErrorCode::UnexpectedExpressionPathSuffix
333            }
334            ResponseVerificationError::ExactExpressionPathNotFoundInTree { .. } => {
335                ResponseVerificationJsErrorCode::ExactExpressionPathNotFoundInTree
336            }
337            ResponseVerificationError::ExactExpressionPathMismatch { .. } => {
338                ResponseVerificationJsErrorCode::ExactExpressionPathMismatch
339            }
340            ResponseVerificationError::ExactExpressionPathMightExistInTree { .. } => {
341                ResponseVerificationJsErrorCode::ExactExpressionPathMightExistInTree
342            }
343            ResponseVerificationError::WildcardExpressionPathNotFoundInTree { .. } => {
344                ResponseVerificationJsErrorCode::WildcardExpressionPathNotFoundInTree
345            }
346            ResponseVerificationError::WildcardExpressionPathMismatch { .. } => {
347                ResponseVerificationJsErrorCode::WildcardExpressionPathMismatch
348            }
349            ResponseVerificationError::MoreSpecificWildcardExpressionMightExistInTree {
350                ..
351            } => ResponseVerificationJsErrorCode::MoreSpecificWildcardExpressionMightExistInTree,
352            ResponseVerificationError::InvalidExpressionHash { .. } => {
353                ResponseVerificationJsErrorCode::InvalidExpressionHash
354            }
355            ResponseVerificationError::InvalidRequestAndResponseHashes { .. } => {
356                ResponseVerificationJsErrorCode::InvalidRequestAndResponseHashes
357            }
358            ResponseVerificationError::MissingLeafNode { .. } => {
359                ResponseVerificationJsErrorCode::MissingLeafNode
360            }
361            ResponseVerificationError::InvalidResponseBody => {
362                ResponseVerificationJsErrorCode::InvalidResponseBody
363            }
364            ResponseVerificationError::HeaderMissingCertificate => {
365                ResponseVerificationJsErrorCode::HeaderMissingCertificate
366            }
367            ResponseVerificationError::HeaderMissingTree => {
368                ResponseVerificationJsErrorCode::HeaderMissingTree
369            }
370            ResponseVerificationError::HeaderMissingCertificateExpressionPath => {
371                ResponseVerificationJsErrorCode::HeaderMissingCertificateExpression
372            }
373            ResponseVerificationError::HeaderMissingCertificateExpression => {
374                ResponseVerificationJsErrorCode::MissingCertificateExpression
375            }
376            ResponseVerificationError::HeaderMissingCertification => {
377                ResponseVerificationJsErrorCode::HeaderMissingCertification
378            }
379            ResponseVerificationError::CborDecodingFailed(_) => {
380                ResponseVerificationJsErrorCode::CborDecodingFailed
381            }
382            ResponseVerificationError::CertificateVerificationFailed(_) => {
383                ResponseVerificationJsErrorCode::CertificateVerificationFailed
384            }
385            ResponseVerificationError::HttpCertificationError(_) => {
386                ResponseVerificationJsErrorCode::HttpCertificationError
387            }
388        };
389        let message = error.to_string();
390
391        ResponseVerificationJsError {
392            code: code.into(),
393            message,
394        }
395    }
396}
397
398#[cfg(all(target_arch = "wasm32", feature = "js", test))]
399mod tests {
400    use super::*;
401    use crate::cel::CelParserError;
402    use base64::{engine::general_purpose, Engine as _};
403    use ic_cbor::CborError;
404    use ic_certificate_verification::CertificateVerificationError;
405    use ic_http_certification::HttpCertificationError;
406    use ic_response_verification_test_utils::hex_decode;
407    use wasm_bindgen_test::wasm_bindgen_test;
408
409    #[wasm_bindgen_test]
410    fn error_into_http_certification_error() {
411        let error = ResponseVerificationError::HttpCertificationError(
412            HttpCertificationError::MalformedUrl("https://internetcomputer.org".into()),
413        );
414        let result = ResponseVerificationJsError::from(error);
415
416        assert_eq!(
417            result,
418            ResponseVerificationJsError {
419                code: ResponseVerificationJsErrorCode::HttpCertificationError,
420                message: r#"HTTP Certification error: "Failed to parse url: "https://internetcomputer.org"""#.into(),
421            }
422        )
423    }
424
425    #[wasm_bindgen_test]
426    fn error_into_io_error() {
427        let inner_error = std::fs::File::open("foo.txt").expect_err("Expected error");
428        let error_msg = inner_error.to_string();
429
430        let error = ResponseVerificationError::IoError(inner_error.to_string());
431
432        let result = ResponseVerificationJsError::from(error);
433
434        assert_eq!(
435            result,
436            ResponseVerificationJsError {
437                code: ResponseVerificationJsErrorCode::IoError,
438                message: format!(r#"IO error: "{}""#, error_msg),
439            }
440        )
441    }
442
443    #[wasm_bindgen_test]
444    fn error_into_utf8_conversion_error() {
445        let invalid_utf_bytes = hex_decode("fca1a1a1a1a1");
446        let inner_error = String::from_utf8(invalid_utf_bytes).expect_err("Expected error");
447
448        let error = ResponseVerificationError::HttpCertificationError(
449            HttpCertificationError::Utf8ConversionError(inner_error.clone()),
450        );
451
452        let result = ResponseVerificationJsError::from(error);
453
454        assert_eq!(
455            result,
456            ResponseVerificationJsError {
457                code: ResponseVerificationJsErrorCode::HttpCertificationError,
458                message: format!(
459                    r#"HTTP Certification error: "Error converting UTF8 string bytes: "{0}"""#,
460                    inner_error.to_string()
461                ),
462            }
463        )
464    }
465
466    #[wasm_bindgen_test]
467    fn error_into_unsupported_verification_version() {
468        let error = ResponseVerificationError::UnsupportedVerificationVersion {
469            min_supported_version: 1,
470            max_supported_version: 2,
471            requested_version: 42,
472        };
473
474        let result = ResponseVerificationJsError::from(error);
475
476        assert_eq!(
477            result,
478            ResponseVerificationJsError {
479                code: ResponseVerificationJsErrorCode::UnsupportedVerificationVersion,
480                message: r#"The requested verification version 42 is not supported, the current supported range is 1-2"#.into(),
481            }
482        )
483    }
484
485    #[wasm_bindgen_test]
486    fn error_into_verification_version_mismatch() {
487        let error = ResponseVerificationError::RequestedVerificationVersionMismatch {
488            min_requested_verification_version: 2,
489            requested_version: 1,
490        };
491
492        let result = ResponseVerificationJsError::from(error);
493
494        assert_eq!(
495            result,
496            ResponseVerificationJsError {
497                code: ResponseVerificationJsErrorCode::RequestedVerificationVersionMismatch,
498                message: r#"The requested verification version 1 is lower than the minimum requested version 2"#.into(),
499            }
500        )
501    }
502
503    #[wasm_bindgen_test]
504    fn error_into_cel_error() {
505        let inner_error = CelParserError::CelSyntaxException(
506            "Garbage is not allowed in the CEL expression!".into(),
507        );
508        let error = ResponseVerificationError::from(inner_error);
509
510        let result = ResponseVerificationJsError::from(error);
511
512        assert_eq!(
513            result,
514            ResponseVerificationJsError {
515                code: ResponseVerificationJsErrorCode::CelError,
516                message: r#"Cel parser error"#.into(),
517            }
518        )
519    }
520
521    #[wasm_bindgen_test]
522    fn error_into_base64_decoding_error() {
523        let invalid_base64 = hex_decode("fca1a1a1a1a1");
524        let inner_error = general_purpose::STANDARD
525            .decode(invalid_base64)
526            .expect_err("Expected error");
527
528        let error = ResponseVerificationError::Base64DecodingError(inner_error);
529
530        let result = ResponseVerificationJsError::from(error);
531
532        assert_eq!(
533            result,
534            ResponseVerificationJsError {
535                code: ResponseVerificationJsErrorCode::Base64DecodingError,
536                message: format!(r#"Base64 decoding error"#),
537            }
538        )
539    }
540
541    #[wasm_bindgen_test]
542    fn error_into_parse_int_error() {
543        let invalid_int = "fortytwo";
544        let inner_error = invalid_int.parse::<u8>().expect_err("Expected error");
545
546        let error = ResponseVerificationError::ParseIntError(inner_error);
547
548        let result = ResponseVerificationJsError::from(error);
549
550        assert_eq!(
551            result,
552            ResponseVerificationJsError {
553                code: ResponseVerificationJsErrorCode::ParseIntError,
554                message: format!(r#"Error parsing int"#),
555            }
556        )
557    }
558
559    #[wasm_bindgen_test]
560    fn error_into_invalid_tree_error() {
561        let error = ResponseVerificationError::InvalidTreeRootHash;
562        let result = ResponseVerificationJsError::from(error);
563
564        assert_eq!(
565            result,
566            ResponseVerificationJsError {
567                code: ResponseVerificationJsErrorCode::InvalidTreeRootHash,
568                message: format!(r#"Invalid tree root hash"#),
569            }
570        )
571    }
572
573    #[wasm_bindgen_test]
574    fn error_into_unexpected_expression_path_prefix_error() {
575        let error = ResponseVerificationError::UnexpectedExpressionPathPrefix {
576            provided_expr_path: vec!["http_expr".into()],
577        };
578        let result = ResponseVerificationJsError::from(error);
579
580        assert_eq!(
581            result,
582            ResponseVerificationJsError {
583                code: ResponseVerificationJsErrorCode::UnexpectedExpressionPathPrefix,
584                message: format!(
585                    r#"The expression path provided by the "IC-Certificate" response header (["http_expr"]) has an unexpected prefix and should start with "http_expr"#
586                ),
587            }
588        )
589    }
590
591    #[wasm_bindgen_test]
592    fn error_into_unexpected_expression_path_suffix_error() {
593        let error = ResponseVerificationError::UnexpectedExpressionPathSuffix {
594            provided_expr_path: vec!["http_expr".into()],
595        };
596        let result = ResponseVerificationJsError::from(error);
597
598        assert_eq!(
599            result,
600            ResponseVerificationJsError {
601                code: ResponseVerificationJsErrorCode::UnexpectedExpressionPathSuffix,
602                message: format!(
603                    r#"The expression path provided by the "IC-Certificate" response header (["http_expr"]) has an unexpected suffix and should end with "<$>" or "<*>"#
604                ),
605            }
606        )
607    }
608
609    #[wasm_bindgen_test]
610    fn error_into_exact_expression_path_not_found_in_tree_error() {
611        let error = ResponseVerificationError::ExactExpressionPathNotFoundInTree {
612            provided_expr_path: vec!["http_expr".into()],
613        };
614        let result = ResponseVerificationJsError::from(error);
615
616        assert_eq!(
617            result,
618            ResponseVerificationJsError {
619                code: ResponseVerificationJsErrorCode::ExactExpressionPathNotFoundInTree,
620                message: format!(
621                    r#"The exact expression path provided by the "IC-Certificate" response header (["http_expr"]) was not found in the tree"#
622                ),
623            }
624        )
625    }
626
627    #[wasm_bindgen_test]
628    fn error_into_exact_expression_path_mismatch_error() {
629        let error = ResponseVerificationError::ExactExpressionPathMismatch {
630            provided_expr_path: vec!["http_expr".into()],
631            request_path: "/path".into(),
632        };
633        let result = ResponseVerificationJsError::from(error);
634
635        assert_eq!(
636            result,
637            ResponseVerificationJsError {
638                code: ResponseVerificationJsErrorCode::ExactExpressionPathMismatch,
639                message: format!(
640                    r#"The exact expression path provided by the "IC-Certificate" response header (["http_expr"]) is not valid for the request path ("/path")"#
641                ),
642            }
643        )
644    }
645
646    #[wasm_bindgen_test]
647    fn error_into_exact_expression_path_might_exist_in_tree_error() {
648        let error = ResponseVerificationError::ExactExpressionPathMightExistInTree {
649            provided_expr_path: vec!["http_expr".into()],
650            potential_expr_path: vec!["http_expr".into()],
651            request_path: "/path".into(),
652        };
653        let result = ResponseVerificationJsError::from(error);
654
655        assert_eq!(
656            result,
657            ResponseVerificationJsError {
658                code: ResponseVerificationJsErrorCode::ExactExpressionPathMightExistInTree,
659                message: format!(
660                    r#"A wildcard expression path was provided by the "IC-Certificate" response header (["http_expr"]), but a potential exact expression path (["http_expr"]) is valid for the request path ("/path") and might exist in the tree"#
661                ),
662            }
663        )
664    }
665
666    #[wasm_bindgen_test]
667    fn error_into_wildcard_expression_path_not_found_in_tree_error() {
668        let error = ResponseVerificationError::WildcardExpressionPathNotFoundInTree {
669            provided_expr_path: vec!["http_expr".into()],
670            request_path: "/path".into(),
671        };
672        let result = ResponseVerificationJsError::from(error);
673
674        assert_eq!(
675            result,
676            ResponseVerificationJsError {
677                code: ResponseVerificationJsErrorCode::WildcardExpressionPathNotFoundInTree,
678                message: format!(
679                    r#"The wildcard expression path provided by the "IC-Certificate" response header (["http_expr"]) is valid for the request path ("/path"), but was not found in the tree"#
680                ),
681            }
682        )
683    }
684
685    #[wasm_bindgen_test]
686    fn error_into_wildcard_expression_path_mismatch_error() {
687        let error = ResponseVerificationError::WildcardExpressionPathMismatch {
688            provided_expr_path: vec!["http_expr".into()],
689            request_path: "/path".into(),
690        };
691        let result = ResponseVerificationJsError::from(error);
692
693        assert_eq!(
694            result,
695            ResponseVerificationJsError {
696                code: ResponseVerificationJsErrorCode::WildcardExpressionPathMismatch,
697                message: format!(
698                    r#"The wildcard expression path provided by the "IC-Certificate" response header (["http_expr"]) is not valid for the request path ("/path")"#
699                ),
700            }
701        )
702    }
703
704    #[wasm_bindgen_test]
705    fn error_into_more_specific_wildcard_expression_might_exist_in_tree_error() {
706        let error = ResponseVerificationError::MoreSpecificWildcardExpressionMightExistInTree {
707            provided_expr_path: vec!["http_expr".into()],
708            more_specific_expr_path: vec!["http_expr".into()],
709            request_path: "/path".into(),
710        };
711        let result = ResponseVerificationJsError::from(error);
712
713        assert_eq!(
714            result,
715            ResponseVerificationJsError {
716                code:
717                    ResponseVerificationJsErrorCode::MoreSpecificWildcardExpressionMightExistInTree,
718                message: format!(
719                    r#"A more specific wildcard expression path (["http_expr"]) than the one provided by the "IC-Certificate" response header (["http_expr"]) that is valid for the request path ("/path") might exist in the tree"#
720                ),
721            }
722        )
723    }
724
725    #[wasm_bindgen_test]
726    fn error_into_invalid_response_body_error() {
727        let error = ResponseVerificationError::InvalidResponseBody;
728        let result = ResponseVerificationJsError::from(error);
729
730        assert_eq!(
731            result,
732            ResponseVerificationJsError {
733                code: ResponseVerificationJsErrorCode::InvalidResponseBody,
734                message: format!(r#"Invalid response body"#),
735            }
736        )
737    }
738
739    #[wasm_bindgen_test]
740    fn error_into_invalid_missing_certificate_error() {
741        let error = ResponseVerificationError::HeaderMissingCertificate;
742        let result = ResponseVerificationJsError::from(error);
743
744        assert_eq!(
745            result,
746            ResponseVerificationJsError {
747                code: ResponseVerificationJsErrorCode::HeaderMissingCertificate,
748                message: format!(r#"Certificate not found"#),
749            }
750        )
751    }
752
753    #[wasm_bindgen_test]
754    fn error_into_invalid_missing_tree_error() {
755        let error = ResponseVerificationError::HeaderMissingTree;
756        let result = ResponseVerificationJsError::from(error);
757
758        assert_eq!(
759            result,
760            ResponseVerificationJsError {
761                code: ResponseVerificationJsErrorCode::HeaderMissingTree,
762                message: format!(r#"Tree not found"#),
763            }
764        )
765    }
766
767    #[wasm_bindgen_test]
768    fn error_into_invalid_missing_certificate_expr_path_error() {
769        let error = ResponseVerificationError::HeaderMissingCertificateExpressionPath;
770        let result = ResponseVerificationJsError::from(error);
771
772        assert_eq!(
773            result,
774            ResponseVerificationJsError {
775                code: ResponseVerificationJsErrorCode::HeaderMissingCertificateExpression,
776                message: format!(r#"Certificate expression path not found"#),
777            }
778        )
779    }
780
781    #[wasm_bindgen_test]
782    fn error_into_invalid_missing_certificate_expr_error() {
783        let error = ResponseVerificationError::HeaderMissingCertificateExpression;
784        let result = ResponseVerificationJsError::from(error);
785
786        assert_eq!(
787            result,
788            ResponseVerificationJsError {
789                code: ResponseVerificationJsErrorCode::MissingCertificateExpression,
790                message: format!(r#"Certificate expression not found"#),
791            }
792        )
793    }
794
795    #[wasm_bindgen_test]
796    fn error_into_invalid_missing_certification_error() {
797        let error = ResponseVerificationError::HeaderMissingCertification;
798        let result = ResponseVerificationJsError::from(error);
799
800        assert_eq!(
801            result,
802            ResponseVerificationJsError {
803                code: ResponseVerificationJsErrorCode::HeaderMissingCertification,
804                message: format!(r#"Certification values not found"#),
805            }
806        )
807    }
808
809    #[wasm_bindgen_test]
810    fn error_into_cbor_decoding_failed_error() {
811        let error = ResponseVerificationError::CborDecodingFailed(CborError::MalformedCbor(
812            "HashTree CBOR is malformed".into(),
813        ));
814        let result = ResponseVerificationJsError::from(error);
815
816        assert_eq!(
817            result,
818            ResponseVerificationJsError {
819                code: ResponseVerificationJsErrorCode::CborDecodingFailed,
820                message: format!(r#"CBOR decoding failed"#),
821            }
822        )
823    }
824
825    #[wasm_bindgen_test]
826    fn error_into_certificate_verification_failed_error() {
827        let error = ResponseVerificationError::CertificateVerificationFailed(
828            CertificateVerificationError::MissingTimePathInTree {
829                path: vec![b"time".to_vec()],
830            },
831        );
832        let result = ResponseVerificationJsError::from(error);
833
834        assert_eq!(
835            result,
836            ResponseVerificationJsError {
837                code: ResponseVerificationJsErrorCode::CertificateVerificationFailed,
838                message: format!(r#"Certificate verification failed"#),
839            }
840        )
841    }
842}