diff options
Diffstat (limited to 'src/login/repo')
| -rw-r--r-- | src/login/repo/logins.rs | 27 | ||||
| -rw-r--r-- | src/login/repo/tokens.rs | 29 |
2 files changed, 43 insertions, 13 deletions
diff --git a/src/login/repo/logins.rs b/src/login/repo/logins.rs index c6db86e..84b4bf8 100644 --- a/src/login/repo/logins.rs +++ b/src/login/repo/logins.rs @@ -16,19 +16,17 @@ impl<'c> Provider for Transaction<'c, Sqlite> { } } +// This also implements FromRequestParts (see `src/login/extract/login.rs`). As +// a result, it can be used as an extractor. pub struct Logins<'t>(&'t mut SqliteConnection); #[derive(Debug)] pub struct Login { pub id: Id, - // Field unused (as of this writing), omitted to avoid warnings. - // Feel free to add it: - // - // pub name: String, - - // However, the omission of the hashed password is deliberate, to minimize - // the chance that it ends up tangled up in debug output or in some other - // chunk of logic elsewhere. + pub name: String, + // The omission of the hashed password is deliberate, to minimize the + // chance that it ends up tangled up in debug output or in some other chunk + // of logic elsewhere. } impl<'c> Logins<'c> { @@ -49,7 +47,7 @@ impl<'c> Logins<'c> { insert or fail into login (id, name, password_hash) values ($1, $2, $3) - returning id as "id: Id" + returning id as "id: Id", name "#, id, name, @@ -107,13 +105,22 @@ impl<'c> Logins<'c> { r#" select id as "id: Id", + name, password_hash as "password_hash: StoredHash" from login where name = $1 "#, name, ) - .map(|rec| (Login { id: rec.id }, rec.password_hash)) + .map(|rec| { + ( + Login { + id: rec.id, + name: rec.name, + }, + rec.password_hash, + ) + }) .fetch_optional(&mut *self.0) .await?; diff --git a/src/login/repo/tokens.rs b/src/login/repo/tokens.rs index e31a301..584f6dc 100644 --- a/src/login/repo/tokens.rs +++ b/src/login/repo/tokens.rs @@ -1,7 +1,7 @@ use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; use uuid::Uuid; -use super::logins::Id as LoginId; +use super::logins::{Id as LoginId, Login}; use crate::error::BoxedError; type DateTime = chrono::DateTime<chrono::Utc>; @@ -45,18 +45,41 @@ impl<'c> Tokens<'c> { Ok(secret) } - pub async fn revoke(&mut self, token: &str) -> Result<(), BoxedError> { + /// Revoke a token by its secret. If there is no such token with that + /// secret, this will succeed by doing nothing. + pub async fn revoke(&mut self, secret: &str) -> Result<(), BoxedError> { sqlx::query!( r#" delete from token where secret = $1 "#, - token, + secret, ) .execute(&mut *self.0) .await?; Ok(()) } + + /// Validate a token by its secret, retrieving the associated Login record. + /// Will return [None] if the token is not valid. + pub async fn validate(&mut self, secret: &str) -> Result<Option<Login>, BoxedError> { + let login = sqlx::query_as!( + Login, + r#" + select + login.id as "id: LoginId", + name + from login + join token on login.id = token.login + where token.secret = $1 + "#, + secret, + ) + .fetch_optional(&mut *self.0) + .await?; + + Ok(login) + } } |
