summaryrefslogtreecommitdiff
path: root/src/login/app.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/login/app.rs')
-rw-r--r--src/login/app.rs85
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),
}