From 9005931e2ad2f17737389664699409cc3fc0e8ec Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Wed, 18 Jan 2023 17:32:54 +0100 Subject: [PATCH] handlers: box the rng and clock, and extract it from the state --- Cargo.lock | 2 +- crates/axum-utils/src/csrf.rs | 21 +++++++--- crates/axum-utils/src/user_authorization.rs | 15 ++++--- crates/data-model/src/tokens.rs | 4 +- crates/handlers/src/app_state.rs | 39 ++++++++++++++++- crates/handlers/src/compat/login.rs | 29 +++++++++---- .../handlers/src/compat/login_sso_complete.rs | 12 +++--- .../handlers/src/compat/login_sso_redirect.rs | 8 ++-- crates/handlers/src/compat/logout.rs | 5 +-- crates/handlers/src/compat/refresh.rs | 6 +-- crates/handlers/src/lib.rs | 25 +++++------ .../src/oauth2/authorization/complete.rs | 12 +++--- .../handlers/src/oauth2/authorization/mod.rs | 26 +++++++++--- crates/handlers/src/oauth2/consent.rs | 13 +++--- crates/handlers/src/oauth2/introspection.rs | 5 +-- crates/handlers/src/oauth2/registration.rs | 6 +-- crates/handlers/src/oauth2/token.rs | 42 ++++++++++++------- crates/handlers/src/oauth2/userinfo.rs | 8 ++-- .../handlers/src/upstream_oauth2/authorize.rs | 9 ++-- .../handlers/src/upstream_oauth2/callback.rs | 9 ++-- crates/handlers/src/upstream_oauth2/cookie.rs | 11 ++--- crates/handlers/src/upstream_oauth2/link.rs | 16 +++---- .../handlers/src/views/account/emails/add.rs | 12 +++--- .../handlers/src/views/account/emails/mod.rs | 13 +++--- .../src/views/account/emails/verify.rs | 11 ++--- crates/handlers/src/views/account/mod.rs | 7 ++-- crates/handlers/src/views/account/password.rs | 12 +++--- crates/handlers/src/views/index.rs | 7 ++-- crates/handlers/src/views/login.rs | 14 ++++--- crates/handlers/src/views/logout.rs | 6 +-- crates/handlers/src/views/reauth.rs | 12 +++--- crates/handlers/src/views/register.rs | 14 ++++--- crates/storage-pg/src/oauth2/client.rs | 6 +-- crates/storage/Cargo.toml | 2 +- crates/storage/src/clock.rs | 6 +++ crates/storage/src/compat/access_token.rs | 2 +- crates/storage/src/compat/refresh_token.rs | 2 +- crates/storage/src/compat/session.rs | 2 +- crates/storage/src/compat/sso_login.rs | 2 +- crates/storage/src/lib.rs | 5 +++ crates/storage/src/oauth2/access_token.rs | 2 +- .../storage/src/oauth2/authorization_grant.rs | 2 +- crates/storage/src/oauth2/client.rs | 4 +- crates/storage/src/oauth2/refresh_token.rs | 2 +- crates/storage/src/oauth2/session.rs | 2 +- crates/storage/src/upstream_oauth2/link.rs | 2 +- .../storage/src/upstream_oauth2/provider.rs | 2 +- crates/storage/src/upstream_oauth2/session.rs | 2 +- crates/storage/src/user/email.rs | 2 +- crates/storage/src/user/mod.rs | 2 +- crates/storage/src/user/password.rs | 2 +- crates/storage/src/user/session.rs | 2 +- 52 files changed, 291 insertions(+), 193 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ecc512d..253809cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3105,7 +3105,7 @@ dependencies = [ "mas-iana", "mas-jose", "oauth2-types", - "rand 0.8.5", + "rand_core 0.6.4", "thiserror", "ulid", "url", diff --git a/crates/axum-utils/src/csrf.rs b/crates/axum-utils/src/csrf.rs index e7037d55..9886fedb 100644 --- a/crates/axum-utils/src/csrf.rs +++ b/crates/axum-utils/src/csrf.rs @@ -15,6 +15,7 @@ use axum_extra::extract::cookie::{Cookie, PrivateCookieJar}; use chrono::{DateTime, Duration, Utc}; use data_encoding::{DecodeError, BASE64URL_NOPAD}; +use mas_storage::Clock; use rand::{Rng, RngCore}; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, TimestampSeconds}; @@ -108,22 +109,27 @@ pub struct ProtectedForm { } pub trait CsrfExt { - fn csrf_token(self, now: DateTime, rng: R) -> (CsrfToken, Self) + fn csrf_token(self, clock: &C, rng: R) -> (CsrfToken, Self) where - R: RngCore; - fn verify_form(&self, now: DateTime, form: ProtectedForm) -> Result; + R: RngCore, + C: Clock; + fn verify_form(&self, clock: &C, form: ProtectedForm) -> Result + where + C: Clock; } impl CsrfExt for PrivateCookieJar { - fn csrf_token(self, now: DateTime, rng: R) -> (CsrfToken, Self) + fn csrf_token(self, clock: &C, rng: R) -> (CsrfToken, Self) where R: RngCore, + C: Clock, { let jar = self; let mut cookie = jar.get("csrf").unwrap_or_else(|| Cookie::new("csrf", "")); cookie.set_path("/"); cookie.set_http_only(true); + let now = clock.now(); let new_token = cookie .decode() .ok() @@ -136,10 +142,13 @@ impl CsrfExt for PrivateCookieJar { (new_token, jar) } - fn verify_form(&self, now: DateTime, form: ProtectedForm) -> Result { + fn verify_form(&self, clock: &C, form: ProtectedForm) -> Result + where + C: Clock, + { let cookie = self.get("csrf").ok_or(CsrfError::Missing)?; let token: CsrfToken = cookie.decode()?; - let token = token.verify_expiration(now)?; + let token = token.verify_expiration(clock.now())?; token.verify_form_value(&form.csrf)?; Ok(form.inner) } diff --git a/crates/axum-utils/src/user_authorization.rs b/crates/axum-utils/src/user_authorization.rs index 11d79312..9a5956c9 100644 --- a/crates/axum-utils/src/user_authorization.rs +++ b/crates/axum-utils/src/user_authorization.rs @@ -24,13 +24,12 @@ use axum::{ response::{IntoResponse, Response}, BoxError, }; -use chrono::{DateTime, Utc}; use headers::{authorization::Bearer, Authorization, Header, HeaderMapExt, HeaderName}; use http::{header::WWW_AUTHENTICATE, HeaderMap, HeaderValue, Request, StatusCode}; use mas_data_model::Session; use mas_storage::{ oauth2::{OAuth2AccessTokenRepository, OAuth2SessionRepository}, - Repository, + Clock, Repository, }; use serde::{de::DeserializeOwned, Deserialize}; use thiserror::Error; @@ -86,10 +85,10 @@ pub struct UserAuthorization { impl UserAuthorization { // TODO: take scopes to validate as parameter - pub async fn protected_form( + pub async fn protected_form( self, repo: &mut R, - now: DateTime, + clock: &C, ) -> Result<(Session, F), AuthorizationVerificationError> { let form = match self.form { Some(f) => f, @@ -98,7 +97,7 @@ impl UserAuthorization { let (token, session) = self.access_token.fetch(repo).await?; - if !token.is_valid(now) || !session.is_valid() { + if !token.is_valid(clock.now()) || !session.is_valid() { return Err(AuthorizationVerificationError::InvalidToken); } @@ -106,14 +105,14 @@ impl UserAuthorization { } // TODO: take scopes to validate as parameter - pub async fn protected( + pub async fn protected( self, repo: &mut R, - now: DateTime, + clock: &C, ) -> Result> { let (token, session) = self.access_token.fetch(repo).await?; - if !token.is_valid(now) || !session.is_valid() { + if !token.is_valid(clock.now()) || !session.is_valid() { return Err(AuthorizationVerificationError::InvalidToken); } diff --git a/crates/data-model/src/tokens.rs b/crates/data-model/src/tokens.rs index 2d57a663..ad8c407e 100644 --- a/crates/data-model/src/tokens.rs +++ b/crates/data-model/src/tokens.rs @@ -15,7 +15,7 @@ use chrono::{DateTime, Utc}; use crc::{Crc, CRC_32_ISO_HDLC}; use mas_iana::oauth::OAuthTokenTypeHint; -use rand::{distributions::Alphanumeric, Rng}; +use rand::{distributions::Alphanumeric, Rng, RngCore}; use thiserror::Error; use ulid::Ulid; @@ -193,7 +193,7 @@ impl TokenType { /// AccessToken.generate(thread_rng()); /// RefreshToken.generate(thread_rng()); /// ``` - pub fn generate(self, rng: impl Rng) -> String { + pub fn generate(self, rng: &mut (impl RngCore + ?Sized)) -> String { let random_part: String = rng .sample_iter(&Alphanumeric) .take(30) diff --git a/crates/handlers/src/app_state.rs b/crates/handlers/src/app_state.rs index c9c65090..45446e10 100644 --- a/crates/handlers/src/app_state.rs +++ b/crates/handlers/src/app_state.rs @@ -12,15 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::Arc; +use std::{convert::Infallible, sync::Arc}; -use axum::extract::FromRef; +use axum::{ + async_trait, + extract::{FromRef, FromRequestParts}, +}; use mas_axum_utils::http_client_factory::HttpClientFactory; use mas_email::Mailer; use mas_keystore::{Encrypter, Keystore}; use mas_policy::PolicyFactory; use mas_router::UrlBuilder; +use mas_storage::{BoxClock, BoxRng, SystemClock}; use mas_templates::Templates; +use rand::SeedableRng; use sqlx::PgPool; use crate::{passwords::PasswordManager, MatrixHomeserver}; @@ -105,3 +110,33 @@ impl FromRef for PasswordManager { input.password_manager.clone() } } + +#[async_trait] +impl FromRequestParts for BoxClock { + type Rejection = Infallible; + + async fn from_request_parts( + _parts: &mut axum::http::request::Parts, + _state: &AppState, + ) -> Result { + let clock = SystemClock::default(); + Ok(Box::new(clock)) + } +} + +#[async_trait] +impl FromRequestParts for BoxRng { + type Rejection = Infallible; + + async fn from_request_parts( + _parts: &mut axum::http::request::Parts, + _state: &AppState, + ) -> Result { + // This rng is used to source the local rng + #[allow(clippy::disallowed_methods)] + let rng = rand::thread_rng(); + + let rng = rand_chacha::ChaChaRng::from_rng(rng).expect("Failed to seed RNG"); + Ok(Box::new(rng)) + } +} diff --git a/crates/handlers/src/compat/login.rs b/crates/handlers/src/compat/login.rs index 9b0a0792..279b575d 100644 --- a/crates/handlers/src/compat/login.rs +++ b/crates/handlers/src/compat/login.rs @@ -22,9 +22,10 @@ use mas_storage::{ CompatSsoLoginRepository, }, user::{UserPasswordRepository, UserRepository}, - Clock, Repository, SystemClock, + BoxClock, BoxRng, Clock, Repository, }; use mas_storage_pg::PgRepository; +use rand::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, skip_serializing_none, DurationMilliSeconds}; use sqlx::PgPool; @@ -154,7 +155,6 @@ pub enum RouteError { InvalidLoginToken, } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl IntoResponse for RouteError { @@ -194,18 +194,29 @@ impl IntoResponse for RouteError { #[tracing::instrument(skip_all, err)] pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(password_manager): State, State(pool): State, State(homeserver): State, Json(input): Json, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; let (session, user) = match input.credentials { Credentials::Password { identifier: Identifier::User { user }, password, - } => user_password_login(&password_manager, &mut repo, user, password).await?, + } => { + user_password_login( + &mut rng, + &clock, + &password_manager, + &mut repo, + user, + password, + ) + .await? + } Credentials::Token { token } => token_login(&mut repo, &clock, &token).await?, @@ -254,7 +265,7 @@ pub(crate) async fn post( async fn token_login( repo: &mut PgRepository, - clock: &SystemClock, + clock: &dyn Clock, token: &str, ) -> Result<(CompatSession, User), RouteError> { let login = repo @@ -319,13 +330,13 @@ async fn token_login( } async fn user_password_login( + mut rng: &mut (impl RngCore + CryptoRng + Send), + clock: &impl Clock, password_manager: &PasswordManager, repo: &mut PgRepository, username: String, password: String, ) -> Result<(CompatSession, User), RouteError> { - let (clock, mut rng) = crate::clock_and_rng(); - // Find the user let user = repo .user() @@ -358,7 +369,7 @@ async fn user_password_login( repo.user_password() .add( &mut rng, - &clock, + clock, &user, version, hashed_password, @@ -371,7 +382,7 @@ async fn user_password_login( let device = Device::generate(&mut rng); let session = repo .compat_session() - .add(&mut rng, &clock, &user, device) + .add(&mut rng, clock, &user, device) .await?; Ok((session, user)) diff --git a/crates/handlers/src/compat/login_sso_complete.rs b/crates/handlers/src/compat/login_sso_complete.rs index 631d1126..6201b0c6 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}, - Clock, Repository, + BoxClock, BoxRng, Clock, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{CompatSsoContext, ErrorContext, TemplateContext, Templates}; @@ -54,17 +54,18 @@ pub struct Params { } pub async fn get( + mut rng: BoxRng, + clock: BoxClock, State(pool): State, State(templates): State, cookie_jar: PrivateCookieJar, Path(id): Path, Query(params): Query, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; let (session_info, cookie_jar) = cookie_jar.session_info(); - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let maybe_session = session_info.load_session(&mut repo).await?; @@ -117,6 +118,8 @@ pub async fn get( } pub async fn post( + mut rng: BoxRng, + clock: BoxClock, State(pool): State, State(templates): State, cookie_jar: PrivateCookieJar, @@ -124,11 +127,10 @@ pub async fn post( Query(params): Query, Form(form): Form>, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; let (session_info, cookie_jar) = cookie_jar.session_info(); - cookie_jar.verify_form(clock.now(), form)?; + cookie_jar.verify_form(&clock, form)?; let maybe_session = session_info.load_session(&mut repo).await?; diff --git a/crates/handlers/src/compat/login_sso_redirect.rs b/crates/handlers/src/compat/login_sso_redirect.rs index 38aa0894..a8063141 100644 --- a/crates/handlers/src/compat/login_sso_redirect.rs +++ b/crates/handlers/src/compat/login_sso_redirect.rs @@ -19,7 +19,7 @@ use axum::{ }; use hyper::StatusCode; use mas_router::{CompatLoginSsoAction, CompatLoginSsoComplete, UrlBuilder}; -use mas_storage::{compat::CompatSsoLoginRepository, Repository}; +use mas_storage::{compat::CompatSsoLoginRepository, BoxClock, BoxRng, Repository}; use mas_storage_pg::PgRepository; use rand::distributions::{Alphanumeric, DistString}; use serde::Deserialize; @@ -49,7 +49,6 @@ pub enum RouteError { InvalidRedirectUrl, } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl IntoResponse for RouteError { @@ -58,14 +57,13 @@ impl IntoResponse for RouteError { } } -#[tracing::instrument(skip(pool, url_builder), err)] pub async fn get( + mut rng: BoxRng, + clock: BoxClock, State(pool): State, State(url_builder): State, Query(params): Query, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); - // Check the redirectUrl parameter let redirect_url = params.redirect_url.ok_or(RouteError::MissingRedirectUrl)?; let redirect_url = Url::parse(&redirect_url).map_err(|_| RouteError::InvalidRedirectUrl)?; diff --git a/crates/handlers/src/compat/logout.rs b/crates/handlers/src/compat/logout.rs index 310fef2e..bfc767fa 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, SystemClock, + BoxClock, Clock, Repository, }; use mas_storage_pg::PgRepository; use sqlx::PgPool; @@ -42,7 +42,6 @@ pub enum RouteError { InvalidAuthorization, } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl IntoResponse for RouteError { @@ -69,10 +68,10 @@ impl IntoResponse for RouteError { } pub(crate) async fn post( + clock: BoxClock, State(pool): State, maybe_authorization: Option>>, ) -> Result { - 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 8b47a81f..868be9db 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}, - Clock, Repository, + BoxClock, BoxRng, Clock, Repository, }; use mas_storage_pg::PgRepository; use serde::{Deserialize, Serialize}; @@ -70,7 +70,6 @@ impl IntoResponse for RouteError { } } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl From for RouteError { @@ -89,10 +88,11 @@ pub struct ResponseBody { } pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(pool): State, Json(input): Json, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; let token_type = TokenType::check(&input.refresh_token)?; diff --git a/crates/handlers/src/lib.rs b/crates/handlers/src/lib.rs index 0360e741..4d9dcbcd 100644 --- a/crates/handlers/src/lib.rs +++ b/crates/handlers/src/lib.rs @@ -28,7 +28,7 @@ use std::{convert::Infallible, sync::Arc, time::Duration}; use axum::{ body::{Bytes, HttpBody}, - extract::FromRef, + extract::{FromRef, FromRequestParts}, response::{Html, IntoResponse}, routing::{get, on, post, MethodFilter}, Router, @@ -40,9 +40,9 @@ use mas_http::CorsLayerExt; use mas_keystore::{Encrypter, Keystore}; use mas_policy::PolicyFactory; use mas_router::{Route, UrlBuilder}; +use mas_storage::{BoxClock, BoxRng}; use mas_templates::{ErrorContext, Templates}; use passwords::PasswordManager; -use rand::SeedableRng; use sqlx::PgPool; use tower::util::AndThenLayer; use tower_http::cors::{Any, CorsLayer}; @@ -116,6 +116,8 @@ where S: Clone + Send + Sync + 'static, Keystore: FromRef, UrlBuilder: FromRef, + BoxClock: FromRequestParts, + BoxRng: FromRequestParts, { Router::new() .route( @@ -155,6 +157,8 @@ where PgPool: FromRef, Encrypter: FromRef, HttpClientFactory: FromRef, + BoxClock: FromRequestParts, + BoxRng: FromRequestParts, { // All those routes are API-like, with a common CORS layer Router::new() @@ -208,6 +212,8 @@ where PgPool: FromRef, MatrixHomeserver: FromRef, PasswordManager: FromRef, + BoxClock: FromRequestParts, + BoxRng: FromRequestParts, { Router::new() .route( @@ -255,6 +261,8 @@ where Keystore: FromRef, HttpClientFactory: FromRef, PasswordManager: FromRef, + BoxClock: FromRequestParts, + BoxRng: FromRequestParts, { Router::new() .route( @@ -407,16 +415,3 @@ async fn test_state(pool: PgPool) -> Result { password_manager, }) } - -// XXX: that should be moved somewhere else -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)] - let rng = rand::thread_rng(); - - let rng = rand_chacha::ChaChaRng::from_rng(rng).expect("Failed to seed RNG"); - - (clock, rng) -} diff --git a/crates/handlers/src/oauth2/authorization/complete.rs b/crates/handlers/src/oauth2/authorization/complete.rs index 05554e12..934ba088 100644 --- a/crates/handlers/src/oauth2/authorization/complete.rs +++ b/crates/handlers/src/oauth2/authorization/complete.rs @@ -27,7 +27,7 @@ use mas_policy::PolicyFactory; use mas_router::{PostAuthAction, Route}; use mas_storage::{ oauth2::{OAuth2AuthorizationGrantRepository, OAuth2ClientRepository, OAuth2SessionRepository}, - Repository, + BoxClock, BoxRng, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::Templates; @@ -70,7 +70,6 @@ impl IntoResponse for RouteError { } } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl_from_error_for_route!(mas_policy::LoadError); impl_from_error_for_route!(mas_policy::InstanciateError); @@ -79,6 +78,8 @@ impl_from_error_for_route!(super::callback::IntoCallbackDestinationError); impl_from_error_for_route!(super::callback::CallbackDestinationError); pub(crate) async fn get( + rng: BoxRng, + clock: BoxClock, State(policy_factory): State>, State(templates): State, State(pool): State, @@ -108,7 +109,7 @@ pub(crate) async fn get( return Ok((cookie_jar, mas_router::Login::and_then(continue_grant).go()).into_response()); }; - match complete(grant, session, &policy_factory, repo).await { + match complete(rng, clock, grant, session, &policy_factory, repo).await { Ok(params) => { let res = callback_destination.go(&templates, params).await?; Ok((cookie_jar, res).into_response()) @@ -149,7 +150,6 @@ pub enum GrantCompletionError { NoSuchClient, } -impl_from_error_for_route!(GrantCompletionError: sqlx::Error); impl_from_error_for_route!(GrantCompletionError: mas_storage_pg::DatabaseError); impl_from_error_for_route!(GrantCompletionError: super::callback::IntoCallbackDestinationError); impl_from_error_for_route!(GrantCompletionError: mas_policy::LoadError); @@ -157,13 +157,13 @@ impl_from_error_for_route!(GrantCompletionError: mas_policy::InstanciateError); impl_from_error_for_route!(GrantCompletionError: mas_policy::EvaluationError); pub(crate) async fn complete( + mut rng: BoxRng, + clock: BoxClock, grant: AuthorizationGrant, browser_session: BrowserSession, policy_factory: &PolicyFactory, mut repo: PgRepository, ) -> Result>, GrantCompletionError> { - let (clock, mut rng) = crate::clock_and_rng(); - // Verify that the grant is in a pending stage if !grant.stage.is_pending() { return Err(GrantCompletionError::NotPending); diff --git a/crates/handlers/src/oauth2/authorization/mod.rs b/crates/handlers/src/oauth2/authorization/mod.rs index 43bda928..60753482 100644 --- a/crates/handlers/src/oauth2/authorization/mod.rs +++ b/crates/handlers/src/oauth2/authorization/mod.rs @@ -27,7 +27,7 @@ use mas_policy::PolicyFactory; use mas_router::{PostAuthAction, Route}; use mas_storage::{ oauth2::{OAuth2AuthorizationGrantRepository, OAuth2ClientRepository}, - Repository, + BoxClock, BoxRng, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::Templates; @@ -91,7 +91,6 @@ impl IntoResponse for RouteError { } } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl_from_error_for_route!(self::callback::CallbackDestinationError); impl_from_error_for_route!(mas_policy::LoadError); @@ -133,13 +132,14 @@ fn resolve_response_mode( #[allow(clippy::too_many_lines)] pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(policy_factory): State>, State(templates): State, State(pool): State, cookie_jar: PrivateCookieJar, Form(params): Form, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; // First, figure out what client it is @@ -334,7 +334,15 @@ pub(crate) async fn get( // Else, we immediately try to complete the authorization grant Some(user_session) if prompt.contains(&Prompt::None) => { // With prompt=none, we should get back to the client immediately - match self::complete::complete(grant, user_session, &policy_factory, repo).await + match self::complete::complete( + rng, + clock, + grant, + user_session, + &policy_factory, + repo, + ) + .await { Ok(params) => callback_destination.go(&templates, params).await?, Err(GrantCompletionError::RequiresConsent) => { @@ -373,7 +381,15 @@ pub(crate) async fn get( Some(user_session) => { let grant_id = grant.id; // Else, we show the relevant reauth/consent page if necessary - match self::complete::complete(grant, user_session, &policy_factory, repo).await + match self::complete::complete( + rng, + clock, + grant, + user_session, + &policy_factory, + repo, + ) + .await { Ok(params) => callback_destination.go(&templates, params).await?, Err( diff --git a/crates/handlers/src/oauth2/consent.rs b/crates/handlers/src/oauth2/consent.rs index 8fe4d2ac..86c832fb 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}, - Clock, Repository, + BoxClock, BoxRng, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{ConsentContext, PolicyViolationContext, TemplateContext, Templates}; @@ -61,7 +61,6 @@ pub enum RouteError { NoSuchClient, } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_templates::TemplateError); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl_from_error_for_route!(mas_policy::LoadError); @@ -75,13 +74,14 @@ impl IntoResponse for RouteError { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(policy_factory): State>, State(templates): State, State(pool): State, cookie_jar: PrivateCookieJar, Path(grant_id): Path, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; let (session_info, cookie_jar) = cookie_jar.session_info(); @@ -99,7 +99,7 @@ pub(crate) async fn get( } if let Some(session) = maybe_session { - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let mut policy = policy_factory.instantiate().await?; let res = policy @@ -130,16 +130,17 @@ pub(crate) async fn get( } pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(policy_factory): State>, State(pool): State, cookie_jar: PrivateCookieJar, Path(grant_id): Path, Form(form): Form>, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - cookie_jar.verify_form(clock.now(), form)?; + cookie_jar.verify_form(&clock, form)?; let (session_info, cookie_jar) = cookie_jar.session_info(); diff --git a/crates/handlers/src/oauth2/introspection.rs b/crates/handlers/src/oauth2/introspection.rs index 245f2125..d8e64fa0 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, SystemClock, + BoxClock, Clock, Repository, }; use mas_storage_pg::PgRepository; use oauth2_types::{ @@ -97,7 +97,6 @@ impl IntoResponse for RouteError { } } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl From for RouteError { @@ -125,12 +124,12 @@ const API_SCOPE: ScopeToken = ScopeToken::from_static("urn:matrix:org.matrix.msc #[allow(clippy::too_many_lines)] pub(crate) async fn post( + clock: BoxClock, State(http_client_factory): State, State(pool): State, State(encrypter): State, client_authorization: ClientAuthorization, ) -> Result { - let clock = SystemClock::default(); let mut repo = PgRepository::from_pool(&pool).await?; let client = client_authorization diff --git a/crates/handlers/src/oauth2/registration.rs b/crates/handlers/src/oauth2/registration.rs index 8e9489e8..da043b8b 100644 --- a/crates/handlers/src/oauth2/registration.rs +++ b/crates/handlers/src/oauth2/registration.rs @@ -19,7 +19,7 @@ use hyper::StatusCode; use mas_iana::oauth::OAuthClientAuthenticationMethod; use mas_keystore::Encrypter; use mas_policy::{PolicyFactory, Violation}; -use mas_storage::{oauth2::OAuth2ClientRepository, Repository}; +use mas_storage::{oauth2::OAuth2ClientRepository, BoxClock, BoxRng, Repository}; use mas_storage_pg::PgRepository; use oauth2_types::{ errors::{ClientError, ClientErrorCode}, @@ -49,7 +49,6 @@ pub(crate) enum RouteError { PolicyDenied(Vec), } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl_from_error_for_route!(mas_policy::LoadError); impl_from_error_for_route!(mas_policy::InstanciateError); @@ -108,12 +107,13 @@ impl IntoResponse for RouteError { #[tracing::instrument(skip_all, err)] pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(pool): State, State(policy_factory): State>, State(encrypter): State, Json(body): Json, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); info!(?body, "Client registration"); // Validate the body diff --git a/crates/handlers/src/oauth2/token.rs b/crates/handlers/src/oauth2/token.rs index de0118f4..3fe916d8 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, - Clock, Repository, + BoxClock, BoxRng, Clock, Repository, }; use mas_storage_pg::PgRepository; use oauth2_types::{ @@ -151,7 +151,6 @@ impl IntoResponse for RouteError { } } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl_from_error_for_route!(mas_keystore::WrongAlgorithmError); impl_from_error_for_route!(mas_jose::claims::ClaimError); @@ -160,6 +159,8 @@ impl_from_error_for_route!(mas_jose::jwt::JwtSignatureError); #[tracing::instrument(skip_all, err)] pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(http_client_factory): State, State(key_store): State, State(url_builder): State, @@ -189,10 +190,19 @@ pub(crate) async fn post( let reply = match form { AccessTokenRequest::AuthorizationCode(grant) => { - authorization_code_grant(&grant, &client, &key_store, &url_builder, repo).await? + authorization_code_grant( + &mut rng, + &clock, + &grant, + &client, + &key_store, + &url_builder, + repo, + ) + .await? } AccessTokenRequest::RefreshToken(grant) => { - refresh_token_grant(&grant, &client, repo).await? + refresh_token_grant(&mut rng, &clock, &grant, &client, repo).await? } _ => { return Err(RouteError::InvalidGrant); @@ -208,14 +218,14 @@ pub(crate) async fn post( #[allow(clippy::too_many_lines)] async fn authorization_code_grant( + mut rng: &mut BoxRng, + clock: &impl Clock, grant: &AuthorizationCodeGrant, client: &Client, key_store: &Keystore, url_builder: &UrlBuilder, mut repo: PgRepository, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); - let authz_grant = repo .oauth2_authorization_grant() .find_by_code(&grant.code) @@ -244,7 +254,7 @@ async fn authorization_code_grant( .lookup(session_id) .await? .ok_or(RouteError::NoSuchOAuthSession)?; - repo.oauth2_session().finish(&clock, session).await?; + repo.oauth2_session().finish(clock, session).await?; repo.save().await?; } @@ -302,12 +312,12 @@ async fn authorization_code_grant( let access_token = repo .oauth2_access_token() - .add(&mut rng, &clock, &session, access_token_str, ttl) + .add(&mut rng, clock, &session, access_token_str, ttl) .await?; let refresh_token = repo .oauth2_refresh_token() - .add(&mut rng, &clock, &session, &access_token, refresh_token_str) + .add(&mut rng, clock, &session, &access_token, refresh_token_str) .await?; let id_token = if session.scope.contains(&scope::OPENID) { @@ -357,7 +367,7 @@ async fn authorization_code_grant( } repo.oauth2_authorization_grant() - .exchange(&clock, authz_grant) + .exchange(clock, authz_grant) .await?; repo.save().await?; @@ -366,12 +376,12 @@ async fn authorization_code_grant( } async fn refresh_token_grant( + mut rng: &mut BoxRng, + clock: &impl Clock, grant: &RefreshTokenGrant, client: &Client, mut repo: PgRepository, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); - let refresh_token = repo .oauth2_refresh_token() .find_by_token(&grant.refresh_token) @@ -399,14 +409,14 @@ async fn refresh_token_grant( let new_access_token = repo .oauth2_access_token() - .add(&mut rng, &clock, &session, access_token_str.clone(), ttl) + .add(&mut rng, clock, &session, access_token_str.clone(), ttl) .await?; let new_refresh_token = repo .oauth2_refresh_token() .add( &mut rng, - &clock, + clock, &session, &new_access_token, refresh_token_str, @@ -415,13 +425,13 @@ async fn refresh_token_grant( let refresh_token = repo .oauth2_refresh_token() - .consume(&clock, refresh_token) + .consume(clock, refresh_token) .await?; if let Some(access_token_id) = refresh_token.access_token_id { if let Some(access_token) = repo.oauth2_access_token().lookup(access_token_id).await? { repo.oauth2_access_token() - .revoke(&clock, access_token) + .revoke(clock, access_token) .await?; } } diff --git a/crates/handlers/src/oauth2/userinfo.rs b/crates/handlers/src/oauth2/userinfo.rs index 39bc7587..9d60ac1f 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}, - Clock, Repository, + BoxClock, BoxRng, Repository, }; use mas_storage_pg::PgRepository; use oauth2_types::scope; @@ -79,7 +79,6 @@ pub enum RouteError { NoSuchBrowserSession, } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl_from_error_for_route!(mas_keystore::WrongAlgorithmError); impl_from_error_for_route!(mas_jose::jwt::JwtSignatureError); @@ -99,15 +98,16 @@ impl IntoResponse for RouteError { } pub async fn get( + mut rng: BoxRng, + clock: BoxClock, State(url_builder): State, State(pool): State, State(key_store): State, user_authorization: UserAuthorization, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let session = user_authorization.protected(&mut repo, clock.now()).await?; + let session = user_authorization.protected(&mut repo, &clock).await?; let browser_session = repo .browser_session() diff --git a/crates/handlers/src/upstream_oauth2/authorize.rs b/crates/handlers/src/upstream_oauth2/authorize.rs index 565acea8..d6649317 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}, - Clock, Repository, + BoxClock, BoxRng, Repository, }; use mas_storage_pg::PgRepository; use sqlx::PgPool; @@ -43,7 +43,6 @@ pub(crate) enum RouteError { Internal(Box), } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_http::ClientInitError); impl_from_error_for_route!(mas_oidc_client::error::DiscoveryError); impl_from_error_for_route!(mas_oidc_client::error::AuthorizationError); @@ -59,6 +58,8 @@ impl IntoResponse for RouteError { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(http_client_factory): State, State(pool): State, State(url_builder): State, @@ -66,8 +67,6 @@ pub(crate) async fn get( Path(provider_id): Path, Query(query): Query, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); - let mut repo = PgRepository::from_pool(&pool).await?; let provider = repo @@ -115,7 +114,7 @@ pub(crate) async fn get( let cookie_jar = UpstreamSessionsCookie::load(&cookie_jar) .add(session.id, provider.id, data.state, query.post_auth_action) - .save(cookie_jar, clock.now()); + .save(cookie_jar, &clock); repo.save().await?; diff --git a/crates/handlers/src/upstream_oauth2/callback.rs b/crates/handlers/src/upstream_oauth2/callback.rs index ffde4ef3..fd66af09 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, }, - Clock, Repository, + BoxClock, BoxRng, Clock, Repository, }; use mas_storage_pg::PgRepository; use oauth2_types::errors::ClientErrorCode; @@ -102,7 +102,6 @@ pub(crate) enum RouteError { impl_from_error_for_route!(mas_storage_pg::DatabaseError); impl_from_error_for_route!(mas_http::ClientInitError); -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_oidc_client::error::DiscoveryError); impl_from_error_for_route!(mas_oidc_client::error::JwksError); impl_from_error_for_route!(mas_oidc_client::error::TokenAuthorizationCodeError); @@ -122,6 +121,8 @@ impl IntoResponse for RouteError { #[allow(clippy::too_many_lines, clippy::too_many_arguments)] pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(http_client_factory): State, State(pool): State, State(url_builder): State, @@ -131,8 +132,6 @@ pub(crate) async fn get( Path(provider_id): Path, Query(params): Query, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); - let mut repo = PgRepository::from_pool(&pool).await?; let provider = repo @@ -268,7 +267,7 @@ pub(crate) async fn get( let cookie_jar = sessions_cookie .add_link_to_session(session.id, link.id)? - .save(cookie_jar, clock.now()); + .save(cookie_jar, &clock); repo.save().await?; diff --git a/crates/handlers/src/upstream_oauth2/cookie.rs b/crates/handlers/src/upstream_oauth2/cookie.rs index be1d3edf..92cfa565 100644 --- a/crates/handlers/src/upstream_oauth2/cookie.rs +++ b/crates/handlers/src/upstream_oauth2/cookie.rs @@ -18,6 +18,7 @@ use axum_extra::extract::{cookie::Cookie, PrivateCookieJar}; use chrono::{DateTime, Duration, NaiveDateTime, Utc}; use mas_axum_utils::CookieExt; use mas_router::PostAuthAction; +use mas_storage::Clock; use serde::{Deserialize, Serialize}; use thiserror::Error; use time::OffsetDateTime; @@ -65,11 +66,11 @@ impl UpstreamSessions { } /// Save the upstreams sessions to the cookie jar - pub fn save( - self, - cookie_jar: PrivateCookieJar, - now: DateTime, - ) -> PrivateCookieJar { + pub fn save(self, cookie_jar: PrivateCookieJar, clock: &C) -> PrivateCookieJar + where + C: Clock, + { + let now = clock.now(); let this = self.expire(now); let mut cookie = Cookie::named(COOKIE_NAME).encode(&this); cookie.set_path("/"); diff --git a/crates/handlers/src/upstream_oauth2/link.rs b/crates/handlers/src/upstream_oauth2/link.rs index c0408770..d318fc3e 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}, - Clock, Repository, + BoxClock, BoxRng, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{ @@ -70,7 +70,6 @@ pub(crate) enum RouteError { Internal(Box), } -impl_from_error_for_route!(sqlx::Error); impl_from_error_for_route!(mas_templates::TemplateError); impl_from_error_for_route!(mas_axum_utils::csrf::CsrfError); impl_from_error_for_route!(super::cookie::UpstreamSessionNotFound); @@ -95,14 +94,14 @@ pub(crate) enum FormData { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(pool): State, State(templates): State, cookie_jar: PrivateCookieJar, Path(link_id): Path, ) -> Result { let mut repo = PgRepository::from_pool(&pool).await?; - let (clock, mut rng) = crate::clock_and_rng(); - let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar); let (session_id, _post_auth_action) = sessions_cookie .lookup_link(link_id) @@ -131,7 +130,7 @@ pub(crate) async fn get( } let (user_session_info, cookie_jar) = cookie_jar.session_info(); - let (csrf_token, mut cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, mut cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let maybe_user_session = user_session_info.load_session(&mut repo).await?; let render = match (maybe_user_session, link.user_id) { @@ -212,14 +211,15 @@ pub(crate) async fn get( } pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(pool): State, cookie_jar: PrivateCookieJar, Path(link_id): Path, Form(form): Form>, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let form = cookie_jar.verify_form(clock.now(), form)?; + let form = cookie_jar.verify_form(&clock, form)?; let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar); let (session_id, post_auth_action) = sessions_cookie @@ -297,7 +297,7 @@ pub(crate) async fn post( let cookie_jar = sessions_cookie .consume_link(link_id)? - .save(cookie_jar, clock.now()); + .save(cookie_jar, &clock); let cookie_jar = cookie_jar.set_session(&session); repo.save().await?; diff --git a/crates/handlers/src/views/account/emails/add.rs b/crates/handlers/src/views/account/emails/add.rs index 4c11a485..1c8c6665 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, Clock, Repository}; +use mas_storage::{user::UserEmailRepository, BoxClock, BoxRng, Repository}; use mas_storage_pg::PgRepository; use mas_templates::{EmailAddContext, TemplateContext, Templates}; use serde::Deserialize; @@ -39,14 +39,15 @@ pub struct EmailForm { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(pool): State, cookie_jar: PrivateCookieJar, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let (session_info, cookie_jar) = cookie_jar.session_info(); let maybe_session = session_info.load_session(&mut repo).await?; @@ -68,16 +69,17 @@ pub(crate) async fn get( } pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(pool): State, State(mailer): State, cookie_jar: PrivateCookieJar, Query(query): Query, Form(form): Form>, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let form = cookie_jar.verify_form(clock.now(), form)?; + let form = cookie_jar.verify_form(&clock, form)?; let (session_info, cookie_jar) = cookie_jar.session_info(); let maybe_session = session_info.load_session(&mut repo).await?; diff --git a/crates/handlers/src/views/account/emails/mod.rs b/crates/handlers/src/views/account/emails/mod.rs index f1b7c733..10772b87 100644 --- a/crates/handlers/src/views/account/emails/mod.rs +++ b/crates/handlers/src/views/account/emails/mod.rs @@ -28,7 +28,7 @@ use mas_data_model::{BrowserSession, User, UserEmail}; use mas_email::Mailer; use mas_keystore::Encrypter; use mas_router::Route; -use mas_storage::{user::UserEmailRepository, Clock, Repository}; +use mas_storage::{user::UserEmailRepository, BoxClock, BoxRng, Clock, Repository}; use mas_storage_pg::PgRepository; use mas_templates::{AccountEmailsContext, EmailVerificationContext, TemplateContext, Templates}; use rand::{distributions::Uniform, Rng}; @@ -49,12 +49,12 @@ pub enum ManagementForm { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(pool): State, cookie_jar: PrivateCookieJar, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); - let mut repo = PgRepository::from_pool(&pool).await?; let (session_info, cookie_jar) = cookie_jar.session_info(); @@ -77,7 +77,7 @@ async fn render( cookie_jar: PrivateCookieJar, repo: &mut impl Repository, ) -> Result { - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock, rng); let emails = repo.user_email().all(&session.user).await?; @@ -124,13 +124,14 @@ async fn start_email_verification( } pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(pool): State, State(mailer): State, cookie_jar: PrivateCookieJar, Form(form): Form>, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; let (session_info, cookie_jar) = cookie_jar.session_info(); @@ -144,7 +145,7 @@ pub(crate) async fn post( return Ok((cookie_jar, login.go()).into_response()); }; - let form = cookie_jar.verify_form(clock.now(), form)?; + let form = cookie_jar.verify_form(&clock, form)?; match form { ManagementForm::Add { email } => { diff --git a/crates/handlers/src/views/account/emails/verify.rs b/crates/handlers/src/views/account/emails/verify.rs index f37b15e4..644810e5 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, SystemClock}; +use mas_storage::{user::UserEmailRepository, BoxClock, BoxRng, Repository}; use mas_storage_pg::PgRepository; use mas_templates::{EmailVerificationPageContext, TemplateContext, Templates}; use serde::Deserialize; @@ -39,16 +39,17 @@ pub struct CodeForm { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(pool): State, Query(query): Query, Path(id): Path, cookie_jar: PrivateCookieJar, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let (session_info, cookie_jar) = cookie_jar.session_info(); let maybe_session = session_info.load_session(&mut repo).await?; @@ -83,16 +84,16 @@ pub(crate) async fn get( } pub(crate) async fn post( + clock: BoxClock, State(pool): State, cookie_jar: PrivateCookieJar, Query(query): Query, Path(id): Path, Form(form): Form>, ) -> Result { - let clock = SystemClock::default(); let mut repo = PgRepository::from_pool(&pool).await?; - let form = cookie_jar.verify_form(clock.now(), form)?; + let form = cookie_jar.verify_form(&clock, form)?; let (session_info, cookie_jar) = cookie_jar.session_info(); let maybe_session = session_info.load_session(&mut repo).await?; diff --git a/crates/handlers/src/views/account/mod.rs b/crates/handlers/src/views/account/mod.rs index 29aaeda3..660c1416 100644 --- a/crates/handlers/src/views/account/mod.rs +++ b/crates/handlers/src/views/account/mod.rs @@ -25,21 +25,22 @@ use mas_keystore::Encrypter; use mas_router::Route; use mas_storage::{ user::{BrowserSessionRepository, UserEmailRepository}, - Clock, Repository, + BoxClock, BoxRng, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{AccountContext, TemplateContext, Templates}; use sqlx::PgPool; pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(pool): State, cookie_jar: PrivateCookieJar, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let (session_info, cookie_jar) = cookie_jar.session_info(); let maybe_session = session_info.load_session(&mut repo).await?; diff --git a/crates/handlers/src/views/account/password.rs b/crates/handlers/src/views/account/password.rs index 1624f6f6..a9f17123 100644 --- a/crates/handlers/src/views/account/password.rs +++ b/crates/handlers/src/views/account/password.rs @@ -27,7 +27,7 @@ use mas_keystore::Encrypter; use mas_router::Route; use mas_storage::{ user::{BrowserSessionRepository, UserPasswordRepository}, - Clock, Repository, + BoxClock, BoxRng, Clock, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{EmptyContext, TemplateContext, Templates}; @@ -46,11 +46,12 @@ pub struct ChangeForm { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(pool): State, cookie_jar: PrivateCookieJar, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; let (session_info, cookie_jar) = cookie_jar.session_info(); @@ -72,7 +73,7 @@ async fn render( session: BrowserSession, cookie_jar: PrivateCookieJar, ) -> Result { - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock, rng); let ctx = EmptyContext .with_session(session) @@ -84,16 +85,17 @@ async fn render( } pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(password_manager): State, State(templates): State, State(pool): State, cookie_jar: PrivateCookieJar, Form(form): Form>, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let form = cookie_jar.verify_form(clock.now(), form)?; + let form = cookie_jar.verify_form(&clock, form)?; let (session_info, cookie_jar) = cookie_jar.session_info(); diff --git a/crates/handlers/src/views/index.rs b/crates/handlers/src/views/index.rs index 2298e83e..ffe500e7 100644 --- a/crates/handlers/src/views/index.rs +++ b/crates/handlers/src/views/index.rs @@ -20,21 +20,22 @@ 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::{BoxClock, BoxRng}; use mas_storage_pg::PgRepository; use mas_templates::{IndexContext, TemplateContext, Templates}; use sqlx::PgPool; pub async fn get( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(url_builder): State, State(pool): State, cookie_jar: PrivateCookieJar, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let (session_info, cookie_jar) = cookie_jar.session_info(); let session = session_info.load_session(&mut repo).await?; diff --git a/crates/handlers/src/views/login.rs b/crates/handlers/src/views/login.rs index 10295dbc..d8abcb46 100644 --- a/crates/handlers/src/views/login.rs +++ b/crates/handlers/src/views/login.rs @@ -26,7 +26,7 @@ use mas_keystore::Encrypter; use mas_storage::{ upstream_oauth2::UpstreamOAuthProviderRepository, user::{BrowserSessionRepository, UserPasswordRepository, UserRepository}, - Clock, Repository, + BoxClock, BoxRng, Clock, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{ @@ -51,15 +51,16 @@ impl ToFormState for LoginForm { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(pool): State, Query(query): Query, cookie_jar: PrivateCookieJar, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let (session_info, cookie_jar) = cookie_jar.session_info(); let maybe_session = session_info.load_session(&mut repo).await?; @@ -83,6 +84,8 @@ pub(crate) async fn get( } pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(password_manager): State, State(templates): State, State(pool): State, @@ -90,12 +93,11 @@ pub(crate) async fn post( cookie_jar: PrivateCookieJar, Form(form): Form>, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let form = cookie_jar.verify_form(clock.now(), form)?; + let form = cookie_jar.verify_form(&clock, form)?; - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); // Validate the form let state = { diff --git a/crates/handlers/src/views/logout.rs b/crates/handlers/src/views/logout.rs index 781780ca..f8491cb9 100644 --- a/crates/handlers/src/views/logout.rs +++ b/crates/handlers/src/views/logout.rs @@ -23,19 +23,19 @@ use mas_axum_utils::{ }; use mas_keystore::Encrypter; use mas_router::{PostAuthAction, Route}; -use mas_storage::{user::BrowserSessionRepository, Clock, Repository, SystemClock}; +use mas_storage::{user::BrowserSessionRepository, BoxClock, Repository}; use mas_storage_pg::PgRepository; use sqlx::PgPool; pub(crate) async fn post( + clock: BoxClock, State(pool): State, cookie_jar: PrivateCookieJar, Form(form): Form>>, ) -> Result { - let clock = SystemClock::default(); let mut repo = PgRepository::from_pool(&pool).await?; - let form = cookie_jar.verify_form(clock.now(), form)?; + let form = cookie_jar.verify_form(&clock, form)?; let (session_info, mut cookie_jar) = cookie_jar.session_info(); diff --git a/crates/handlers/src/views/reauth.rs b/crates/handlers/src/views/reauth.rs index 571d2e17..9c2330a3 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}, - Clock, Repository, + BoxClock, BoxRng, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{ReauthContext, TemplateContext, Templates}; @@ -43,15 +43,16 @@ pub(crate) struct ReauthForm { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(pool): State, Query(query): Query, cookie_jar: PrivateCookieJar, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let (session_info, cookie_jar) = cookie_jar.session_info(); let maybe_session = session_info.load_session(&mut repo).await?; @@ -80,16 +81,17 @@ pub(crate) async fn get( } pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(password_manager): State, State(pool): State, Query(query): Query, cookie_jar: PrivateCookieJar, Form(form): Form>, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let form = cookie_jar.verify_form(clock.now(), form)?; + let form = cookie_jar.verify_form(&clock, form)?; let (session_info, cookie_jar) = cookie_jar.session_info(); diff --git a/crates/handlers/src/views/register.rs b/crates/handlers/src/views/register.rs index 3e2d87a9..a8fc7bae 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}, - Clock, Repository, + BoxClock, BoxRng, Repository, }; use mas_storage_pg::PgRepository; use mas_templates::{ @@ -61,15 +61,16 @@ impl ToFormState for RegisterForm { } pub(crate) async fn get( + mut rng: BoxRng, + clock: BoxClock, State(templates): State, State(pool): State, Query(query): Query, cookie_jar: PrivateCookieJar, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let (session_info, cookie_jar) = cookie_jar.session_info(); let maybe_session = session_info.load_session(&mut repo).await?; @@ -93,6 +94,8 @@ pub(crate) async fn get( #[allow(clippy::too_many_lines, clippy::too_many_arguments)] pub(crate) async fn post( + mut rng: BoxRng, + clock: BoxClock, State(password_manager): State, State(mailer): State, State(policy_factory): State>, @@ -102,12 +105,11 @@ pub(crate) async fn post( cookie_jar: PrivateCookieJar, Form(form): Form>, ) -> Result { - let (clock, mut rng) = crate::clock_and_rng(); let mut repo = PgRepository::from_pool(&pool).await?; - let form = cookie_jar.verify_form(clock.now(), form)?; + let form = cookie_jar.verify_form(&clock, form)?; - let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock.now(), &mut rng); + let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); // Validate the form let state = { diff --git a/crates/storage-pg/src/oauth2/client.rs b/crates/storage-pg/src/oauth2/client.rs index 1b8a99f9..e17245aa 100644 --- a/crates/storage-pg/src/oauth2/client.rs +++ b/crates/storage-pg/src/oauth2/client.rs @@ -30,7 +30,7 @@ use oauth2_types::{ requests::GrantType, scope::{Scope, ScopeToken}, }; -use rand::{Rng, RngCore}; +use rand::RngCore; use sqlx::PgConnection; use tracing::{info_span, Instrument}; use ulid::Ulid; @@ -534,7 +534,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> { )] async fn add_from_config( &mut self, - mut rng: impl Rng + Send, + rng: &mut (dyn RngCore + Send), clock: &dyn Clock, client_id: Ulid, client_auth_method: OAuthClientAuthenticationMethod, @@ -597,7 +597,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> { .iter() .map(|uri| { ( - Uuid::from(Ulid::from_datetime_with_source(now.into(), &mut rng)), + Uuid::from(Ulid::from_datetime_with_source(now.into(), &mut *rng)), uri.as_str().to_owned(), ) }) diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index 97089e95..86ca9f07 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -10,7 +10,7 @@ async-trait = "0.1.60" chrono = "0.4.23" thiserror = "1.0.38" -rand = "0.8.5" +rand_core = "0.6.4" url = "2.3.1" ulid = "1.0.0" diff --git a/crates/storage/src/clock.rs b/crates/storage/src/clock.rs index 54ca3b4f..04c69f25 100644 --- a/crates/storage/src/clock.rs +++ b/crates/storage/src/clock.rs @@ -28,6 +28,12 @@ pub trait Clock: Sync { fn now(&self) -> DateTime; } +impl Clock for Box { + fn now(&self) -> DateTime { + (**self).now() + } +} + /// A clock which uses the system time #[derive(Clone, Default)] pub struct SystemClock { diff --git a/crates/storage/src/compat/access_token.rs b/crates/storage/src/compat/access_token.rs index e135be39..32ba1f73 100644 --- a/crates/storage/src/compat/access_token.rs +++ b/crates/storage/src/compat/access_token.rs @@ -15,7 +15,7 @@ use async_trait::async_trait; use chrono::Duration; use mas_data_model::{CompatAccessToken, CompatSession}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::Clock; diff --git a/crates/storage/src/compat/refresh_token.rs b/crates/storage/src/compat/refresh_token.rs index f8e8dfaa..627b59a1 100644 --- a/crates/storage/src/compat/refresh_token.rs +++ b/crates/storage/src/compat/refresh_token.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{CompatAccessToken, CompatRefreshToken, CompatSession}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::Clock; diff --git a/crates/storage/src/compat/session.rs b/crates/storage/src/compat/session.rs index fa5cbd6e..0c5bc125 100644 --- a/crates/storage/src/compat/session.rs +++ b/crates/storage/src/compat/session.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{CompatSession, Device, User}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::Clock; diff --git a/crates/storage/src/compat/sso_login.rs b/crates/storage/src/compat/sso_login.rs index 6ee3270a..1ed3e5d8 100644 --- a/crates/storage/src/compat/sso_login.rs +++ b/crates/storage/src/compat/sso_login.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{CompatSession, CompatSsoLogin, User}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use url::Url; diff --git a/crates/storage/src/lib.rs b/crates/storage/src/lib.rs index 2a83b55e..d5a45372 100644 --- a/crates/storage/src/lib.rs +++ b/crates/storage/src/lib.rs @@ -37,8 +37,13 @@ pub(crate) mod repository; pub mod upstream_oauth2; pub mod user; +use rand_core::CryptoRngCore; + pub use self::{ clock::{Clock, SystemClock}, pagination::{Page, Pagination}, repository::Repository, }; + +pub type BoxClock = Box; +pub type BoxRng = Box; diff --git a/crates/storage/src/oauth2/access_token.rs b/crates/storage/src/oauth2/access_token.rs index 4bbcf885..1148136f 100644 --- a/crates/storage/src/oauth2/access_token.rs +++ b/crates/storage/src/oauth2/access_token.rs @@ -15,7 +15,7 @@ use async_trait::async_trait; use chrono::Duration; use mas_data_model::{AccessToken, Session}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::Clock; diff --git a/crates/storage/src/oauth2/authorization_grant.rs b/crates/storage/src/oauth2/authorization_grant.rs index 96403f12..1130e6a8 100644 --- a/crates/storage/src/oauth2/authorization_grant.rs +++ b/crates/storage/src/oauth2/authorization_grant.rs @@ -17,7 +17,7 @@ use std::num::NonZeroU32; use async_trait::async_trait; use mas_data_model::{AuthorizationCode, AuthorizationGrant, Client, Session}; use oauth2_types::{requests::ResponseMode, scope::Scope}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use url::Url; diff --git a/crates/storage/src/oauth2/client.rs b/crates/storage/src/oauth2/client.rs index 30f37bc6..3c7d7dbb 100644 --- a/crates/storage/src/oauth2/client.rs +++ b/crates/storage/src/oauth2/client.rs @@ -19,7 +19,7 @@ use mas_data_model::{Client, User}; use mas_iana::{jose::JsonWebSignatureAlg, oauth::OAuthClientAuthenticationMethod}; use mas_jose::jwk::PublicJsonWebKeySet; use oauth2_types::{requests::GrantType, scope::Scope}; -use rand::{Rng, RngCore}; +use rand_core::RngCore; use ulid::Ulid; use url::Url; @@ -67,7 +67,7 @@ pub trait OAuth2ClientRepository: Send + Sync { #[allow(clippy::too_many_arguments)] async fn add_from_config( &mut self, - mut rng: impl Rng + Send, + rng: &mut (dyn RngCore + Send), clock: &dyn Clock, client_id: Ulid, client_auth_method: OAuthClientAuthenticationMethod, diff --git a/crates/storage/src/oauth2/refresh_token.rs b/crates/storage/src/oauth2/refresh_token.rs index 88bb26fb..66ec2c32 100644 --- a/crates/storage/src/oauth2/refresh_token.rs +++ b/crates/storage/src/oauth2/refresh_token.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{AccessToken, RefreshToken, Session}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::Clock; diff --git a/crates/storage/src/oauth2/session.rs b/crates/storage/src/oauth2/session.rs index 2b6c63b7..3813810b 100644 --- a/crates/storage/src/oauth2/session.rs +++ b/crates/storage/src/oauth2/session.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{AuthorizationGrant, BrowserSession, Session, User}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::{pagination::Page, Clock, Pagination}; diff --git a/crates/storage/src/upstream_oauth2/link.rs b/crates/storage/src/upstream_oauth2/link.rs index 474c21d9..bf9e0aad 100644 --- a/crates/storage/src/upstream_oauth2/link.rs +++ b/crates/storage/src/upstream_oauth2/link.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{UpstreamOAuthLink, UpstreamOAuthProvider, User}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::{pagination::Page, Clock, Pagination}; diff --git a/crates/storage/src/upstream_oauth2/provider.rs b/crates/storage/src/upstream_oauth2/provider.rs index 10a03e2b..521a7e7a 100644 --- a/crates/storage/src/upstream_oauth2/provider.rs +++ b/crates/storage/src/upstream_oauth2/provider.rs @@ -16,7 +16,7 @@ use async_trait::async_trait; use mas_data_model::UpstreamOAuthProvider; use mas_iana::{jose::JsonWebSignatureAlg, oauth::OAuthClientAuthenticationMethod}; use oauth2_types::scope::Scope; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::{pagination::Page, Clock, Pagination}; diff --git a/crates/storage/src/upstream_oauth2/session.rs b/crates/storage/src/upstream_oauth2/session.rs index e1b6abc1..f4441b2a 100644 --- a/crates/storage/src/upstream_oauth2/session.rs +++ b/crates/storage/src/upstream_oauth2/session.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{UpstreamOAuthAuthorizationSession, UpstreamOAuthLink, UpstreamOAuthProvider}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::Clock; diff --git a/crates/storage/src/user/email.rs b/crates/storage/src/user/email.rs index 4b8f846d..65ee465b 100644 --- a/crates/storage/src/user/email.rs +++ b/crates/storage/src/user/email.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{User, UserEmail, UserEmailVerification}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::{pagination::Page, Clock, Pagination}; diff --git a/crates/storage/src/user/mod.rs b/crates/storage/src/user/mod.rs index 8e046a9d..b3bd0bc2 100644 --- a/crates/storage/src/user/mod.rs +++ b/crates/storage/src/user/mod.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::User; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::Clock; diff --git a/crates/storage/src/user/password.rs b/crates/storage/src/user/password.rs index 306f7d93..609198b2 100644 --- a/crates/storage/src/user/password.rs +++ b/crates/storage/src/user/password.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{Password, User}; -use rand::RngCore; +use rand_core::RngCore; use crate::Clock; diff --git a/crates/storage/src/user/session.rs b/crates/storage/src/user/session.rs index 5499f45a..5556547c 100644 --- a/crates/storage/src/user/session.rs +++ b/crates/storage/src/user/session.rs @@ -14,7 +14,7 @@ use async_trait::async_trait; use mas_data_model::{BrowserSession, Password, UpstreamOAuthLink, User}; -use rand::RngCore; +use rand_core::RngCore; use ulid::Ulid; use crate::{pagination::Page, Clock, Pagination};