230 lines
7.7 KiB
Rust
230 lines
7.7 KiB
Rust
// Copyright 2020 The Matrix.org Foundation C.I.C.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Error conditions.
|
|
|
|
use std::io::Error as IoError;
|
|
|
|
use http::StatusCode;
|
|
#[cfg(feature = "encryption")]
|
|
use matrix_sdk_base::crypto::{
|
|
CryptoStoreError, DecryptorError, KeyExportError, MegolmError, OlmError,
|
|
};
|
|
use matrix_sdk_base::{Error as SdkBaseError, StoreError};
|
|
use reqwest::Error as ReqwestError;
|
|
use ruma::{
|
|
api::{
|
|
client::{
|
|
r0::uiaa::{UiaaInfo, UiaaResponse as UiaaError},
|
|
Error as RumaClientApiError,
|
|
},
|
|
error::{FromHttpResponseError, IntoHttpError, MatrixError as RumaApiError, ServerError},
|
|
},
|
|
identifiers::Error as IdentifierError,
|
|
};
|
|
use serde_json::Error as JsonError;
|
|
use thiserror::Error;
|
|
use url::ParseError as UrlParseError;
|
|
|
|
/// Result type of the rust-sdk.
|
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
|
|
/// An HTTP error, representing either a connection error or an error while
|
|
/// converting the raw HTTP response into a Matrix response.
|
|
#[derive(Error, Debug)]
|
|
pub enum HttpError {
|
|
/// An error at the HTTP layer.
|
|
#[error(transparent)]
|
|
Reqwest(#[from] ReqwestError),
|
|
|
|
/// Queried endpoint requires authentication but was called on an anonymous
|
|
/// client.
|
|
#[error("the queried endpoint requires authentication but was called before logging in")]
|
|
AuthenticationRequired,
|
|
|
|
/// Client tried to force authentication but did not provide an access
|
|
/// token.
|
|
#[error("tried to force authentication but no access token was provided")]
|
|
ForcedAuthenticationWithoutAccessToken,
|
|
|
|
/// Queried endpoint is not meant for clients.
|
|
#[error("the queried endpoint is not meant for clients")]
|
|
NotClientRequest,
|
|
|
|
/// An error converting between ruma_*_api types and Hyper types.
|
|
#[error(transparent)]
|
|
Api(#[from] FromHttpResponseError<RumaApiError>),
|
|
|
|
/// An error converting between ruma_client_api types and Hyper types.
|
|
#[error(transparent)]
|
|
ClientApi(#[from] FromHttpResponseError<RumaClientApiError>),
|
|
|
|
/// An error converting between ruma_client_api types and Hyper types.
|
|
#[error(transparent)]
|
|
IntoHttp(#[from] IntoHttpError),
|
|
|
|
/// An error occurred while authenticating.
|
|
///
|
|
/// When registering or authenticating the Matrix server can send a
|
|
/// `UiaaResponse` as the error type, this is a User-Interactive
|
|
/// Authentication API response. This represents an error with
|
|
/// information about how to authenticate the user.
|
|
#[error(transparent)]
|
|
UiaaError(#[from] FromHttpResponseError<UiaaError>),
|
|
|
|
/// The server returned a status code that should be retried.
|
|
#[error("Server returned an error {0}")]
|
|
Server(StatusCode),
|
|
|
|
/// The given request can't be cloned and thus can't be retried.
|
|
#[error("The request cannot be cloned")]
|
|
UnableToCloneRequest,
|
|
|
|
/// Tried to send a request without `user_id` in the `Session`
|
|
#[error("missing user_id in session")]
|
|
UserIdRequired,
|
|
}
|
|
|
|
/// Internal representation of errors.
|
|
#[derive(Error, Debug)]
|
|
pub enum Error {
|
|
/// Error doing an HTTP request.
|
|
#[error(transparent)]
|
|
Http(#[from] HttpError),
|
|
|
|
/// Queried endpoint requires authentication but was called on an anonymous
|
|
/// client.
|
|
#[error("the queried endpoint requires authentication but was called before logging in")]
|
|
AuthenticationRequired,
|
|
|
|
/// An error de/serializing type for the `StateStore`
|
|
#[error(transparent)]
|
|
SerdeJson(#[from] JsonError),
|
|
|
|
/// An IO error happened.
|
|
#[error(transparent)]
|
|
Io(#[from] IoError),
|
|
|
|
/// An error occurred in the crypto store.
|
|
#[cfg(feature = "encryption")]
|
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
|
#[error(transparent)]
|
|
CryptoStoreError(#[from] CryptoStoreError),
|
|
|
|
/// An error occurred during a E2EE operation.
|
|
#[cfg(feature = "encryption")]
|
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
|
#[error(transparent)]
|
|
OlmError(#[from] OlmError),
|
|
|
|
/// An error occurred during a E2EE group operation.
|
|
#[cfg(feature = "encryption")]
|
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
|
#[error(transparent)]
|
|
MegolmError(#[from] MegolmError),
|
|
|
|
/// An error occurred during decryption.
|
|
#[cfg(feature = "encryption")]
|
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
|
#[error(transparent)]
|
|
DecryptorError(#[from] DecryptorError),
|
|
|
|
/// An error occurred in the state store.
|
|
#[error(transparent)]
|
|
StateStore(#[from] StoreError),
|
|
|
|
/// An error encountered when trying to parse an identifier.
|
|
#[error(transparent)]
|
|
Identifier(#[from] IdentifierError),
|
|
|
|
/// An error encountered when trying to parse a url.
|
|
#[error(transparent)]
|
|
Url(#[from] UrlParseError),
|
|
}
|
|
|
|
/// Error for the room key importing functionality.
|
|
#[cfg(feature = "encryption")]
|
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
|
#[derive(Error, Debug)]
|
|
// This is allowed because key importing isn't enabled under wasm.
|
|
#[allow(dead_code)]
|
|
pub enum RoomKeyImportError {
|
|
/// An error de/serializing type for the `StateStore`
|
|
#[error(transparent)]
|
|
SerdeJson(#[from] JsonError),
|
|
|
|
/// The cryptostore isn't yet open, logging in is required to open the
|
|
/// cryptostore.
|
|
#[error("The cryptostore hasn't been yet opened, can't import yet.")]
|
|
StoreClosed,
|
|
|
|
/// An IO error happened.
|
|
#[error(transparent)]
|
|
Io(#[from] IoError),
|
|
|
|
/// An error occurred in the crypto store.
|
|
#[error(transparent)]
|
|
CryptoStore(#[from] CryptoStoreError),
|
|
|
|
/// An error occurred while importing the key export.
|
|
#[error(transparent)]
|
|
Export(#[from] KeyExportError),
|
|
}
|
|
|
|
impl Error {
|
|
/// Try to destructure the error into an universal interactive auth info.
|
|
///
|
|
/// Some requests require universal interactive auth, doing such a request
|
|
/// will always fail the first time with a 401 status code, the response
|
|
/// body will contain info how the client can authenticate.
|
|
///
|
|
/// The request will need to be retried, this time containing additional
|
|
/// authentication data.
|
|
///
|
|
/// This method is an convenience method to get to the info the server
|
|
/// returned on the first, failed request.
|
|
pub fn uiaa_response(&self) -> Option<&UiaaInfo> {
|
|
if let Error::Http(HttpError::UiaaError(FromHttpResponseError::Http(ServerError::Known(
|
|
UiaaError::AuthResponse(i),
|
|
)))) = self
|
|
{
|
|
Some(i)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<SdkBaseError> for Error {
|
|
fn from(e: SdkBaseError) -> Self {
|
|
match e {
|
|
SdkBaseError::AuthenticationRequired => Self::AuthenticationRequired,
|
|
SdkBaseError::StateStore(e) => Self::StateStore(e),
|
|
SdkBaseError::SerdeJson(e) => Self::SerdeJson(e),
|
|
SdkBaseError::IoError(e) => Self::Io(e),
|
|
#[cfg(feature = "encryption")]
|
|
SdkBaseError::CryptoStore(e) => Self::CryptoStoreError(e),
|
|
#[cfg(feature = "encryption")]
|
|
SdkBaseError::OlmError(e) => Self::OlmError(e),
|
|
#[cfg(feature = "encryption")]
|
|
SdkBaseError::MegolmError(e) => Self::MegolmError(e),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<ReqwestError> for Error {
|
|
fn from(e: ReqwestError) -> Self {
|
|
Error::Http(HttpError::Reqwest(e))
|
|
}
|
|
}
|