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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
//! Error types used in saltyrtc-client.
//!
//! The implementation is done using the
//! [`failure`](https://crates.io/crates/failure) crate.

use std::convert::From;
use std::sync::TryLockError;

use failure::Fail;
use rmp_serde::decode::Error as SerdeDecodeError;
use tokio_timer::TimeoutError;

/// Re-exported [`Error`](../../failure/struct.Error.html) type from the
/// [failure crate](https://crates.io/crates/failure).
pub type Error = ::failure::Error;

/// Errors that are exposed to the user of the library.
#[derive(Fail, Debug, PartialEq)]
pub enum SaltyError {
    /// A problem with encrypting or decrypting data.
    #[fail(display = "Crypto error: {}", _0)]
    Crypto(String),

    /// A problem when parsing or decoding data.
    #[fail(display = "Decoding error: {}", _0)]
    Decode(String),

    /// A network related problem.
    #[fail(display = "Network error: {}", _0)]
    Network(String),

    /// A protocol related error.
    #[fail(display = "Protocol error: {}", _0)]
    Protocol(String),

    /// No shared task was found.
    #[fail(display = "No shared task found")]
    NoSharedTask,

    /// Peer has not (yet) been determined.
    #[fail(display = "Peer has not (yet) been determined")]
    NoPeer,

    /// A problem occured related to a task.
    #[fail(display = "Task error: {}", _0)]
    Task(String),

    /// An unexpected error. This should never happen and indicates a bug in
    /// the implementation.
    #[fail(
        display = "An unexpected error occurred: {}. This indicates a bug and should be reported!",
        _0
    )]
    Crash(String),

    /// A future timed out.
    #[fail(display = "Future timed out")]
    Timeout,
}

impl From<SignalingError> for SaltyError {
    fn from(e: SignalingError) -> Self {
        match e {
            SignalingError::Crash(msg) => SaltyError::Crash(format!("Signaling error: {}", msg)),
            SignalingError::Crypto(msg) => SaltyError::Crypto(msg),
            SignalingError::CsnOverflow => SaltyError::Crypto(e.to_string()),
            SignalingError::Decode(msg) => SaltyError::Decode(msg),
            SignalingError::InitiatorCouldNotDecrypt => SaltyError::Crypto(e.to_string()),
            SignalingError::InvalidMessage(_) => SaltyError::Protocol(e.to_string()),
            SignalingError::InvalidNonce(_) => SaltyError::Protocol(e.to_string()),
            SignalingError::InvalidStateTransition(_) => SaltyError::Crash(e.to_string()),
            SignalingError::NoSharedTask => SaltyError::NoSharedTask,
            SignalingError::NoPeer => SaltyError::NoPeer,
            SignalingError::Protocol(msg) => SaltyError::Protocol(msg),
            SignalingError::SendError => SaltyError::Network(e.to_string()),
            SignalingError::TaskInitialization(_) => SaltyError::Task(e.to_string()),
        }
    }
}

impl<F> From<TimeoutError<F>> for SaltyError {
    fn from(_: TimeoutError<F>) -> Self {
        SaltyError::Timeout
    }
}

impl<T> From<TryLockError<T>> for SaltyError {
    fn from(e: TryLockError<T>) -> Self {
        SaltyError::Crash(format!("Could not acquire lock: {}", e))
    }
}

/// A result with [`SaltyError`](enum.SaltyError.html) as error type.
pub type SaltyResult<T> = ::std::result::Result<T, SaltyError>;

/// Internal errors that occur during signaling and that will probably result
/// in the connection being closed.
#[derive(Fail, Debug, PartialEq)]
pub(crate) enum SignalingError {
    /// A problem with decoding data.
    #[fail(display = "Decoding error: {}", _0)]
    Decode(String),

    /// Nonce validation fails.
    #[fail(display = "Invalid nonce: {}", _0)]
    InvalidNonce(String),

    /// A problem with encrypting or decrypting data.
    #[fail(display = "Crypto error: {}", _0)]
    Crypto(String),

    /// A CSN overflowed.
    /// This is extremely unlikely and must always be treated as a protocol error.
    #[fail(display = "CSN overflow")]
    CsnOverflow,

    /// An invalid state transition was attempted.
    #[fail(display = "Invalid state transition: {}", _0)]
    InvalidStateTransition(String),

    /// A message is not valid.
    #[fail(display = "Invalid message: {}", _0)]
    InvalidMessage(String),

    /// Something happened that violates the protocol.
    /// This error should mainly be used if the event that happened is outside
    /// of our control (e.g. if the peer sends a message we didn't expect).
    /// If the error is an implementation bug, use
    /// [`SignalingError::Crash`](enum.SignalingError.html#crash) instead!
    #[fail(display = "A protocol error occurred: {}", _0)]
    Protocol(String),

    /// The server returned a `SendError` message. This means that a
    /// client-to-client message could not be relayed (the connection between
    /// server and the receiver has been severed).
    #[fail(display = "Server could not relay message")]
    SendError,

    /// No shared task was found during the handshake.
    #[fail(display = "No shared task found")]
    NoSharedTask,

    /// Peer has not (yet) been determined.
    #[fail(display = "Peer has not (yet) been determined")]
    NoPeer,

    /// Task initialization failed.
    #[fail(display = "Task initialization failed: {}", _0)]
    TaskInitialization(String),

    /// Initiator could not decrypt key message.
    #[fail(display = "Initiator could not decrypt key message")]
    InitiatorCouldNotDecrypt,

    /// An unexpected error. This should never happen and indicates a bug in
    /// the implementation.
    #[fail(
        display = "An unexpected error occurred: {}. This indicates a bug and should be reported!",
        _0
    )]
    Crash(String),
}

/// A result with [`SignalingError`](enum.SignalingError.html) as error type.
pub(crate) type SignalingResult<T> = ::std::result::Result<T, SignalingError>;

impl From<SerdeDecodeError> for SignalingError {
    fn from(e: SerdeDecodeError) -> Self {
        SignalingError::Decode(format!("Could not decode msgpack data: {}", e))
    }
}

impl<T> From<TryLockError<T>> for SignalingError {
    fn from(e: TryLockError<T>) -> Self {
        SignalingError::Crash(format!("Could not acquire lock: {}", e))
    }
}

/// Errors that may be returned by the [`SaltyClientBuilder`](../struct.SaltyClientBuilder.html).
#[derive(Fail, Debug, PartialEq)]
pub enum BuilderError {
    /// No task has been added.
    #[fail(display = "No task specified")]
    MissingTask,
}

/// Result of the nonce validation.
pub(crate) enum ValidationError {
    /// Ignore message
    DropMsg(String),
    /// Validation failed
    Fail(String),
    /// A critical error occurred
    Crash(String),
}

impl<T> From<TryLockError<T>> for ValidationError {
    fn from(e: TryLockError<T>) -> Self {
        ValidationError::Crash(format!("Could not acquire lock: {}", e))
    }
}