1use crate::api::{HumanVerification, ResponseCode};
4
5pub type Result<T> = std::result::Result<T, ProtonError>;
6
7#[derive(Debug, thiserror::Error)]
9pub enum ProtonError {
10 #[error(transparent)]
12 Api(#[from] ProtonApiError),
13
14 #[error("HTTP transport error: {0}")]
16 Transport(#[from] reqwest::Error),
17
18 #[error("serialization error: {0}")]
20 Serialization(#[from] serde_json::Error),
21
22 #[error("cryptography error: {0}")]
24 Crypto(#[from] crate::crypto::CryptoError),
25
26 #[error("invalid operation: {0}")]
28 InvalidOperation(String),
29}
30
31impl ProtonError {
32 pub fn invalid_operation(message: impl Into<String>) -> Self {
33 Self::InvalidOperation(message.into())
34 }
35}
36
37#[derive(Debug, Clone, thiserror::Error)]
39#[error("proton api error {code:?} (http {http_status}): {message}")]
40pub struct ProtonApiError {
41 pub code: ResponseCode,
43 pub http_status: u16,
45 pub message: String,
47 pub details: Option<serde_json::Value>,
50}
51
52impl ProtonApiError {
53 pub fn is_unauthorized(&self) -> bool {
54 self.http_status == 401
55 }
56
57 pub fn is_invalid_refresh_token(&self) -> bool {
58 matches!(self.code, ResponseCode::InvalidRefreshToken)
59 }
60
61 pub fn is_insufficient_scope(&self) -> bool {
64 matches!(self.code, ResponseCode::InsufficientScope)
65 }
66
67 pub fn is_human_verification_required(&self) -> bool {
69 matches!(self.code, ResponseCode::HumanVerificationRequired)
70 }
71
72 pub fn human_verification(&self) -> Option<HumanVerification> {
78 if !self.is_human_verification_required() {
79 return None;
80 }
81 serde_json::from_value(self.details.clone()?).ok()
82 }
83}