codlet_core/error.rs
1//! Error types for codlet-core.
2//!
3//! This is the internal error layer (RFC-012/021): structured, useful for
4//! developers and operators, and safe to log because no variant carries a
5//! plaintext secret. The public, enumeration-resistant error layer
6//! (`PublicAuthFailure`) is introduced with the redemption flow (RFC-012) once
7//! the store traits exist.
8
9use thiserror::Error;
10
11/// Randomness could not be obtained. Generation fails closed on this error;
12/// codlet never substitutes a deterministic value (INV-3, SR-29-adjacent).
13#[derive(Debug, Error, PartialEq, Eq)]
14#[error("secure randomness unavailable")]
15pub struct RandomError;
16
17/// A key provider could not supply usable key material.
18///
19/// Carries no key bytes. Missing material is fatal to the operation; there is
20/// no fallback key (INV-2, SR-29).
21#[derive(Debug, Error, PartialEq, Eq)]
22pub enum KeyError {
23 /// No active key is configured.
24 #[error("no active HMAC key configured")]
25 MissingActiveKey,
26 /// The requested historical key version is not available. Validation fails
27 /// closed for that candidate rather than falling back.
28 #[error("HMAC key version not available")]
29 MissingKeyVersion,
30 /// Key material was present but unusable (e.g. empty).
31 #[error("HMAC key material is invalid")]
32 InvalidKeyMaterial,
33}
34
35/// A [`crate::code::CodePolicy`] was constructed with an impossible or unsafe
36/// shape (RFC-003 ยง11.1).
37#[derive(Debug, Error, PartialEq, Eq)]
38pub enum PolicyError {
39 /// Alphabet has fewer than two distinct symbols.
40 #[error("alphabet must contain at least 2 symbols")]
41 AlphabetTooSmall,
42 /// Alphabet contains a duplicate symbol, which would bias generation.
43 #[error("alphabet contains duplicate symbols")]
44 AlphabetNotUnique,
45 /// Alphabet contains a non-ASCII or otherwise unsupported byte.
46 #[error("alphabet contains an unsupported (non-ASCII) symbol")]
47 AlphabetNotAscii,
48 /// Requested code length is below the secure minimum and no explicit
49 /// short-code opt-in was used.
50 #[error("code length {got} is below the secure minimum of {min}")]
51 LengthBelowMinimum {
52 /// Requested length.
53 got: usize,
54 /// Enforced minimum.
55 min: usize,
56 },
57 /// Requested code length is zero.
58 #[error("code length must be non-zero")]
59 ZeroLength,
60}
61
62/// Rejection of user-supplied code input during validation (RFC-003 FR-2).
63///
64/// All variants map to the same generic public message; the distinction here
65/// exists only for internal diagnostics and metrics, never for user display
66/// (INV-8).
67#[derive(Debug, Error, PartialEq, Eq)]
68pub enum CodeInputError {
69 /// Input was empty after trimming.
70 #[error("code input is empty")]
71 Empty,
72 /// Raw input exceeded the maximum accepted length before normalization.
73 #[error("code input exceeds maximum raw length")]
74 TooLongRaw,
75 /// Normalized input length does not match the configured code length.
76 #[error("normalized code length does not match policy")]
77 WrongLength,
78 /// Normalized input contains a character outside the accepted set.
79 #[error("code input contains unsupported characters")]
80 UnsupportedCharacters,
81}