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
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use failure::{Backtrace, Context, Fail};
use std::{boxed::Box, fmt, result};

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub struct Error(Box<Context<ErrorKind>>);

impl Fail for Error {
    #[inline]
    fn cause(&self) -> Option<&Fail> {
        self.0.cause()
    }

    #[inline]
    fn backtrace(&self) -> Option<&Backtrace> {
        self.0.backtrace()
    }
}

impl fmt::Display for Error {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&*self.0, f)
    }
}

impl Error {
    #[inline]
    pub fn kind(&self) -> &ErrorKind {
        &*self.0.get_context()
    }
}

impl From<ErrorKind> for Error {
    #[inline]
    fn from(kind: ErrorKind) -> Error {
        Error(Box::new(Context::new(kind)))
    }
}

impl From<Context<ErrorKind>> for Error {
    #[inline]
    fn from(inner: Context<ErrorKind>) -> Error {
        Error(Box::new(inner))
    }
}

#[derive(Debug, Fail)]
pub enum ErrorKind {
    #[fail(display = "Invalid auth secret")]
    InvalidAuthSecret,

    #[fail(display = "Invalid salt")]
    InvalidSalt,

    #[fail(display = "Invalid key length")]
    InvalidKeyLength,

    #[fail(display = "Invalid record size")]
    InvalidRecordSize,

    #[fail(display = "Invalid header size (too short)")]
    HeaderTooShort,

    #[fail(display = "Truncated ciphertext")]
    DecryptTruncated,

    #[fail(display = "Zero-length ciphertext")]
    ZeroCiphertext,

    #[fail(display = "Zero-length plaintext")]
    ZeroPlaintext,

    #[fail(display = "Block too short")]
    BlockTooShort,

    #[fail(display = "Invalid decryption padding")]
    DecryptPadding,

    #[fail(display = "Invalid encryption padding")]
    EncryptPadding,

    #[fail(display = "Could not decode base64 entry")]
    DecodeError,

    #[cfg(feature = "backend-openssl")]
    #[fail(display = "OpenSSL error: {}", _0)]
    OpenSSLError(#[fail(cause)] openssl::error::ErrorStack),
}

impl From<base64::DecodeError> for Error {
    #[inline]
    fn from(_: base64::DecodeError) -> Error {
        ErrorKind::DecodeError.into()
    }
}

macro_rules! impl_from_error {
    ($(($variant:ident, $type:ty)),+) => ($(
        impl From<$type> for ErrorKind {
            #[inline]
            fn from(e: $type) -> ErrorKind {
                ErrorKind::$variant(e)
            }
        }

        impl From<$type> for Error {
            #[inline]
            fn from(e: $type) -> Error {
                ErrorKind::from(e).into()
            }
        }
    )*);
}

#[cfg(feature = "backend-openssl")]
impl_from_error! {
    (OpenSSLError, ::openssl::error::ErrorStack)
}