atagen

macltok

public
Star0
Watch0
fa9114fcf75f7bdf1a7cec3b3367d604cf7de472
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git
src/error.rsRust170 lines6.6 KB
1
use thiserror::Error;
2
3
use matrix_sdk::{
4
    HttpError, RefreshTokenError,
5
    authentication::oauth::error::{
6
        OAuthAuthorizationCodeError, OAuthDiscoveryError, OAuthError, OAuthTokenRevocationError,
7
        RequestTokenError,
8
    },
9
    encryption::{
10
        identities::{ManualVerifyError, RequestVerificationError},
11
        recovery::RecoveryError,
12
        secret_storage::{ImportError, SecretStorageError},
13
    },
14
};
15
16
use crate::CommandErrorKind;
17
18
#[derive(Debug, Error)]
19
#[error("{message}")]
20
pub(crate) struct CommandError {
21
    pub(crate) kind: CommandErrorKind,
22
    message: String,
23
    #[source]
24
    source: Option<Box<dyn std::error::Error + Send + Sync>>,
25
}
26
27
impl CommandError {
28
    pub(crate) fn new(kind: CommandErrorKind, message: impl Into<String>) -> Self {
29
        Self {
30
            kind,
31
            message: message.into(),
32
            source: None,
33
        }
34
    }
35
36
    pub(crate) fn with_source(
37
        kind: CommandErrorKind,
38
        message: impl Into<String>,
39
        source: impl std::error::Error + Send + Sync + 'static,
40
    ) -> Self {
41
        Self {
42
            kind,
43
            message: message.into(),
44
            source: Some(Box::new(source)),
45
        }
46
    }
47
48
    pub(crate) fn from_sdk(message: impl Into<String>, source: matrix_sdk::Error) -> Self {
49
        Self::with_source(classify_sdk_error(&source), message, source)
50
    }
51
52
    pub(crate) fn from_http(message: impl Into<String>, source: HttpError) -> Self {
53
        Self::with_source(classify_http_error(&source), message, source)
54
    }
55
    pub(crate) fn from_refresh_token(
56
        message: impl Into<String>,
57
        source: RefreshTokenError,
58
    ) -> Self {
59
        Self::with_source(classify_refresh_token_error(&source), message, source)
60
    }
61
62
    pub(crate) fn from_recovery(message: impl Into<String>, source: RecoveryError) -> Self {
63
        let kind = match &source {
64
            RecoveryError::Sdk(source) => classify_sdk_error(source),
65
            RecoveryError::SecretStorage(SecretStorageError::Sdk(source)) => {
66
                classify_sdk_error(source)
67
            }
68
            RecoveryError::SecretStorage(SecretStorageError::ImportError { error, .. }) => {
69
                match error {
70
                    ImportError::Sdk(source) => classify_sdk_error(source),
71
                    _ => CommandErrorKind::RecoveryRejected,
72
                }
73
            }
74
            RecoveryError::SecretStorage(SecretStorageError::Verification(source)) => {
75
                match source {
76
                    ManualVerifyError::Http(source) => classify_http_error(source),
77
                    _ => CommandErrorKind::RecoveryRejected,
78
                }
79
            }
80
            RecoveryError::SecretStorage(SecretStorageError::SecretStorageKey(_)) => {
81
                CommandErrorKind::RecoveryRejected
82
            }
83
            RecoveryError::SecretStorage(SecretStorageError::Storage(_)) => CommandErrorKind::Store,
84
            RecoveryError::BackupExistsOnServer | RecoveryError::SecretStorage(_) => {
85
                CommandErrorKind::RecoveryRejected
86
            }
87
        };
88
        Self::with_source(kind, message, source)
89
    }
90
91
    pub(crate) fn from_verification_request(
92
        message: impl Into<String>,
93
        source: RequestVerificationError,
94
    ) -> Self {
95
        let kind = match &source {
96
            RequestVerificationError::Sdk(source) => classify_sdk_error(source),
97
            RequestVerificationError::RoomCreation(_) => CommandErrorKind::Encryption,
98
        };
99
        Self::with_source(kind, message, source)
100
    }
101
}
102
103
pub(crate) fn classify_sdk_error(source: &matrix_sdk::Error) -> CommandErrorKind {
104
    match source {
105
        matrix_sdk::Error::Http(source) => classify_http_error(source),
106
        matrix_sdk::Error::OAuth(source) => classify_oauth_error(source),
107
        matrix_sdk::Error::AuthenticationRequired => CommandErrorKind::Unauthenticated,
108
        matrix_sdk::Error::BadCryptoStoreState
109
        | matrix_sdk::Error::CryptoStoreError(_)
110
        | matrix_sdk::Error::CrossProcessLockError(_)
111
        | matrix_sdk::Error::StateStore(_)
112
        | matrix_sdk::Error::EventCacheStore(_)
113
        | matrix_sdk::Error::MediaStore(_) => CommandErrorKind::Store,
114
        matrix_sdk::Error::NoOlmMachine
115
        | matrix_sdk::Error::OlmError(_)
116
        | matrix_sdk::Error::MegolmError(_)
117
        | matrix_sdk::Error::DecryptorError(_) => CommandErrorKind::Encryption,
118
        matrix_sdk::Error::Media(_) => CommandErrorKind::MediaUnavailable,
119
        matrix_sdk::Error::Timeout => CommandErrorKind::Network,
120
        _ => CommandErrorKind::Other,
121
    }
122
}
123
124
fn classify_http_error(source: &HttpError) -> CommandErrorKind {
125
    match source {
126
        HttpError::Reqwest(_) => CommandErrorKind::Network,
127
        HttpError::Api(_) => CommandErrorKind::Server,
128
        HttpError::RefreshToken(source) => classify_refresh_token_error(source),
129
        HttpError::Cached(source) => classify_http_error(source),
130
        _ => CommandErrorKind::Other,
131
    }
132
}
133
134
fn classify_refresh_token_error(source: &RefreshTokenError) -> CommandErrorKind {
135
    match source {
136
        RefreshTokenError::RefreshTokenRequired => CommandErrorKind::Unauthenticated,
137
        RefreshTokenError::MatrixAuth(source) => classify_http_error(source),
138
        RefreshTokenError::OAuth(source) => classify_oauth_error(source),
139
    }
140
}
141
142
fn classify_oauth_error(source: &OAuthError) -> CommandErrorKind {
143
    let classify_token_request_error = |source: &_| match source {
144
        RequestTokenError::Request(_) => CommandErrorKind::Network,
145
        RequestTokenError::ServerResponse(_) => CommandErrorKind::Unauthenticated,
146
        _ => CommandErrorKind::Other,
147
    };
148
    match source {
149
        OAuthError::Discovery(source) => match source {
150
            OAuthDiscoveryError::Http(source) => classify_http_error(source),
151
            OAuthDiscoveryError::Oidc(source) => classify_token_request_error(source),
152
            _ => CommandErrorKind::Unauthenticated,
153
        },
154
        OAuthError::RefreshToken(source) => classify_token_request_error(source),
155
        OAuthError::AuthorizationCode(OAuthAuthorizationCodeError::RequestToken(source)) => {
156
            classify_token_request_error(source)
157
        }
158
        OAuthError::AuthorizationCode(_) => CommandErrorKind::Unauthenticated,
159
        OAuthError::Logout(source) => match source {
160
            OAuthTokenRevocationError::Revoke(RequestTokenError::Request(_)) => {
161
                CommandErrorKind::Network
162
            }
163
            OAuthTokenRevocationError::Revoke(RequestTokenError::ServerResponse(_)) => {
164
                CommandErrorKind::Unauthenticated
165
            }
166
            _ => CommandErrorKind::Other,
167
        },
168
        _ => CommandErrorKind::Unauthenticated,
169
    }
170
}