Skip to content

Commit d558b05

Browse files
committed
feat: add configurable max download mb
1 parent 43ea6d3 commit d558b05

File tree

7 files changed

+54
-20
lines changed

7 files changed

+54
-20
lines changed

.env.example

+2
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ DISCORD_WEBHOOK_URL=
1616

1717
# Config
1818

19+
MAX_MOD_FILESIZE_MB=250
20+
1921
# Globally disables download counting, in the event of abuse
2022
DISABLE_DOWNLOAD_COUNTS=0

src/endpoints/mod_versions.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,14 @@ pub async fn create_version(
273273
.filter(|c| c.is_ascii() && *c != '\0')
274274
.collect();
275275

276-
let mut file_path = download_geode_file(&download_link).await?;
277-
let json = ModJson::from_zip(&mut file_path, &download_link, dev.verified).map_err(|err| {
276+
let mut file_path = download_geode_file(&download_link, data.max_download_mb).await?;
277+
let json = ModJson::from_zip(
278+
&mut file_path,
279+
&download_link,
280+
dev.verified,
281+
data.max_download_mb,
282+
)
283+
.map_err(|err| {
278284
log::error!("Failed to parse mod.json: {}", err);
279285
ApiError::FilesystemError
280286
})?;
@@ -366,6 +372,7 @@ pub async fn update_version(
366372
payload.status,
367373
payload.info.clone(),
368374
dev.id,
375+
data.max_download_mb,
369376
&mut transaction,
370377
)
371378
.await

src/endpoints/mods.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ use actix_web::{get, post, put, web, HttpResponse, Responder};
22
use serde::Deserialize;
33
use sqlx::Acquire;
44

5-
use crate::webhook::send_webhook;
65
use crate::extractors::auth::Auth;
76
use crate::types::api::{create_download_link, ApiError, ApiResponse};
87
use crate::types::mod_json::ModJson;
8+
use crate::types::models::developer::Developer;
99
use crate::types::models::incompatibility::Incompatibility;
1010
use crate::types::models::mod_entity::{download_geode_file, Mod, ModUpdate};
1111
use crate::types::models::mod_gd_version::{GDVersionEnum, VerPlatform};
1212
use crate::types::models::mod_version_status::ModVersionStatusEnum;
13-
use crate::types::models::developer::Developer;
13+
use crate::webhook::send_webhook;
1414
use crate::AppData;
1515

1616
#[derive(Deserialize, Default)]
@@ -85,9 +85,8 @@ pub async fn get(
8585
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
8686

8787
let has_extended_permissions = match auth.developer() {
88-
Ok(dev) => dev.admin ||
89-
Developer::has_access_to_mod(dev.id, &id, &mut pool).await?,
90-
_ => false
88+
Ok(dev) => dev.admin || Developer::has_access_to_mod(dev.id, &id, &mut pool).await?,
89+
_ => false,
9190
};
9291

9392
let found = Mod::get_one(&id, false, &mut pool).await?;
@@ -113,8 +112,13 @@ pub async fn create(
113112
) -> Result<impl Responder, ApiError> {
114113
let dev = auth.developer()?;
115114
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
116-
let mut file_path = download_geode_file(&payload.download_link).await?;
117-
let json = ModJson::from_zip(&mut file_path, &payload.download_link, false)?;
115+
let mut file_path = download_geode_file(&payload.download_link, data.max_download_mb).await?;
116+
let json = ModJson::from_zip(
117+
&mut file_path,
118+
&payload.download_link,
119+
false,
120+
data.max_download_mb,
121+
)?;
118122
json.validate()?;
119123
let mut transaction = pool.begin().await.or(Err(ApiError::TransactionError))?;
120124
let result = Mod::from_json(&json, dev.clone(), &mut transaction).await;

src/main.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub struct AppData {
2727
github_client_secret: String,
2828
webhook_url: String,
2929
disable_downloads: bool,
30+
max_download_mb: u32,
3031
}
3132

3233
#[derive(Debug, Parser)]
@@ -66,7 +67,12 @@ async fn main() -> anyhow::Result<()> {
6667
let github_client = dotenvy::var("GITHUB_CLIENT_ID").unwrap_or("".to_string());
6768
let github_secret = dotenvy::var("GITHUB_CLIENT_SECRET").unwrap_or("".to_string());
6869
let webhook_url = dotenvy::var("DISCORD_WEBHOOK_URL").unwrap_or("".to_string());
69-
let disable_downloads = dotenvy::var("DISABLE_DOWNLOAD_COUNTS").unwrap_or("0".to_string()) == "1";
70+
let disable_downloads =
71+
dotenvy::var("DISABLE_DOWNLOAD_COUNTS").unwrap_or("0".to_string()) == "1";
72+
let max_downloadmb = dotenvy::var("MAX_MOD_FILESIZE_MB")
73+
.unwrap_or("250".to_string())
74+
.parse::<u32>()
75+
.unwrap_or(250);
7076

7177
let app_data = AppData {
7278
db: pool.clone(),
@@ -75,6 +81,7 @@ async fn main() -> anyhow::Result<()> {
7581
github_client_secret: github_secret.clone(),
7682
webhook_url: webhook_url.clone(),
7783
disable_downloads,
84+
max_download_mb: max_downloadmb,
7885
};
7986

8087
let args = Args::parse();

src/types/mod_json.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,11 @@ impl ModJson {
9393
file: &mut Cursor<Bytes>,
9494
download_url: &str,
9595
store_image: bool,
96+
max_size_mb: u32
9697
) -> Result<ModJson, ApiError> {
98+
let max_size_bytes = max_size_mb * 1_000_000;
9799
let mut bytes: Vec<u8> = vec![];
98-
let mut take = file.take(100_000_000);
100+
let mut take = file.take(max_size_bytes as u64);
99101
match take.read_to_end(&mut bytes) {
100102
Err(e) => {
101103
log::error!("Failed to read bytes from {}: {}", download_url, e);

src/types/models/mod_entity.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1436,9 +1436,10 @@ impl Mod {
14361436
id: &str,
14371437
hash: &str,
14381438
download_link: &str,
1439+
limit_mb: u32,
14391440
pool: &mut PgConnection,
14401441
) -> Result<(), ApiError> {
1441-
let mut cursor = download_geode_file(download_link).await?;
1442+
let mut cursor = download_geode_file(download_link, limit_mb).await?;
14421443
let mut bytes: Vec<u8> = vec![];
14431444
match cursor.read_to_end(&mut bytes) {
14441445
Err(e) => {
@@ -1501,11 +1502,12 @@ impl Mod {
15011502
}
15021503
}
15031504

1504-
pub async fn download_geode_file(url: &str) -> Result<Cursor<Bytes>, ApiError> {
1505+
pub async fn download_geode_file(url: &str, limit_mb: u32) -> Result<Cursor<Bytes>, ApiError> {
1506+
let limit_bytes = limit_mb * 1_000_000;
15051507
let size = get_download_size(url).await?;
1506-
if size > 100_000_000 {
1508+
if size > limit_bytes as u64 {
15071509
return Err(ApiError::BadRequest(
1508-
"File size is too large, max 100MB".to_string(),
1510+
format!("File size is too large, max {}MB", limit_mb)
15091511
));
15101512
}
15111513
let res = reqwest::get(url)

src/types/models/mod_version.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -680,10 +680,12 @@ impl ModVersion {
680680
let json_tags = json.tags.clone().unwrap_or_default();
681681
let tags = Tag::get_tag_ids(json_tags, pool).await?;
682682
Tag::update_mod_tags(&json.id, tags.into_iter().map(|x| x.id).collect(), pool).await?;
683-
ModGDVersion::clear_for_mod_version(version_id, pool).await.map_err(|err| {
684-
log::error!("{}", err);
685-
ApiError::DbError
686-
})?;
683+
ModGDVersion::clear_for_mod_version(version_id, pool)
684+
.await
685+
.map_err(|err| {
686+
log::error!("{}", err);
687+
ApiError::DbError
688+
})?;
687689
ModGDVersion::create_from_json(json.gd.to_create_payload(json), version_id, pool).await?;
688690
Dependency::clear_for_mod_version(version_id, pool).await?;
689691
Incompatibility::clear_for_mod_version(version_id, pool).await?;
@@ -822,6 +824,7 @@ impl ModVersion {
822824
new_status: ModVersionStatusEnum,
823825
info: Option<String>,
824826
admin_id: i32,
827+
limit_geode_mb: u32,
825828
pool: &mut PgConnection,
826829
) -> Result<(), ApiError> {
827830
struct CurrentStatusRes {
@@ -913,7 +916,14 @@ impl ModVersion {
913916
}
914917
Ok(r) => r,
915918
};
916-
Mod::update_mod_image(&info.mod_id, &info.hash, &info.download_link, pool).await?;
919+
Mod::update_mod_image(
920+
&info.mod_id,
921+
&info.hash,
922+
&info.download_link,
923+
limit_geode_mb,
924+
pool,
925+
)
926+
.await?;
917927
}
918928

919929
if new_status == ModVersionStatusEnum::Accepted {

0 commit comments

Comments
 (0)