You've already forked AstralRinth
forked from didirus/AstralRinth
Verify Email + Reset Password flows (#654)
* verifiers * add missing emails * fix gh perms
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
use crate::auth::flows::AuthProvider;
|
||||
use crate::auth::{get_user_from_headers, AuthenticationError};
|
||||
use crate::database::models::User;
|
||||
use crate::file_hosting::FileHost;
|
||||
@@ -12,12 +11,8 @@ use crate::routes::ApiError;
|
||||
use crate::util::routes::read_from_payload;
|
||||
use crate::util::validate::validation_errors_to_string;
|
||||
use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse};
|
||||
use argon2::password_hash::SaltString;
|
||||
use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
|
||||
use chrono::{DateTime, Utc};
|
||||
use lazy_static::lazy_static;
|
||||
use rand_chacha::rand_core::SeedableRng;
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
use regex::Regex;
|
||||
use rust_decimal::Decimal;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -193,8 +188,6 @@ pub struct EditUser {
|
||||
)]
|
||||
#[validate]
|
||||
pub payout_data: Option<Option<EditPayoutData>>,
|
||||
pub password: Option<(Option<String>, Option<String>)>,
|
||||
pub remove_auth_providers: Option<Vec<AuthProvider>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate)]
|
||||
@@ -407,194 +400,6 @@ pub async fn user_edit(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((old_password, new_password)) = &new_user.password {
|
||||
if !scopes.contains(Scopes::USER_AUTH_WRITE) {
|
||||
return Err(ApiError::Authentication(
|
||||
AuthenticationError::InvalidCredentials,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(pass) = actual_user.password.as_ref() {
|
||||
let old_password = old_password.as_ref().ok_or_else(|| {
|
||||
ApiError::CustomAuthentication(
|
||||
"You must specify the old password to change your password!"
|
||||
.to_string(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let hasher = Argon2::default();
|
||||
hasher.verify_password(old_password.as_bytes(), &PasswordHash::new(pass)?)?;
|
||||
}
|
||||
|
||||
let update_password = if let Some(new_password) = new_password {
|
||||
let score = zxcvbn::zxcvbn(
|
||||
new_password,
|
||||
&[
|
||||
&actual_user.username,
|
||||
&actual_user.email.unwrap_or_default(),
|
||||
&actual_user.name.unwrap_or_default(),
|
||||
],
|
||||
)?;
|
||||
|
||||
if score.score() < 3 {
|
||||
return Err(ApiError::InvalidInput(
|
||||
if let Some(feedback) =
|
||||
score.feedback().clone().and_then(|x| x.warning())
|
||||
{
|
||||
format!("Password too weak: {}", feedback)
|
||||
} else {
|
||||
"Specified password is too weak! Please improve its strength."
|
||||
.to_string()
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let hasher = Argon2::default();
|
||||
let salt = SaltString::generate(&mut ChaCha20Rng::from_entropy());
|
||||
let password_hash = hasher
|
||||
.hash_password(new_password.as_bytes(), &salt)?
|
||||
.to_string();
|
||||
|
||||
Some(password_hash)
|
||||
} else {
|
||||
if !(actual_user.github_id.is_some()
|
||||
|| actual_user.gitlab_id.is_some()
|
||||
|| actual_user.microsoft_id.is_some()
|
||||
|| actual_user.google_id.is_some()
|
||||
|| actual_user.steam_id.is_some()
|
||||
|| actual_user.discord_id.is_some())
|
||||
{
|
||||
return Err(ApiError::InvalidInput(
|
||||
"You must have another authentication method added to remove password authentication!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
None
|
||||
};
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET password = $1
|
||||
WHERE (id = $2)
|
||||
",
|
||||
update_password,
|
||||
id as crate::database::models::ids::UserId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(remove_auth_providers) = &new_user.remove_auth_providers {
|
||||
if !scopes.contains(Scopes::USER_AUTH_WRITE) {
|
||||
return Err(ApiError::Authentication(
|
||||
AuthenticationError::InvalidCredentials,
|
||||
));
|
||||
}
|
||||
|
||||
let mut auth_providers = Vec::new();
|
||||
if actual_user.github_id.is_some() {
|
||||
auth_providers.push(AuthProvider::GitHub)
|
||||
}
|
||||
if actual_user.gitlab_id.is_some() {
|
||||
auth_providers.push(AuthProvider::GitLab)
|
||||
}
|
||||
if actual_user.discord_id.is_some() {
|
||||
auth_providers.push(AuthProvider::Discord)
|
||||
}
|
||||
if actual_user.google_id.is_some() {
|
||||
auth_providers.push(AuthProvider::Google)
|
||||
}
|
||||
if actual_user.microsoft_id.is_some() {
|
||||
auth_providers.push(AuthProvider::Microsoft)
|
||||
}
|
||||
if actual_user.steam_id.is_some() {
|
||||
auth_providers.push(AuthProvider::Steam)
|
||||
}
|
||||
|
||||
if auth_providers.len() <= remove_auth_providers.len()
|
||||
&& actual_user.password.is_none()
|
||||
{
|
||||
return Err(ApiError::InvalidInput(
|
||||
"You must have another authentication method added to this method!"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if remove_auth_providers.contains(&AuthProvider::GitHub) {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET github_id = NULL
|
||||
WHERE (id = $1)
|
||||
",
|
||||
id as crate::database::models::ids::UserId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
}
|
||||
if remove_auth_providers.contains(&AuthProvider::GitLab) {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET gitlab_id = NULL
|
||||
WHERE (id = $1)
|
||||
",
|
||||
id as crate::database::models::ids::UserId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
}
|
||||
if remove_auth_providers.contains(&AuthProvider::Google) {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET google_id = NULL
|
||||
WHERE (id = $1)
|
||||
",
|
||||
id as crate::database::models::ids::UserId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
}
|
||||
if remove_auth_providers.contains(&AuthProvider::Steam) {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET steam_id = NULL
|
||||
WHERE (id = $1)
|
||||
",
|
||||
id as crate::database::models::ids::UserId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
}
|
||||
if remove_auth_providers.contains(&AuthProvider::Discord) {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET discord_id = NULL
|
||||
WHERE (id = $1)
|
||||
",
|
||||
id as crate::database::models::ids::UserId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
}
|
||||
if remove_auth_providers.contains(&AuthProvider::Microsoft) {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET microsoft_id = NULL
|
||||
WHERE (id = $1)
|
||||
",
|
||||
id as crate::database::models::ids::UserId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
User::clear_caches(&[(id, Some(actual_user.username))], &redis).await?;
|
||||
transaction.commit().await?;
|
||||
Ok(HttpResponse::NoContent().body(""))
|
||||
|
||||
Reference in New Issue
Block a user