indy_crypto/errors/
mod.rs

1extern crate serde_json;
2extern crate log;
3
4use ffi::ErrorCode;
5
6use std::fmt;
7use std::cell::RefCell;
8use std::ptr;
9use std::ffi::CString;
10
11use failure::{Backtrace, Context, Fail};
12use libc::c_char;
13
14use utils::ctypes;
15
16pub mod prelude {
17    pub use super::{err_msg, IndyCryptoError, IndyCryptoErrorExt, IndyCryptoErrorKind, IndyCryptoResult, set_current_error, get_current_error_c_json};
18}
19
20#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
21pub enum IndyCryptoErrorKind {
22    // Common errors
23    #[fail(display = "Invalid library state")]
24    InvalidState,
25    #[fail(display = "Invalid structure")]
26    InvalidStructure,
27    #[fail(display = "Invalid parameter {}", 0)]
28    InvalidParam(u32),
29    #[fail(display = "IO error")]
30    IOError,
31    // CL errors
32    #[fail(display = "Proof rejected")]
33    ProofRejected,
34    #[fail(display = "Revocation accumulator is full")]
35    RevocationAccumulatorIsFull,
36    #[fail(display = "Invalid revocation id")]
37    InvalidRevocationAccumulatorIndex,
38    #[fail(display = "Credential revoked")]
39    CredentialRevoked,
40}
41
42#[derive(Debug)]
43pub struct IndyCryptoError {
44    inner: Context<IndyCryptoErrorKind>
45}
46
47impl Fail for IndyCryptoError {
48    fn cause(&self) -> Option<&Fail> {
49        self.inner.cause()
50    }
51
52    fn backtrace(&self) -> Option<&Backtrace> {
53        self.inner.backtrace()
54    }
55}
56
57impl IndyCryptoError {
58    pub fn from_msg<D>(kind: IndyCryptoErrorKind, msg: D) -> IndyCryptoError
59        where D: fmt::Display + fmt::Debug + Send + Sync + 'static {
60        IndyCryptoError { inner: Context::new(msg).context(kind) }
61    }
62
63    pub fn kind(&self) -> IndyCryptoErrorKind {
64        *self.inner.get_context()
65    }
66}
67
68impl fmt::Display for IndyCryptoError {
69    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70        let mut first = true;
71
72        for cause in Fail::iter_chain(&self.inner) {
73            if first {
74                first = false;
75                writeln!(f, "Error: {}", cause)?;
76            } else {
77                writeln!(f, "Caused by: {}", cause)?;
78            }
79        }
80
81        Ok(())
82    }
83}
84
85pub fn err_msg<D>(kind: IndyCryptoErrorKind, msg: D) -> IndyCryptoError
86    where D: fmt::Display + fmt::Debug + Send + Sync + 'static {
87    IndyCryptoError::from_msg(kind, msg)
88}
89
90impl From<Context<IndyCryptoErrorKind>> for IndyCryptoError {
91    fn from(inner: Context<IndyCryptoErrorKind>) -> IndyCryptoError {
92        IndyCryptoError { inner }
93    }
94}
95
96impl From<log::SetLoggerError> for IndyCryptoError {
97    fn from(err: log::SetLoggerError) -> IndyCryptoError {
98        err.context(IndyCryptoErrorKind::InvalidState).into()
99    }
100}
101
102impl From<IndyCryptoErrorKind> for ErrorCode {
103    fn from(code: IndyCryptoErrorKind) -> ErrorCode {
104        match code {
105            IndyCryptoErrorKind::InvalidState => ErrorCode::CommonInvalidState,
106            IndyCryptoErrorKind::InvalidStructure => ErrorCode::CommonInvalidStructure,
107            IndyCryptoErrorKind::InvalidParam(num) =>
108                match num {
109                    1 => ErrorCode::CommonInvalidParam1,
110                    2 => ErrorCode::CommonInvalidParam2,
111                    3 => ErrorCode::CommonInvalidParam3,
112                    4 => ErrorCode::CommonInvalidParam4,
113                    5 => ErrorCode::CommonInvalidParam5,
114                    6 => ErrorCode::CommonInvalidParam6,
115                    7 => ErrorCode::CommonInvalidParam7,
116                    8 => ErrorCode::CommonInvalidParam8,
117                    9 => ErrorCode::CommonInvalidParam9,
118                    10 => ErrorCode::CommonInvalidParam10,
119                    11 => ErrorCode::CommonInvalidParam11,
120                    12 => ErrorCode::CommonInvalidParam12,
121                    _ => ErrorCode::CommonInvalidState
122                },
123            IndyCryptoErrorKind::IOError => ErrorCode::CommonIOError,
124            IndyCryptoErrorKind::ProofRejected => ErrorCode::AnoncredsProofRejected,
125            IndyCryptoErrorKind::RevocationAccumulatorIsFull => ErrorCode::AnoncredsRevocationAccumulatorIsFull,
126            IndyCryptoErrorKind::InvalidRevocationAccumulatorIndex => ErrorCode::AnoncredsInvalidRevocationAccumulatorIndex,
127            IndyCryptoErrorKind::CredentialRevoked => ErrorCode::AnoncredsCredentialRevoked,
128        }
129    }
130}
131
132impl From<ErrorCode> for IndyCryptoErrorKind {
133    fn from(err: ErrorCode) -> IndyCryptoErrorKind {
134        match err {
135            ErrorCode::CommonInvalidState => IndyCryptoErrorKind::InvalidState,
136            ErrorCode::CommonInvalidStructure => IndyCryptoErrorKind::InvalidStructure,
137            ErrorCode::CommonInvalidParam1 => IndyCryptoErrorKind::InvalidParam(1),
138            ErrorCode::CommonInvalidParam2 => IndyCryptoErrorKind::InvalidParam(2),
139            ErrorCode::CommonInvalidParam3 => IndyCryptoErrorKind::InvalidParam(3),
140            ErrorCode::CommonInvalidParam4 => IndyCryptoErrorKind::InvalidParam(4),
141            ErrorCode::CommonInvalidParam5 => IndyCryptoErrorKind::InvalidParam(5),
142            ErrorCode::CommonInvalidParam6 => IndyCryptoErrorKind::InvalidParam(6),
143            ErrorCode::CommonInvalidParam7 => IndyCryptoErrorKind::InvalidParam(7),
144            ErrorCode::CommonInvalidParam8 => IndyCryptoErrorKind::InvalidParam(8),
145            ErrorCode::CommonInvalidParam9 => IndyCryptoErrorKind::InvalidParam(9),
146            ErrorCode::CommonInvalidParam10 => IndyCryptoErrorKind::InvalidParam(10),
147            ErrorCode::CommonInvalidParam11 => IndyCryptoErrorKind::InvalidParam(11),
148            ErrorCode::CommonInvalidParam12 => IndyCryptoErrorKind::InvalidParam(12),
149            ErrorCode::CommonIOError => IndyCryptoErrorKind::IOError,
150            ErrorCode::AnoncredsProofRejected => IndyCryptoErrorKind::ProofRejected,
151            ErrorCode::AnoncredsRevocationAccumulatorIsFull => IndyCryptoErrorKind::RevocationAccumulatorIsFull,
152            ErrorCode::AnoncredsInvalidRevocationAccumulatorIndex => IndyCryptoErrorKind::InvalidRevocationAccumulatorIndex,
153            ErrorCode::AnoncredsCredentialRevoked => IndyCryptoErrorKind::CredentialRevoked,
154            _code => IndyCryptoErrorKind::InvalidState
155        }
156    }
157}
158
159impl From<IndyCryptoError> for ErrorCode {
160    fn from(err: IndyCryptoError) -> ErrorCode {
161        set_current_error(&err);
162        err.kind().into()
163    }
164}
165
166pub type IndyCryptoResult<T> = Result<T, IndyCryptoError>;
167
168/// Extension methods for `Error`.
169pub trait IndyCryptoErrorExt {
170    fn to_indy<D>(self, kind: IndyCryptoErrorKind, msg: D) -> IndyCryptoError where D: fmt::Display + Send + Sync + 'static;
171}
172
173impl<E> IndyCryptoErrorExt for E where E: Fail
174{
175    fn to_indy<D>(self, kind: IndyCryptoErrorKind, msg: D) -> IndyCryptoError where D: fmt::Display + Send + Sync + 'static {
176        self.context(msg).context(kind).into()
177    }
178}
179
180thread_local! {
181    pub static CURRENT_ERROR_C_JSON: RefCell<Option<CString>> = RefCell::new(None);
182}
183
184pub fn set_current_error(err: &IndyCryptoError) {
185    CURRENT_ERROR_C_JSON.with(|error| {
186        let error_json = json!({
187            "message": err.to_string(),
188            "backtrace": err.backtrace().map(|bt| bt.to_string())
189        }).to_string();
190        error.replace(Some(ctypes::string_to_cstring(error_json)));
191    });
192}
193
194pub fn get_current_error_c_json() -> *const c_char {
195    let mut value = ptr::null();
196
197    CURRENT_ERROR_C_JSON.with(|err|
198        err.borrow().as_ref().map(|err| value = err.as_ptr())
199    );
200
201    value
202}