mirror of
https://github.com/lldap/lldap.git
synced 2026-07-25 17:58:44 +00:00
server: Add methods to get/set a password reset token
This commit is contained in:
committed by
nitnelave
parent
88732556c1
commit
e1503743b5
@@ -6,10 +6,19 @@ use sea_query::{Expr, Iden, Query, SimpleExpr};
|
||||
use sqlx::Row;
|
||||
use std::collections::HashSet;
|
||||
|
||||
fn gen_random_string(len: usize) -> String {
|
||||
use rand::{distributions::Alphanumeric, rngs::SmallRng, Rng, SeedableRng};
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
std::iter::repeat(())
|
||||
.map(|()| rng.sample(Alphanumeric))
|
||||
.map(char::from)
|
||||
.take(len)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TcpBackendHandler for SqlBackendHandler {
|
||||
async fn get_jwt_blacklist(&self) -> anyhow::Result<HashSet<u64>> {
|
||||
use sqlx::Result;
|
||||
let query = Query::select()
|
||||
.column(JwtStorage::JwtHash)
|
||||
.from(JwtStorage::Table)
|
||||
@@ -21,21 +30,15 @@ impl TcpBackendHandler for SqlBackendHandler {
|
||||
.collect::<Vec<sqlx::Result<u64>>>()
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<HashSet<u64>>>()
|
||||
.collect::<sqlx::Result<HashSet<u64>>>()
|
||||
.map_err(|e| anyhow::anyhow!(e))
|
||||
}
|
||||
|
||||
async fn create_refresh_token(&self, user: &str) -> Result<(String, chrono::Duration)> {
|
||||
use rand::{distributions::Alphanumeric, rngs::SmallRng, Rng, SeedableRng};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
// TODO: Initialize the rng only once. Maybe Arc<Cell>?
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let refresh_token: String = std::iter::repeat(())
|
||||
.map(|()| rng.sample(Alphanumeric))
|
||||
.map(char::from)
|
||||
.take(100)
|
||||
.collect();
|
||||
let refresh_token = gen_random_string(100);
|
||||
let refresh_token_hash = {
|
||||
let mut s = DefaultHasher::new();
|
||||
refresh_token.hash(&mut s);
|
||||
@@ -71,7 +74,7 @@ impl TcpBackendHandler for SqlBackendHandler {
|
||||
.await?
|
||||
.is_some())
|
||||
}
|
||||
async fn blacklist_jwts(&self, user: &str) -> DomainResult<HashSet<u64>> {
|
||||
async fn blacklist_jwts(&self, user: &str) -> Result<HashSet<u64>> {
|
||||
use sqlx::Result;
|
||||
let query = Query::select()
|
||||
.column(JwtStorage::JwtHash)
|
||||
@@ -94,7 +97,7 @@ impl TcpBackendHandler for SqlBackendHandler {
|
||||
sqlx::query(&query).execute(&self.sql_pool).await?;
|
||||
Ok(result?)
|
||||
}
|
||||
async fn delete_refresh_token(&self, refresh_token_hash: u64) -> DomainResult<()> {
|
||||
async fn delete_refresh_token(&self, refresh_token_hash: u64) -> Result<()> {
|
||||
let query = Query::delete()
|
||||
.from_table(JwtRefreshStorage::Table)
|
||||
.and_where(Expr::col(JwtRefreshStorage::RefreshTokenHash).eq(refresh_token_hash))
|
||||
@@ -102,4 +105,50 @@ impl TcpBackendHandler for SqlBackendHandler {
|
||||
sqlx::query(&query).execute(&self.sql_pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn start_password_reset(&self, user: &str) -> Result<Option<String>> {
|
||||
let query = Query::select()
|
||||
.column(Users::UserId)
|
||||
.from(Users::Table)
|
||||
.and_where(Expr::col(Users::UserId).eq(user))
|
||||
.to_string(DbQueryBuilder {});
|
||||
|
||||
// Check that the user exists.
|
||||
if sqlx::query(&query).fetch_one(&self.sql_pool).await.is_err() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let token = gen_random_string(100);
|
||||
let duration = chrono::Duration::minutes(10);
|
||||
|
||||
let query = Query::insert()
|
||||
.into_table(PasswordResetTokens::Table)
|
||||
.columns(vec![
|
||||
PasswordResetTokens::Token,
|
||||
PasswordResetTokens::UserId,
|
||||
PasswordResetTokens::ExpiryDate,
|
||||
])
|
||||
.values_panic(vec![
|
||||
token.clone().into(),
|
||||
user.into(),
|
||||
(chrono::Utc::now() + duration).naive_utc().into(),
|
||||
])
|
||||
.to_string(DbQueryBuilder {});
|
||||
sqlx::query(&query).execute(&self.sql_pool).await?;
|
||||
Ok(Some(token))
|
||||
}
|
||||
|
||||
async fn get_user_id_for_password_reset_token(&self, token: &str) -> Result<String> {
|
||||
let query = Query::select()
|
||||
.column(PasswordResetTokens::UserId)
|
||||
.from(PasswordResetTokens::Table)
|
||||
.and_where(Expr::col(PasswordResetTokens::Token).eq(token))
|
||||
.and_where(
|
||||
Expr::col(PasswordResetTokens::ExpiryDate).gt(chrono::Utc::now().naive_utc()),
|
||||
)
|
||||
.to_string(DbQueryBuilder {});
|
||||
|
||||
let (user_id,) = sqlx::query_as(&query).fetch_one(&self.sql_pool).await?;
|
||||
Ok(user_id)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user