Skip to main content

phc/
error.rs

1//! Error types.
2
3use crate::Salt;
4use base64ct::Error as B64Error;
5use core::{cmp::Ordering, fmt};
6
7/// Result type.
8pub type Result<T> = core::result::Result<T, Error>;
9
10/// Password hashing errors.
11#[derive(Copy, Clone, Debug, Eq, PartialEq)]
12#[non_exhaustive]
13pub enum Error {
14    /// "B64" encoding error.
15    Base64(B64Error),
16
17    /// Password hash string invalid.
18    MissingField,
19
20    /// Output size unexpected.
21    OutputSize {
22        /// Indicates why the output size is unexpected.
23        ///
24        /// - [`Ordering::Less`]: Size is too small.
25        /// - [`Ordering::Equal`]: Size is not exactly as `expected`.
26        /// - [`Ordering::Greater`]: Size is too long.
27        provided: Ordering,
28
29        /// Expected output size in relation to `provided`.
30        ///
31        /// - [`Ordering::Less`]: Minimum size.
32        /// - [`Ordering::Equal`]: Expected size.
33        /// - [`Ordering::Greater`]: Maximum size.
34        expected: usize,
35    },
36
37    /// Duplicate parameter name encountered.
38    ParamNameDuplicated,
39
40    /// Invalid parameter name.
41    ParamNameInvalid,
42
43    /// Parameter value is invalid.
44    ParamValueInvalid,
45
46    /// Parameter value is too long.
47    ParamValueTooLong,
48
49    /// Maximum number of parameters exceeded.
50    ParamsMaxExceeded,
51
52    /// Salt too short.
53    SaltTooShort,
54
55    /// Salt too long.
56    SaltTooLong,
57
58    /// Password hash string contains trailing data.
59    TrailingData,
60
61    /// Value exceeds the maximum allowed length.
62    ValueTooLong,
63}
64
65impl fmt::Display for Error {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
67        match self {
68            Self::Base64(err) => write!(f, "{err}"),
69            Self::MissingField => write!(f, "password hash string missing field"),
70            Self::OutputSize { provided, expected } => match provided {
71                Ordering::Less => write!(
72                    f,
73                    "output size too short, expected at least {expected} bytes",
74                ),
75                Ordering::Equal => write!(f, "output size unexpected, expected {expected} bytes"),
76                Ordering::Greater => {
77                    write!(f, "output size too long, expected at most {expected} bytes")
78                }
79            },
80            Self::ParamNameDuplicated => write!(f, "duplicate parameter"),
81            Self::ParamNameInvalid => write!(f, "invalid parameter name"),
82            Self::ParamValueInvalid => write!(f, "invalid parameter value"),
83            Self::ParamValueTooLong => write!(f, "parameter value too long"),
84            Self::ParamsMaxExceeded => write!(f, "maximum number of parameters reached"),
85            Self::SaltTooShort => write!(f, "salt too short (minimum {} bytes)", Salt::MIN_LENGTH),
86            Self::SaltTooLong => write!(f, "salt too long (maximum {} bytes)", Salt::MAX_LENGTH),
87            Self::TrailingData => write!(f, "password hash has unexpected trailing characters"),
88            Self::ValueTooLong => f.write_str("value too long"),
89        }
90    }
91}
92
93impl core::error::Error for Error {
94    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
95        match self {
96            Self::Base64(err) => Some(err),
97            _ => None,
98        }
99    }
100}
101
102impl From<B64Error> for Error {
103    fn from(err: B64Error) -> Error {
104        Error::Base64(err)
105    }
106}
107
108impl From<base64ct::InvalidLengthError> for Error {
109    fn from(_: base64ct::InvalidLengthError) -> Error {
110        Error::Base64(B64Error::InvalidLength)
111    }
112}