diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2024-10-02 01:02:58 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2024-10-02 01:02:58 -0400 |
| commit | 5d3392799f88c5a3d3f9c656c73d6e8ac5c4d793 (patch) | |
| tree | 426c568d82b67a98095d25952d2b5b2345a6545b /src/repo | |
| parent | 357116366c1307bedaac6a3dfe9c5ed8e0e0c210 (diff) | |
Split login and token handling.
Diffstat (limited to 'src/repo')
| -rw-r--r-- | src/repo/login.rs | 50 | ||||
| -rw-r--r-- | src/repo/mod.rs | 2 | ||||
| -rw-r--r-- | src/repo/token.rs | 151 |
3 files changed, 0 insertions, 203 deletions
diff --git a/src/repo/login.rs b/src/repo/login.rs deleted file mode 100644 index d1a02c4..0000000 --- a/src/repo/login.rs +++ /dev/null @@ -1,50 +0,0 @@ -use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; - -use crate::login::{password::StoredHash, Id, Login}; - -pub trait Provider { - fn logins(&mut self) -> Logins; -} - -impl<'c> Provider for Transaction<'c, Sqlite> { - fn logins(&mut self) -> Logins { - Logins(self) - } -} - -pub struct Logins<'t>(&'t mut SqliteConnection); - -impl<'c> Logins<'c> { - pub async fn create( - &mut self, - name: &str, - password_hash: &StoredHash, - ) -> Result<Login, sqlx::Error> { - let id = Id::generate(); - - let login = sqlx::query_as!( - Login, - r#" - insert or fail - into login (id, name, password_hash) - values ($1, $2, $3) - returning - id as "id: Id", - name - "#, - id, - name, - password_hash, - ) - .fetch_one(&mut *self.0) - .await?; - - Ok(login) - } -} - -impl<'t> From<&'t mut SqliteConnection> for Logins<'t> { - fn from(tx: &'t mut SqliteConnection) -> Self { - Self(tx) - } -} diff --git a/src/repo/mod.rs b/src/repo/mod.rs index 69ad82c..7abd46b 100644 --- a/src/repo/mod.rs +++ b/src/repo/mod.rs @@ -1,6 +1,4 @@ pub mod channel; pub mod error; -pub mod login; pub mod pool; pub mod sequence; -pub mod token; diff --git a/src/repo/token.rs b/src/repo/token.rs deleted file mode 100644 index 5f64dac..0000000 --- a/src/repo/token.rs +++ /dev/null @@ -1,151 +0,0 @@ -use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; -use uuid::Uuid; - -use crate::{ - clock::DateTime, - login::{self, Login}, - token::{Id, Secret}, -}; - -pub trait Provider { - fn tokens(&mut self) -> Tokens; -} - -impl<'c> Provider for Transaction<'c, Sqlite> { - fn tokens(&mut self) -> Tokens { - Tokens(self) - } -} - -pub struct Tokens<'t>(&'t mut SqliteConnection); - -impl<'c> Tokens<'c> { - // Issue a new token for an existing login. The issued_at timestamp will - // be used to control expiry, until the token is actually used. - pub async fn issue( - &mut self, - login: &Login, - issued_at: &DateTime, - ) -> Result<Secret, sqlx::Error> { - let id = Id::generate(); - let secret = Uuid::new_v4().to_string(); - - let secret = sqlx::query_scalar!( - r#" - insert - into token (id, secret, login, issued_at, last_used_at) - values ($1, $2, $3, $4, $4) - returning secret as "secret!: Secret" - "#, - id, - secret, - login.id, - issued_at, - ) - .fetch_one(&mut *self.0) - .await?; - - Ok(secret) - } - - pub async fn require(&mut self, token: &Id) -> Result<(), sqlx::Error> { - sqlx::query_scalar!( - r#" - select id as "id: Id" - from token - where id = $1 - "#, - token, - ) - .fetch_one(&mut *self.0) - .await?; - - Ok(()) - } - - // Revoke a token by its secret. - pub async fn revoke(&mut self, token: &Id) -> Result<(), sqlx::Error> { - sqlx::query_scalar!( - r#" - delete - from token - where id = $1 - returning id as "id: Id" - "#, - token, - ) - .fetch_one(&mut *self.0) - .await?; - - Ok(()) - } - - // Expire and delete all tokens that haven't been used more recently than - // `expire_at`. - pub async fn expire(&mut self, expire_at: &DateTime) -> Result<Vec<Id>, sqlx::Error> { - let tokens = sqlx::query_scalar!( - r#" - delete - from token - where last_used_at < $1 - returning id as "id: Id" - "#, - expire_at, - ) - .fetch_all(&mut *self.0) - .await?; - - Ok(tokens) - } - - // Validate a token by its secret, retrieving the associated Login record. - // Will return [None] if the token is not valid. The token's last-used - // timestamp will be set to `used_at`. - pub async fn validate( - &mut self, - secret: &Secret, - used_at: &DateTime, - ) -> Result<(Id, Login), sqlx::Error> { - // I would use `update … returning` to do this in one query, but - // sqlite3, as of this writing, does not allow an update's `returning` - // clause to reference columns from tables joined into the update. Two - // queries is fine, but it feels untidy. - sqlx::query!( - r#" - update token - set last_used_at = $1 - where secret = $2 - "#, - used_at, - secret, - ) - .execute(&mut *self.0) - .await?; - - let login = sqlx::query!( - r#" - select - token.id as "token_id: Id", - login.id as "login_id: login::Id", - name as "login_name" - from login - join token on login.id = token.login - where token.secret = $1 - "#, - secret, - ) - .map(|row| { - ( - row.token_id, - Login { - id: row.login_id, - name: row.login_name, - }, - ) - }) - .fetch_one(&mut *self.0) - .await?; - - Ok(login) - } -} |
