You've already forked AstralRinth
forked from didirus/AstralRinth
2FA + Add/Remove Auth Providers (#652)
* 2FA + Add/Remove Auth Providers * fix fmt issue
This commit is contained in:
@@ -785,8 +785,8 @@ async fn project_create_inner(
|
||||
project_id: Some(id),
|
||||
report_id: None,
|
||||
}
|
||||
.insert(&mut *transaction)
|
||||
.await?;
|
||||
.insert(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
let response = crate::models::projects::Project {
|
||||
id: project_id,
|
||||
|
||||
@@ -584,8 +584,8 @@ pub async fn project_edit(
|
||||
},
|
||||
thread_id: project_item.thread_id,
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
|
||||
@@ -153,8 +153,8 @@ pub async fn report_create(
|
||||
project_id: None,
|
||||
report_id: Some(report.id),
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
|
||||
transaction.commit().await?;
|
||||
|
||||
@@ -395,8 +395,8 @@ pub async fn report_edit(
|
||||
},
|
||||
thread_id: report.thread_id,
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
|
||||
@@ -45,12 +45,14 @@ pub async fn is_authorized_thread(
|
||||
report_id as database::models::ids::ReportId,
|
||||
user_id as database::models::ids::UserId,
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?
|
||||
.exists;
|
||||
.fetch_one(pool)
|
||||
.await?
|
||||
.exists;
|
||||
|
||||
report_exists.unwrap_or(false)
|
||||
} else { false }
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ThreadType::Project => {
|
||||
if let Some(project_id) = thread.project_id {
|
||||
@@ -379,12 +381,7 @@ pub async fn thread_send_message(
|
||||
.await?;
|
||||
|
||||
let mod_notif = if let Some(project_id) = thread.project_id {
|
||||
let project = database::models::Project::get_id(
|
||||
project_id,
|
||||
&**pool,
|
||||
&redis,
|
||||
)
|
||||
.await?;
|
||||
let project = database::models::Project::get_id(project_id, &**pool, &redis).await?;
|
||||
|
||||
if let Some(project) = project {
|
||||
if project.inner.status != ProjectStatus::Processing && user.role.is_mod() {
|
||||
@@ -393,7 +390,7 @@ pub async fn thread_send_message(
|
||||
&**pool,
|
||||
&redis,
|
||||
)
|
||||
.await?;
|
||||
.await?;
|
||||
|
||||
NotificationBuilder {
|
||||
body: NotificationBody::ModeratorMessage {
|
||||
@@ -403,11 +400,11 @@ pub async fn thread_send_message(
|
||||
report_id: None,
|
||||
},
|
||||
}
|
||||
.insert_many(
|
||||
members.into_iter().map(|x| x.user_id).collect(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
.insert_many(
|
||||
members.into_iter().map(|x| x.user_id).collect(),
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
project.inner.status == ProjectStatus::Processing && !user.role.is_mod()
|
||||
@@ -415,11 +412,7 @@ pub async fn thread_send_message(
|
||||
!user.role.is_mod()
|
||||
}
|
||||
} else if let Some(report_id) = thread.report_id {
|
||||
let report = database::models::report_item::Report::get(
|
||||
report_id,
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
let report = database::models::report_item::Report::get(report_id, &**pool).await?;
|
||||
|
||||
if let Some(report) = report {
|
||||
if report.closed && !user.role.is_mod() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::auth::flows::AuthProvider;
|
||||
use crate::auth::{get_user_from_headers, AuthenticationError};
|
||||
use crate::database::models::User;
|
||||
use crate::file_hosting::FileHost;
|
||||
@@ -193,6 +194,7 @@ 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)]
|
||||
@@ -412,7 +414,7 @@ pub async fn user_edit(
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(pass) = actual_user.password {
|
||||
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!"
|
||||
@@ -421,7 +423,7 @@ pub async fn user_edit(
|
||||
})?;
|
||||
|
||||
let hasher = Argon2::default();
|
||||
hasher.verify_password(old_password.as_bytes(), &PasswordHash::new(&pass)?)?;
|
||||
hasher.verify_password(old_password.as_bytes(), &PasswordHash::new(pass)?)?;
|
||||
}
|
||||
|
||||
let update_password = if let Some(new_password) = new_password {
|
||||
@@ -483,6 +485,116 @@ pub async fn user_edit(
|
||||
.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(""))
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::auth::{
|
||||
};
|
||||
use crate::database;
|
||||
use crate::models;
|
||||
use crate::models::ids::base62_impl::parse_base62;
|
||||
use crate::models::pats::Scopes;
|
||||
use crate::models::projects::{Dependency, FileType, VersionStatus, VersionType};
|
||||
use crate::models::teams::Permissions;
|
||||
@@ -165,8 +166,8 @@ pub async fn version_project_get(
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let id = info.into_inner();
|
||||
let version_data =
|
||||
database::models::Version::get_full_from_id_slug(&id.0, &id.1, &**pool, &redis).await?;
|
||||
|
||||
let result = database::models::Project::get(&id.0, &**pool, &redis).await?;
|
||||
|
||||
let user_option = get_user_from_headers(
|
||||
&req,
|
||||
@@ -179,9 +180,23 @@ pub async fn version_project_get(
|
||||
.map(|x| x.1)
|
||||
.ok();
|
||||
|
||||
if let Some(data) = version_data {
|
||||
if is_authorized_version(&data.inner, &user_option, &pool).await? {
|
||||
return Ok(HttpResponse::Ok().json(models::projects::Version::from(data)));
|
||||
if let Some(project) = result {
|
||||
if !is_authorized(&project.inner, &user_option, &pool).await? {
|
||||
return Ok(HttpResponse::NotFound().body(""));
|
||||
}
|
||||
|
||||
let versions =
|
||||
database::models::Version::get_many(&project.versions, &**pool, &redis).await?;
|
||||
|
||||
let id_opt = parse_base62(&id.1).ok();
|
||||
let version = versions
|
||||
.into_iter()
|
||||
.find(|x| Some(x.inner.id.0 as u64) == id_opt || x.inner.version_number == id.1);
|
||||
|
||||
if let Some(version) = version {
|
||||
if is_authorized_version(&version.inner, &user_option, &pool).await? {
|
||||
return Ok(HttpResponse::Ok().json(models::projects::Version::from(version)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user