From cd514285d99048c50cca548cd2fbc2b0d685f582 Mon Sep 17 00:00:00 2001 From: Geometrically <18202329+Geometrically@users.noreply.github.com> Date: Sat, 18 Jun 2022 14:09:37 -0700 Subject: [PATCH] Fix rejected files showing in hash routes (#375) * Fix rejected files showing in hash routes * Run prepare and formatter * Add modrinth.com exception for callback URLs * run fmt --- .env | 2 +- Cargo.lock | 2 +- Cargo.toml | 2 +- sqlx-data.json | 292 ++++++++++++----------- src/database/models/notification_item.rs | 46 ++-- src/routes/auth.rs | 17 +- src/routes/version_file.rs | 47 +++- src/util/auth.rs | 2 +- 8 files changed, 233 insertions(+), 177 deletions(-) diff --git a/.env b/.env index fe98ea8b..e2189242 100644 --- a/.env +++ b/.env @@ -42,4 +42,4 @@ RATE_LIMIT_IGNORE_IPS='["127.0.0.1"]' WHITELISTED_MODPACK_DOMAINS='["cdn.modrinth.com", "edge.forgecdn.net", "github.com", "raw.githubusercontent.com"]' -ALLOWED_CALLBACK_URLS='["localhost", ".modrinth.com", "modrinth.com", "-modrinth.vercel.app"]' \ No newline at end of file +ALLOWED_CALLBACK_URLS='["localhost", ".modrinth.com", "-modrinth.vercel.app"]' \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 454fb590..ebc52676 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1441,7 +1441,7 @@ dependencies = [ [[package]] name = "labrinth" -version = "2.4.2" +version = "2.4.3" dependencies = [ "actix", "actix-cors", diff --git a/Cargo.toml b/Cargo.toml index 0df71d34..ce6fc14a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "labrinth" -version = "2.4.2" +version = "2.4.3" #Team members, please add your emails and usernames authors = ["geometrically ", "Redblueflame ", "Aeledfyr ", "Charalampos Fanoulis ", "AppleTheGolden "] edition = "2018" diff --git a/sqlx-data.json b/sqlx-data.json index fc006d2d..23501b76 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -1,44 +1,5 @@ { "db": "PostgreSQL", - "002a7e9d3ccfb94348b1e7ad93b923aab9d2c377e41bc2cc22e3a94d799d44de": { - "query": "\n SELECT f.url url, f.id id, f.version_id version_id, v.mod_id project_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id\n WHERE h.algorithm = $2 AND h.hash = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "url", - "type_info": "Varchar" - }, - { - "ordinal": 1, - "name": "id", - "type_info": "Int8" - }, - { - "ordinal": 2, - "name": "version_id", - "type_info": "Int8" - }, - { - "ordinal": 3, - "name": "project_id", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Bytea", - "Text" - ] - }, - "nullable": [ - false, - false, - false, - false - ] - } - }, "017c9fd0c8103c590489453a25b3317e6790a21f388bcf7ec8c93cd26255f368": { "query": "\n SELECT id, team_id, role, permissions, accepted\n FROM team_members\n WHERE (user_id = $1 AND accepted = TRUE)\n ", "describe": { @@ -198,32 +159,20 @@ "nullable": [] } }, - "0a1a470c12b84c7e171f0f51e8e541e9abe8bbee17fc441a5054e1dfd5607c05": { - "query": "\n UPDATE versions\n SET name = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - } - }, - "0a1e0cbcdfe68e111326e2dc070e7903d4abb92180c7957f2408b4d6f810c2e5": { - "query": "\n SELECT v.mod_id project_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id\n WHERE h.algorithm = $2 AND h.hash = $1\n ", + "091f325c84d0cf6dfe6933567c58fea815912ba613ffb3536466770d71ea613e": { + "query": "\n SELECT f.version_id version_id\n FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v on f.version_id = v.id\n INNER JOIN mods m on v.mod_id = m.id\n INNER JOIN statuses s on m.status = s.id\n WHERE h.algorithm = $2 AND h.hash = $1 AND s.status != $3\n ", "describe": { "columns": [ { "ordinal": 0, - "name": "project_id", + "name": "version_id", "type_info": "Int8" } ], "parameters": { "Left": [ "Bytea", + "Text", "Text" ] }, @@ -232,6 +181,19 @@ ] } }, + "0a1a470c12b84c7e171f0f51e8e541e9abe8bbee17fc441a5054e1dfd5607c05": { + "query": "\n UPDATE versions\n SET name = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + } + }, "0ca11a32b2860e4f5c3d20892a5be3cb419e084f42ba0f98e09b9995027fcc4e": { "query": "\n SELECT id FROM statuses\n WHERE status = $1\n ", "describe": { @@ -760,6 +722,46 @@ "nullable": [] } }, + "292da3eec2cc7d7eb635fa123be1b1387e9e91466f007e10101053fdb9874e3f": { + "query": "\n SELECT f.url url, f.id id, f.version_id version_id, v.mod_id project_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id\n INNER JOIN mods m on v.mod_id = m.id\n INNER JOIN statuses s on m.status = s.id\n WHERE h.algorithm = $2 AND h.hash = $1 AND s.status != $3\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "url", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "version_id", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "project_id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false + ] + } + }, "29e657d26f0fb24a766f5b5eb6a94d01d1616884d8ca10e91536e974d5b585a6": { "query": "\n INSERT INTO loaders_versions (loader_id, version_id)\n VALUES ($1, $2)\n ", "describe": { @@ -1051,6 +1053,40 @@ "nullable": [] } }, + "3b1fba1ce47e94c0301c8a234bc7609e3c62fc02acd1485283c0f824cff2d69b": { + "query": "\n SELECT h.hash hash, h.algorithm algorithm, f.version_id version_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id\n INNER JOIN mods m on v.mod_id = m.id\n INNER JOIN statuses s on m.status = s.id\n WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[]) AND s.status != $3\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "algorithm", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "version_id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "ByteaArray", + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false + ] + } + }, "3bdcbfa5abe43cc9b4f996f147277a7f6921cca00f82cad0ef5d85032c761a36": { "query": "\n DELETE FROM mod_follows\n WHERE follower_id = $1 AND mod_id = $2\n ", "describe": { @@ -1438,51 +1474,6 @@ "nullable": [] } }, - "4ed40527a52e96490066653f3838c763180835a14c6f8dc6a5e54667d9d7ffef": { - "query": "\n SELECT f.url url, h.hash hash, h.algorithm algorithm, f.version_id version_id, v.mod_id project_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id\n WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[])\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "url", - "type_info": "Varchar" - }, - { - "ordinal": 1, - "name": "hash", - "type_info": "Bytea" - }, - { - "ordinal": 2, - "name": "algorithm", - "type_info": "Varchar" - }, - { - "ordinal": 3, - "name": "version_id", - "type_info": "Int8" - }, - { - "ordinal": 4, - "name": "project_id", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "ByteaArray", - "Text" - ] - }, - "nullable": [ - false, - false, - false, - false, - false - ] - } - }, "4f307a8851b0cab7870798ba017955c8ebaba7444791dd65ffebcbac32d3585d": { "query": "\n INSERT INTO states (id, url)\n VALUES ($1, $2)\n ", "describe": { @@ -2699,6 +2690,28 @@ "nullable": [] } }, + "740424ba1af7b0cf85d6031365d2c026e0b0003fb618bb82eeebcdad9599774a": { + "query": "\n SELECT v.mod_id project_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id\n INNER JOIN mods m on v.mod_id = m.id\n INNER JOIN statuses s on m.status = s.id\n WHERE h.algorithm = $2 AND h.hash = $1 AND s.status != $3\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "project_id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea", + "Text", + "Text" + ] + }, + "nullable": [ + false + ] + } + }, "75a860ca8087536a9fcf932846341c8bd322d314231bb8acac124d1cea93270b": { "query": "\n SELECT mf.mod_id FROM mod_follows mf\n WHERE mf.follower_id = $1\n ", "describe": { @@ -3672,6 +3685,52 @@ "nullable": [] } }, + "9b231e09e8a1e56cca49bf82f9a605e3d13b9e6a1cfc6357b5f544d3d9a89dfd": { + "query": "\n SELECT f.url url, h.hash hash, h.algorithm algorithm, f.version_id version_id, v.mod_id project_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id\n INNER JOIN mods m on v.mod_id = m.id\n INNER JOIN statuses s on m.status = s.id\n WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[]) AND s.status != $3\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "url", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "hash", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "algorithm", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "version_id", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "project_id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "ByteaArray", + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false + ] + } + }, "9ceca63fb11f35f09f77bb9db175a1ac74dfcc2200c8134866922742fbbedea3": { "query": "\n UPDATE dependencies\n SET dependency_id = $2\n WHERE dependency_id = $1\n ", "describe": { @@ -6001,39 +6060,6 @@ "nullable": [] } }, - "f30bff55ee84fb390c6c240d5a46826f8e2481b701d956f38b484f140f23e2dc": { - "query": "\n SELECT h.hash hash, h.algorithm algorithm, f.version_id version_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[])\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "hash", - "type_info": "Bytea" - }, - { - "ordinal": 1, - "name": "algorithm", - "type_info": "Varchar" - }, - { - "ordinal": 2, - "name": "version_id", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "ByteaArray", - "Text" - ] - }, - "nullable": [ - false, - false, - false - ] - } - }, "f3a8ad4a802dde0eb9304078e0368066e7d48121dfe73a63b2911b0998840a79": { "query": "\n SELECT id FROM users\n WHERE LOWER(username) = LOWER($1)\n ", "describe": { diff --git a/src/database/models/notification_item.rs b/src/database/models/notification_item.rs index bdef52f7..b0b77b19 100644 --- a/src/database/models/notification_item.rs +++ b/src/database/models/notification_item.rs @@ -118,8 +118,8 @@ impl Notification { id: NotificationId, executor: E, ) -> Result, sqlx::error::Error> - where - E: sqlx::Executor<'a, Database = sqlx::Postgres>, + where + E: sqlx::Executor<'a, Database = sqlx::Postgres>, { let result = sqlx::query!( " @@ -138,19 +138,24 @@ impl Notification { if let Some(row) = result { let mut actions: Vec = Vec::new(); - row.actions.unwrap_or_default().split(" ~~~~ ").for_each(|x| { - let action: Vec<&str> = x.split(" |||| ").collect(); - - if action.len() >= 3 { - actions.push(NotificationAction { - id: NotificationActionId(action[0].parse().unwrap_or(0)), - notification_id: id, - title: action[1].to_string(), - action_route_method: action[3].to_string(), - action_route: action[2].to_string(), - }); - } - }); + row.actions + .unwrap_or_default() + .split(" ~~~~ ") + .for_each(|x| { + let action: Vec<&str> = x.split(" |||| ").collect(); + + if action.len() >= 3 { + actions.push(NotificationAction { + id: NotificationActionId( + action[0].parse().unwrap_or(0), + ), + notification_id: id, + title: action[1].to_string(), + action_route_method: action[3].to_string(), + action_route: action[2].to_string(), + }); + } + }); Ok(Some(Notification { id, @@ -172,12 +177,13 @@ impl Notification { notification_ids: Vec, exec: E, ) -> Result, sqlx::Error> - where - E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy, + where + E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy, { use futures::stream::TryStreamExt; - let notification_ids_parsed: Vec = notification_ids.into_iter().map(|x| x.0).collect(); + let notification_ids_parsed: Vec = + notification_ids.into_iter().map(|x| x.0).collect(); sqlx::query!( " SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type, @@ -231,8 +237,8 @@ impl Notification { user_id: UserId, exec: E, ) -> Result, sqlx::Error> - where - E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy, + where + E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy, { use futures::stream::TryStreamExt; diff --git a/src/routes/auth.rs b/src/routes/auth.rs index 97a95565..5d5c9a03 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -1,4 +1,4 @@ - /*! +/*! This auth module is primarily for use within the main website. Applications interacting with the authenticated API (a very small portion - notifications, private projects, editing/creating projects and versions) should either retrieve the Modrinth GitHub token through the site, or create a personal @@ -16,6 +16,7 @@ use crate::models::error::ApiError; use crate::models::ids::base62_impl::{parse_base62, to_base62}; use crate::models::ids::DecodingError; use crate::models::users::Role; +use crate::parse_strings_from_var; use crate::util::auth::get_github_user_from_token; use actix_web::http::StatusCode; use actix_web::web::{scope, Data, Query, ServiceConfig}; @@ -24,7 +25,6 @@ use serde::{Deserialize, Serialize}; use sqlx::postgres::PgPool; use thiserror::Error; use time::OffsetDateTime; -use crate::parse_strings_from_var; pub fn config(cfg: &mut ServiceConfig) { cfg.service(scope("auth").service(auth_callback).service(init)); @@ -82,7 +82,7 @@ impl actix_web::ResponseError for AuthorizationError { AuthorizationError::Decoding(..) => "decoding_error", AuthorizationError::Authentication(..) => { "authentication_error" - }, + } AuthorizationError::Url => "url_error", }, description: &self.to_string(), @@ -114,13 +114,16 @@ pub async fn init( Query(info): Query, client: Data, ) -> Result { - let url = url::Url::parse(&info.url).map_err(|_| AuthorizationError::Url)?; + let url = + url::Url::parse(&info.url).map_err(|_| AuthorizationError::Url)?; - let allowed_callback_urls = parse_strings_from_var("ALLOWED_CALLBACK_URLS") - .unwrap_or_default(); + let allowed_callback_urls = + parse_strings_from_var("ALLOWED_CALLBACK_URLS").unwrap_or_default(); let domain = url.domain().ok_or(AuthorizationError::Url)?; - if !allowed_callback_urls.iter().any(|x| domain.ends_with(x)) { + if !allowed_callback_urls.iter().any(|x| domain.ends_with(x)) + || domain == "modrinth.com" + { return Err(AuthorizationError::Url); } diff --git a/src/routes/version_file.rs b/src/routes/version_file.rs index 7a695b65..45bf7c63 100644 --- a/src/routes/version_file.rs +++ b/src/routes/version_file.rs @@ -34,12 +34,17 @@ pub async fn get_version_from_hash( let result = sqlx::query!( " - SELECT f.version_id version_id FROM hashes h + SELECT f.version_id version_id + FROM hashes h INNER JOIN files f ON h.file_id = f.id - WHERE h.algorithm = $2 AND h.hash = $1 + INNER JOIN versions v on f.version_id = v.id + INNER JOIN mods m on v.mod_id = m.id + INNER JOIN statuses s on m.status = s.id + WHERE h.algorithm = $2 AND h.hash = $1 AND s.status != $3 ", hash.as_bytes(), - algorithm.algorithm + algorithm.algorithm, + models::projects::ProjectStatus::Rejected.to_string() ) .fetch_optional(&**pool) .await?; @@ -81,10 +86,13 @@ pub async fn download_version( SELECT f.url url, f.id id, f.version_id version_id, v.mod_id project_id FROM hashes h INNER JOIN files f ON h.file_id = f.id INNER JOIN versions v ON v.id = f.version_id - WHERE h.algorithm = $2 AND h.hash = $1 + INNER JOIN mods m on v.mod_id = m.id + INNER JOIN statuses s on m.status = s.id + WHERE h.algorithm = $2 AND h.hash = $1 AND s.status != $3 ", hash.as_bytes(), - algorithm.algorithm + algorithm.algorithm, + models::projects::ProjectStatus::Rejected.to_string() ) .fetch_optional(&mut *transaction) .await?; @@ -242,10 +250,13 @@ pub async fn get_update_from_hash( SELECT v.mod_id project_id FROM hashes h INNER JOIN files f ON h.file_id = f.id INNER JOIN versions v ON v.id = f.version_id - WHERE h.algorithm = $2 AND h.hash = $1 + INNER JOIN mods m on v.mod_id = m.id + INNER JOIN statuses s on m.status = s.id + WHERE h.algorithm = $2 AND h.hash = $1 AND s.status != $3 ", hash.as_bytes(), - algorithm.algorithm + algorithm.algorithm, + models::projects::ProjectStatus::Rejected.to_string() ) .fetch_optional(&**pool) .await?; @@ -310,10 +321,14 @@ pub async fn get_versions_from_hashes( " SELECT h.hash hash, h.algorithm algorithm, f.version_id version_id FROM hashes h INNER JOIN files f ON h.file_id = f.id - WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[]) + INNER JOIN versions v ON v.id = f.version_id + INNER JOIN mods m on v.mod_id = m.id + INNER JOIN statuses s on m.status = s.id + WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[]) AND s.status != $3 ", hashes_parsed.as_slice(), - file_data.algorithm + file_data.algorithm, + models::projects::ProjectStatus::Rejected.to_string() ) .fetch_all(&**pool) .await?; @@ -370,10 +385,13 @@ pub async fn download_files( SELECT f.url url, h.hash hash, h.algorithm algorithm, f.version_id version_id, v.mod_id project_id FROM hashes h INNER JOIN files f ON h.file_id = f.id INNER JOIN versions v ON v.id = f.version_id - WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[]) + INNER JOIN mods m on v.mod_id = m.id + INNER JOIN statuses s on m.status = s.id + WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[]) AND s.status != $3 ", hashes_parsed.as_slice(), - file_data.algorithm + file_data.algorithm, + models::projects::ProjectStatus::Rejected.to_string() ) .fetch_all(&mut *transaction) .await?; @@ -421,10 +439,13 @@ pub async fn update_files( SELECT f.url url, h.hash hash, h.algorithm algorithm, f.version_id version_id, v.mod_id project_id FROM hashes h INNER JOIN files f ON h.file_id = f.id INNER JOIN versions v ON v.id = f.version_id - WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[]) + INNER JOIN mods m on v.mod_id = m.id + INNER JOIN statuses s on m.status = s.id + WHERE h.algorithm = $2 AND h.hash = ANY($1::bytea[]) AND s.status != $3 ", hashes_parsed.as_slice(), - update_data.algorithm + update_data.algorithm, + models::projects::ProjectStatus::Rejected.to_string() ) .fetch_all(&mut *transaction) .await?; diff --git a/src/util/auth.rs b/src/util/auth.rs index 40b93ec2..aa675240 100644 --- a/src/util/auth.rs +++ b/src/util/auth.rs @@ -14,7 +14,7 @@ pub enum AuthenticationError { #[error("An unknown database error occurred")] Sqlx(#[from] sqlx::Error), #[error("Database Error: {0}")] - Database(#[from] crate::database::models::DatabaseError), + Database(#[from] models::DatabaseError), #[error("Error while parsing JSON: {0}")] SerDe(#[from] serde_json::Error), #[error("Error while communicating to GitHub OAuth2: {0}")]