You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +03:00
Data model and repository for the user recovery flow
This commit is contained in:
@ -31,8 +31,8 @@ use crate::{
|
||||
UpstreamOAuthSessionRepository,
|
||||
},
|
||||
user::{
|
||||
BrowserSessionRepository, UserEmailRepository, UserPasswordRepository, UserRepository,
|
||||
UserTermsRepository,
|
||||
BrowserSessionRepository, UserEmailRepository, UserPasswordRepository,
|
||||
UserRecoveryRepository, UserRepository, UserTermsRepository,
|
||||
},
|
||||
MapErr,
|
||||
};
|
||||
@ -149,6 +149,10 @@ pub trait RepositoryAccess: Send {
|
||||
fn user_password<'c>(&'c mut self)
|
||||
-> Box<dyn UserPasswordRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
/// Get an [`UserRecoveryRepository`]
|
||||
fn user_recovery<'c>(&'c mut self)
|
||||
-> Box<dyn UserRecoveryRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
/// Get an [`UserTermsRepository`]
|
||||
fn user_terms<'c>(&'c mut self) -> Box<dyn UserTermsRepository<Error = Self::Error> + 'c>;
|
||||
|
||||
@ -322,6 +326,12 @@ mod impls {
|
||||
Box::new(MapErr::new(self.inner.user_password(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn user_recovery<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn crate::user::UserRecoveryRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.user_recovery(), &mut self.mapper))
|
||||
}
|
||||
|
||||
fn user_terms<'c>(&'c mut self) -> Box<dyn UserTermsRepository<Error = Self::Error> + 'c> {
|
||||
Box::new(MapErr::new(self.inner.user_terms(), &mut self.mapper))
|
||||
}
|
||||
@ -456,6 +466,12 @@ mod impls {
|
||||
(**self).user_password()
|
||||
}
|
||||
|
||||
fn user_recovery<'c>(
|
||||
&'c mut self,
|
||||
) -> Box<dyn crate::user::UserRecoveryRepository<Error = Self::Error> + 'c> {
|
||||
(**self).user_recovery()
|
||||
}
|
||||
|
||||
fn user_terms<'c>(&'c mut self) -> Box<dyn UserTermsRepository<Error = Self::Error> + 'c> {
|
||||
(**self).user_terms()
|
||||
}
|
||||
|
@ -23,12 +23,14 @@ use crate::{repository_impl, Clock};
|
||||
|
||||
mod email;
|
||||
mod password;
|
||||
mod recovery;
|
||||
mod session;
|
||||
mod terms;
|
||||
|
||||
pub use self::{
|
||||
email::{UserEmailFilter, UserEmailRepository},
|
||||
password::UserPasswordRepository,
|
||||
recovery::UserRecoveryRepository,
|
||||
session::{BrowserSessionFilter, BrowserSessionRepository},
|
||||
terms::UserTermsRepository,
|
||||
};
|
||||
|
167
crates/storage/src/user/recovery.rs
Normal file
167
crates/storage/src/user/recovery.rs
Normal file
@ -0,0 +1,167 @@
|
||||
// Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::net::IpAddr;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use mas_data_model::{UserAgent, UserEmail, UserRecoverySession, UserRecoveryTicket};
|
||||
use rand_core::RngCore;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::{repository_impl, Clock};
|
||||
|
||||
/// A [`UserRecoveryRepository`] helps interacting with [`UserRecoverySession`]
|
||||
/// and [`UserRecoveryTicket`] saved in the storage backend
|
||||
#[async_trait]
|
||||
pub trait UserRecoveryRepository: Send + Sync {
|
||||
/// The error type returned by the repository
|
||||
type Error;
|
||||
|
||||
/// Lookup an [`UserRecoverySession`] by its ID
|
||||
///
|
||||
/// Returns `None` if no [`UserRecoverySession`] was found
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `id`: The ID of the [`UserRecoverySession`] to lookup
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`Self::Error`] if the underlying repository fails
|
||||
async fn lookup_session(
|
||||
&mut self,
|
||||
id: Ulid,
|
||||
) -> Result<Option<UserRecoverySession>, Self::Error>;
|
||||
|
||||
/// Create a new [`UserRecoverySession`] for the given email
|
||||
///
|
||||
/// Returns the newly created [`UserRecoverySession`]
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `rng`: The random number generator to use
|
||||
/// * `clock`: The clock to use
|
||||
/// * `email`: The email to create the session for
|
||||
/// * `user_agent`: The user agent of the browser which initiated the
|
||||
/// session
|
||||
/// * `ip_address`: The IP address of the browser which initiated the
|
||||
/// session, if known
|
||||
/// * `locale`: The locale of the browser which initiated the session
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`Self::Error`] if the underlying repository fails
|
||||
async fn add_session(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
email: String,
|
||||
user_agent: UserAgent,
|
||||
ip_address: Option<IpAddr>,
|
||||
locale: String,
|
||||
) -> Result<UserRecoverySession, Self::Error>;
|
||||
|
||||
/// Find a [`UserRecoveryTicket`] by its ticket
|
||||
///
|
||||
/// Returns `None` if no [`UserRecoveryTicket`] was found
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `ticket`: The ticket of the [`UserRecoveryTicket`] to lookup
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`Self::Error`] if the underlying repository fails
|
||||
async fn find_ticket(
|
||||
&mut self,
|
||||
ticket: &str,
|
||||
) -> Result<Option<UserRecoveryTicket>, Self::Error>;
|
||||
|
||||
/// Add a [`UserRecoveryTicket`] to the given [`UserRecoverySession`] for
|
||||
/// the given [`UserEmail`]
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `rng`: The random number generator to use
|
||||
/// * `clock`: The clock to use
|
||||
/// * `session`: The [`UserRecoverySession`] to add the ticket to
|
||||
/// * `user_email`: The [`UserEmail`] to add the ticket for
|
||||
/// * `ticket`: The ticket to add
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`Self::Error`] if the underlying repository fails
|
||||
async fn add_ticket(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
user_recovery_session: &UserRecoverySession,
|
||||
user_email: &UserEmail,
|
||||
ticket: String,
|
||||
) -> Result<UserRecoveryTicket, Self::Error>;
|
||||
|
||||
/// Consume a [`UserRecoveryTicket`] and mark the session as used
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `clock`: The clock to use to record the time of consumption
|
||||
/// * `ticket`: The [`UserRecoveryTicket`] to consume
|
||||
/// * `session`: The [`UserRecoverySession`] to mark as used
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`Self::Error`] if the underlying repository fails or if the
|
||||
/// recovery session was already used
|
||||
async fn consume_ticket(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
user_recovery_ticket: UserRecoveryTicket,
|
||||
user_recovery_session: UserRecoverySession,
|
||||
) -> Result<UserRecoverySession, Self::Error>;
|
||||
}
|
||||
|
||||
repository_impl!(UserRecoveryRepository:
|
||||
async fn lookup_session(&mut self, id: Ulid) -> Result<Option<UserRecoverySession>, Self::Error>;
|
||||
|
||||
async fn add_session(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
email: String,
|
||||
user_agent: UserAgent,
|
||||
ip_address: Option<IpAddr>,
|
||||
locale: String,
|
||||
) -> Result<UserRecoverySession, Self::Error>;
|
||||
|
||||
async fn find_ticket(
|
||||
&mut self,
|
||||
ticket: &str,
|
||||
) -> Result<Option<UserRecoveryTicket>, Self::Error>;
|
||||
|
||||
async fn add_ticket(
|
||||
&mut self,
|
||||
rng: &mut (dyn RngCore + Send),
|
||||
clock: &dyn Clock,
|
||||
user_recovery_session: &UserRecoverySession,
|
||||
user_email: &UserEmail,
|
||||
ticket: String,
|
||||
) -> Result<UserRecoveryTicket, Self::Error>;
|
||||
|
||||
async fn consume_ticket(
|
||||
&mut self,
|
||||
clock: &dyn Clock,
|
||||
user_recovery_ticket: UserRecoveryTicket,
|
||||
user_recovery_session: UserRecoverySession,
|
||||
) -> Result<UserRecoverySession, Self::Error>;
|
||||
);
|
Reference in New Issue
Block a user