diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2024-09-03 01:25:20 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2024-09-03 02:09:25 -0400 |
| commit | b404344a7c4ab5cb6c7d7b445fab796be79b848f (patch) | |
| tree | c476b125316b9d4aa7bdece7c9bb8e2f65d2961e /src/login/repo/tokens.rs | |
| parent | 92a7518975c6bc4b2f9b9c6c12c458b24e8cfaf5 (diff) | |
Allow login creation and authentication.
This is a beefy change, as it adds a TON of smaller pieces needed to make this all function:
* A database migration.
* A ton of new crates for things like password validation, timekeeping, and HTML generation.
* A first cut at a module structure for routes, templates, repositories.
* A family of ID types, for identifying various kinds of domain thing.
* AppError, which _doesn't_ implement Error but can be sent to clients.
Diffstat (limited to 'src/login/repo/tokens.rs')
| -rw-r--r-- | src/login/repo/tokens.rs | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/src/login/repo/tokens.rs b/src/login/repo/tokens.rs new file mode 100644 index 0000000..080e35a --- /dev/null +++ b/src/login/repo/tokens.rs @@ -0,0 +1,47 @@ +use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; +use uuid::Uuid; + +use super::logins::Id as LoginId; +use crate::error::BoxedError; + +type DateTime = chrono::DateTime<chrono::Utc>; + +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. + pub async fn issue( + &mut self, + login: &LoginId, + issued_at: DateTime, + ) -> Result<String, BoxedError> { + let secret = Uuid::new_v4().to_string(); + + let secret = sqlx::query_scalar!( + r#" + insert + into token (secret, login, issued_at) + values ($1, $2, $3) + returning secret as "secret!" + "#, + secret, + login, + issued_at, + ) + .fetch_one(&mut *self.0) + .await?; + + Ok(secret) + } +} |
