diff options
Diffstat (limited to 'src/token')
| -rw-r--r-- | src/token/app.rs | 49 | ||||
| -rw-r--r-- | src/token/broadcaster.rs | 3 | ||||
| -rw-r--r-- | src/token/event.rs | 10 | ||||
| -rw-r--r-- | src/token/mod.rs | 4 | ||||
| -rw-r--r-- | src/token/repo/auth.rs | 28 | ||||
| -rw-r--r-- | src/token/repo/token.rs | 9 |
6 files changed, 65 insertions, 38 deletions
diff --git a/src/token/app.rs b/src/token/app.rs index 5c4fcd5..b8af637 100644 --- a/src/token/app.rs +++ b/src/token/app.rs @@ -7,23 +7,34 @@ use futures::{ use sqlx::sqlite::SqlitePool; use super::{ - broadcaster::Broadcaster, event, repo::auth::Provider as _, repo::Provider as _, Id, Secret, + repo::auth::Provider as _, repo::Provider as _, Broadcaster, Event as TokenEvent, Id, Secret, }; use crate::{ clock::DateTime, db::NotFound as _, + event::{self, repo::Provider as _, Event as ServiceEvent}, login::{repo::Provider as _, Login, Password}, }; pub struct Tokens<'a> { db: &'a SqlitePool, - tokens: &'a Broadcaster, + events: &'a event::Broadcaster, + token_events: &'a Broadcaster, } impl<'a> Tokens<'a> { - pub const fn new(db: &'a SqlitePool, tokens: &'a Broadcaster) -> Self { - Self { db, tokens } + pub const fn new( + db: &'a SqlitePool, + events: &'a event::Broadcaster, + token_events: &'a Broadcaster, + ) -> Self { + Self { + db, + events, + token_events, + } } + pub async fn login( &self, name: &str, @@ -32,22 +43,30 @@ impl<'a> Tokens<'a> { ) -> Result<Secret, LoginError> { let mut tx = self.db.begin().await?; - let login = if let Some((login, stored_hash)) = tx.auth().for_name(name).await? { + let (login, created) = if let Some((login, stored_hash)) = tx.auth().for_name(name).await? { if stored_hash.verify(password)? { - // Password verified; use the login. - login + // Password verified, proceed with login + (login, false) } else { // Password NOT verified. return Err(LoginError::Rejected); } } else { let password_hash = password.hash()?; - tx.logins().create(name, &password_hash).await? + let created = tx.sequence().next(login_at).await?; + let login = tx.logins().create(name, &password_hash, &created).await?; + + (login, true) }; let token = tx.tokens().issue(&login, login_at).await?; tx.commit().await?; + if created { + self.events + .broadcast(login.events().map(ServiceEvent::from).collect::<Vec<_>>()); + } + Ok(token) } @@ -76,7 +95,7 @@ impl<'a> Tokens<'a> { E: std::fmt::Debug, { // Subscribe, first. - let token_events = self.tokens.subscribe(); + let token_events = self.token_events.subscribe(); // Check that the token is valid at this point in time, second. If it is, then // any future revocations will appear in the subscription. If not, bail now. @@ -102,7 +121,9 @@ impl<'a> Tokens<'a> { // Then construct the guarded stream. First, project both streams into // `GuardedEvent`. let token_events = token_events - .filter(move |event| future::ready(event.token == token)) + .filter(move |event| { + future::ready(matches!(event, TokenEvent::Revoked(id) if id == &token)) + }) .map(|_| GuardedEvent::TokenRevoked); let events = events.map(|event| GuardedEvent::Event(event)); @@ -126,8 +147,8 @@ impl<'a> Tokens<'a> { let tokens = tx.tokens().expire(&expire_at).await?; tx.commit().await?; - for event in tokens.into_iter().map(event::TokenRevoked::from) { - self.tokens.broadcast(event); + for event in tokens.into_iter().map(TokenEvent::Revoked) { + self.token_events.broadcast(event); } Ok(()) @@ -138,8 +159,8 @@ impl<'a> Tokens<'a> { tx.tokens().revoke(token).await?; tx.commit().await?; - self.tokens - .broadcast(event::TokenRevoked::from(token.clone())); + self.token_events + .broadcast(TokenEvent::Revoked(token.clone())); Ok(()) } diff --git a/src/token/broadcaster.rs b/src/token/broadcaster.rs index 8e2e006..de2513a 100644 --- a/src/token/broadcaster.rs +++ b/src/token/broadcaster.rs @@ -1,4 +1,3 @@ -use super::event; use crate::broadcast; -pub type Broadcaster = broadcast::Broadcaster<event::TokenRevoked>; +pub type Broadcaster = broadcast::Broadcaster<super::Event>; diff --git a/src/token/event.rs b/src/token/event.rs index d53d436..51b74d7 100644 --- a/src/token/event.rs +++ b/src/token/event.rs @@ -1,12 +1,6 @@ use crate::token; #[derive(Clone, Debug)] -pub struct TokenRevoked { - pub token: token::Id, -} - -impl From<token::Id> for TokenRevoked { - fn from(token: token::Id) -> Self { - Self { token } - } +pub enum Event { + Revoked(token::Id), } diff --git a/src/token/mod.rs b/src/token/mod.rs index d122611..eccb3cd 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -1,9 +1,9 @@ pub mod app; -pub mod broadcaster; +mod broadcaster; mod event; pub mod extract; mod id; mod repo; mod secret; -pub use self::{id::Id, secret::Secret}; +pub use self::{broadcaster::Broadcaster, event::Event, id::Id, secret::Secret}; diff --git a/src/token/repo/auth.rs b/src/token/repo/auth.rs index b299697..ddb5136 100644 --- a/src/token/repo/auth.rs +++ b/src/token/repo/auth.rs @@ -1,6 +1,10 @@ use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; -use crate::login::{self, password::StoredHash, Login}; +use crate::{ + clock::DateTime, + event::{Instant, Sequence}, + login::{self, password::StoredHash, History, Login}, +}; pub trait Provider { fn auth(&mut self) -> Auth; @@ -21,25 +25,33 @@ impl<'t> Auth<'t> { pub async fn for_name( &mut self, name: &str, - ) -> Result<Option<(Login, StoredHash)>, sqlx::Error> { + ) -> Result<Option<(History, StoredHash)>, sqlx::Error> { let found = sqlx::query!( r#" select id as "id: login::Id", name, - password_hash as "password_hash: StoredHash" + password_hash as "password_hash: StoredHash", + created_sequence as "created_sequence: Sequence", + created_at as "created_at: DateTime" from login where name = $1 "#, name, ) - .map(|rec| { + .map(|row| { ( - Login { - id: rec.id, - name: rec.name, + History { + login: Login { + id: row.id, + name: row.name, + }, + created: Instant { + at: row.created_at, + sequence: row.created_sequence, + }, }, - rec.password_hash, + row.password_hash, ) }) .fetch_optional(&mut *self.0) diff --git a/src/token/repo/token.rs b/src/token/repo/token.rs index 5f64dac..c592dcd 100644 --- a/src/token/repo/token.rs +++ b/src/token/repo/token.rs @@ -3,7 +3,7 @@ use uuid::Uuid; use crate::{ clock::DateTime, - login::{self, Login}, + login::{self, History, Login}, token::{Id, Secret}, }; @@ -24,11 +24,12 @@ impl<'c> Tokens<'c> { // be used to control expiry, until the token is actually used. pub async fn issue( &mut self, - login: &Login, + login: &History, issued_at: &DateTime, ) -> Result<Secret, sqlx::Error> { let id = Id::generate(); let secret = Uuid::new_v4().to_string(); + let login = login.id(); let secret = sqlx::query_scalar!( r#" @@ -39,7 +40,7 @@ impl<'c> Tokens<'c> { "#, id, secret, - login.id, + login, issued_at, ) .fetch_one(&mut *self.0) @@ -127,7 +128,7 @@ impl<'c> Tokens<'c> { select token.id as "token_id: Id", login.id as "login_id: login::Id", - name as "login_name" + login.name as "login_name" from login join token on login.id = token.login where token.secret = $1 |
