db: newtype PasswordHash for users & app passwords

Lewis: May this revision serve well! <lu5a@proton.me>
This commit is contained in:
Lewis
2026-07-12 08:03:14 +02:00
parent 8559764d31
commit 469255f5a9
13 changed files with 96 additions and 84 deletions
+12 -9
View File
@@ -5,7 +5,7 @@ use tracing::error;
use tranquil_db_traits::{CommsChannel, DidWebOverrides, SessionRepository, UserRepository};
use tranquil_pds::api::error::ApiError;
use tranquil_pds::api::error::DbResultExt;
use tranquil_pds::types::{AtIdentifier, Did, Handle};
use tranquil_pds::types::{AtIdentifier, Did, Handle, PasswordHash};
pub struct ResolvedRepo {
pub user_id: uuid::Uuid,
@@ -216,7 +216,7 @@ pub async fn verify_credential(
session_repo: &dyn SessionRepository,
user_id: uuid::Uuid,
password: &str,
password_hash: Option<&str>,
password_hash: Option<&PasswordHash>,
) -> Option<CredentialMatch> {
let main_valid = password_hash
.map(|h| bcrypt::verify(password, h).unwrap_or(false))
@@ -230,7 +230,7 @@ pub async fn verify_credential(
.unwrap_or_default();
app_passwords
.into_iter()
.find(|app| bcrypt::verify(password, &app.password_hash).unwrap_or(false))
.find(|app| bcrypt::verify(password, app.password_hash.as_str()).unwrap_or(false))
.map(|app| {
let scopes = app.scopes.unwrap_or_else(|| {
if app.privilege.is_privileged() {
@@ -247,14 +247,16 @@ pub async fn verify_credential(
})
}
pub fn hash_or_internal_error(value: &str) -> Result<String, ApiError> {
bcrypt::hash(value, DEFAULT_COST).map_err(|e| {
error!("Bcrypt hash error: {:?}", e);
ApiError::InternalError(None)
})
pub fn hash_or_internal_error(value: &str) -> Result<PasswordHash, ApiError> {
bcrypt::hash(value, DEFAULT_COST)
.map(PasswordHash::new)
.map_err(|e| {
error!("Bcrypt hash error: {:?}", e);
ApiError::InternalError(None)
})
}
pub async fn hash_password_async(password: &str) -> Result<String, ApiError> {
pub async fn hash_password_async(password: &str) -> Result<PasswordHash, ApiError> {
let password = password.to_string();
tokio::task::spawn_blocking(move || hash(password, DEFAULT_COST))
.await
@@ -262,6 +264,7 @@ pub async fn hash_password_async(password: &str) -> Result<String, ApiError> {
error!("Failed to spawn blocking task: {:?}", e);
ApiError::InternalError(None)
})?
.map(PasswordHash::new)
.map_err(|e| {
error!("Failed to hash password: {:?}", e);
ApiError::InternalError(None)
@@ -637,7 +637,7 @@ pub async fn delete_account(
state.repos.session.as_ref(),
user_id,
password,
password_hash.as_deref(),
password_hash.as_ref(),
)
.await
.is_none()
+1 -1
View File
@@ -74,7 +74,7 @@ pub async fn reauth_password(
.log_db_err("fetching password hash")?
.ok_or(ApiError::AccountNotFound)?;
let password_valid = bcrypt::verify(&input.password, &password_hash).unwrap_or(false);
let password_valid = bcrypt::verify(&input.password, password_hash.as_str()).unwrap_or(false);
if !password_valid {
let app_password_hashes = state
+1 -1
View File
@@ -112,7 +112,7 @@ pub async fn create_session(
state.repos.session.as_ref(),
row.id,
&input.password,
row.password_hash.as_deref(),
row.password_hash.as_ref(),
)
.await;
let (app_password_name, app_password_scopes, app_password_controller) = match credential {
+3 -3
View File
@@ -1,6 +1,6 @@
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use tranquil_types::Did;
use tranquil_types::{Did, Jti, PasswordHash};
use uuid::Uuid;
use crate::DbError;
@@ -134,7 +134,7 @@ pub struct AppPasswordRecord {
pub id: Uuid,
pub user_id: Uuid,
pub name: String,
pub password_hash: String,
pub password_hash: PasswordHash,
pub created_at: DateTime<Utc>,
pub privilege: AppPasswordPrivilege,
pub scopes: Option<String>,
@@ -145,7 +145,7 @@ pub struct AppPasswordRecord {
pub struct AppPasswordCreate {
pub user_id: Uuid,
pub name: String,
pub password_hash: String,
pub password_hash: PasswordHash,
pub privilege: AppPasswordPrivilege,
pub scopes: Option<String>,
pub created_by_controller_did: Option<Did>,
+22 -17
View File
@@ -1,7 +1,9 @@
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use tranquil_types::{Did, Handle};
use tranquil_types::{
AtIdentifier, CidLink, Did, Handle, InviteCode, Jti, PasswordHash, Tid, TokenId,
};
use uuid::Uuid;
use crate::{ChannelVerificationStatus, CommsChannel, DbError, SsoProviderType};
@@ -78,7 +80,7 @@ pub struct UserEmailInfo {
#[derive(Debug, Clone)]
pub struct UserLoginCheck {
pub did: Did,
pub password_hash: Option<String>,
pub password_hash: Option<PasswordHash>,
}
#[derive(Debug, Clone)]
@@ -86,7 +88,7 @@ pub struct UserLoginInfo {
pub id: Uuid,
pub did: Did,
pub email: Option<String>,
pub password_hash: Option<String>,
pub password_hash: Option<PasswordHash>,
pub password_required: bool,
pub two_factor_enabled: bool,
pub preferred_comms_channel: CommsChannel,
@@ -313,7 +315,7 @@ pub trait UserRepository: Send + Sync {
async fn has_passkeys(&self, did: &Did) -> Result<bool, DbError>;
async fn get_password_hash_by_did(&self, did: &Did) -> Result<Option<String>, DbError>;
async fn get_password_hash_by_did(&self, did: &Did) -> Result<Option<PasswordHash>, DbError>;
async fn get_passkeys_for_user(&self, did: &Did) -> Result<Vec<StoredPasskey>, DbError>;
@@ -466,13 +468,16 @@ pub trait UserRepository: Send + Sync {
did: &Did,
) -> Result<Option<UserIdAndPasswordHash>, DbError>;
async fn update_password_hash(&self, user_id: Uuid, password_hash: &str)
-> Result<(), DbError>;
async fn update_password_hash(
&self,
user_id: Uuid,
password_hash: &PasswordHash,
) -> Result<(), DbError>;
async fn reset_password_with_sessions(
&self,
user_id: Uuid,
password_hash: &str,
password_hash: &PasswordHash,
) -> Result<PasswordResetResult, DbError>;
async fn activate_account(&self, did: &Did) -> Result<bool, DbError>;
@@ -495,7 +500,7 @@ pub trait UserRepository: Send + Sync {
async fn set_new_user_password(
&self,
user_id: Uuid,
password_hash: &str,
password_hash: &PasswordHash,
) -> Result<(), DbError>;
async fn get_user_key_by_did(&self, did: &Did) -> Result<Option<UserKeyInfo>, DbError>;
@@ -699,7 +704,7 @@ pub struct AccountSearchResult {
pub struct UserAuthInfo {
pub id: Uuid,
pub did: Did,
pub password_hash: Option<String>,
pub password_hash: Option<PasswordHash>,
pub deactivated_at: Option<DateTime<Utc>>,
pub takedown_ref: Option<String>,
pub channel_verification: ChannelVerificationStatus,
@@ -863,7 +868,7 @@ pub struct UserLoginFull {
pub id: Uuid,
pub did: Did,
pub handle: Handle,
pub password_hash: Option<String>,
pub password_hash: Option<PasswordHash>,
pub email: Option<String>,
pub deactivated_at: Option<DateTime<Utc>>,
pub takedown_ref: Option<String>,
@@ -914,13 +919,13 @@ pub struct UserResetCodeInfo {
#[derive(Debug, Clone)]
pub struct UserPasswordInfo {
pub id: Uuid,
pub password_hash: Option<String>,
pub password_hash: Option<PasswordHash>,
}
#[derive(Debug, Clone)]
pub struct UserIdAndPasswordHash {
pub id: Uuid,
pub password_hash: String,
pub password_hash: PasswordHash,
}
#[derive(Debug, Clone)]
@@ -932,7 +937,7 @@ pub struct PasswordResetResult {
#[derive(Debug, Clone)]
pub struct UserForDeletion {
pub id: Uuid,
pub password_hash: Option<String>,
pub password_hash: Option<PasswordHash>,
pub handle: Handle,
}
@@ -988,7 +993,7 @@ pub struct CreatePasswordAccountInput {
pub handle: Handle,
pub email: Option<String>,
pub did: Did,
pub password_hash: String,
pub password_hash: PasswordHash,
pub preferred_comms_channel: CommsChannel,
pub discord_username: Option<String>,
pub telegram_username: Option<String>,
@@ -1044,7 +1049,7 @@ pub struct CreatePasskeyAccountInput {
pub discord_username: Option<String>,
pub telegram_username: Option<String>,
pub signal_username: Option<String>,
pub setup_token_hash: String,
pub setup_token_hash: PasswordHash,
pub setup_expires_at: DateTime<Utc>,
pub deactivated_at: Option<DateTime<Utc>>,
pub encrypted_key_bytes: Vec<u8>,
@@ -1086,13 +1091,13 @@ pub struct CompletePasskeySetupInput {
pub user_id: Uuid,
pub did: Did,
pub app_password_name: String,
pub app_password_hash: String,
pub app_password_hash: PasswordHash,
}
#[derive(Debug, Clone)]
pub struct RecoverPasskeyAccountInput {
pub did: Did,
pub password_hash: String,
pub password_hash: PasswordHash,
}
#[derive(Debug, Clone)]
+6 -6
View File
@@ -7,7 +7,7 @@ use tranquil_db_traits::{
SessionForRefresh, SessionId, SessionListItem, SessionMfaStatus, SessionRefreshData,
SessionRepository, SessionToken, SessionTokenCreate,
};
use tranquil_types::Did;
use tranquil_types::{Did, Jti, PasswordHash};
use uuid::Uuid;
use super::user::map_sqlx_error;
@@ -318,7 +318,7 @@ impl SessionRepository for PostgresSessionRepository {
id: r.id,
user_id: r.user_id,
name: r.name,
password_hash: r.password_hash,
password_hash: PasswordHash::new(r.password_hash),
created_at: r.created_at,
privilege: AppPasswordPrivilege::from_privileged_flag(r.privileged),
scopes: r.scopes,
@@ -351,7 +351,7 @@ impl SessionRepository for PostgresSessionRepository {
id: r.id,
user_id: r.user_id,
name: r.name,
password_hash: r.password_hash,
password_hash: PasswordHash::new(r.password_hash),
created_at: r.created_at,
privilege: AppPasswordPrivilege::from_privileged_flag(r.privileged),
scopes: r.scopes,
@@ -382,7 +382,7 @@ impl SessionRepository for PostgresSessionRepository {
id: r.id,
user_id: r.user_id,
name: r.name,
password_hash: r.password_hash,
password_hash: PasswordHash::new(r.password_hash),
created_at: r.created_at,
privilege: AppPasswordPrivilege::from_privileged_flag(r.privileged),
scopes: r.scopes,
@@ -399,7 +399,7 @@ impl SessionRepository for PostgresSessionRepository {
"#,
data.user_id,
data.name,
data.password_hash,
data.password_hash.as_str(),
data.privilege.is_privileged(),
data.scopes,
data.created_by_controller_did.as_ref().map(|d| d.as_str())
@@ -510,7 +510,7 @@ impl SessionRepository for PostgresSessionRepository {
.await
.map_err(map_sqlx_error)?;
Ok(rows)
Ok(rows.into_iter().map(PasswordHash::new).collect())
}
async fn refresh_session_atomic(
+19 -19
View File
@@ -1,7 +1,7 @@
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use sqlx::PgPool;
use tranquil_types::{Did, Handle};
use tranquil_types::{AtIdentifier, Did, Handle, Jti, PasswordHash, TokenId};
use uuid::Uuid;
use tranquil_db_traits::{
@@ -314,7 +314,7 @@ impl UserRepository for PostgresUserRepository {
Ok(row.map(|r| UserAuthInfo {
id: r.id,
did: Did::from(r.did),
password_hash: r.password_hash,
password_hash: r.password_hash.map(PasswordHash::new),
deactivated_at: r.deactivated_at,
takedown_ref: r.takedown_ref,
channel_verification: ChannelVerificationStatus::from_db_row(
@@ -654,7 +654,7 @@ impl UserRepository for PostgresUserRepository {
async fn admin_update_password(&self, did: &Did, password_hash: &str) -> Result<u64, DbError> {
let result = sqlx::query!(
"UPDATE users SET password_hash = $1 WHERE did = $2",
password_hash,
password_hash.as_str(),
did.as_str()
)
.execute(&self.pool)
@@ -927,7 +927,7 @@ impl UserRepository for PostgresUserRepository {
Ok(count.unwrap_or(0) > 0)
}
async fn get_password_hash_by_did(&self, did: &Did) -> Result<Option<String>, DbError> {
async fn get_password_hash_by_did(&self, did: &Did) -> Result<Option<PasswordHash>, DbError> {
let row = sqlx::query_scalar!(
"SELECT password_hash FROM users WHERE did = $1",
did.as_str()
@@ -936,7 +936,7 @@ impl UserRepository for PostgresUserRepository {
.await
.map_err(map_sqlx_error)?;
Ok(row.flatten())
Ok(row.flatten().map(PasswordHash::new))
}
async fn get_passkeys_for_user(&self, did: &Did) -> Result<Vec<StoredPasskey>, DbError> {
@@ -1431,7 +1431,7 @@ impl UserRepository for PostgresUserRepository {
.map(|opt| {
opt.map(|r| UserLoginCheck {
did: Did::from(r.did),
password_hash: r.password_hash,
password_hash: r.password_hash.map(PasswordHash::new),
})
})
}
@@ -1460,7 +1460,7 @@ impl UserRepository for PostgresUserRepository {
id: row.id,
did: Did::from(row.did),
email: row.email,
password_hash: row.password_hash,
password_hash: row.password_hash.map(PasswordHash::new),
password_required: row.password_required,
two_factor_enabled: row.two_factor_enabled,
preferred_comms_channel: row.preferred_comms_channel,
@@ -1622,7 +1622,7 @@ impl UserRepository for PostgresUserRepository {
id: row.id,
did: Did::from(row.did),
handle: Handle::from(row.handle),
password_hash: row.password_hash,
password_hash: row.password_hash.map(PasswordHash::new),
email: row.email,
deactivated_at: row.deactivated_at,
takedown_ref: row.takedown_ref,
@@ -1831,7 +1831,7 @@ impl UserRepository for PostgresUserRepository {
opt.and_then(|row| {
row.password_hash.map(|hash| UserIdAndPasswordHash {
id: row.id,
password_hash: hash,
password_hash: PasswordHash::new(hash),
})
})
})
@@ -1840,11 +1840,11 @@ impl UserRepository for PostgresUserRepository {
async fn update_password_hash(
&self,
user_id: Uuid,
password_hash: &str,
password_hash: &PasswordHash,
) -> Result<(), DbError> {
sqlx::query!(
"UPDATE users SET password_hash = $1 WHERE id = $2",
password_hash,
password_hash.as_str(),
user_id
)
.execute(&self.pool)
@@ -1856,13 +1856,13 @@ impl UserRepository for PostgresUserRepository {
async fn reset_password_with_sessions(
&self,
user_id: Uuid,
password_hash: &str,
password_hash: &PasswordHash,
) -> Result<PasswordResetResult, DbError> {
let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;
sqlx::query!(
"UPDATE users SET password_hash = $1, password_reset_code = NULL, password_reset_code_expires_at = NULL, password_required = TRUE WHERE id = $2",
password_hash,
password_hash.as_str(),
user_id
)
.execute(&mut *tx)
@@ -1950,7 +1950,7 @@ impl UserRepository for PostgresUserRepository {
.map(|opt| {
opt.map(|row| UserPasswordInfo {
id: row.id,
password_hash: row.password_hash,
password_hash: row.password_hash.map(PasswordHash::new),
})
})
}
@@ -1969,11 +1969,11 @@ impl UserRepository for PostgresUserRepository {
async fn set_new_user_password(
&self,
user_id: Uuid,
password_hash: &str,
password_hash: &PasswordHash,
) -> Result<(), DbError> {
sqlx::query!(
"UPDATE users SET password_hash = $1, password_required = TRUE WHERE id = $2",
password_hash,
password_hash.as_str(),
user_id
)
.execute(&self.pool)
@@ -2004,7 +2004,7 @@ impl UserRepository for PostgresUserRepository {
.map(|opt| {
opt.map(|row| UserForDeletion {
id: row.id,
password_hash: row.password_hash,
password_hash: row.password_hash.map(PasswordHash::new),
handle: Handle::from(row.handle),
})
})
@@ -3113,7 +3113,7 @@ impl UserRepository for PostgresUserRepository {
"INSERT INTO app_passwords (user_id, name, password_hash, privileged) VALUES ($1, $2, $3, FALSE)",
input.user_id,
input.app_password_name,
input.app_password_hash
input.app_password_hash.as_str()
)
.execute(&mut *tx)
.await
@@ -3140,7 +3140,7 @@ impl UserRepository for PostgresUserRepository {
sqlx::query!(
"UPDATE users SET password_hash = $1, password_required = TRUE, recovery_token = NULL, recovery_token_expires_at = NULL WHERE did = $2",
input.password_hash,
input.password_hash.as_str(),
input.did.as_str()
)
.execute(&mut *tx)
+1 -1
View File
@@ -144,7 +144,7 @@ async fn seed_user(repos: &PostgresRepositories, did: &Did, handle: &Handle) ->
handle: handle.clone(),
email: None,
did: did.clone(),
password_hash: "parity-test-hash".to_string(),
password_hash: tranquil_types::PasswordHash::new("parity-test-hash"),
preferred_comms_channel: CommsChannel::Email,
discord_username: None,
telegram_username: None,
+15 -11
View File
@@ -29,7 +29,7 @@ use tranquil_db_traits::{
use tranquil_oauth::{AuthorizedClientData, DeviceData, RequestData, TokenData};
use tranquil_types::{
AtUri, AuthorizationCode, CidLink, ClientId, DPoPProofId, DeviceId, Did, Handle, Nsid,
RefreshToken, RequestId, Rkey, TokenId,
InviteCode, Jti, Nsid, PasswordHash, RefreshToken, RequestId, Rkey, Tid, TokenId,
};
use uuid::Uuid;
@@ -1734,7 +1734,9 @@ impl<S: StorageIO + 'static> tranquil_db_traits::SessionRepository for Metastore
tx,
},
))?;
recv(rx).await
recv(rx)
.await
.map(|hashes: Vec<String>| hashes.into_iter().map(PasswordHash::new).collect())
}
async fn refresh_session_atomic(
@@ -3733,7 +3735,7 @@ impl<S: StorageIO + 'static> tranquil_db_traits::UserRepository for MetastoreCli
self.pool
.send(MetastoreRequest::User(UserRequest::AdminUpdatePassword {
did: did.clone(),
password_hash: password_hash.to_owned(),
password_hash: password_hash.as_str().to_owned(),
tx,
}))?;
recv(rx).await
@@ -4032,14 +4034,16 @@ impl<S: StorageIO + 'static> tranquil_db_traits::UserRepository for MetastoreCli
recv(rx).await
}
async fn get_password_hash_by_did(&self, did: &Did) -> Result<Option<String>, DbError> {
async fn get_password_hash_by_did(&self, did: &Did) -> Result<Option<PasswordHash>, DbError> {
let (tx, rx) = oneshot::channel();
self.pool
.send(MetastoreRequest::User(UserRequest::GetPasswordHashByDid {
did: did.clone(),
tx,
}))?;
recv(rx).await
recv(rx)
.await
.map(|hash: Option<String>| hash.map(PasswordHash::new))
}
async fn get_passkeys_for_user(&self, did: &Did) -> Result<Vec<StoredPasskey>, DbError> {
@@ -4556,13 +4560,13 @@ impl<S: StorageIO + 'static> tranquil_db_traits::UserRepository for MetastoreCli
async fn update_password_hash(
&self,
user_id: Uuid,
password_hash: &str,
password_hash: &PasswordHash,
) -> Result<(), DbError> {
let (tx, rx) = oneshot::channel();
self.pool
.send(MetastoreRequest::User(UserRequest::UpdatePasswordHash {
user_id,
password_hash: password_hash.to_owned(),
password_hash: password_hash.as_str().to_owned(),
tx,
}))?;
recv(rx).await
@@ -4571,13 +4575,13 @@ impl<S: StorageIO + 'static> tranquil_db_traits::UserRepository for MetastoreCli
async fn reset_password_with_sessions(
&self,
user_id: Uuid,
password_hash: &str,
password_hash: &PasswordHash,
) -> Result<PasswordResetResult, DbError> {
let (tx, rx) = oneshot::channel();
self.pool.send(MetastoreRequest::User(
UserRequest::ResetPasswordWithSessions {
user_id,
password_hash: password_hash.to_owned(),
password_hash: password_hash.as_str().to_owned(),
tx,
},
))?;
@@ -4645,13 +4649,13 @@ impl<S: StorageIO + 'static> tranquil_db_traits::UserRepository for MetastoreCli
async fn set_new_user_password(
&self,
user_id: Uuid,
password_hash: &str,
password_hash: &PasswordHash,
) -> Result<(), DbError> {
let (tx, rx) = oneshot::channel();
self.pool
.send(MetastoreRequest::User(UserRequest::SetNewUserPassword {
user_id,
password_hash: password_hash.to_owned(),
password_hash: password_hash.as_str().to_owned(),
tx,
}))?;
recv(rx).await
+1 -1
View File
@@ -455,7 +455,7 @@ mod tests {
handle: tranquil_types::Handle::new(handle.to_string()).unwrap(),
email: None,
did: tranquil_types::Did::new(did.to_string()).unwrap(),
password_hash: "test-hash".to_string(),
password_hash: tranquil_types::PasswordHash::new("test-hash"),
preferred_comms_channel: tranquil_db_traits::CommsChannel::Email,
discord_username: None,
telegram_username: None,
@@ -24,7 +24,7 @@ use tranquil_db_traits::{
RefreshGraceReplay, RefreshSessionResult, SessionForRefresh, SessionId, SessionListItem,
SessionMfaStatus, SessionRefreshData, SessionToken, SessionTokenCreate,
};
use tranquil_types::Did;
use tranquil_types::{Did, Jti, PasswordHash};
pub struct SessionOps {
db: Database,
@@ -112,7 +112,7 @@ impl SessionOps {
id: v.id,
user_id: v.user_id,
name: v.name.clone(),
password_hash: v.password_hash.clone(),
password_hash: PasswordHash::new(v.password_hash.clone()),
created_at: DateTime::from_timestamp_millis(v.created_at_ms).unwrap_or_default(),
privilege: u8_to_privilege(v.privilege)
.unwrap_or(tranquil_db_traits::AppPasswordPrivilege::Standard),
@@ -620,7 +620,7 @@ impl SessionOps {
id,
user_id: data.user_id,
name: data.name.clone(),
password_hash: data.password_hash.clone(),
password_hash: data.password_hash.as_str().to_owned(),
created_at_ms: now_ms,
privilege: privilege_to_u8(data.privilege),
scopes: data.scopes.clone(),
+11 -11
View File
@@ -38,7 +38,7 @@ use tranquil_db_traits::{
UserResetCodeInfo, UserRow, UserSessionInfo, UserStatus, UserVerificationInfo, UserWithKey,
WebauthnChallengeType,
};
use tranquil_types::{CidLink, Did, Handle};
use tranquil_types::{CidLink, Did, Handle, Jti, PasswordHash};
pub struct UserOps {
db: Database,
@@ -440,7 +440,7 @@ impl UserOps {
id: v.id,
did: Did::new(v.did.clone())
.map_err(|_| MetastoreError::CorruptData("invalid user did"))?,
password_hash: v.password_hash.clone(),
password_hash: v.password_hash.clone().map(PasswordHash::new),
deactivated_at: v
.deactivated_at_ms
.and_then(DateTime::from_timestamp_millis),
@@ -476,7 +476,7 @@ impl UserOps {
Ok(UserLoginCheck {
did: Did::new(v.did.clone())
.map_err(|_| MetastoreError::CorruptData("invalid user did"))?,
password_hash: v.password_hash.clone(),
password_hash: v.password_hash.clone().map(PasswordHash::new),
})
})
.transpose()
@@ -493,7 +493,7 @@ impl UserOps {
did: Did::new(v.did.clone())
.map_err(|_| MetastoreError::CorruptData("invalid user did"))?,
email: v.email.clone(),
password_hash: v.password_hash.clone(),
password_hash: v.password_hash.clone().map(PasswordHash::new),
password_required: v.password_required,
two_factor_enabled: v.two_factor_enabled,
preferred_comms_channel: Self::comms_channel(&v),
@@ -625,7 +625,7 @@ impl UserOps {
.map(|v| {
Ok(UserForDeletion {
id: v.id,
password_hash: v.password_hash.clone(),
password_hash: v.password_hash.clone().map(PasswordHash::new),
handle: Handle::new(v.handle.clone())
.map_err(|_| MetastoreError::CorruptData("invalid user handle"))?,
})
@@ -1956,7 +1956,7 @@ impl UserOps {
.map_err(|_| MetastoreError::CorruptData("invalid user did"))?,
handle: Handle::new(v.handle.clone())
.map_err(|_| MetastoreError::CorruptData("invalid user handle"))?,
password_hash: v.password_hash.clone(),
password_hash: v.password_hash.clone().map(PasswordHash::new),
email: v.email.clone(),
deactivated_at: v
.deactivated_at_ms
@@ -2160,7 +2160,7 @@ impl UserOps {
.map(|(id, ph)| {
Ok(UserIdAndPasswordHash {
id,
password_hash: ph,
password_hash: PasswordHash::new(ph),
})
})
.transpose()
@@ -2279,7 +2279,7 @@ impl UserOps {
.load_user_by_did(did.as_str())?
.map(|v| UserPasswordInfo {
id: v.id,
password_hash: v.password_hash.clone(),
password_hash: v.password_hash.clone().map(PasswordHash::new),
}))
}
@@ -2854,7 +2854,7 @@ impl UserOps {
&input.did,
&input.handle,
input.email.as_deref(),
Some(&input.password_hash),
Some(input.password_hash.as_str()),
input.preferred_comms_channel,
input.discord_username.as_deref(),
input.telegram_username.as_deref(),
@@ -3135,7 +3135,7 @@ impl UserOps {
let user_hash = self.resolve_hash(input.did.as_str());
self.mutate_user(user_hash, |u| {
u.password_hash = Some(input.app_password_hash.clone());
u.password_hash = Some(input.app_password_hash.as_str().to_owned());
u.password_required = false;
})?;
@@ -3173,7 +3173,7 @@ impl UserOps {
batch.remove(&self.users, recovery_token_key(user_hash).as_slice());
if let Some(mut user) = self.load_user(user_hash)? {
user.password_hash = Some(input.password_hash.clone());
user.password_hash = Some(input.password_hash.as_str().to_owned());
user.password_required = true;
batch.insert(
&self.users,