diff --git a/crates/cli/src/commands/manage.rs b/crates/cli/src/commands/manage.rs index c608db83..2f3e8852 100644 --- a/crates/cli/src/commands/manage.rs +++ b/crates/cli/src/commands/manage.rs @@ -21,7 +21,7 @@ use mas_storage::{ oauth2::OAuth2ClientRepository, upstream_oauth2::UpstreamOAuthProviderRepository, user::{UserEmailRepository, UserPasswordRepository, UserRepository}, - Clock, Repository, + Repository, SystemClock, }; use mas_storage_pg::PgRepository; use oauth2_types::scope::Scope; @@ -188,7 +188,7 @@ impl Options { #[allow(clippy::too_many_lines)] pub async fn run(&self, root: &super::Options) -> anyhow::Result<()> { use Subcommand as SC; - let clock = Clock::default(); + let clock = SystemClock::default(); // XXX: we should disallow SeedableRng::from_entropy let mut rng = rand_chacha::ChaChaRng::from_entropy(); diff --git a/crates/cli/src/commands/templates.rs b/crates/cli/src/commands/templates.rs index a3a1bf9c..6f09b751 100644 --- a/crates/cli/src/commands/templates.rs +++ b/crates/cli/src/commands/templates.rs @@ -14,7 +14,7 @@ use camino::Utf8PathBuf; use clap::Parser; -use mas_storage::Clock; +use mas_storage::{Clock, SystemClock}; use mas_templates::Templates; use rand::SeedableRng; use tracing::info_span; @@ -41,7 +41,7 @@ impl Options { SC::Check { path } => { let _span = info_span!("cli.templates.check").entered(); - let clock = Clock::default(); + let clock = SystemClock::default(); // XXX: we should disallow SeedableRng::from_entropy let mut rng = rand_chacha::ChaChaRng::from_entropy(); let url_builder = mas_router::UrlBuilder::new("https://example.com/".parse()?); diff --git a/crates/handlers/src/compat/login.rs b/crates/handlers/src/compat/login.rs index bfd36d8a..9b0a0792 100644 --- a/crates/handlers/src/compat/login.rs +++ b/crates/handlers/src/compat/login.rs @@ -22,7 +22,7 @@ use mas_storage::{ CompatSsoLoginRepository, }, user::{UserPasswordRepository, UserRepository}, - Clock, Repository, + Clock, Repository, SystemClock, }; use mas_storage_pg::PgRepository; use serde::{Deserialize, Serialize}; @@ -254,7 +254,7 @@ pub(crate) async fn post( async fn token_login( repo: &mut PgRepository, - clock: &Clock, + clock: &SystemClock, token: &str, ) -> Result<(CompatSession, User), RouteError> { let login = repo diff --git a/crates/handlers/src/compat/login_sso_complete.rs b/crates/handlers/src/compat/login_sso_complete.rs index 1fea922e..631d1126 100644 --- a/crates/handlers/src/compat/login_sso_complete.rs +++ b/crates/handlers/src/compat/login_sso_complete.rs @@ -31,7 +31,7 @@ use mas_keystore::Encrypter; use mas_router::{CompatLoginSsoAction, PostAuthAction, Route}; use mas_storage::{ compat::{CompatSessionRepository, CompatSsoLoginRepository}, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{CompatSsoContext, ErrorContext, TemplateContext, Templates}; diff --git a/crates/handlers/src/compat/logout.rs b/crates/handlers/src/compat/logout.rs index 21229fe7..310fef2e 100644 --- a/crates/handlers/src/compat/logout.rs +++ b/crates/handlers/src/compat/logout.rs @@ -18,7 +18,7 @@ use hyper::StatusCode; use mas_data_model::TokenType; use mas_storage::{ compat::{CompatAccessTokenRepository, CompatSessionRepository}, - Clock, Repository, + Clock, Repository, SystemClock, }; use mas_storage_pg::PgRepository; use sqlx::PgPool; @@ -72,7 +72,7 @@ pub(crate) async fn post( State(pool): State, maybe_authorization: Option>>, ) -> Result { - let clock = Clock::default(); + let clock = SystemClock::default(); let mut repo = PgRepository::from_pool(&pool).await?; let TypedHeader(authorization) = maybe_authorization.ok_or(RouteError::MissingAuthorization)?; diff --git a/crates/handlers/src/compat/refresh.rs b/crates/handlers/src/compat/refresh.rs index e1601395..8b47a81f 100644 --- a/crates/handlers/src/compat/refresh.rs +++ b/crates/handlers/src/compat/refresh.rs @@ -18,7 +18,7 @@ use hyper::StatusCode; use mas_data_model::{TokenFormatError, TokenType}; use mas_storage::{ compat::{CompatAccessTokenRepository, CompatRefreshTokenRepository, CompatSessionRepository}, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use serde::{Deserialize, Serialize}; diff --git a/crates/handlers/src/lib.rs b/crates/handlers/src/lib.rs index 501f3176..0360e741 100644 --- a/crates/handlers/src/lib.rs +++ b/crates/handlers/src/lib.rs @@ -409,8 +409,8 @@ async fn test_state(pool: PgPool) -> Result { } // XXX: that should be moved somewhere else -fn clock_and_rng() -> (mas_storage::Clock, rand_chacha::ChaChaRng) { - let clock = mas_storage::Clock::default(); +fn clock_and_rng() -> (mas_storage::SystemClock, rand_chacha::ChaChaRng) { + let clock = mas_storage::SystemClock::default(); // This rng is used to source the local rng #[allow(clippy::disallowed_methods)] diff --git a/crates/handlers/src/oauth2/consent.rs b/crates/handlers/src/oauth2/consent.rs index b0f752f7..8fe4d2ac 100644 --- a/crates/handlers/src/oauth2/consent.rs +++ b/crates/handlers/src/oauth2/consent.rs @@ -30,7 +30,7 @@ use mas_policy::PolicyFactory; use mas_router::{PostAuthAction, Route}; use mas_storage::{ oauth2::{OAuth2AuthorizationGrantRepository, OAuth2ClientRepository}, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{ConsentContext, PolicyViolationContext, TemplateContext, Templates}; diff --git a/crates/handlers/src/oauth2/introspection.rs b/crates/handlers/src/oauth2/introspection.rs index e8f9941f..245f2125 100644 --- a/crates/handlers/src/oauth2/introspection.rs +++ b/crates/handlers/src/oauth2/introspection.rs @@ -25,7 +25,7 @@ use mas_storage::{ compat::{CompatAccessTokenRepository, CompatRefreshTokenRepository, CompatSessionRepository}, oauth2::{OAuth2AccessTokenRepository, OAuth2RefreshTokenRepository, OAuth2SessionRepository}, user::{BrowserSessionRepository, UserRepository}, - Clock, Repository, + Clock, Repository, SystemClock, }; use mas_storage_pg::PgRepository; use oauth2_types::{ @@ -130,7 +130,7 @@ pub(crate) async fn post( State(encrypter): State, client_authorization: ClientAuthorization, ) -> Result { - let clock = Clock::default(); + let clock = SystemClock::default(); let mut repo = PgRepository::from_pool(&pool).await?; let client = client_authorization diff --git a/crates/handlers/src/oauth2/token.rs b/crates/handlers/src/oauth2/token.rs index 67ecb498..de0118f4 100644 --- a/crates/handlers/src/oauth2/token.rs +++ b/crates/handlers/src/oauth2/token.rs @@ -37,7 +37,7 @@ use mas_storage::{ OAuth2RefreshTokenRepository, OAuth2SessionRepository, }, user::BrowserSessionRepository, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use oauth2_types::{ diff --git a/crates/handlers/src/oauth2/userinfo.rs b/crates/handlers/src/oauth2/userinfo.rs index 2f560037..39bc7587 100644 --- a/crates/handlers/src/oauth2/userinfo.rs +++ b/crates/handlers/src/oauth2/userinfo.rs @@ -31,7 +31,7 @@ use mas_router::UrlBuilder; use mas_storage::{ oauth2::OAuth2ClientRepository, user::{BrowserSessionRepository, UserEmailRepository}, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use oauth2_types::scope; diff --git a/crates/handlers/src/upstream_oauth2/authorize.rs b/crates/handlers/src/upstream_oauth2/authorize.rs index fcf5a7d1..565acea8 100644 --- a/crates/handlers/src/upstream_oauth2/authorize.rs +++ b/crates/handlers/src/upstream_oauth2/authorize.rs @@ -24,7 +24,7 @@ use mas_oidc_client::requests::authorization_code::AuthorizationRequestData; use mas_router::UrlBuilder; use mas_storage::{ upstream_oauth2::{UpstreamOAuthProviderRepository, UpstreamOAuthSessionRepository}, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use sqlx::PgPool; diff --git a/crates/handlers/src/upstream_oauth2/callback.rs b/crates/handlers/src/upstream_oauth2/callback.rs index d243666d..ffde4ef3 100644 --- a/crates/handlers/src/upstream_oauth2/callback.rs +++ b/crates/handlers/src/upstream_oauth2/callback.rs @@ -30,7 +30,7 @@ use mas_storage::{ UpstreamOAuthLinkRepository, UpstreamOAuthProviderRepository, UpstreamOAuthSessionRepository, }, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use oauth2_types::errors::ClientErrorCode; diff --git a/crates/handlers/src/upstream_oauth2/link.rs b/crates/handlers/src/upstream_oauth2/link.rs index 8709ff21..c0408770 100644 --- a/crates/handlers/src/upstream_oauth2/link.rs +++ b/crates/handlers/src/upstream_oauth2/link.rs @@ -27,7 +27,7 @@ use mas_keystore::Encrypter; use mas_storage::{ upstream_oauth2::{UpstreamOAuthLinkRepository, UpstreamOAuthSessionRepository}, user::{BrowserSessionRepository, UserRepository}, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{ diff --git a/crates/handlers/src/views/account/emails/add.rs b/crates/handlers/src/views/account/emails/add.rs index e99c8e4d..4c11a485 100644 --- a/crates/handlers/src/views/account/emails/add.rs +++ b/crates/handlers/src/views/account/emails/add.rs @@ -24,7 +24,7 @@ use mas_axum_utils::{ use mas_email::Mailer; use mas_keystore::Encrypter; use mas_router::Route; -use mas_storage::{user::UserEmailRepository, Repository}; +use mas_storage::{user::UserEmailRepository, Clock, Repository}; use mas_storage_pg::PgRepository; use mas_templates::{EmailAddContext, TemplateContext, Templates}; use serde::Deserialize; diff --git a/crates/handlers/src/views/account/emails/mod.rs b/crates/handlers/src/views/account/emails/mod.rs index 4d70ab33..f1b7c733 100644 --- a/crates/handlers/src/views/account/emails/mod.rs +++ b/crates/handlers/src/views/account/emails/mod.rs @@ -71,7 +71,7 @@ pub(crate) async fn get( async fn render( rng: impl Rng + Send, - clock: &Clock, + clock: &impl Clock, templates: Templates, session: BrowserSession, cookie_jar: PrivateCookieJar, @@ -94,7 +94,7 @@ async fn start_email_verification( mailer: &Mailer, repo: &mut impl Repository, mut rng: impl Rng + Send, - clock: &Clock, + clock: &impl Clock, user: &User, user_email: UserEmail, ) -> anyhow::Result<()> { diff --git a/crates/handlers/src/views/account/emails/verify.rs b/crates/handlers/src/views/account/emails/verify.rs index 2b398b42..f37b15e4 100644 --- a/crates/handlers/src/views/account/emails/verify.rs +++ b/crates/handlers/src/views/account/emails/verify.rs @@ -24,7 +24,7 @@ use mas_axum_utils::{ }; use mas_keystore::Encrypter; use mas_router::Route; -use mas_storage::{user::UserEmailRepository, Clock, Repository}; +use mas_storage::{user::UserEmailRepository, Clock, Repository, SystemClock}; use mas_storage_pg::PgRepository; use mas_templates::{EmailVerificationPageContext, TemplateContext, Templates}; use serde::Deserialize; @@ -89,7 +89,7 @@ pub(crate) async fn post( Path(id): Path, Form(form): Form>, ) -> Result { - let clock = Clock::default(); + let clock = SystemClock::default(); let mut repo = PgRepository::from_pool(&pool).await?; let form = cookie_jar.verify_form(clock.now(), form)?; diff --git a/crates/handlers/src/views/account/mod.rs b/crates/handlers/src/views/account/mod.rs index 8d2eb3e2..29aaeda3 100644 --- a/crates/handlers/src/views/account/mod.rs +++ b/crates/handlers/src/views/account/mod.rs @@ -25,7 +25,7 @@ use mas_keystore::Encrypter; use mas_router::Route; use mas_storage::{ user::{BrowserSessionRepository, UserEmailRepository}, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{AccountContext, TemplateContext, Templates}; diff --git a/crates/handlers/src/views/account/password.rs b/crates/handlers/src/views/account/password.rs index 089093f6..1624f6f6 100644 --- a/crates/handlers/src/views/account/password.rs +++ b/crates/handlers/src/views/account/password.rs @@ -67,7 +67,7 @@ pub(crate) async fn get( async fn render( rng: impl Rng + Send, - clock: &Clock, + clock: &impl Clock, templates: Templates, session: BrowserSession, cookie_jar: PrivateCookieJar, diff --git a/crates/handlers/src/views/index.rs b/crates/handlers/src/views/index.rs index cab7c743..2298e83e 100644 --- a/crates/handlers/src/views/index.rs +++ b/crates/handlers/src/views/index.rs @@ -20,6 +20,7 @@ use axum_extra::extract::PrivateCookieJar; use mas_axum_utils::{csrf::CsrfExt, FancyError, SessionInfoExt}; use mas_keystore::Encrypter; use mas_router::UrlBuilder; +use mas_storage::Clock; use mas_storage_pg::PgRepository; use mas_templates::{IndexContext, TemplateContext, Templates}; use sqlx::PgPool; diff --git a/crates/handlers/src/views/login.rs b/crates/handlers/src/views/login.rs index 87ba9e84..10295dbc 100644 --- a/crates/handlers/src/views/login.rs +++ b/crates/handlers/src/views/login.rs @@ -167,7 +167,7 @@ async fn login( password_manager: PasswordManager, repo: &mut impl Repository, mut rng: impl Rng + CryptoRng + Send, - clock: &Clock, + clock: &impl Clock, username: &str, password: &str, ) -> Result { diff --git a/crates/handlers/src/views/logout.rs b/crates/handlers/src/views/logout.rs index 373264d0..781780ca 100644 --- a/crates/handlers/src/views/logout.rs +++ b/crates/handlers/src/views/logout.rs @@ -23,7 +23,7 @@ use mas_axum_utils::{ }; use mas_keystore::Encrypter; use mas_router::{PostAuthAction, Route}; -use mas_storage::{user::BrowserSessionRepository, Clock, Repository}; +use mas_storage::{user::BrowserSessionRepository, Clock, Repository, SystemClock}; use mas_storage_pg::PgRepository; use sqlx::PgPool; @@ -32,7 +32,7 @@ pub(crate) async fn post( cookie_jar: PrivateCookieJar, Form(form): Form>>, ) -> Result { - let clock = Clock::default(); + let clock = SystemClock::default(); let mut repo = PgRepository::from_pool(&pool).await?; let form = cookie_jar.verify_form(clock.now(), form)?; diff --git a/crates/handlers/src/views/reauth.rs b/crates/handlers/src/views/reauth.rs index 49249f3c..571d2e17 100644 --- a/crates/handlers/src/views/reauth.rs +++ b/crates/handlers/src/views/reauth.rs @@ -26,7 +26,7 @@ use mas_keystore::Encrypter; use mas_router::Route; use mas_storage::{ user::{BrowserSessionRepository, UserPasswordRepository}, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{ReauthContext, TemplateContext, Templates}; diff --git a/crates/handlers/src/views/register.rs b/crates/handlers/src/views/register.rs index 58db6ec1..3e2d87a9 100644 --- a/crates/handlers/src/views/register.rs +++ b/crates/handlers/src/views/register.rs @@ -33,7 +33,7 @@ use mas_policy::PolicyFactory; use mas_router::Route; use mas_storage::{ user::{BrowserSessionRepository, UserEmailRepository, UserPasswordRepository, UserRepository}, - Repository, + Clock, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{ diff --git a/crates/storage-pg/src/compat/access_token.rs b/crates/storage-pg/src/compat/access_token.rs index 5f73ed9e..822c3a8a 100644 --- a/crates/storage-pg/src/compat/access_token.rs +++ b/crates/storage-pg/src/compat/access_token.rs @@ -143,7 +143,7 @@ impl<'c> CompatAccessTokenRepository for PgCompatAccessTokenRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, compat_session: &CompatSession, token: String, expires_after: Option, @@ -191,7 +191,7 @@ impl<'c> CompatAccessTokenRepository for PgCompatAccessTokenRepository<'c> { )] async fn expire( &mut self, - clock: &Clock, + clock: &dyn Clock, mut compat_access_token: CompatAccessToken, ) -> Result { let expires_at = clock.now(); diff --git a/crates/storage-pg/src/compat/mod.rs b/crates/storage-pg/src/compat/mod.rs index 732ce3aa..dd68e4d5 100644 --- a/crates/storage-pg/src/compat/mod.rs +++ b/crates/storage-pg/src/compat/mod.rs @@ -27,6 +27,7 @@ mod tests { use chrono::Duration; use mas_data_model::Device; use mas_storage::{ + clock::MockClock, compat::{ CompatAccessTokenRepository, CompatRefreshTokenRepository, CompatSessionRepository, }, @@ -44,7 +45,7 @@ mod tests { const FIRST_TOKEN: &str = "first_access_token"; const SECOND_TOKEN: &str = "second_access_token"; let mut rng = ChaChaRng::seed_from_u64(42); - let clock = Clock::mock(); + let clock = MockClock::default(); let mut repo = PgRepository::from_pool(&pool).await.unwrap(); // Create a user @@ -101,7 +102,7 @@ mod tests { const FIRST_TOKEN: &str = "first_access_token"; const SECOND_TOKEN: &str = "second_access_token"; let mut rng = ChaChaRng::seed_from_u64(42); - let clock = Clock::mock(); + let clock = MockClock::default(); let mut repo = PgRepository::from_pool(&pool).await.unwrap(); // Create a user @@ -221,7 +222,7 @@ mod tests { const ACCESS_TOKEN: &str = "access_token"; const REFRESH_TOKEN: &str = "refresh_token"; let mut rng = ChaChaRng::seed_from_u64(42); - let clock = Clock::mock(); + let clock = MockClock::default(); let mut repo = PgRepository::from_pool(&pool).await.unwrap(); // Create a user diff --git a/crates/storage-pg/src/compat/refresh_token.rs b/crates/storage-pg/src/compat/refresh_token.rs index 314e8147..991e1438 100644 --- a/crates/storage-pg/src/compat/refresh_token.rs +++ b/crates/storage-pg/src/compat/refresh_token.rs @@ -154,7 +154,7 @@ impl<'c> CompatRefreshTokenRepository for PgCompatRefreshTokenRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, compat_session: &CompatSession, compat_access_token: &CompatAccessToken, token: String, @@ -202,7 +202,7 @@ impl<'c> CompatRefreshTokenRepository for PgCompatRefreshTokenRepository<'c> { )] async fn consume( &mut self, - clock: &Clock, + clock: &dyn Clock, compat_refresh_token: CompatRefreshToken, ) -> Result { let consumed_at = clock.now(); diff --git a/crates/storage-pg/src/compat/session.rs b/crates/storage-pg/src/compat/session.rs index a6e65f9a..16208b4f 100644 --- a/crates/storage-pg/src/compat/session.rs +++ b/crates/storage-pg/src/compat/session.rs @@ -122,7 +122,7 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user: &User, device: Device, ) -> Result { @@ -166,7 +166,7 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> { )] async fn finish( &mut self, - clock: &Clock, + clock: &dyn Clock, compat_session: CompatSession, ) -> Result { let finished_at = clock.now(); diff --git a/crates/storage-pg/src/compat/sso_login.rs b/crates/storage-pg/src/compat/sso_login.rs index a2eeb926..1b8e0225 100644 --- a/crates/storage-pg/src/compat/sso_login.rs +++ b/crates/storage-pg/src/compat/sso_login.rs @@ -177,7 +177,7 @@ impl<'c> CompatSsoLoginRepository for PgCompatSsoLoginRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, login_token: String, redirect_uri: Url, ) -> Result { @@ -223,7 +223,7 @@ impl<'c> CompatSsoLoginRepository for PgCompatSsoLoginRepository<'c> { )] async fn fulfill( &mut self, - clock: &Clock, + clock: &dyn Clock, compat_sso_login: CompatSsoLogin, compat_session: &CompatSession, ) -> Result { @@ -265,7 +265,7 @@ impl<'c> CompatSsoLoginRepository for PgCompatSsoLoginRepository<'c> { )] async fn exchange( &mut self, - clock: &Clock, + clock: &dyn Clock, compat_sso_login: CompatSsoLogin, ) -> Result { let exchanged_at = clock.now(); diff --git a/crates/storage-pg/src/oauth2/access_token.rs b/crates/storage-pg/src/oauth2/access_token.rs index 33d95242..ecd5798b 100644 --- a/crates/storage-pg/src/oauth2/access_token.rs +++ b/crates/storage-pg/src/oauth2/access_token.rs @@ -142,7 +142,7 @@ impl<'c> OAuth2AccessTokenRepository for PgOAuth2AccessTokenRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, session: &Session, access_token: String, expires_after: Duration, @@ -182,7 +182,7 @@ impl<'c> OAuth2AccessTokenRepository for PgOAuth2AccessTokenRepository<'c> { async fn revoke( &mut self, - clock: &Clock, + clock: &dyn Clock, access_token: AccessToken, ) -> Result { let revoked_at = clock.now(); @@ -205,7 +205,7 @@ impl<'c> OAuth2AccessTokenRepository for PgOAuth2AccessTokenRepository<'c> { .map_err(DatabaseError::to_invalid_operation) } - async fn cleanup_expired(&mut self, clock: &Clock) -> Result { + async fn cleanup_expired(&mut self, clock: &dyn Clock) -> Result { // Cleanup token which expired more than 15 minutes ago let threshold = clock.now() - Duration::minutes(15); let res = sqlx::query!( diff --git a/crates/storage-pg/src/oauth2/authorization_grant.rs b/crates/storage-pg/src/oauth2/authorization_grant.rs index 027111a7..92116a62 100644 --- a/crates/storage-pg/src/oauth2/authorization_grant.rs +++ b/crates/storage-pg/src/oauth2/authorization_grant.rs @@ -211,7 +211,7 @@ impl<'c> OAuth2AuthorizationGrantRepository for PgOAuth2AuthorizationGrantReposi async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, client: &Client, redirect_uri: Url, scope: Scope, @@ -410,7 +410,7 @@ impl<'c> OAuth2AuthorizationGrantRepository for PgOAuth2AuthorizationGrantReposi )] async fn fulfill( &mut self, - clock: &Clock, + clock: &dyn Clock, session: &Session, grant: AuthorizationGrant, ) -> Result { @@ -451,7 +451,7 @@ impl<'c> OAuth2AuthorizationGrantRepository for PgOAuth2AuthorizationGrantReposi )] async fn exchange( &mut self, - clock: &Clock, + clock: &dyn Clock, grant: AuthorizationGrant, ) -> Result { let exchanged_at = clock.now(); diff --git a/crates/storage-pg/src/oauth2/client.rs b/crates/storage-pg/src/oauth2/client.rs index 4430c669..1b8a99f9 100644 --- a/crates/storage-pg/src/oauth2/client.rs +++ b/crates/storage-pg/src/oauth2/client.rs @@ -378,7 +378,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> { async fn add( &mut self, mut rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, redirect_uris: Vec, encrypted_client_secret: Option, grant_types: Vec, @@ -535,7 +535,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> { async fn add_from_config( &mut self, mut rng: impl Rng + Send, - clock: &Clock, + clock: &dyn Clock, client_id: Ulid, client_auth_method: OAuthClientAuthenticationMethod, encrypted_client_secret: Option, @@ -707,7 +707,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> { async fn give_consent_for_user( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, client: &Client, user: &User, scope: &Scope, diff --git a/crates/storage-pg/src/oauth2/refresh_token.rs b/crates/storage-pg/src/oauth2/refresh_token.rs index 47281d93..ba2fa533 100644 --- a/crates/storage-pg/src/oauth2/refresh_token.rs +++ b/crates/storage-pg/src/oauth2/refresh_token.rs @@ -150,7 +150,7 @@ impl<'c> OAuth2RefreshTokenRepository for PgOAuth2RefreshTokenRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, session: &Session, access_token: &AccessToken, refresh_token: String, @@ -199,7 +199,7 @@ impl<'c> OAuth2RefreshTokenRepository for PgOAuth2RefreshTokenRepository<'c> { )] async fn consume( &mut self, - clock: &Clock, + clock: &dyn Clock, refresh_token: RefreshToken, ) -> Result { let consumed_at = clock.now(); diff --git a/crates/storage-pg/src/oauth2/session.rs b/crates/storage-pg/src/oauth2/session.rs index 96f798e6..f1c41279 100644 --- a/crates/storage-pg/src/oauth2/session.rs +++ b/crates/storage-pg/src/oauth2/session.rs @@ -131,7 +131,7 @@ impl<'c> OAuth2SessionRepository for PgOAuth2SessionRepository<'c> { async fn create_from_grant( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, grant: &AuthorizationGrant, user_session: &BrowserSession, ) -> Result { @@ -182,7 +182,7 @@ impl<'c> OAuth2SessionRepository for PgOAuth2SessionRepository<'c> { ), err, )] - async fn finish(&mut self, clock: &Clock, session: Session) -> Result { + async fn finish(&mut self, clock: &dyn Clock, session: Session) -> Result { let finished_at = clock.now(); let res = sqlx::query!( r#" diff --git a/crates/storage-pg/src/upstream_oauth2/link.rs b/crates/storage-pg/src/upstream_oauth2/link.rs index 4087e2c7..c38b344b 100644 --- a/crates/storage-pg/src/upstream_oauth2/link.rs +++ b/crates/storage-pg/src/upstream_oauth2/link.rs @@ -149,7 +149,7 @@ impl<'c> UpstreamOAuthLinkRepository for PgUpstreamOAuthLinkRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, upstream_oauth_provider: &UpstreamOAuthProvider, subject: String, ) -> Result { diff --git a/crates/storage-pg/src/upstream_oauth2/mod.rs b/crates/storage-pg/src/upstream_oauth2/mod.rs index e77daba2..af631f15 100644 --- a/crates/storage-pg/src/upstream_oauth2/mod.rs +++ b/crates/storage-pg/src/upstream_oauth2/mod.rs @@ -25,12 +25,13 @@ pub use self::{ mod tests { use chrono::Duration; use mas_storage::{ + clock::MockClock, upstream_oauth2::{ UpstreamOAuthLinkRepository, UpstreamOAuthProviderRepository, UpstreamOAuthSessionRepository, }, user::UserRepository, - Clock, Pagination, Repository, + Pagination, Repository, }; use oauth2_types::scope::{Scope, OPENID}; use rand::SeedableRng; @@ -41,7 +42,7 @@ mod tests { #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_repository(pool: PgPool) { let mut rng = rand_chacha::ChaChaRng::seed_from_u64(42); - let clock = Clock::mock(); + let clock = MockClock::default(); let mut repo = PgRepository::from_pool(&pool).await.unwrap(); // The provider list should be empty at the start @@ -183,7 +184,7 @@ mod tests { let scope = Scope::from_iter([OPENID]); let mut rng = rand_chacha::ChaChaRng::seed_from_u64(42); - let clock = Clock::mock(); + let clock = MockClock::default(); let mut repo = PgRepository::from_pool(&pool).await.unwrap(); let mut ids = Vec::with_capacity(20); diff --git a/crates/storage-pg/src/upstream_oauth2/provider.rs b/crates/storage-pg/src/upstream_oauth2/provider.rs index 480249ee..dc1b0c85 100644 --- a/crates/storage-pg/src/upstream_oauth2/provider.rs +++ b/crates/storage-pg/src/upstream_oauth2/provider.rs @@ -149,7 +149,7 @@ impl<'c> UpstreamOAuthProviderRepository for PgUpstreamOAuthProviderRepository<' async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, issuer: String, scope: Scope, token_endpoint_auth_method: OAuthClientAuthenticationMethod, diff --git a/crates/storage-pg/src/upstream_oauth2/session.rs b/crates/storage-pg/src/upstream_oauth2/session.rs index 699a463f..3cdef0c7 100644 --- a/crates/storage-pg/src/upstream_oauth2/session.rs +++ b/crates/storage-pg/src/upstream_oauth2/session.rs @@ -156,7 +156,7 @@ impl<'c> UpstreamOAuthSessionRepository for PgUpstreamOAuthSessionRepository<'c> async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, upstream_oauth_provider: &UpstreamOAuthProvider, state_str: String, code_challenge_verifier: Option, @@ -217,7 +217,7 @@ impl<'c> UpstreamOAuthSessionRepository for PgUpstreamOAuthSessionRepository<'c> )] async fn complete_with_link( &mut self, - clock: &Clock, + clock: &dyn Clock, upstream_oauth_authorization_session: UpstreamOAuthAuthorizationSession, upstream_oauth_link: &UpstreamOAuthLink, id_token: Option, @@ -260,7 +260,7 @@ impl<'c> UpstreamOAuthSessionRepository for PgUpstreamOAuthSessionRepository<'c> )] async fn consume( &mut self, - clock: &Clock, + clock: &dyn Clock, upstream_oauth_authorization_session: UpstreamOAuthAuthorizationSession, ) -> Result { let consumed_at = clock.now(); diff --git a/crates/storage-pg/src/user/email.rs b/crates/storage-pg/src/user/email.rs index 936b0649..b9d732de 100644 --- a/crates/storage-pg/src/user/email.rs +++ b/crates/storage-pg/src/user/email.rs @@ -68,7 +68,7 @@ struct UserEmailConfirmationCodeLookup { } impl UserEmailConfirmationCodeLookup { - fn into_verification(self, clock: &Clock) -> UserEmailVerification { + fn into_verification(self, clock: &dyn Clock) -> UserEmailVerification { let now = clock.now(); let state = if let Some(when) = self.consumed_at { UserEmailVerificationState::AlreadyUsed { when } @@ -301,7 +301,7 @@ impl<'c> UserEmailRepository for PgUserEmailRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user: &User, email: String, ) -> Result { @@ -378,7 +378,7 @@ impl<'c> UserEmailRepository for PgUserEmailRepository<'c> { async fn mark_as_verified( &mut self, - clock: &Clock, + clock: &dyn Clock, mut user_email: UserEmail, ) -> Result { let confirmed_at = clock.now(); @@ -430,7 +430,7 @@ impl<'c> UserEmailRepository for PgUserEmailRepository<'c> { async fn add_verification_code( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user_email: &UserEmail, max_age: chrono::Duration, code: String, @@ -479,7 +479,7 @@ impl<'c> UserEmailRepository for PgUserEmailRepository<'c> { )] async fn find_verification_code( &mut self, - clock: &Clock, + clock: &dyn Clock, user_email: &UserEmail, code: &str, ) -> Result, Self::Error> { @@ -521,7 +521,7 @@ impl<'c> UserEmailRepository for PgUserEmailRepository<'c> { )] async fn consume_verification_code( &mut self, - clock: &Clock, + clock: &dyn Clock, mut user_email_verification: UserEmailVerification, ) -> Result { if !matches!( diff --git a/crates/storage-pg/src/user/mod.rs b/crates/storage-pg/src/user/mod.rs index d7320261..8ec6170f 100644 --- a/crates/storage-pg/src/user/mod.rs +++ b/crates/storage-pg/src/user/mod.rs @@ -148,7 +148,7 @@ impl<'c> UserRepository for PgUserRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, username: String, ) -> Result { let created_at = clock.now(); diff --git a/crates/storage-pg/src/user/password.rs b/crates/storage-pg/src/user/password.rs index 997b1227..696b30e7 100644 --- a/crates/storage-pg/src/user/password.rs +++ b/crates/storage-pg/src/user/password.rs @@ -115,7 +115,7 @@ impl<'c> UserPasswordRepository for PgUserPasswordRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user: &User, version: u16, hashed_password: String, diff --git a/crates/storage-pg/src/user/session.rs b/crates/storage-pg/src/user/session.rs index d216c067..e5616fff 100644 --- a/crates/storage-pg/src/user/session.rs +++ b/crates/storage-pg/src/user/session.rs @@ -142,7 +142,7 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user: &User, ) -> Result { let created_at = clock.now(); @@ -185,7 +185,7 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> { )] async fn finish( &mut self, - clock: &Clock, + clock: &dyn Clock, mut user_session: BrowserSession, ) -> Result { let finished_at = clock.now(); @@ -297,7 +297,7 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> { async fn authenticate_with_password( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, mut user_session: BrowserSession, user_password: &Password, ) -> Result { @@ -342,7 +342,7 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> { async fn authenticate_with_upstream( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, mut user_session: BrowserSession, upstream_oauth_link: &UpstreamOAuthLink, ) -> Result { diff --git a/crates/storage-pg/src/user/tests.rs b/crates/storage-pg/src/user/tests.rs index f0a071b0..097bca74 100644 --- a/crates/storage-pg/src/user/tests.rs +++ b/crates/storage-pg/src/user/tests.rs @@ -14,8 +14,9 @@ use chrono::Duration; use mas_storage::{ + clock::MockClock, user::{BrowserSessionRepository, UserEmailRepository, UserPasswordRepository, UserRepository}, - Clock, Repository, + Repository, }; use rand::SeedableRng; use rand_chacha::ChaChaRng; @@ -30,7 +31,7 @@ async fn test_user_repo(pool: PgPool) { let mut repo = PgRepository::from_pool(&pool).await.unwrap(); let mut rng = ChaChaRng::seed_from_u64(42); - let clock = Clock::mock(); + let clock = MockClock::default(); // Initially, the user shouldn't exist assert!(!repo.user().exists(USERNAME).await.unwrap()); @@ -78,7 +79,7 @@ async fn test_user_email_repo(pool: PgPool) { let mut repo = PgRepository::from_pool(&pool).await.unwrap(); let mut rng = ChaChaRng::seed_from_u64(42); - let clock = Clock::mock(); + let clock = MockClock::default(); let user = repo .user() @@ -89,7 +90,7 @@ async fn test_user_email_repo(pool: PgPool) { // The user email should not exist yet assert!(repo .user_email() - .find(&user, EMAIL) + .find(&user, &EMAIL) .await .unwrap() .is_none()); @@ -110,7 +111,7 @@ async fn test_user_email_repo(pool: PgPool) { assert!(repo .user_email() - .find(&user, EMAIL) + .find(&user, &EMAIL) .await .unwrap() .is_some()); @@ -180,7 +181,7 @@ async fn test_user_email_repo(pool: PgPool) { // Reload the user_email let user_email = repo .user_email() - .find(&user, EMAIL) + .find(&user, &EMAIL) .await .unwrap() .expect("user email was not found"); @@ -260,7 +261,7 @@ async fn test_user_password_repo(pool: PgPool) { let mut repo = PgRepository::from_pool(&pool).await.unwrap(); let mut rng = ChaChaRng::seed_from_u64(42); - let clock = Clock::mock(); + let clock = MockClock::default(); let user = repo .user() @@ -340,7 +341,7 @@ async fn test_user_session(pool: PgPool) { let mut repo = PgRepository::from_pool(&pool).await.unwrap(); let mut rng = ChaChaRng::seed_from_u64(42); - let clock = Clock::mock(); + let clock = MockClock::default(); let user = repo .user() diff --git a/crates/storage/src/clock.rs b/crates/storage/src/clock.rs new file mode 100644 index 00000000..54ca3b4f --- /dev/null +++ b/crates/storage/src/clock.rs @@ -0,0 +1,129 @@ +// Copyright 2023 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A [`Clock`] is a way to get the current date and time. +//! +//! This module defines two implemetation of the [`Clock`] trait: +//! [`SystemClock`] which uses the system time, and a [`MockClock`], which can +//! be used and freely manipulated in tests. + +use std::sync::atomic::AtomicI64; + +use chrono::{DateTime, TimeZone, Utc}; + +/// Represents a clock which can give the current date and time +pub trait Clock: Sync { + /// Get the current date and time + fn now(&self) -> DateTime; +} + +/// A clock which uses the system time +#[derive(Clone, Default)] +pub struct SystemClock { + _private: (), +} + +impl Clock for SystemClock { + fn now(&self) -> DateTime { + // This is the clock used elsewhere, it's fine to call Utc::now here + #[allow(clippy::disallowed_methods)] + Utc::now() + } +} + +/// A fake clock, which uses a fixed timestamp, and can be advanced with the +/// [`MockClock::advance`] method. +/// +/// ```rust +/// use mas_storage::clock::{Clock, MockClock}; +/// use chrono::Duration; +/// +/// let clock = MockClock::default(); +/// let t1 = clock.now(); +/// let t2 = clock.now(); +/// assert_eq!(t1, t2); +/// +/// clock.advance(Duration::seconds(10)); +/// let t3 = clock.now(); +/// assert_eq!(t2 + Duration::seconds(10), t3); +/// ``` +pub struct MockClock { + timestamp: AtomicI64, +} + +impl Default for MockClock { + fn default() -> Self { + let datetime = Utc.with_ymd_and_hms(2022, 1, 16, 14, 40, 0).unwrap(); + Self::new(datetime) + } +} + +impl MockClock { + /// Create a new clock which starts at the given datetime + #[must_use] + pub fn new(datetime: DateTime) -> Self { + let timestamp = AtomicI64::new(datetime.timestamp()); + Self { timestamp } + } + + /// Move the clock forward by the given amount of time + pub fn advance(&self, duration: chrono::Duration) { + self.timestamp + .fetch_add(duration.num_seconds(), std::sync::atomic::Ordering::Relaxed); + } +} + +impl Clock for MockClock { + fn now(&self) -> DateTime { + let timestamp = self.timestamp.load(std::sync::atomic::Ordering::Relaxed); + chrono::TimeZone::timestamp_opt(&Utc, timestamp, 0).unwrap() + } +} + +#[cfg(test)] +mod tests { + use chrono::Duration; + + use super::*; + + #[test] + fn test_mocked_clock() { + let clock = MockClock::default(); + + // Time should be frozen, and give out the same timestamp on each call + let first = clock.now(); + std::thread::sleep(std::time::Duration::from_millis(10)); + let second = clock.now(); + + assert_eq!(first, second); + + // Clock can be advanced by a fixed duration + clock.advance(Duration::seconds(10)); + let third = clock.now(); + assert_eq!(first + Duration::seconds(10), third); + } + + #[test] + fn test_real_clock() { + let clock = SystemClock::default(); + + // Time should not be frozen + let first = clock.now(); + std::thread::sleep(std::time::Duration::from_millis(10)); + let second = clock.now(); + + assert_ne!(first, second); + assert!(first < second); + } +} diff --git a/crates/storage/src/compat/access_token.rs b/crates/storage/src/compat/access_token.rs index 46ff6e3f..e135be39 100644 --- a/crates/storage/src/compat/access_token.rs +++ b/crates/storage/src/compat/access_token.rs @@ -37,7 +37,7 @@ pub trait CompatAccessTokenRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, compat_session: &CompatSession, token: String, expires_after: Option, @@ -46,7 +46,7 @@ pub trait CompatAccessTokenRepository: Send + Sync { /// Set the expiration time of the compat access token to now async fn expire( &mut self, - clock: &Clock, + clock: &dyn Clock, compat_access_token: CompatAccessToken, ) -> Result; } diff --git a/crates/storage/src/compat/refresh_token.rs b/crates/storage/src/compat/refresh_token.rs index 7a1057ff..f8e8dfaa 100644 --- a/crates/storage/src/compat/refresh_token.rs +++ b/crates/storage/src/compat/refresh_token.rs @@ -36,7 +36,7 @@ pub trait CompatRefreshTokenRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, compat_session: &CompatSession, compat_access_token: &CompatAccessToken, token: String, @@ -45,7 +45,7 @@ pub trait CompatRefreshTokenRepository: Send + Sync { /// Consume a compat refresh token async fn consume( &mut self, - clock: &Clock, + clock: &dyn Clock, compat_refresh_token: CompatRefreshToken, ) -> Result; } diff --git a/crates/storage/src/compat/session.rs b/crates/storage/src/compat/session.rs index 34bc6838..fa5cbd6e 100644 --- a/crates/storage/src/compat/session.rs +++ b/crates/storage/src/compat/session.rs @@ -30,7 +30,7 @@ pub trait CompatSessionRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user: &User, device: Device, ) -> Result; @@ -38,7 +38,7 @@ pub trait CompatSessionRepository: Send + Sync { /// End a compat session async fn finish( &mut self, - clock: &Clock, + clock: &dyn Clock, compat_session: CompatSession, ) -> Result; } diff --git a/crates/storage/src/compat/sso_login.rs b/crates/storage/src/compat/sso_login.rs index 348e0ac5..6ee3270a 100644 --- a/crates/storage/src/compat/sso_login.rs +++ b/crates/storage/src/compat/sso_login.rs @@ -37,7 +37,7 @@ pub trait CompatSsoLoginRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, login_token: String, redirect_uri: Url, ) -> Result; @@ -45,7 +45,7 @@ pub trait CompatSsoLoginRepository: Send + Sync { /// Fulfill a compat SSO login by providing a compat session async fn fulfill( &mut self, - clock: &Clock, + clock: &dyn Clock, compat_sso_login: CompatSsoLogin, compat_session: &CompatSession, ) -> Result; @@ -53,7 +53,7 @@ pub trait CompatSsoLoginRepository: Send + Sync { /// Mark a compat SSO login as exchanged async fn exchange( &mut self, - clock: &Clock, + clock: &dyn Clock, compat_sso_login: CompatSsoLogin, ) -> Result; diff --git a/crates/storage/src/lib.rs b/crates/storage/src/lib.rs index a65c806c..2a83b55e 100644 --- a/crates/storage/src/lib.rs +++ b/crates/storage/src/lib.rs @@ -28,92 +28,7 @@ clippy::module_name_repetitions )] -use chrono::{DateTime, Utc}; - -#[derive(Debug, Clone, Default)] -pub struct Clock { - _private: (), - - // #[cfg(test)] - mock: Option>, -} - -impl Clock { - #[must_use] - pub fn now(&self) -> DateTime { - // #[cfg(test)] - if let Some(timestamp) = &self.mock { - let timestamp = timestamp.load(std::sync::atomic::Ordering::Relaxed); - return chrono::TimeZone::timestamp_opt(&Utc, timestamp, 0).unwrap(); - } - - // This is the clock used elsewhere, it's fine to call Utc::now here - #[allow(clippy::disallowed_methods)] - Utc::now() - } - - // #[cfg(test)] - #[must_use] - pub fn mock() -> Self { - use std::sync::{atomic::AtomicI64, Arc}; - - use chrono::TimeZone; - - let datetime = Utc.with_ymd_and_hms(2022, 1, 16, 14, 40, 0).unwrap(); - let timestamp = datetime.timestamp(); - - Self { - mock: Some(Arc::new(AtomicI64::new(timestamp))), - _private: (), - } - } - - // #[cfg(test)] - pub fn advance(&self, duration: chrono::Duration) { - let timestamp = self - .mock - .as_ref() - .expect("Clock::advance should only be called on mocked clocks in tests"); - timestamp.fetch_add(duration.num_seconds(), std::sync::atomic::Ordering::Relaxed); - } -} - -#[cfg(test)] -mod tests { - use chrono::Duration; - - use super::*; - - #[test] - fn test_mocked_clock() { - let clock = Clock::mock(); - - // Time should be frozen, and give out the same timestamp on each call - let first = clock.now(); - std::thread::sleep(std::time::Duration::from_millis(10)); - let second = clock.now(); - - assert_eq!(first, second); - - // Clock can be advanced by a fixed duration - clock.advance(Duration::seconds(10)); - let third = clock.now(); - assert_eq!(first + Duration::seconds(10), third); - } - - #[test] - fn test_real_clock() { - let clock = Clock::default(); - - // Time should not be frozen - let first = clock.now(); - std::thread::sleep(std::time::Duration::from_millis(10)); - let second = clock.now(); - - assert_ne!(first, second); - assert!(first < second); - } -} +pub mod clock; pub mod compat; pub mod oauth2; @@ -123,6 +38,7 @@ pub mod upstream_oauth2; pub mod user; pub use self::{ + clock::{Clock, SystemClock}, pagination::{Page, Pagination}, repository::Repository, }; diff --git a/crates/storage/src/oauth2/access_token.rs b/crates/storage/src/oauth2/access_token.rs index a0406e44..4bbcf885 100644 --- a/crates/storage/src/oauth2/access_token.rs +++ b/crates/storage/src/oauth2/access_token.rs @@ -37,7 +37,7 @@ pub trait OAuth2AccessTokenRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, session: &Session, access_token: String, expires_after: Duration, @@ -46,10 +46,10 @@ pub trait OAuth2AccessTokenRepository: Send + Sync { /// Revoke an access token async fn revoke( &mut self, - clock: &Clock, + clock: &dyn Clock, access_token: AccessToken, ) -> Result; /// Cleanup expired access tokens - async fn cleanup_expired(&mut self, clock: &Clock) -> Result; + async fn cleanup_expired(&mut self, clock: &dyn Clock) -> Result; } diff --git a/crates/storage/src/oauth2/authorization_grant.rs b/crates/storage/src/oauth2/authorization_grant.rs index ce1a716f..96403f12 100644 --- a/crates/storage/src/oauth2/authorization_grant.rs +++ b/crates/storage/src/oauth2/authorization_grant.rs @@ -31,7 +31,7 @@ pub trait OAuth2AuthorizationGrantRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, client: &Client, redirect_uri: Url, scope: Scope, @@ -51,14 +51,14 @@ pub trait OAuth2AuthorizationGrantRepository: Send + Sync { async fn fulfill( &mut self, - clock: &Clock, + clock: &dyn Clock, session: &Session, authorization_grant: AuthorizationGrant, ) -> Result; async fn exchange( &mut self, - clock: &Clock, + clock: &dyn Clock, authorization_grant: AuthorizationGrant, ) -> Result; diff --git a/crates/storage/src/oauth2/client.rs b/crates/storage/src/oauth2/client.rs index 093369a4..30f37bc6 100644 --- a/crates/storage/src/oauth2/client.rs +++ b/crates/storage/src/oauth2/client.rs @@ -45,7 +45,7 @@ pub trait OAuth2ClientRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, redirect_uris: Vec, encrypted_client_secret: Option, grant_types: Vec, @@ -68,7 +68,7 @@ pub trait OAuth2ClientRepository: Send + Sync { async fn add_from_config( &mut self, mut rng: impl Rng + Send, - clock: &Clock, + clock: &dyn Clock, client_id: Ulid, client_auth_method: OAuthClientAuthenticationMethod, encrypted_client_secret: Option, @@ -86,7 +86,7 @@ pub trait OAuth2ClientRepository: Send + Sync { async fn give_consent_for_user( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, client: &Client, user: &User, scope: &Scope, diff --git a/crates/storage/src/oauth2/refresh_token.rs b/crates/storage/src/oauth2/refresh_token.rs index 1e23634a..88bb26fb 100644 --- a/crates/storage/src/oauth2/refresh_token.rs +++ b/crates/storage/src/oauth2/refresh_token.rs @@ -36,7 +36,7 @@ pub trait OAuth2RefreshTokenRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, session: &Session, access_token: &AccessToken, refresh_token: String, @@ -45,7 +45,7 @@ pub trait OAuth2RefreshTokenRepository: Send + Sync { /// Consume a refresh token async fn consume( &mut self, - clock: &Clock, + clock: &dyn Clock, refresh_token: RefreshToken, ) -> Result; } diff --git a/crates/storage/src/oauth2/session.rs b/crates/storage/src/oauth2/session.rs index 5e6498d8..944c7784 100644 --- a/crates/storage/src/oauth2/session.rs +++ b/crates/storage/src/oauth2/session.rs @@ -28,12 +28,12 @@ pub trait OAuth2SessionRepository: Send + Sync { async fn create_from_grant( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, grant: &AuthorizationGrant, user_session: &BrowserSession, ) -> Result; - async fn finish(&mut self, clock: &Clock, session: Session) -> Result; + async fn finish(&mut self, clock: &dyn Clock, session: Session) -> Result; async fn list_paginated( &mut self, diff --git a/crates/storage/src/upstream_oauth2/link.rs b/crates/storage/src/upstream_oauth2/link.rs index bc20c6ea..474c21d9 100644 --- a/crates/storage/src/upstream_oauth2/link.rs +++ b/crates/storage/src/upstream_oauth2/link.rs @@ -37,7 +37,7 @@ pub trait UpstreamOAuthLinkRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, upstream_oauth_provider: &UpstreamOAuthProvider, subject: String, ) -> Result; diff --git a/crates/storage/src/upstream_oauth2/provider.rs b/crates/storage/src/upstream_oauth2/provider.rs index 4be8f127..10a03e2b 100644 --- a/crates/storage/src/upstream_oauth2/provider.rs +++ b/crates/storage/src/upstream_oauth2/provider.rs @@ -33,7 +33,7 @@ pub trait UpstreamOAuthProviderRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, issuer: String, scope: Scope, token_endpoint_auth_method: OAuthClientAuthenticationMethod, diff --git a/crates/storage/src/upstream_oauth2/session.rs b/crates/storage/src/upstream_oauth2/session.rs index 4d41a8ec..e1b6abc1 100644 --- a/crates/storage/src/upstream_oauth2/session.rs +++ b/crates/storage/src/upstream_oauth2/session.rs @@ -33,7 +33,7 @@ pub trait UpstreamOAuthSessionRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, upstream_oauth_provider: &UpstreamOAuthProvider, state: String, code_challenge_verifier: Option, @@ -43,7 +43,7 @@ pub trait UpstreamOAuthSessionRepository: Send + Sync { /// Mark a session as completed and associate the given link async fn complete_with_link( &mut self, - clock: &Clock, + clock: &dyn Clock, upstream_oauth_authorization_session: UpstreamOAuthAuthorizationSession, upstream_oauth_link: &UpstreamOAuthLink, id_token: Option, @@ -52,7 +52,7 @@ pub trait UpstreamOAuthSessionRepository: Send + Sync { /// Mark a session as consumed async fn consume( &mut self, - clock: &Clock, + clock: &dyn Clock, upstream_oauth_authorization_session: UpstreamOAuthAuthorizationSession, ) -> Result; } diff --git a/crates/storage/src/user/email.rs b/crates/storage/src/user/email.rs index 41a7d293..4b8f846d 100644 --- a/crates/storage/src/user/email.rs +++ b/crates/storage/src/user/email.rs @@ -38,7 +38,7 @@ pub trait UserEmailRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user: &User, email: String, ) -> Result; @@ -46,7 +46,7 @@ pub trait UserEmailRepository: Send + Sync { async fn mark_as_verified( &mut self, - clock: &Clock, + clock: &dyn Clock, user_email: UserEmail, ) -> Result; @@ -55,7 +55,7 @@ pub trait UserEmailRepository: Send + Sync { async fn add_verification_code( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user_email: &UserEmail, max_age: chrono::Duration, code: String, @@ -63,14 +63,14 @@ pub trait UserEmailRepository: Send + Sync { async fn find_verification_code( &mut self, - clock: &Clock, + clock: &dyn Clock, user_email: &UserEmail, code: &str, ) -> Result, Self::Error>; async fn consume_verification_code( &mut self, - clock: &Clock, + clock: &dyn Clock, verification: UserEmailVerification, ) -> Result; } diff --git a/crates/storage/src/user/mod.rs b/crates/storage/src/user/mod.rs index 23c2f6d1..8e046a9d 100644 --- a/crates/storage/src/user/mod.rs +++ b/crates/storage/src/user/mod.rs @@ -36,7 +36,7 @@ pub trait UserRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, username: String, ) -> Result; async fn exists(&mut self, username: &str) -> Result; diff --git a/crates/storage/src/user/password.rs b/crates/storage/src/user/password.rs index 2d2d2534..306f7d93 100644 --- a/crates/storage/src/user/password.rs +++ b/crates/storage/src/user/password.rs @@ -26,7 +26,7 @@ pub trait UserPasswordRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user: &User, version: u16, hashed_password: String, diff --git a/crates/storage/src/user/session.rs b/crates/storage/src/user/session.rs index 2e55f40c..5499f45a 100644 --- a/crates/storage/src/user/session.rs +++ b/crates/storage/src/user/session.rs @@ -27,12 +27,12 @@ pub trait BrowserSessionRepository: Send + Sync { async fn add( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user: &User, ) -> Result; async fn finish( &mut self, - clock: &Clock, + clock: &dyn Clock, user_session: BrowserSession, ) -> Result; async fn list_active_paginated( @@ -45,7 +45,7 @@ pub trait BrowserSessionRepository: Send + Sync { async fn authenticate_with_password( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user_session: BrowserSession, user_password: &Password, ) -> Result; @@ -53,7 +53,7 @@ pub trait BrowserSessionRepository: Send + Sync { async fn authenticate_with_upstream( &mut self, rng: &mut (dyn RngCore + Send), - clock: &Clock, + clock: &dyn Clock, user_session: BrowserSession, upstream_oauth_link: &UpstreamOAuthLink, ) -> Result; diff --git a/crates/tasks/src/database.rs b/crates/tasks/src/database.rs index 66068860..9e31880c 100644 --- a/crates/tasks/src/database.rs +++ b/crates/tasks/src/database.rs @@ -14,7 +14,7 @@ //! Database-related tasks -use mas_storage::{oauth2::OAuth2AccessTokenRepository, Clock, Repository}; +use mas_storage::{oauth2::OAuth2AccessTokenRepository, Repository, SystemClock}; use mas_storage_pg::PgRepository; use sqlx::{Pool, Postgres}; use tracing::{debug, error, info}; @@ -22,7 +22,7 @@ use tracing::{debug, error, info}; use super::Task; #[derive(Clone)] -struct CleanupExpired(Pool, Clock); +struct CleanupExpired(Pool, SystemClock); impl std::fmt::Debug for CleanupExpired { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -57,5 +57,5 @@ impl Task for CleanupExpired { #[must_use] pub fn cleanup_expired(pool: &Pool) -> impl Task + Clone { // XXX: the clock should come from somewhere else - CleanupExpired(pool.clone(), Clock::default()) + CleanupExpired(pool.clone(), SystemClock::default()) }