Skip to main content

canaad_core/
error.rs

1//! Error types for AAD parsing and validation.
2
3use std::fmt;
4use thiserror::Error;
5
6/// All possible errors during AAD parsing, validation, and canonicalization.
7#[derive(Debug, Error)]
8pub enum AadError {
9    /// Integer value exceeds the safe range (0 to 2^53-1).
10    #[error("field '{field}' integer out of range: {value} exceeds maximum safe value {max}")]
11    IntegerOutOfRange {
12        /// The field whose value was out of range
13        field: String,
14        /// The value that was out of range
15        value: u64,
16        /// The maximum allowed value (2^53-1)
17        max: u64,
18    },
19
20    /// Negative integer encountered where unsigned was expected.
21    #[error("field '{field}' negative integer not allowed: {value}")]
22    NegativeInteger {
23        /// The field that received the negative value
24        field: String,
25        /// The negative value encountered
26        value: i64,
27    },
28
29    /// Field key is empty.
30    #[error("field key cannot be empty")]
31    EmptyFieldKey,
32
33    /// Field key contains invalid characters.
34    #[error("invalid field key '{key}': {reason}")]
35    InvalidFieldKey {
36        /// The invalid key
37        key: String,
38        /// Explanation of why it's invalid
39        reason: String,
40    },
41
42    /// Attempted to use a reserved key name as an extension.
43    #[error("reserved key '{key}' cannot be used as extension field")]
44    ReservedKeyAsExtension {
45        /// The reserved key that was misused
46        key: String,
47    },
48
49    /// Extension key does not match required pattern `x_<app>_<field>`.
50    #[error("invalid extension key format '{key}': expected pattern {expected_pattern}")]
51    InvalidExtensionKeyFormat {
52        /// The invalid extension key
53        key: String,
54        /// The expected pattern description
55        expected_pattern: &'static str,
56    },
57
58    /// String field is shorter than minimum length.
59    #[error("field '{field}' too short: minimum {min_bytes} bytes, got {actual_bytes}")]
60    FieldTooShort {
61        /// The field name
62        field: &'static str,
63        /// Minimum required bytes
64        min_bytes: usize,
65        /// Actual bytes provided
66        actual_bytes: usize,
67    },
68
69    /// String field exceeds maximum length.
70    #[error("field '{field}' too long: maximum {max_bytes} bytes, got {actual_bytes}")]
71    FieldTooLong {
72        /// The field name
73        field: &'static str,
74        /// Maximum allowed bytes
75        max_bytes: usize,
76        /// Actual bytes provided
77        actual_bytes: usize,
78    },
79
80    /// NUL byte (0x00) found in string value.
81    #[error("field '{field}' contains NUL byte (0x00)")]
82    NulByteInValue {
83        /// The field containing the NUL byte
84        field: &'static str,
85    },
86
87    /// Required field is missing from the AAD object.
88    #[error("missing required field: {field}")]
89    MissingRequiredField {
90        /// The name of the missing field
91        field: &'static str,
92    },
93
94    /// Duplicate key found in JSON object.
95    #[error("duplicate key: '{key}'")]
96    DuplicateKey {
97        /// The duplicated key
98        key: String,
99    },
100
101    /// Unknown field for the specified schema version.
102    #[error("unknown field '{field}' for schema version {version}")]
103    UnknownField {
104        /// The unknown field name
105        field: String,
106        /// The schema version
107        version: u64,
108    },
109
110    /// Unsupported schema version.
111    #[error("unsupported schema version: {version}")]
112    UnsupportedVersion {
113        /// The unsupported version number
114        version: u64,
115    },
116
117    /// Field has wrong type (e.g., string instead of integer).
118    #[error("field '{field}' has wrong type: expected {expected}, got {actual}")]
119    WrongFieldType {
120        /// The field with wrong type
121        field: &'static str,
122        /// The expected type
123        expected: &'static str,
124        /// The actual type found
125        actual: JsonType,
126    },
127
128    /// Serialized AAD exceeds the 16 KiB limit.
129    #[error("serialized AAD too large: maximum {max_bytes} bytes, got {actual_bytes}")]
130    SerializedTooLarge {
131        /// Maximum allowed bytes (16384)
132        max_bytes: usize,
133        /// Actual serialized size
134        actual_bytes: usize,
135    },
136
137    /// Invalid JSON syntax or structure.
138    #[error("invalid JSON: {message}")]
139    InvalidJson {
140        /// Description of the JSON error
141        message: String,
142    },
143
144    /// Non-integer or non-finite float where an integer was required.
145    #[error("field '{field}' is not a valid integer: {reason}")]
146    InvalidFloat {
147        /// The field name
148        field: String,
149        /// `"NaN"`, `"Infinity"`, `"negative"`, `"fractional"`, or `"exceeds MAX_SAFE_INTEGER"`
150        reason: &'static str,
151    },
152}
153
154/// JSON value type for error reporting.
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub enum JsonType {
157    /// JSON null value
158    Null,
159    /// JSON boolean value
160    Bool,
161    /// JSON number value
162    Number,
163    /// JSON string value
164    String,
165    /// JSON array value
166    Array,
167    /// JSON object value
168    Object,
169}
170
171impl fmt::Display for JsonType {
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        match self {
174            Self::Null => write!(f, "null"),
175            Self::Bool => write!(f, "boolean"),
176            Self::Number => write!(f, "number"),
177            Self::String => write!(f, "string"),
178            Self::Array => write!(f, "array"),
179            Self::Object => write!(f, "object"),
180        }
181    }
182}
183
184impl From<&serde_json::Value> for JsonType {
185    fn from(value: &serde_json::Value) -> Self {
186        match value {
187            serde_json::Value::Null => Self::Null,
188            serde_json::Value::Bool(_) => Self::Bool,
189            serde_json::Value::Number(_) => Self::Number,
190            serde_json::Value::String(_) => Self::String,
191            serde_json::Value::Array(_) => Self::Array,
192            serde_json::Value::Object(_) => Self::Object,
193        }
194    }
195}