From a89418e33ba36bc782b8f022be57019a395192af Mon Sep 17 00:00:00 2001 From: Geometrically <18202329+Geometrically@users.noreply.github.com> Date: Thu, 13 Jul 2023 19:50:42 -0700 Subject: [PATCH] First auth fixes (#656) --- src/auth/email/mod.rs | 10 +--- src/auth/flows.rs | 6 +- src/routes/v2/version_file.rs | 108 +++++++++++++++++++++++++++++++++- 3 files changed, 113 insertions(+), 11 deletions(-) diff --git a/src/auth/email/mod.rs b/src/auth/email/mod.rs index d2737f218..b2f057396 100644 --- a/src/auth/email/mod.rs +++ b/src/auth/email/mod.rs @@ -22,21 +22,17 @@ pub fn send_email_raw(to: String, subject: String, body: String) -> Result<(), M Some("Modrinth".to_string()), Address::new("no-reply", "mail.modrinth.com")?, )) - .to(to.parse().unwrap()) + .to(to.parse()?) .subject(subject) .header(ContentType::TEXT_HTML) - .body(body) - .unwrap(); + .body(body)?; let username = dotenvy::var("SMTP_USERNAME")?; let password = dotenvy::var("SMTP_PASSWORD")?; let host = dotenvy::var("SMTP_HOST")?; let creds = Credentials::new(username, password); - let mailer = SmtpTransport::relay(&host) - .unwrap() - .credentials(creds) - .build(); + let mailer = SmtpTransport::relay(&host)?.credentials(creds).build(); mailer.send(&email)?; diff --git a/src/auth/flows.rs b/src/auth/flows.rs index 5ae8ee092..026b24e81 100644 --- a/src/auth/flows.rs +++ b/src/auth/flows.rs @@ -1114,7 +1114,7 @@ pub async fn create_account_with_password( .validate() .map_err(|err| ApiError::InvalidInput(validation_errors_to_string(err, None)))?; - if check_turnstile_captcha(&req, &new_account.challenge).await? { + if !check_turnstile_captcha(&req, &new_account.challenge).await? { return Err(ApiError::Turnstile); } @@ -1221,7 +1221,7 @@ pub async fn login_password( redis: Data, login: web::Json, ) -> Result { - if check_turnstile_captcha(&req, &login.challenge).await? { + if !check_turnstile_captcha(&req, &login.challenge).await? { return Err(ApiError::Turnstile); } @@ -1590,7 +1590,7 @@ pub async fn reset_password_begin( redis: Data, reset_password: web::Json, ) -> Result { - if check_turnstile_captcha(&req, &reset_password.challenge).await? { + if !check_turnstile_captcha(&req, &reset_password.challenge).await? { return Err(ApiError::Turnstile); } diff --git a/src/routes/v2/version_file.rs b/src/routes/v2/version_file.rs index c0953679f..06bde8456 100644 --- a/src/routes/v2/version_file.rs +++ b/src/routes/v2/version_file.rs @@ -27,7 +27,8 @@ pub fn config(cfg: &mut web::ServiceConfig) { cfg.service( web::scope("version_files") .service(get_versions_from_hashes) - .service(update_files), + .service(update_files) + .service(update_individual_files), ); } @@ -518,3 +519,108 @@ pub async fn update_files( Ok(HttpResponse::Ok().json(response)) } + +#[derive(Deserialize)] +pub struct FileUpdateData { + pub hash: String, + pub loaders: Option>, + pub game_versions: Option>, + pub version_types: Option>, +} + +#[derive(Deserialize)] +pub struct ManyFileUpdateData { + pub algorithm: String, + pub hashes: Vec, +} + +#[post("update_individual")] +pub async fn update_individual_files( + req: HttpRequest, + pool: web::Data, + redis: web::Data, + update_data: web::Json, + session_queue: web::Data, +) -> Result { + let user_option = get_user_from_headers( + &req, + &**pool, + &redis, + &session_queue, + Some(&[Scopes::VERSION_READ]), + ) + .await + .map(|x| x.1) + .ok(); + + let files = database::models::Version::get_files_from_hash( + update_data.algorithm.clone(), + &update_data + .hashes + .iter() + .map(|x| x.hash.clone()) + .collect::>(), + &**pool, + &redis, + ) + .await?; + + let projects = database::models::Project::get_many_ids( + &files.iter().map(|x| x.project_id).collect::>(), + &**pool, + &redis, + ) + .await?; + let all_versions = database::models::Version::get_many( + &projects + .iter() + .flat_map(|x| x.versions.clone()) + .collect::>(), + &**pool, + &redis, + ) + .await?; + + let mut response = HashMap::new(); + + for project in projects { + for file in files.iter().filter(|x| x.project_id == project.inner.id) { + if let Some(hash) = file.hashes.get(&update_data.algorithm) { + if let Some(query_file) = update_data.hashes.iter().find(|x| &x.hash == hash) { + let version = all_versions + .iter() + .filter(|x| { + let mut bool = true; + + if let Some(version_types) = &query_file.version_types { + bool &= version_types + .iter() + .any(|y| y.as_str() == x.inner.version_type); + } + if let Some(loaders) = &query_file.loaders { + bool &= x.loaders.iter().any(|y| loaders.contains(y)); + } + if let Some(game_versions) = &query_file.game_versions { + bool &= x.game_versions.iter().any(|y| game_versions.contains(y)); + } + + bool + }) + .sorted_by(|a, b| b.inner.date_published.cmp(&a.inner.date_published)) + .next(); + + if let Some(version) = version { + if is_authorized_version(&version.inner, &user_option, &pool).await? { + response.insert( + hash.clone(), + models::projects::Version::from(version.clone()), + ); + } + } + } + } + } + } + + Ok(HttpResponse::Ok().json(response)) +}