summaryrefslogtreecommitdiff
path: root/src/login/repo/tokens.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/login/repo/tokens.rs')
-rw-r--r--src/login/repo/tokens.rs125
1 files changed, 0 insertions, 125 deletions
diff --git a/src/login/repo/tokens.rs b/src/login/repo/tokens.rs
deleted file mode 100644
index ec95f6a..0000000
--- a/src/login/repo/tokens.rs
+++ /dev/null
@@ -1,125 +0,0 @@
-use chrono::TimeDelta;
-use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
-use uuid::Uuid;
-
-use super::logins::{Id as LoginId, Login};
-use crate::clock::DateTime;
-
-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: &LoginId,
- issued_at: DateTime,
- ) -> Result<String, sqlx::Error> {
- let secret = Uuid::new_v4().to_string();
-
- let secret = sqlx::query_scalar!(
- r#"
- insert
- into token (secret, login, issued_at, last_used_at)
- values ($1, $2, $3, $3)
- returning secret as "secret!"
- "#,
- secret,
- login,
- issued_at,
- )
- .fetch_one(&mut *self.0)
- .await?;
-
- Ok(secret)
- }
-
- /// Revoke a token by its secret.
- pub async fn revoke(&mut self, secret: &str) -> Result<(), sqlx::Error> {
- sqlx::query!(
- r#"
- delete
- from token
- where secret = $1
- returning 1 as "found: u32"
- "#,
- secret,
- )
- .fetch_one(&mut *self.0)
- .await?;
-
- Ok(())
- }
-
- /// Expire and delete all tokens that haven't been used within the expiry
- /// interval (right now, 7 days) prior to `expire_at`. Tokens that are in
- /// use within that period will be retained.
- pub async fn expire(&mut self, expire_at: DateTime) -> Result<(), sqlx::Error> {
- // Somewhat arbitrarily, expire after 7 days.
- let expired_issue_at = expire_at - TimeDelta::days(7);
- sqlx::query!(
- r#"
- delete
- from token
- where last_used_at < $1
- "#,
- expired_issue_at,
- )
- .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. The token's last-used
- /// timestamp will be set to `used_at`.
- pub async fn validate(
- &mut self,
- secret: &str,
- used_at: DateTime,
- ) -> Result<Option<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_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)
- }
-}