You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
storage: ensure the repository trait can be boxed
and define some wrappers to map the errors
This commit is contained in:
@ -18,7 +18,7 @@ use mas_data_model::{CompatAccessToken, CompatSession};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
#[async_trait]
|
||||
pub trait CompatAccessTokenRepository: Send + Sync {
|
||||
@ -50,3 +50,27 @@ pub trait CompatAccessTokenRepository: Send + Sync {
|
||||
compat_access_token: CompatAccessToken,
|
||||
) -> Result<CompatAccessToken, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(CompatAccessTokenRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<CompatAccessToken>, Self::Error>;
|
||||
|
||||
async fn find_by_token(
|
||||
&mut self,
|
||||
access_token: &str,
|
||||
) -> Result<Option<CompatAccessToken>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
compat_session: &CompatSession,
|
||||
token: String,
|
||||
expires_after: Option<Duration>,
|
||||
) -> Result<CompatAccessToken, Self::Error>;
|
||||
|
||||
async fn expire(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
compat_access_token: CompatAccessToken,
|
||||
) -> Result<CompatAccessToken, Self::Error>;
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ use mas_data_model::{CompatAccessToken, CompatRefreshToken, CompatSession};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
#[async_trait]
|
||||
pub trait CompatRefreshTokenRepository: Send + Sync {
|
||||
@ -49,3 +49,27 @@ pub trait CompatRefreshTokenRepository: Send + Sync {
|
||||
compat_refresh_token: CompatRefreshToken,
|
||||
) -> Result<CompatRefreshToken, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(CompatRefreshTokenRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<CompatRefreshToken>, Self::Error>;
|
||||
|
||||
async fn find_by_token(
|
||||
&mut self,
|
||||
refresh_token: &str,
|
||||
) -> Result<Option<CompatRefreshToken>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
compat_session: &CompatSession,
|
||||
compat_access_token: &CompatAccessToken,
|
||||
token: String,
|
||||
) -> Result<CompatRefreshToken, Self::Error>;
|
||||
|
||||
async fn consume(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
compat_refresh_token: CompatRefreshToken,
|
||||
) -> Result<CompatRefreshToken, Self::Error>;
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ use mas_data_model::{CompatSession, Device, User};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
#[async_trait]
|
||||
pub trait CompatSessionRepository: Send + Sync {
|
||||
@ -42,3 +42,21 @@ pub trait CompatSessionRepository: Send + Sync {
|
||||
compat_session: CompatSession,
|
||||
) -> Result<CompatSession, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(CompatSessionRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<CompatSession>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
user: &User,
|
||||
device: Device,
|
||||
) -> Result<CompatSession, Self::Error>;
|
||||
|
||||
async fn finish(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
compat_session: CompatSession,
|
||||
) -> Result<CompatSession, Self::Error>;
|
||||
);
|
||||
|
@ -18,7 +18,7 @@ use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
use url::Url;
|
||||
|
||||
use crate::{pagination::Page, Clock, Pagination};
|
||||
use crate::{pagination::Page, repository_impl, Clock, Pagination};
|
||||
|
||||
#[async_trait]
|
||||
pub trait CompatSsoLoginRepository: Send + Sync {
|
||||
@ -64,3 +64,39 @@ pub trait CompatSsoLoginRepository: Send + Sync {
|
||||
pagination: Pagination,
|
||||
) -> Result<Page<CompatSsoLogin>, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(CompatSsoLoginRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<CompatSsoLogin>, Self::Error>;
|
||||
|
||||
async fn find_by_token(
|
||||
&mut self,
|
||||
login_token: &str,
|
||||
) -> Result<Option<CompatSsoLogin>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
login_token: String,
|
||||
redirect_uri: Url,
|
||||
) -> Result<CompatSsoLogin, Self::Error>;
|
||||
|
||||
async fn fulfill(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
compat_sso_login: CompatSsoLogin,
|
||||
compat_session: &CompatSession,
|
||||
) -> Result<CompatSsoLogin, Self::Error>;
|
||||
|
||||
async fn exchange(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
compat_sso_login: CompatSsoLogin,
|
||||
) -> Result<CompatSsoLogin, Self::Error>;
|
||||
|
||||
async fn list_paginated(
|
||||
&mut self,
|
||||
user: &User,
|
||||
pagination: Pagination,
|
||||
) -> Result<Page<CompatSsoLogin>, Self::Error>;
|
||||
);
|
||||
|
@ -45,5 +45,59 @@ pub use self::{
|
||||
repository::Repository,
|
||||
};
|
||||
|
||||
pub struct MapErr<Repository, Mapper> {
|
||||
inner: Repository,
|
||||
mapper: Mapper,
|
||||
}
|
||||
|
||||
impl<Repository, Mapper> MapErr<Repository, Mapper> {
|
||||
fn new(inner: Repository, mapper: Mapper) -> Self {
|
||||
Self { inner, mapper }
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! repository_impl {
|
||||
($repo_trait:ident:
|
||||
$(
|
||||
async fn $method:ident (
|
||||
&mut self
|
||||
$(, $arg:ident: $arg_ty:ty )*
|
||||
$(,)?
|
||||
) -> Result<$ret_ty:ty, Self::Error>;
|
||||
)*
|
||||
) => {
|
||||
#[::async_trait::async_trait]
|
||||
impl<R: ?Sized> $repo_trait for ::std::boxed::Box<R>
|
||||
where
|
||||
R: $repo_trait,
|
||||
{
|
||||
type Error = <R as $repo_trait>::Error;
|
||||
|
||||
$(
|
||||
async fn $method (&mut self $(, $arg: $arg_ty)*) -> Result<$ret_ty, Self::Error> {
|
||||
(**self).$method ( $($arg),* ).await
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
#[::async_trait::async_trait]
|
||||
impl<R, F, E> $repo_trait for $crate::MapErr<R, F>
|
||||
where
|
||||
R: $repo_trait,
|
||||
F: FnMut(<R as $repo_trait>::Error) -> E + ::std::marker::Send + ::std::marker::Sync,
|
||||
E: ::std::error::Error + ::std::marker::Send + ::std::marker::Sync,
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
$(
|
||||
async fn $method (&mut self $(, $arg: $arg_ty)*) -> Result<$ret_ty, Self::Error> {
|
||||
self.inner.$method ( $($arg),* ).await.map_err(&mut self.mapper)
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub type BoxClock = Box<dyn Clock + Send>;
|
||||
pub type BoxRng = Box<dyn CryptoRngCore + Send>;
|
||||
|
@ -18,7 +18,7 @@ use mas_data_model::{AccessToken, Session};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
#[async_trait]
|
||||
pub trait OAuth2AccessTokenRepository: Send + Sync {
|
||||
@ -53,3 +53,29 @@ pub trait OAuth2AccessTokenRepository: Send + Sync {
|
||||
/// Cleanup expired access tokens
|
||||
async fn cleanup_expired(&mut self, clock: &dyn Clock) -> Result<usize, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(OAuth2AccessTokenRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<AccessToken>, Self::Error>;
|
||||
|
||||
async fn find_by_token(
|
||||
&mut self,
|
||||
access_token: &str,
|
||||
) -> Result<Option<AccessToken>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
session: &Session,
|
||||
access_token: String,
|
||||
expires_after: Duration,
|
||||
) -> Result<AccessToken, Self::Error>;
|
||||
|
||||
async fn revoke(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
access_token: AccessToken,
|
||||
) -> Result<AccessToken, Self::Error>;
|
||||
|
||||
async fn cleanup_expired(&mut self, clock: &dyn Clock) -> Result<usize, Self::Error>;
|
||||
);
|
||||
|
@ -21,7 +21,7 @@ use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
use url::Url;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
#[async_trait]
|
||||
pub trait OAuth2AuthorizationGrantRepository: Send + Sync {
|
||||
@ -67,3 +67,44 @@ pub trait OAuth2AuthorizationGrantRepository: Send + Sync {
|
||||
authorization_grant: AuthorizationGrant,
|
||||
) -> Result<AuthorizationGrant, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(OAuth2AuthorizationGrantRepository:
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
client: &Client,
|
||||
redirect_uri: Url,
|
||||
scope: Scope,
|
||||
code: Option<AuthorizationCode>,
|
||||
state: Option<String>,
|
||||
nonce: Option<String>,
|
||||
max_age: Option<NonZeroU32>,
|
||||
response_mode: ResponseMode,
|
||||
response_type_id_token: bool,
|
||||
requires_consent: bool,
|
||||
) -> Result<AuthorizationGrant, Self::Error>;
|
||||
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<AuthorizationGrant>, Self::Error>;
|
||||
|
||||
async fn find_by_code(&mut self, code: &str)
|
||||
-> Result<Option<AuthorizationGrant>, Self::Error>;
|
||||
|
||||
async fn fulfill(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
session: &Session,
|
||||
authorization_grant: AuthorizationGrant,
|
||||
) -> Result<AuthorizationGrant, Self::Error>;
|
||||
|
||||
async fn exchange(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
authorization_grant: AuthorizationGrant,
|
||||
) -> Result<AuthorizationGrant, Self::Error>;
|
||||
|
||||
async fn give_consent(
|
||||
&mut self,
|
||||
authorization_grant: AuthorizationGrant,
|
||||
) -> Result<AuthorizationGrant, Self::Error>;
|
||||
);
|
||||
|
@ -23,7 +23,7 @@ use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
use url::Url;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
#[async_trait]
|
||||
pub trait OAuth2ClientRepository: Send + Sync {
|
||||
@ -92,3 +92,61 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
||||
scope: &Scope,
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(OAuth2ClientRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<Client>, Self::Error>;
|
||||
|
||||
async fn load_batch(
|
||||
&mut self,
|
||||
ids: BTreeSet<Ulid>,
|
||||
) -> Result<BTreeMap<Ulid, Client>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
redirect_uris: Vec<Url>,
|
||||
encrypted_client_secret: Option<String>,
|
||||
grant_types: Vec<GrantType>,
|
||||
contacts: Vec<String>,
|
||||
client_name: Option<String>,
|
||||
logo_uri: Option<Url>,
|
||||
client_uri: Option<Url>,
|
||||
policy_uri: Option<Url>,
|
||||
tos_uri: Option<Url>,
|
||||
jwks_uri: Option<Url>,
|
||||
jwks: Option<PublicJsonWebKeySet>,
|
||||
id_token_signed_response_alg: Option<JsonWebSignatureAlg>,
|
||||
userinfo_signed_response_alg: Option<JsonWebSignatureAlg>,
|
||||
token_endpoint_auth_method: Option<OAuthClientAuthenticationMethod>,
|
||||
token_endpoint_auth_signing_alg: Option<JsonWebSignatureAlg>,
|
||||
initiate_login_uri: Option<Url>,
|
||||
) -> Result<Client, Self::Error>;
|
||||
|
||||
async fn add_from_config(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
client_id: Ulid,
|
||||
client_auth_method: OAuthClientAuthenticationMethod,
|
||||
encrypted_client_secret: Option<String>,
|
||||
jwks: Option<PublicJsonWebKeySet>,
|
||||
jwks_uri: Option<Url>,
|
||||
redirect_uris: Vec<Url>,
|
||||
) -> Result<Client, Self::Error>;
|
||||
|
||||
async fn get_consent_for_user(
|
||||
&mut self,
|
||||
client: &Client,
|
||||
user: &User,
|
||||
) -> Result<Scope, Self::Error>;
|
||||
|
||||
async fn give_consent_for_user(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
client: &Client,
|
||||
user: &User,
|
||||
scope: &Scope,
|
||||
) -> Result<(), Self::Error>;
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ use mas_data_model::{AccessToken, RefreshToken, Session};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
#[async_trait]
|
||||
pub trait OAuth2RefreshTokenRepository: Send + Sync {
|
||||
@ -49,3 +49,27 @@ pub trait OAuth2RefreshTokenRepository: Send + Sync {
|
||||
refresh_token: RefreshToken,
|
||||
) -> Result<RefreshToken, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(OAuth2RefreshTokenRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<RefreshToken>, Self::Error>;
|
||||
|
||||
async fn find_by_token(
|
||||
&mut self,
|
||||
refresh_token: &str,
|
||||
) -> Result<Option<RefreshToken>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
session: &Session,
|
||||
access_token: &AccessToken,
|
||||
refresh_token: String,
|
||||
) -> Result<RefreshToken, Self::Error>;
|
||||
|
||||
async fn consume(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
refresh_token: RefreshToken,
|
||||
) -> Result<RefreshToken, Self::Error>;
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ use mas_data_model::{AuthorizationGrant, BrowserSession, Session, User};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::{pagination::Page, Clock, Pagination};
|
||||
use crate::{pagination::Page, repository_impl, Clock, Pagination};
|
||||
|
||||
#[async_trait]
|
||||
pub trait OAuth2SessionRepository: Send + Sync {
|
||||
@ -42,3 +42,24 @@ pub trait OAuth2SessionRepository: Send + Sync {
|
||||
pagination: Pagination,
|
||||
) -> Result<Page<Session>, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(OAuth2SessionRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<Session>, Self::Error>;
|
||||
|
||||
async fn create_from_grant(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
grant: &AuthorizationGrant,
|
||||
user_session: &BrowserSession,
|
||||
) -> Result<Session, Self::Error>;
|
||||
|
||||
async fn finish(&mut self, clock: &dyn Clock, session: Session)
|
||||
-> Result<Session, Self::Error>;
|
||||
|
||||
async fn list_paginated(
|
||||
&mut self,
|
||||
user: &User,
|
||||
pagination: Pagination,
|
||||
) -> Result<Page<Session>, Self::Error>;
|
||||
);
|
||||
|
@ -26,92 +26,192 @@ use crate::{
|
||||
UpstreamOAuthSessionRepository,
|
||||
},
|
||||
user::{BrowserSessionRepository, UserEmailRepository, UserPasswordRepository, UserRepository},
|
||||
MapErr,
|
||||
};
|
||||
|
||||
pub trait Repository: Send {
|
||||
type Error: std::error::Error + Send + Sync + 'static;
|
||||
|
||||
type UpstreamOAuthLinkRepository<'c>: UpstreamOAuthLinkRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn upstream_oauth_link<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn UpstreamOAuthLinkRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type UpstreamOAuthProviderRepository<'c>: UpstreamOAuthProviderRepository<Error = Self::Error>
|
||||
+ 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn upstream_oauth_provider<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn UpstreamOAuthProviderRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type UpstreamOAuthSessionRepository<'c>: UpstreamOAuthSessionRepository<Error = Self::Error>
|
||||
+ 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn upstream_oauth_session<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn UpstreamOAuthSessionRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type UserRepository<'c>: UserRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn user<'c>(&'c mut self) -> Box<dyn UserRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type UserEmailRepository<'c>: UserEmailRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn user_email<'c>(&'c mut self) -> Box<dyn UserEmailRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type UserPasswordRepository<'c>: UserPasswordRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn user_password<'c>(&'c mut self)
|
||||
-> Box<dyn UserPasswordRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type BrowserSessionRepository<'c>: BrowserSessionRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn browser_session<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn BrowserSessionRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type OAuth2ClientRepository<'c>: OAuth2ClientRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn oauth2_client<'c>(&'c mut self)
|
||||
-> Box<dyn OAuth2ClientRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type OAuth2AuthorizationGrantRepository<'c>: OAuth2AuthorizationGrantRepository<Error = Self::Error>
|
||||
+ 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn oauth2_authorization_grant<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn OAuth2AuthorizationGrantRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type OAuth2SessionRepository<'c>: OAuth2SessionRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn oauth2_session<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn OAuth2SessionRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type OAuth2AccessTokenRepository<'c>: OAuth2AccessTokenRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn oauth2_access_token<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn OAuth2AccessTokenRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type OAuth2RefreshTokenRepository<'c>: OAuth2RefreshTokenRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn oauth2_refresh_token<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn OAuth2RefreshTokenRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type CompatSessionRepository<'c>: CompatSessionRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn compat_session<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn CompatSessionRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type CompatSsoLoginRepository<'c>: CompatSsoLoginRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn compat_sso_login<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn CompatSsoLoginRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type CompatAccessTokenRepository<'c>: CompatAccessTokenRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
fn compat_access_token<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn CompatAccessTokenRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
type CompatRefreshTokenRepository<'c>: CompatRefreshTokenRepository<Error = Self::Error> + 'c
|
||||
where
|
||||
Self: 'c;
|
||||
|
||||
fn upstream_oauth_link(&mut self) -> Self::UpstreamOAuthLinkRepository<'_>;
|
||||
fn upstream_oauth_provider(&mut self) -> Self::UpstreamOAuthProviderRepository<'_>;
|
||||
fn upstream_oauth_session(&mut self) -> Self::UpstreamOAuthSessionRepository<'_>;
|
||||
fn user(&mut self) -> Self::UserRepository<'_>;
|
||||
fn user_email(&mut self) -> Self::UserEmailRepository<'_>;
|
||||
fn user_password(&mut self) -> Self::UserPasswordRepository<'_>;
|
||||
fn browser_session(&mut self) -> Self::BrowserSessionRepository<'_>;
|
||||
fn oauth2_client(&mut self) -> Self::OAuth2ClientRepository<'_>;
|
||||
fn oauth2_authorization_grant(&mut self) -> Self::OAuth2AuthorizationGrantRepository<'_>;
|
||||
fn oauth2_session(&mut self) -> Self::OAuth2SessionRepository<'_>;
|
||||
fn oauth2_access_token(&mut self) -> Self::OAuth2AccessTokenRepository<'_>;
|
||||
fn oauth2_refresh_token(&mut self) -> Self::OAuth2RefreshTokenRepository<'_>;
|
||||
fn compat_session(&mut self) -> Self::CompatSessionRepository<'_>;
|
||||
fn compat_sso_login(&mut self) -> Self::CompatSsoLoginRepository<'_>;
|
||||
fn compat_access_token(&mut self) -> Self::CompatAccessTokenRepository<'_>;
|
||||
fn compat_refresh_token(&mut self) -> Self::CompatRefreshTokenRepository<'_>;
|
||||
fn compat_refresh_token<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn CompatRefreshTokenRepository<Error = Self::Error> + 'c>;
|
||||
}
|
||||
|
||||
impl<R, F, E> Repository for crate::MapErr<R, F>
|
||||
where
|
||||
R: Repository,
|
||||
F: FnMut(R::Error) -> E + Send + Sync,
|
||||
E: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn upstream_oauth_link<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn UpstreamOAuthLinkRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(
|
||||
self.inner.upstream_oauth_link(),
|
||||
&mut self.mapper,
|
||||
))
|
||||
}
|
||||
|
||||
fn upstream_oauth_provider<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn UpstreamOAuthProviderRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(
|
||||
self.inner.upstream_oauth_provider(),
|
||||
&mut self.mapper,
|
||||
))
|
||||
}
|
||||
|
||||
fn upstream_oauth_session<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn UpstreamOAuthSessionRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(
|
||||
self.inner.upstream_oauth_session(),
|
||||
&mut self.mapper,
|
||||
))
|
||||
}
|
||||
|
||||
fn user<'c>(&'c mut self) -> Box<dyn UserRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.user(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn user_email<'c>(&'c mut self) -> Box<dyn UserEmailRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.user_email(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn user_password<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn UserPasswordRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.user_password(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn browser_session<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn BrowserSessionRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.browser_session(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn oauth2_client<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn OAuth2ClientRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.oauth2_client(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn oauth2_authorization_grant<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn OAuth2AuthorizationGrantRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(
|
||||
self.inner.oauth2_authorization_grant(),
|
||||
&mut self.mapper,
|
||||
))
|
||||
}
|
||||
|
||||
fn oauth2_session<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn OAuth2SessionRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.oauth2_session(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn oauth2_access_token<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn OAuth2AccessTokenRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(
|
||||
self.inner.oauth2_access_token(),
|
||||
&mut self.mapper,
|
||||
))
|
||||
}
|
||||
|
||||
fn oauth2_refresh_token<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn OAuth2RefreshTokenRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(
|
||||
self.inner.oauth2_refresh_token(),
|
||||
&mut self.mapper,
|
||||
))
|
||||
}
|
||||
|
||||
fn compat_session<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn CompatSessionRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.compat_session(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn compat_sso_login<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn CompatSsoLoginRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.compat_sso_login(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn compat_access_token<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn CompatAccessTokenRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(
|
||||
self.inner.compat_access_token(),
|
||||
&mut self.mapper,
|
||||
))
|
||||
}
|
||||
|
||||
fn compat_refresh_token<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn CompatRefreshTokenRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(
|
||||
self.inner.compat_refresh_token(),
|
||||
&mut self.mapper,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,11 @@ use mas_data_model::{UpstreamOAuthLink, UpstreamOAuthProvider, User};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::{pagination::Page, Clock, Pagination};
|
||||
use crate::{pagination::Page, repository_impl, Clock, Pagination};
|
||||
|
||||
#[async_trait]
|
||||
pub trait UpstreamOAuthLinkRepository: Send + Sync {
|
||||
type Error;
|
||||
type Error: std::error::Error + Send + Sync;
|
||||
|
||||
/// Lookup an upstream OAuth link by its ID
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<UpstreamOAuthLink>, Self::Error>;
|
||||
@ -56,3 +56,33 @@ pub trait UpstreamOAuthLinkRepository: Send + Sync {
|
||||
pagination: Pagination,
|
||||
) -> Result<Page<UpstreamOAuthLink>, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(UpstreamOAuthLinkRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<UpstreamOAuthLink>, Self::Error>;
|
||||
|
||||
async fn find_by_subject(
|
||||
&mut self,
|
||||
upstream_oauth_provider: &UpstreamOAuthProvider,
|
||||
subject: &str,
|
||||
) -> Result<Option<UpstreamOAuthLink>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
upstream_oauth_provider: &UpstreamOAuthProvider,
|
||||
subject: String,
|
||||
) -> Result<UpstreamOAuthLink, Self::Error>;
|
||||
|
||||
async fn associate_to_user(
|
||||
&mut self,
|
||||
upstream_oauth_link: &UpstreamOAuthLink,
|
||||
user: &User,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
async fn list_paginated(
|
||||
&mut self,
|
||||
user: &User,
|
||||
pagination: Pagination,
|
||||
) -> Result<Page<UpstreamOAuthLink>, Self::Error>;
|
||||
);
|
||||
|
@ -19,7 +19,7 @@ use oauth2_types::scope::Scope;
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::{pagination::Page, Clock, Pagination};
|
||||
use crate::{pagination::Page, repository_impl, Clock, Pagination};
|
||||
|
||||
#[async_trait]
|
||||
pub trait UpstreamOAuthProviderRepository: Send + Sync {
|
||||
@ -51,3 +51,26 @@ pub trait UpstreamOAuthProviderRepository: Send + Sync {
|
||||
/// Get all upstream OAuth providers
|
||||
async fn all(&mut self) -> Result<Vec<UpstreamOAuthProvider>, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(UpstreamOAuthProviderRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<UpstreamOAuthProvider>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
issuer: String,
|
||||
scope: Scope,
|
||||
token_endpoint_auth_method: OAuthClientAuthenticationMethod,
|
||||
token_endpoint_signing_alg: Option<JsonWebSignatureAlg>,
|
||||
client_id: String,
|
||||
encrypted_client_secret: Option<String>
|
||||
) -> Result<UpstreamOAuthProvider, Self::Error>;
|
||||
|
||||
async fn list_paginated(
|
||||
&mut self,
|
||||
pagination: Pagination
|
||||
) -> Result<Page<UpstreamOAuthProvider>, Self::Error>;
|
||||
|
||||
async fn all(&mut self) -> Result<Vec<UpstreamOAuthProvider>, Self::Error>;
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ use mas_data_model::{UpstreamOAuthAuthorizationSession, UpstreamOAuthLink, Upstr
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
#[async_trait]
|
||||
pub trait UpstreamOAuthSessionRepository: Send + Sync {
|
||||
@ -56,3 +56,34 @@ pub trait UpstreamOAuthSessionRepository: Send + Sync {
|
||||
upstream_oauth_authorization_session: UpstreamOAuthAuthorizationSession,
|
||||
) -> Result<UpstreamOAuthAuthorizationSession, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(UpstreamOAuthSessionRepository:
|
||||
async fn lookup(
|
||||
&mut self,
|
||||
id: Ulid,
|
||||
) -> Result<Option<UpstreamOAuthAuthorizationSession>, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
upstream_oauth_provider: &UpstreamOAuthProvider,
|
||||
state: String,
|
||||
code_challenge_verifier: Option<String>,
|
||||
nonce: String,
|
||||
) -> Result<UpstreamOAuthAuthorizationSession, Self::Error>;
|
||||
|
||||
async fn complete_with_link(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
upstream_oauth_authorization_session: UpstreamOAuthAuthorizationSession,
|
||||
upstream_oauth_link: &UpstreamOAuthLink,
|
||||
id_token: Option<String>,
|
||||
) -> Result<UpstreamOAuthAuthorizationSession, Self::Error>;
|
||||
|
||||
async fn consume(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
upstream_oauth_authorization_session: UpstreamOAuthAuthorizationSession,
|
||||
) -> Result<UpstreamOAuthAuthorizationSession, Self::Error>;
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ use mas_data_model::{User, UserEmail, UserEmailVerification};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::{pagination::Page, Clock, Pagination};
|
||||
use crate::{pagination::Page, repository_impl, Clock, Pagination};
|
||||
|
||||
#[async_trait]
|
||||
pub trait UserEmailRepository: Send + Sync {
|
||||
@ -74,3 +74,56 @@ pub trait UserEmailRepository: Send + Sync {
|
||||
verification: UserEmailVerification,
|
||||
) -> Result<UserEmailVerification, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(UserEmailRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<UserEmail>, Self::Error>;
|
||||
async fn find(&mut self, user: &User, email: &str) -> Result<Option<UserEmail>, Self::Error>;
|
||||
async fn get_primary(&mut self, user: &User) -> Result<Option<UserEmail>, Self::Error>;
|
||||
|
||||
async fn all(&mut self, user: &User) -> Result<Vec<UserEmail>, Self::Error>;
|
||||
async fn list_paginated(
|
||||
&mut self,
|
||||
user: &User,
|
||||
pagination: Pagination,
|
||||
) -> Result<Page<UserEmail>, Self::Error>;
|
||||
async fn count(&mut self, user: &User) -> Result<usize, Self::Error>;
|
||||
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
user: &User,
|
||||
email: String,
|
||||
) -> Result<UserEmail, Self::Error>;
|
||||
async fn remove(&mut self, user_email: UserEmail) -> Result<(), Self::Error>;
|
||||
|
||||
async fn mark_as_verified(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
user_email: UserEmail,
|
||||
) -> Result<UserEmail, Self::Error>;
|
||||
|
||||
async fn set_as_primary(&mut self, user_email: &UserEmail) -> Result<(), Self::Error>;
|
||||
|
||||
async fn add_verification_code(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
user_email: &UserEmail,
|
||||
max_age: chrono::Duration,
|
||||
code: String,
|
||||
) -> Result<UserEmailVerification, Self::Error>;
|
||||
|
||||
async fn find_verification_code(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
user_email: &UserEmail,
|
||||
code: &str,
|
||||
) -> Result<Option<UserEmailVerification>, Self::Error>;
|
||||
|
||||
async fn consume_verification_code(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
verification: UserEmailVerification,
|
||||
) -> Result<UserEmailVerification, Self::Error>;
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ use mas_data_model::User;
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
mod email;
|
||||
mod password;
|
||||
@ -41,3 +41,15 @@ pub trait UserRepository: Send + Sync {
|
||||
) -> Result<User, Self::Error>;
|
||||
async fn exists(&mut self, username: &str) -> Result<bool, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(UserRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<User>, Self::Error>;
|
||||
async fn find_by_username(&mut self, username: &str) -> Result<Option<User>, Self::Error>;
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
username: String,
|
||||
) -> Result<User, Self::Error>;
|
||||
async fn exists(&mut self, username: &str) -> Result<bool, Self::Error>;
|
||||
);
|
||||
|
@ -16,7 +16,7 @@ use async_trait::async_trait;
|
||||
use mas_data_model::{Password, User};
|
||||
use rand_core::RngCore;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
#[async_trait]
|
||||
pub trait UserPasswordRepository: Send + Sync {
|
||||
@ -33,3 +33,16 @@ pub trait UserPasswordRepository: Send + Sync {
|
||||
upgraded_from: Option<&Password>,
|
||||
) -> Result<Password, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(UserPasswordRepository:
|
||||
async fn active(&mut self, user: &User) -> Result<Option<Password>, Self::Error>;
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
user: &User,
|
||||
version: u16,
|
||||
hashed_password: String,
|
||||
upgraded_from: Option<&Password>,
|
||||
) -> Result<Password, Self::Error>;
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ use mas_data_model::{BrowserSession, Password, UpstreamOAuthLink, User};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::{pagination::Page, Clock, Pagination};
|
||||
use crate::{pagination::Page, repository_impl, Clock, Pagination};
|
||||
|
||||
#[async_trait]
|
||||
pub trait BrowserSessionRepository: Send + Sync {
|
||||
@ -58,3 +58,40 @@ pub trait BrowserSessionRepository: Send + Sync {
|
||||
upstream_oauth_link: &UpstreamOAuthLink,
|
||||
) -> Result<BrowserSession, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(BrowserSessionRepository:
|
||||
async fn lookup(&mut self, id: Ulid) -> Result<Option<BrowserSession>, Self::Error>;
|
||||
async fn add(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
user: &User,
|
||||
) -> Result<BrowserSession, Self::Error>;
|
||||
async fn finish(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
user_session: BrowserSession,
|
||||
) -> Result<BrowserSession, Self::Error>;
|
||||
async fn list_active_paginated(
|
||||
&mut self,
|
||||
user: &User,
|
||||
pagination: Pagination,
|
||||
) -> Result<Page<BrowserSession>, Self::Error>;
|
||||
async fn count_active(&mut self, user: &User) -> Result<usize, Self::Error>;
|
||||
|
||||
async fn authenticate_with_password(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
user_session: BrowserSession,
|
||||
user_password: &Password,
|
||||
) -> Result<BrowserSession, Self::Error>;
|
||||
|
||||
async fn authenticate_with_upstream(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
user_session: BrowserSession,
|
||||
upstream_oauth_link: &UpstreamOAuthLink,
|
||||
) -> Result<BrowserSession, Self::Error>;
|
||||
);
|
||||
|
Reference in New Issue
Block a user