diff --git a/actix-identity/Cargo.toml b/actix-identity/Cargo.toml index 468159170..4afa8659d 100644 --- a/actix-identity/Cargo.toml +++ b/actix-identity/Cargo.toml @@ -22,6 +22,7 @@ actix-session = "0.7" actix-utils = "3" actix-web = { version = "4", default-features = false, features = ["cookies", "secure-cookies"] } +derive_more = "0.99.7" futures-core = "0.3.7" serde = { version = "1", features = ["derive"] } tracing = { version = "0.1.30", default-features = false, features = ["log"] } diff --git a/actix-identity/src/error.rs b/actix-identity/src/error.rs index b701db900..2db521f92 100644 --- a/actix-identity/src/error.rs +++ b/actix-identity/src/error.rs @@ -1,156 +1,70 @@ //! Failure modes of identity operations. -use std::fmt; - use actix_session::{SessionGetError, SessionInsertError}; use actix_web::{cookie::time::error::ComponentRange, http::StatusCode, ResponseError}; +use derive_more::{Display, Error, From}; /// Error that can occur during login attempts. -#[derive(Debug)] +#[derive(Debug, Display, Error, From)] +#[display(fmt = "{_0}")] pub struct LoginError(SessionInsertError); -impl fmt::Display for LoginError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl std::error::Error for LoginError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - Some(&self.0) - } -} - impl ResponseError for LoginError { fn status_code(&self) -> StatusCode { StatusCode::UNAUTHORIZED } } -impl From for LoginError { - fn from(error: SessionInsertError) -> Self { - Self(error) - } -} - /// Error encountered when working with a session that has expired. -#[derive(Debug)] -pub struct SessionExpiryError(ComponentRange); - -impl fmt::Display for SessionExpiryError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("The given session has expired and is no longer valid") - } -} - -impl std::error::Error for SessionExpiryError {} +#[derive(Debug, Display, Error)] +#[display(fmt = "The given session has expired and is no longer valid")] +pub struct SessionExpiryError(#[error(not(source))] pub(crate) ComponentRange); /// The identity information has been lost. /// /// Seeing this error in user code indicates a bug in actix-identity. -#[derive(Debug)] +#[derive(Debug, Display, Error)] +#[display( + fmt = "The identity information in the current session has disappeared after having been \ + successfully validated. This is likely to be a bug." +)] #[non_exhaustive] pub struct LostIdentityError; -impl fmt::Display for LostIdentityError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str( - "The identity information in the current session has disappeared \ - after having been successfully validated. This is likely to be a bug.", - ) - } -} - -impl std::error::Error for LostIdentityError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - Some(self) - } -} - /// There is no identity information attached to the current session. -#[derive(Debug)] +#[derive(Debug, Display, Error)] +#[display(fmt = "There is no identity information attached to the current session")] #[non_exhaustive] pub struct MissingIdentityError; -impl fmt::Display for MissingIdentityError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("There is no identity information attached to the current session.") - } -} - -impl std::error::Error for MissingIdentityError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - Some(self) - } -} - /// Errors that can occur while retrieving an identity. -#[derive(Debug)] +#[derive(Debug, Display, Error, From)] #[non_exhaustive] pub enum GetIdentityError { /// The session has expired. + #[display(fmt = "{_0}")] SessionExpiryError(SessionExpiryError), /// No identity is found in a session. + #[display(fmt = "{_0}")] MissingIdentityError(MissingIdentityError), /// Failed to accessing the session store. + #[display(fmt = "{_0}")] SessionGetError(SessionGetError), /// Identity info was lost after being validated. /// /// Seeing this error indicates a bug in actix-identity. + #[display(fmt = "{_0}")] LostIdentityError(LostIdentityError), } -impl fmt::Display for GetIdentityError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::SessionExpiryError(err) => write!(f, "{err}"), - Self::MissingIdentityError(err) => write!(f, "{err}"), - Self::SessionGetError(err) => write!(f, "{err}"), - Self::LostIdentityError(err) => write!(f, "{err}"), - } - } -} - -impl std::error::Error for GetIdentityError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::SessionExpiryError(err) => Some(err), - Self::MissingIdentityError(err) => Some(err), - Self::SessionGetError(err) => Some(err), - Self::LostIdentityError(err) => Some(err), - } - } -} - impl ResponseError for GetIdentityError { fn status_code(&self) -> StatusCode { - StatusCode::UNAUTHORIZED - } -} - -impl From for GetIdentityError { - fn from(error: LostIdentityError) -> Self { - Self::LostIdentityError(error) - } -} - -impl From for GetIdentityError { - fn from(error: MissingIdentityError) -> Self { - Self::MissingIdentityError(error) - } -} - -impl From for GetIdentityError { - fn from(error: ComponentRange) -> Self { - Self::SessionExpiryError(SessionExpiryError(error)) - } -} - -impl From for GetIdentityError { - fn from(source: SessionGetError) -> Self { - Self::SessionGetError(source) + match self { + Self::LostIdentityError(_) => StatusCode::INTERNAL_SERVER_ERROR, + _ => StatusCode::UNAUTHORIZED, + } } } diff --git a/actix-identity/src/identity.rs b/actix-identity/src/identity.rs index a991e646f..9a75ede72 100644 --- a/actix-identity/src/identity.rs +++ b/actix-identity/src/identity.rs @@ -9,7 +9,9 @@ use actix_web::{ use crate::{ config::LogoutBehaviour, - error::{GetIdentityError, LoginError, LostIdentityError, MissingIdentityError}, + error::{ + GetIdentityError, LoginError, LostIdentityError, MissingIdentityError, SessionExpiryError, + }, }; /// A verified user identity. It can be used as a request extractor. @@ -212,7 +214,8 @@ impl Identity { .session .get(LOGIN_UNIX_TIMESTAMP_KEY)? .map(OffsetDateTime::from_unix_timestamp) - .transpose()?) + .transpose() + .map_err(SessionExpiryError)?) } pub(crate) fn last_visited_at(&self) -> Result, GetIdentityError> { @@ -221,7 +224,8 @@ impl Identity { .session .get(LAST_VISIT_UNIX_TIMESTAMP_KEY)? .map(OffsetDateTime::from_unix_timestamp) - .transpose()?) + .transpose() + .map_err(SessionExpiryError)?) } pub(crate) fn set_last_visited_at(&self) -> Result<(), LoginError> {