sos_net/
error.rs

1//! Error type for network accounts.
2use sos_core::{AuthenticationError, Origin};
3use sos_core::{ErrorExt, VaultId};
4use sos_protocol::{transfer::CancelReason, AsConflict, ConflictError};
5use std::error::Error as StdError;
6use std::path::PathBuf;
7use thiserror::Error;
8
9/// Errors generated by the client module.
10#[derive(Debug, Error)]
11pub enum Error {
12    /// Error generated when a path is not a directory.
13    #[error("path {0} is not a directory")]
14    NotDirectory(PathBuf),
15
16    /// Error generated when a path is not a file.
17    #[error("path {0} is not a file")]
18    NotFile(PathBuf),
19
20    /// Error generated when a file already exists.
21    #[error("file {0} already exists")]
22    FileExists(PathBuf),
23
24    /// Error generated when a folder already exists.
25    #[error("folder {0} already exists")]
26    FolderExists(VaultId),
27
28    /// Error generated when a return value is expected from a RPC call
29    /// but the response did not have a result.
30    #[error("method did not return a value")]
31    NoReturnValue,
32
33    /// Error generated when a remote origin could not be found.
34    #[error("origin '{0}' not found")]
35    OriginNotFound(Origin),
36
37    /// Error generated attempting to revoke the current device.
38    #[error("cannot revoke access to this device")]
39    RevokeDeviceSelf,
40
41    /// Error generated when failing to sync after revoking a device.
42    #[error("failed to sync after revoking device, {0}")]
43    RevokeDeviceSync(Box<Error>),
44
45    /// Error generated force update of an account failed.
46    #[error("failed to force update, {0}")]
47    ForceUpdate(Box<Error>),
48
49    /// Error generated trying to parse a device enrollment sharing URL.
50    #[deprecated]
51    #[error("invalid share url for device enrollment")]
52    InvalidShareUrl,
53
54    /// Error generated when a conflict is detected.
55    #[error(transparent)]
56    Conflict(#[from] ConflictError),
57
58    /// Error generated parsing to an integer.
59    #[error(transparent)]
60    ParseInt(#[from] std::num::ParseIntError),
61
62    /// Error generated by the io module.
63    #[error(transparent)]
64    Io(#[from] std::io::Error),
65
66    /// Error generated by the JSON library.
67    #[error(transparent)]
68    Json(#[from] serde_json::Error),
69
70    /// Error generated attempting to convert from a slice.
71    #[error(transparent)]
72    TryFromSlice(#[from] std::array::TryFromSliceError),
73
74    /// Error generated by the core library.
75    #[error(transparent)]
76    Core(#[from] sos_core::Error),
77
78    /// Authentication errors.
79    #[error(transparent)]
80    Authentication(#[from] sos_core::AuthenticationError),
81
82    /// Error generated by the backend library.
83    #[error(transparent)]
84    Backend(#[from] sos_backend::Error),
85
86    /// Error generated by the search library.
87    #[cfg(feature = "search")]
88    #[error(transparent)]
89    Search(#[from] sos_search::Error),
90
91    /// Error generated by the vault library.
92    #[error(transparent)]
93    Vault(#[from] sos_vault::Error),
94
95    /// Error generated by the signer library.
96    #[error(transparent)]
97    Signer(#[from] sos_signer::Error),
98
99    /// Error generated by the sync library.
100    #[error(transparent)]
101    Sync(#[from] sos_sync::Error),
102
103    /// Error generated by the storage library.
104    #[error(transparent)]
105    Storage(#[from] sos_client_storage::Error),
106
107    /// Error generated by the password library.
108    #[error(transparent)]
109    Password(#[from] sos_password::Error),
110
111    /// Error generated by the login library.
112    #[error(transparent)]
113    Login(#[from] sos_login::Error),
114
115    /// Error generated by the backend storage.
116    #[error(transparent)]
117    BackendStorage(#[from] sos_backend::StorageError),
118
119    /// Error generated by the database library.
120    #[error(transparent)]
121    Database(#[from] sos_database::Error),
122
123    /// Error generated by the account library.
124    #[error(transparent)]
125    Account(#[from] sos_account::Error),
126
127    /// Error generated attempting to parse a URL.
128    #[error(transparent)]
129    UrlParse(#[from] url::ParseError),
130
131    /// Error generated attempting to convert to a UTF-8 string.
132    #[error(transparent)]
133    Utf8(#[from] std::str::Utf8Error),
134
135    /// Error generated converting an HTTP status code.
136    #[error(transparent)]
137    HttpStatus(#[from] http::status::InvalidStatusCode),
138
139    /// Error generated when converting to a UUID.
140    #[error(transparent)]
141    Uuid(#[from] uuid::Error),
142
143    /// Error generated when parsing from hex.
144    #[error(transparent)]
145    Hex(#[from] hex::FromHexError),
146
147    /// Error generated by the wire protocol library.
148    #[error(transparent)]
149    Protocol(#[from] sos_protocol::Error),
150
151    /// Error generated by the remote sync library.
152    #[error(transparent)]
153    RemoteSync(#[from] sos_remote_sync::Error),
154
155    /// Error generated by the migrate library.
156    #[error(transparent)]
157    #[cfg(feature = "migrate")]
158    Migrate(#[from] sos_migrate::Error),
159
160    /// Error generated by network communication.
161    #[error(transparent)]
162    Network(#[from] sos_protocol::NetworkError),
163}
164
165impl ErrorExt for Error {
166    fn is_secret_not_found(&self) -> bool {
167        matches!(
168            self,
169            Error::Account(sos_account::Error::Storage(
170                sos_client_storage::Error::SecretNotFound(_)
171            ))
172        )
173    }
174
175    fn is_forbidden(&self) -> bool {
176        matches!(
177            self,
178            Error::Account(sos_account::Error::Authentication(
179                AuthenticationError::NotAuthenticated
180            )) | Error::Account(sos_account::Error::Storage(
181                sos_client_storage::Error::Authentication(
182                    AuthenticationError::NotAuthenticated
183                )
184            ))
185        )
186    }
187
188    fn is_permission_denied(&self) -> bool {
189        matches!(
190            self,
191            Error::Vault(sos_vault::Error::Authentication(
192                AuthenticationError::PasswordVerification
193            ))
194        )
195    }
196}
197
198impl Error {
199    /// Determine if this is a canceled error and
200    /// whether the cancellation was triggered by the user.
201    pub fn cancellation_reason(&self) -> Option<&CancelReason> {
202        let source = source_error(self);
203        if let Some(err) = source.downcast_ref::<Error>() {
204            if let Error::Protocol(sos_protocol::Error::TransferCanceled(
205                reason,
206            )) = err
207            {
208                Some(reason)
209            } else {
210                None
211            }
212        } else {
213            None
214        }
215    }
216}
217
218pub(crate) fn source_error<'a>(
219    error: &'a (dyn StdError + 'static),
220) -> &'a (dyn StdError + 'static) {
221    let mut source = error;
222    while let Some(next_source) = source.source() {
223        source = next_source;
224    }
225    source
226}
227
228impl AsConflict for Error {
229    fn is_conflict(&self) -> bool {
230        matches!(self, Error::Conflict(_))
231    }
232
233    fn is_hard_conflict(&self) -> bool {
234        matches!(self, Error::Conflict(ConflictError::Hard))
235    }
236
237    fn take_conflict(self) -> Option<ConflictError> {
238        match self {
239            Self::Conflict(err) => Some(err),
240            _ => None,
241        }
242    }
243}