diff options
Diffstat (limited to 'src/login')
| -rw-r--r-- | src/login/app.rs | 85 | ||||
| -rw-r--r-- | src/login/handlers/login/mod.rs | 2 | ||||
| -rw-r--r-- | src/login/handlers/logout/mod.rs | 4 | ||||
| -rw-r--r-- | src/login/handlers/password/mod.rs | 2 |
4 files changed, 52 insertions, 41 deletions
diff --git a/src/login/app.rs b/src/login/app.rs index 8cc8cd0..5c012c4 100644 --- a/src/login/app.rs +++ b/src/login/app.rs @@ -2,9 +2,11 @@ use sqlx::sqlite::SqlitePool; use crate::{ clock::DateTime, + db, db::NotFound as _, - login::{self, Login, repo::Provider as _}, - name::{self, Name}, + error::failed::{Failed, ResultExt as _}, + login::{Login, repo::Provider as _}, + name::Name, password::Password, push::repo::Provider as _, token::{Broadcaster, Event as TokenEvent, Secret, Token, repo::Provider as _}, @@ -26,24 +28,32 @@ impl Logins { candidate: &Password, login_at: &DateTime, ) -> Result<Secret, LoginError> { - let mut tx = self.db.begin().await?; + let mut tx = self.db.begin().await.fail(db::failed::BEGIN)?; let (login, password) = tx .logins() .by_name(name) .await - .not_found(|| LoginError::Rejected)?; + .optional() + .fail("Failed to load login")? + .ok_or_else(|| LoginError::Rejected)?; // Split the transaction here to avoid holding the tx open (potentially blocking // other writes) while we do the fairly expensive task of verifying the // password. It's okay if the token issuance transaction happens some notional // amount of time after retrieving the login, as inserting the token will fail // if the account is deleted during that time. - tx.commit().await?; + tx.commit().await.fail(db::failed::COMMIT)?; - if password.verify(candidate)? { - let mut tx = self.db.begin().await?; + if password + .verify(candidate) + .fail("Failed to verify password")? + { + let mut tx = self.db.begin().await.fail(db::failed::BEGIN)?; let (token, secret) = Token::generate(&login, login_at); - tx.tokens().create(&token, &secret).await?; - tx.commit().await?; + tx.tokens() + .create(&token, &secret) + .await + .fail("Failed to create token")?; + tx.commit().await.fail(db::failed::COMMIT)?; Ok(secret) } else { Err(LoginError::Rejected) @@ -57,30 +67,47 @@ impl Logins { to: &Password, changed_at: &DateTime, ) -> Result<Secret, LoginError> { - let mut tx = self.db.begin().await?; + let mut tx = self.db.begin().await.fail(db::failed::BEGIN)?; let (login, password) = tx .logins() .by_id(&login.id) .await - .not_found(|| LoginError::Rejected)?; + .optional() + .fail("Failed to load login")? + .ok_or_else(|| LoginError::Rejected)?; // Split the transaction here to avoid holding the tx open (potentially blocking // other writes) while we do the fairly expensive task of verifying the // password. It's okay if the token issuance transaction happens some notional // amount of time after retrieving the login, as inserting the token will fail // if the account is deleted during that time. - tx.commit().await?; + tx.commit().await.fail(db::failed::COMMIT)?; - if password.verify(from)? { - let to_hash = to.hash()?; + if password + .verify(from) + .fail("Failed to verify current password")? + { + let to_hash = to.hash().fail("Failed to digest new password")?; let (token, secret) = Token::generate(&login, changed_at); - let mut tx = self.db.begin().await?; - tx.logins().set_password(&login, &to_hash).await?; - - tx.push().unsubscribe_login(&login).await?; - let revoked = tx.tokens().revoke_all(&login).await?; - tx.tokens().create(&token, &secret).await?; - tx.commit().await?; + let mut tx = self.db.begin().await.fail(db::failed::BEGIN)?; + tx.logins() + .set_password(&login, &to_hash) + .await + .fail("Failed to store new password")?; + tx.push() + .unsubscribe_login(&login) + .await + .fail("Failed to remove push notification subscriptions")?; + let revoked = tx + .tokens() + .revoke_all(&login) + .await + .fail("Failed to revoke existing tokens")?; + tx.tokens() + .create(&token, &secret) + .await + .fail("Failed to create new token")?; + tx.commit().await.fail(db::failed::COMMIT)?; revoked .into_iter() @@ -99,19 +126,5 @@ pub enum LoginError { #[error("invalid login")] Rejected, #[error(transparent)] - Database(#[from] sqlx::Error), - #[error(transparent)] - Name(#[from] name::Error), - #[error(transparent)] - PasswordHash(#[from] password_hash::Error), -} - -impl From<login::repo::LoadError> for LoginError { - fn from(error: login::repo::LoadError) -> Self { - use login::repo::LoadError; - match error { - LoadError::Database(error) => error.into(), - LoadError::Name(error) => error.into(), - } - } + Failed(#[from] Failed), } diff --git a/src/login/handlers/login/mod.rs b/src/login/handlers/login/mod.rs index 2ce8a67..d42cff5 100644 --- a/src/login/handlers/login/mod.rs +++ b/src/login/handlers/login/mod.rs @@ -49,7 +49,7 @@ impl IntoResponse for Error { // not error::Unauthorized due to differing messaging (StatusCode::UNAUTHORIZED, "invalid name or password").into_response() } - other => Internal::from(other).into_response(), + app::LoginError::Failed(_) => Internal::from(error).into_response(), } } } diff --git a/src/login/handlers/logout/mod.rs b/src/login/handlers/logout/mod.rs index ce4cb1a..4bd7a89 100644 --- a/src/login/handlers/logout/mod.rs +++ b/src/login/handlers/logout/mod.rs @@ -42,9 +42,7 @@ impl IntoResponse for Error { let Self(error) = self; match error { app::ValidateError::InvalidToken => Unauthorized.into_response(), - app::ValidateError::Name(_) | app::ValidateError::Database(_) => { - Internal::from(error).into_response() - } + app::ValidateError::Failed(_) => Internal::from(error).into_response(), } } } diff --git a/src/login/handlers/password/mod.rs b/src/login/handlers/password/mod.rs index 8b82605..7eed24a 100644 --- a/src/login/handlers/password/mod.rs +++ b/src/login/handlers/password/mod.rs @@ -48,7 +48,7 @@ impl IntoResponse for Error { app::LoginError::Rejected => { (StatusCode::BAD_REQUEST, "invalid name or password").into_response() } - other => Internal::from(other).into_response(), + app::LoginError::Failed(_) => Internal::from(error).into_response(), } } } |
