aboutsummaryrefslogtreecommitdiff
path: root/src/error.rs
blob: 3f60af2b839ecc105d80a4795763bd70b20467ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use std::borrow;
use std::error;
use std::fmt;
use std::os::raw;
use std::result;

/// An error returned by the nitrokey crate.
#[derive(Debug)]
pub enum Error {
    /// An error reported by the Nitrokey device in the response packet.
    CommandError(CommandError),
    /// Placeholder for testing.
    CommunicationError(CommunicationError),
}

impl From<CommandError> for Error {
    fn from(err: CommandError) -> Self {
        Error::CommandError(err)
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match *self {
            Error::CommandError(ref err) => Some(err),
            Error::CommunicationError(_) => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::CommandError(ref err) => write!(f, "Command error: {}", err),
            Error::CommunicationError(_) => write!(f, "Placeholder"),
        }
    }
}

/// A result returned by the nitrokey crate.
pub type Result<T> = result::Result<T, Error>;

/// An error reported by the Nitrokey device in the response packet.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CommandError {
    /// A packet with a wrong checksum has been sent or received.
    WrongCrc,
    /// A command tried to access an OTP slot that does not exist.
    WrongSlot,
    /// A command tried to generate an OTP on a slot that is not configured.
    SlotNotProgrammed,
    /// The provided password is wrong.
    WrongPassword,
    /// You are not authorized for this command or provided a wrong temporary
    /// password.
    NotAuthorized,
    /// An error occurred when getting or setting the time.
    Timestamp,
    /// You did not provide a name for the OTP slot.
    NoName,
    /// This command is not supported by this device.
    NotSupported,
    /// This command is unknown.
    UnknownCommand,
    /// AES decryption failed.
    AesDecryptionFailed,
    /// An unknown error occurred.
    Unknown(i64),
    /// An unspecified error occurred.
    Undefined,
    /// You passed a string containing a null byte.
    InvalidString,
    /// A supplied string exceeded a length limit.
    StringTooLong,
    /// You passed an invalid slot.
    InvalidSlot,
    /// The supplied string was not in hexadecimal format.
    InvalidHexString,
    /// The target buffer was smaller than the source.
    TargetBufferTooSmall,
    /// An error occurred during random number generation.
    RngError,
}

/// Placeholder for testing.
#[derive(Debug)]
pub enum CommunicationError {
    /// Placeholder for testing.
    NotConnected,
}

impl CommandError {
    fn as_str(&self) -> borrow::Cow<'static, str> {
        match *self {
            CommandError::WrongCrc => {
                "A packet with a wrong checksum has been sent or received".into()
            }
            CommandError::WrongSlot => "The given OTP slot does not exist".into(),
            CommandError::SlotNotProgrammed => "The given OTP slot is not programmed".into(),
            CommandError::WrongPassword => "The given password is wrong".into(),
            CommandError::NotAuthorized => {
                "You are not authorized for this command or provided a wrong temporary \
                 password"
                    .into()
            }
            CommandError::Timestamp => "An error occurred when getting or setting the time".into(),
            CommandError::NoName => "You did not provide a name for the OTP slot".into(),
            CommandError::NotSupported => "This command is not supported by this device".into(),
            CommandError::UnknownCommand => "This command is unknown".into(),
            CommandError::AesDecryptionFailed => "AES decryption failed".into(),
            CommandError::Unknown(x) => {
                borrow::Cow::from(format!("An unknown error occurred ({})", x))
            }
            CommandError::Undefined => "An unspecified error occurred".into(),
            CommandError::InvalidString => "You passed a string containing a null byte".into(),
            CommandError::StringTooLong => "The supplied string is too long".into(),
            CommandError::InvalidSlot => "The given slot is invalid".into(),
            CommandError::InvalidHexString => {
                "The supplied string is not in hexadecimal format".into()
            }
            CommandError::TargetBufferTooSmall => "The target buffer is too small".into(),
            CommandError::RngError => "An error occurred during random number generation".into(),
        }
    }
}

impl error::Error for CommandError {}

impl fmt::Display for CommandError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl From<raw::c_int> for CommandError {
    fn from(value: raw::c_int) -> Self {
        match value {
            1 => CommandError::WrongCrc,
            2 => CommandError::WrongSlot,
            3 => CommandError::SlotNotProgrammed,
            4 => CommandError::WrongPassword,
            5 => CommandError::NotAuthorized,
            6 => CommandError::Timestamp,
            7 => CommandError::NoName,
            8 => CommandError::NotSupported,
            9 => CommandError::UnknownCommand,
            10 => CommandError::AesDecryptionFailed,
            200 => CommandError::StringTooLong,
            201 => CommandError::InvalidSlot,
            202 => CommandError::InvalidHexString,
            203 => CommandError::TargetBufferTooSmall,
            x => CommandError::Unknown(x.into()),
        }
    }
}

impl From<rand_core::Error> for CommandError {
    fn from(_error: rand_core::Error) -> Self {
        CommandError::RngError
    }
}