summaryrefslogtreecommitdiff
path: root/src/token/repo
diff options
context:
space:
mode:
Diffstat (limited to 'src/token/repo')
-rw-r--r--src/token/repo/auth.rs103
-rw-r--r--src/token/repo/mod.rs1
-rw-r--r--src/token/repo/token.rs97
3 files changed, 40 insertions, 161 deletions
diff --git a/src/token/repo/auth.rs b/src/token/repo/auth.rs
deleted file mode 100644
index 600855d..0000000
--- a/src/token/repo/auth.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
-
-use crate::{
- clock::DateTime,
- db::NotFound,
- event::{Instant, Sequence},
- name::{self, Name},
- password::StoredHash,
- user::{self, History, User},
-};
-
-pub trait Provider {
- fn auth(&mut self) -> Auth<'_>;
-}
-
-impl Provider for Transaction<'_, Sqlite> {
- fn auth(&mut self) -> Auth<'_> {
- Auth(self)
- }
-}
-
-pub struct Auth<'t>(&'t mut SqliteConnection);
-
-impl Auth<'_> {
- pub async fn for_name(&mut self, name: &Name) -> Result<(History, StoredHash), LoadError> {
- let name = name.canonical();
- let row = sqlx::query!(
- r#"
- select
- id as "id: user::Id",
- display_name as "display_name: String",
- canonical_name as "canonical_name: String",
- created_sequence as "created_sequence: Sequence",
- created_at as "created_at: DateTime",
- password_hash as "password_hash: StoredHash"
- from user
- where canonical_name = $1
- "#,
- name,
- )
- .fetch_one(&mut *self.0)
- .await?;
-
- let login = History {
- user: User {
- id: row.id,
- name: Name::new(row.display_name, row.canonical_name)?,
- },
- created: Instant::new(row.created_at, row.created_sequence),
- };
-
- Ok((login, row.password_hash))
- }
-
- pub async fn for_user(&mut self, user: &User) -> Result<(History, StoredHash), LoadError> {
- let row = sqlx::query!(
- r#"
- select
- id as "id: user::Id",
- display_name as "display_name: String",
- canonical_name as "canonical_name: String",
- created_sequence as "created_sequence: Sequence",
- created_at as "created_at: DateTime",
- password_hash as "password_hash: StoredHash"
- from user
- where id = $1
- "#,
- user.id,
- )
- .fetch_one(&mut *self.0)
- .await?;
-
- let user = History {
- user: User {
- id: row.id,
- name: Name::new(row.display_name, row.canonical_name)?,
- },
- created: Instant::new(row.created_at, row.created_sequence),
- };
-
- Ok((user, row.password_hash))
- }
-}
-
-#[derive(Debug, thiserror::Error)]
-#[error(transparent)]
-pub enum LoadError {
- Database(#[from] sqlx::Error),
- Name(#[from] name::Error),
-}
-
-impl<T> NotFound for Result<T, LoadError> {
- type Ok = T;
- type Error = LoadError;
-
- fn optional(self) -> Result<Option<T>, LoadError> {
- match self {
- Ok(value) => Ok(Some(value)),
- Err(LoadError::Database(sqlx::Error::RowNotFound)) => Ok(None),
- Err(other) => Err(other),
- }
- }
-}
diff --git a/src/token/repo/mod.rs b/src/token/repo/mod.rs
index d8463eb..9df5bbb 100644
--- a/src/token/repo/mod.rs
+++ b/src/token/repo/mod.rs
@@ -1,4 +1,3 @@
-pub mod auth;
mod token;
pub use self::token::{LoadError, Provider};
diff --git a/src/token/repo/token.rs b/src/token/repo/token.rs
index 7ac4ac5..52a3987 100644
--- a/src/token/repo/token.rs
+++ b/src/token/repo/token.rs
@@ -1,13 +1,11 @@
use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
-use uuid::Uuid;
use crate::{
clock::DateTime,
db::NotFound,
- event::{Instant, Sequence},
+ login::{self, Login},
name::{self, Name},
- token::{Id, Secret},
- user::{self, History, User},
+ token::{Id, Secret, Token},
};
pub trait Provider {
@@ -23,33 +21,23 @@ impl Provider for Transaction<'_, Sqlite> {
pub struct Tokens<'t>(&'t mut SqliteConnection);
impl Tokens<'_> {
- // Issue a new token for an existing user. The issued_at timestamp will
- // determine the token's initial expiry deadline.
- pub async fn issue(
- &mut self,
- user: &History,
- issued_at: &DateTime,
- ) -> Result<Secret, sqlx::Error> {
- let id = Id::generate();
- let secret = Uuid::new_v4().to_string();
- let user = user.id();
-
- let secret = sqlx::query_scalar!(
+ pub async fn create(&mut self, token: &Token, secret: &Secret) -> Result<(), sqlx::Error> {
+ sqlx::query!(
r#"
insert
- into token (id, secret, user, issued_at, last_used_at)
- values ($1, $2, $3, $4, $4)
- returning secret as "secret!: Secret"
+ into token (id, secret, login, issued_at, last_used_at)
+ values ($1, $2, $3, $4, $5)
"#,
- id,
+ token.id,
secret,
- user,
- issued_at,
+ token.login,
+ token.issued_at,
+ token.last_used_at,
)
- .fetch_one(&mut *self.0)
+ .execute(&mut *self.0)
.await?;
- Ok(secret)
+ Ok(())
}
pub async fn require(&mut self, token: &Id) -> Result<(), sqlx::Error> {
@@ -67,34 +55,30 @@ impl Tokens<'_> {
Ok(())
}
- // Revoke a token by its secret.
- pub async fn revoke(&mut self, token: &Id) -> Result<(), sqlx::Error> {
- sqlx::query_scalar!(
+ pub async fn revoke(&mut self, token: &Token) -> Result<(), sqlx::Error> {
+ sqlx::query!(
r#"
- delete
- from token
+ delete from token
where id = $1
- returning id as "id: Id"
"#,
- token,
+ token.id,
)
- .fetch_one(&mut *self.0)
+ .execute(&mut *self.0)
.await?;
Ok(())
}
// Revoke tokens for a login
- pub async fn revoke_all(&mut self, user: &user::History) -> Result<Vec<Id>, sqlx::Error> {
- let user = user.id();
+ pub async fn revoke_all(&mut self, login: &Login) -> Result<Vec<Id>, sqlx::Error> {
let tokens = sqlx::query_scalar!(
r#"
delete
from token
- where user = $1
+ where login = $1
returning id as "id: Id"
"#,
- user,
+ login.id,
)
.fetch_all(&mut *self.0)
.await?;
@@ -120,54 +104,53 @@ impl Tokens<'_> {
Ok(tokens)
}
- // Validate a token by its secret, retrieving the associated Login record.
- // Will return an error if the token is not valid. If successful, the
- // retrieved token's last-used timestamp will be set to `used_at`.
pub async fn validate(
&mut self,
secret: &Secret,
used_at: &DateTime,
- ) -> Result<(Id, History), LoadError> {
+ ) -> Result<(Token, Login), LoadError> {
// 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.
- let (token, user) = sqlx::query!(
+ let token = sqlx::query!(
r#"
update token
set last_used_at = $1
where secret = $2
returning
- id as "token: Id",
- user as "user: user::Id"
+ id as "id: Id",
+ login as "login: login::Id",
+ issued_at as "issued_at: DateTime",
+ last_used_at as "last_used_at: DateTime"
"#,
used_at,
secret,
)
- .map(|row| (row.token, row.user))
+ .map(|row| Token {
+ id: row.id,
+ login: row.login,
+ issued_at: row.issued_at,
+ last_used_at: row.last_used_at,
+ })
.fetch_one(&mut *self.0)
.await?;
let user = sqlx::query!(
r#"
select
- id as "id: user::Id",
- display_name as "display_name: String",
- canonical_name as "canonical_name: String",
- created_sequence as "created_sequence: Sequence",
- created_at as "created_at: DateTime"
- from user
+ id as "id: login::Id",
+ display_name,
+ canonical_name
+ from login
where id = $1
"#,
- user,
+ token.login,
)
.map(|row| {
- Ok::<_, name::Error>(History {
- user: User {
- id: row.id,
- name: Name::new(row.display_name, row.canonical_name)?,
- },
- created: Instant::new(row.created_at, row.created_sequence),
+ Ok::<_, name::Error>(Login {
+ id: row.id,
+ name: Name::new(row.display_name, row.canonical_name)?,
})
})
.fetch_one(&mut *self.0)