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
use http::StatusCode;

use crate::event_message::cesr_adapter::ParseError;
use crate::keys::KeysError;
#[cfg(feature = "oobi")]
use crate::oobi::{error::OobiError, Role};
#[cfg(feature = "oobi")]
use crate::transport::TransportError;
use crate::{
    actor::SignedQueryError, database::DbError, error::Error as KeriError, prefix::IdentifierPrefix,
};
use said::version::error::Error as VersionError;

#[derive(Debug, thiserror::Error, serde::Serialize, serde::Deserialize)]
pub enum ActorError {
    #[cfg(feature = "oobi")]
    #[error("network request failed")]
    TransportError(Box<TransportError>),

    #[error("keri error")]
    KeriError(#[from] KeriError),

    #[error("DB error")]
    DbError(#[from] DbError),

    #[cfg(feature = "oobi")]
    #[error("OOBI error")]
    OobiError(#[from] OobiError),

    #[error("processing query failed")]
    QueryError(#[from] SignedQueryError),

    #[error("Keri event parsing error: {0}")]
    ParseError(#[from] ParseError),

    #[error("location not found for {id:?}")]
    NoLocation { id: IdentifierPrefix }, // TODO: should be Oobi error

    #[error("wrong reply route")]
    WrongReplyRoute,

    #[cfg(feature = "oobi")]
    #[error("role {role:?} missing for {id:?}")]
    MissingRole { role: Role, id: IdentifierPrefix }, // TODO: should be Oobi error

    #[error("no identifier state for prefix {prefix:?}")]
    NoIdentState { prefix: IdentifierPrefix },

    #[error("Missing signer identifier")]
    MissingSignerId,

    #[error("Signing error: {0}")]
    SigningError(#[from] KeysError),
}

#[cfg(feature = "oobi")]
impl From<TransportError> for ActorError {
    fn from(err: TransportError) -> Self {
        ActorError::TransportError(Box::new(err))
    }
}

impl From<VersionError> for ActorError {
    fn from(err: VersionError) -> Self {
        ActorError::KeriError(err.into())
    }
}

impl ActorError {
    pub fn http_status_code(&self) -> StatusCode {
        match self {
            ActorError::DbError(_) => StatusCode::INTERNAL_SERVER_ERROR,

            ActorError::KeriError(err) => match err {
                KeriError::DeserializeError(_) | KeriError::IncorrectDigest => {
                    StatusCode::BAD_REQUEST
                }

                KeriError::FaultySignatureVerification | KeriError::SignatureVerificationError => {
                    StatusCode::FORBIDDEN
                }

                _ => StatusCode::INTERNAL_SERVER_ERROR,
            },

            #[cfg(feature = "oobi")]
            ActorError::OobiError(OobiError::SignerMismatch) => StatusCode::UNAUTHORIZED,

            _ => StatusCode::INTERNAL_SERVER_ERROR,
        }
    }
}