diff options
Diffstat (limited to 'src/login/app.rs')
| -rw-r--r-- | src/login/app.rs | 85 |
1 files changed, 49 insertions, 36 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), } |
