diff --git a/src/database/redis.rs b/src/database/redis.rs index e63a37bc..aa221521 100644 --- a/src/database/redis.rs +++ b/src/database/redis.rs @@ -217,7 +217,7 @@ impl RedisPool { let mut cached_values = cached_values_raw .into_iter() .filter_map(|(key, val)| { - if Utc.timestamp(val.iat + ACTUAL_EXPIRY, 0) < current_time { + if Utc.timestamp_opt(val.iat + ACTUAL_EXPIRY, 0).unwrap() < current_time { expired_values.insert(val.key.to_string(), val); None diff --git a/src/validate/fabric.rs b/src/validate/fabric.rs index 5e22bad3..11b9e499 100644 --- a/src/validate/fabric.rs +++ b/src/validate/fabric.rs @@ -1,5 +1,4 @@ -use crate::validate::{SupportedGameVersions, ValidationError, ValidationResult}; -use chrono::{DateTime, NaiveDateTime, Utc}; +use crate::validate::{filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult}; use std::io::Cursor; use zip::ZipArchive; @@ -7,7 +6,7 @@ pub struct FabricValidator; impl super::Validator for FabricValidator { fn get_file_extensions(&self) -> &[&str] { - &["jar", "zip"] + &["jar"] } fn get_supported_loaders(&self) -> &[&str] { @@ -15,11 +14,7 @@ impl super::Validator for FabricValidator { } fn get_supported_game_versions(&self) -> SupportedGameVersions { - // Time since release of 18w49a, the first fabric version - SupportedGameVersions::PastDate(DateTime::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(1543969469, 0).unwrap(), - Utc, - )) + SupportedGameVersions::All } fn validate( @@ -32,6 +27,8 @@ impl super::Validator for FabricValidator { )); } + filter_out_packs(archive)?; + Ok(ValidationResult::Pass) } } diff --git a/src/validate/forge.rs b/src/validate/forge.rs index 77b42b81..3f6ba480 100644 --- a/src/validate/forge.rs +++ b/src/validate/forge.rs @@ -1,4 +1,4 @@ -use crate::validate::{SupportedGameVersions, ValidationError, ValidationResult}; +use crate::validate::{filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult}; use chrono::{DateTime, NaiveDateTime, Utc}; use std::io::Cursor; use zip::ZipArchive; @@ -24,13 +24,17 @@ impl super::Validator for ForgeValidator { fn validate( &self, - _archive: &mut ZipArchive>, + archive: &mut ZipArchive>, ) -> Result { - // if archive.by_name("META-INF/mods.toml").is_err() { - // return Ok(ValidationResult::Warning( - // "No mods.toml present for Forge file.", - // )); - // } + if archive.by_name("META-INF/mods.toml").is_err() + && !archive.file_names().any(|x| x.ends_with(".class")) + { + return Ok(ValidationResult::Warning( + "No mods.toml or valid class files present for Forge file.", + )); + } + + filter_out_packs(archive)?; Ok(ValidationResult::Pass) } @@ -51,11 +55,11 @@ impl super::Validator for LegacyForgeValidator { // Times between versions 1.5.2 to 1.12.2, which all use the legacy way of defining mods SupportedGameVersions::Range( DateTime::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(1366818300, 0).unwrap(), + NaiveDateTime::from_timestamp_opt(0, 0).unwrap(), Utc, ), DateTime::from_naive_utc_and_offset( - NaiveDateTime::from_timestamp_opt(1505810340, 0).unwrap(), + NaiveDateTime::from_timestamp_opt(1540122066, 0).unwrap(), Utc, ), ) @@ -63,13 +67,17 @@ impl super::Validator for LegacyForgeValidator { fn validate( &self, - _archive: &mut ZipArchive>, + archive: &mut ZipArchive>, ) -> Result { - // if archive.by_name("mcmod.info").is_err() { - // return Ok(ValidationResult::Warning( - // "Forge mod file does not contain mcmod.info!", - // )); - // }; + if archive.by_name("mcmod.info").is_err() + && !archive.file_names().any(|x| x.ends_with(".class")) + { + return Ok(ValidationResult::Warning( + "Forge mod file does not contain mcmod.info or valid class files!", + )); + }; + + filter_out_packs(archive)?; Ok(ValidationResult::Pass) } diff --git a/src/validate/liteloader.rs b/src/validate/liteloader.rs index af88c027..7056d015 100644 --- a/src/validate/liteloader.rs +++ b/src/validate/liteloader.rs @@ -1,4 +1,4 @@ -use crate::validate::{SupportedGameVersions, ValidationError, ValidationResult}; +use crate::validate::{filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult}; use std::io::Cursor; use zip::ZipArchive; @@ -27,6 +27,8 @@ impl super::Validator for LiteLoaderValidator { )); } + filter_out_packs(archive)?; + Ok(ValidationResult::Pass) } } diff --git a/src/validate/mod.rs b/src/validate/mod.rs index 148d80b8..5f5c605f 100644 --- a/src/validate/mod.rs +++ b/src/validate/mod.rs @@ -9,9 +9,11 @@ use crate::validate::fabric::FabricValidator; use crate::validate::forge::{ForgeValidator, LegacyForgeValidator}; use crate::validate::liteloader::LiteLoaderValidator; use crate::validate::modpack::ModpackValidator; +use crate::validate::neoforge::NeoForgeValidator; use crate::validate::plugin::*; use crate::validate::quilt::QuiltValidator; use crate::validate::resourcepack::{PackValidator, TexturePackValidator}; +use crate::validate::rift::RiftValidator; use crate::validate::shader::{CanvasShaderValidator, CoreShaderValidator, ShaderValidator}; use chrono::{DateTime, Utc}; use std::io::Cursor; @@ -23,9 +25,11 @@ mod fabric; mod forge; mod liteloader; mod modpack; +mod neoforge; pub mod plugin; mod quilt; mod resourcepack; +mod rift; mod shader; #[derive(Error, Debug)] @@ -104,6 +108,8 @@ static VALIDATORS: &[&dyn Validator] = &[ &ShaderValidator, &CoreShaderValidator, &DataPackValidator, + &RiftValidator, + &NeoForgeValidator, ]; /// The return value is whether this file should be marked as primary or not, based on the analysis of the file @@ -239,3 +245,22 @@ fn game_version_supported( } } } + +pub fn filter_out_packs( + archive: &mut ZipArchive>, +) -> Result { + if (archive.by_name("modlist.html").is_ok() && archive.by_name("manifest.json").is_ok()) + || archive + .file_names() + .any(|x| x.starts_with("mods/") && x.ends_with(".jar")) + || archive + .file_names() + .any(|x| x.starts_with("override/mods/") && x.ends_with(".jar")) + { + return Ok(ValidationResult::Warning( + "Invalid modpack file. You must upload a valid .MRPACK file.", + )); + } + + Ok(ValidationResult::Pass) +} diff --git a/src/validate/modpack.rs b/src/validate/modpack.rs index cb6a7f87..43711996 100644 --- a/src/validate/modpack.rs +++ b/src/validate/modpack.rs @@ -48,6 +48,10 @@ impl super::Validator for ModpackValidator { )); } + if pack.files.is_empty() && !archive.file_names().any(|x| x.starts_with("overrides/")) { + return Err(ValidationError::InvalidInput("Pack has no files!".into())); + } + for file in &pack.files { if !file.hashes.contains_key(&PackFileHash::Sha1) { return Err(ValidationError::InvalidInput( diff --git a/src/validate/neoforge.rs b/src/validate/neoforge.rs new file mode 100644 index 00000000..8e20778e --- /dev/null +++ b/src/validate/neoforge.rs @@ -0,0 +1,37 @@ +use crate::validate::{filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult}; +use std::io::Cursor; +use zip::ZipArchive; + +pub struct NeoForgeValidator; + +impl super::Validator for NeoForgeValidator { + fn get_file_extensions(&self) -> &[&str] { + &["jar", "zip"] + } + + fn get_supported_loaders(&self) -> &[&str] { + &["forge"] + } + + fn get_supported_game_versions(&self) -> SupportedGameVersions { + SupportedGameVersions::All + } + + fn validate( + &self, + archive: &mut ZipArchive>, + ) -> Result { + if archive.by_name("META-INF/mods.toml").is_err() + && archive.by_name("META-INF/neoforge.mods.toml").is_err() + && !archive.file_names().any(|x| x.ends_with(".class")) + { + return Ok(ValidationResult::Warning( + "No neoforge.mods.toml, mods.toml, or valid class files present for NeoForge file.", + )); + } + + filter_out_packs(archive)?; + + Ok(ValidationResult::Pass) + } +} diff --git a/src/validate/plugin.rs b/src/validate/plugin.rs index a2b7e35c..9a8f44e7 100644 --- a/src/validate/plugin.rs +++ b/src/validate/plugin.rs @@ -10,7 +10,7 @@ impl super::Validator for PluginYmlValidator { } fn get_supported_loaders(&self) -> &[&str] { - &["bukkit", "spigot", "paper", "purpur"] + &["bukkit", "spigot", "paper", "purpur", "folia"] } fn get_supported_game_versions(&self) -> SupportedGameVersions { diff --git a/src/validate/quilt.rs b/src/validate/quilt.rs index 8e3e5b0a..0e7af803 100644 --- a/src/validate/quilt.rs +++ b/src/validate/quilt.rs @@ -1,4 +1,4 @@ -use crate::validate::{SupportedGameVersions, ValidationError, ValidationResult}; +use crate::validate::{filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult}; use chrono::{DateTime, NaiveDateTime, Utc}; use std::io::Cursor; use zip::ZipArchive; @@ -32,6 +32,8 @@ impl super::Validator for QuiltValidator { )); } + filter_out_packs(archive)?; + Ok(ValidationResult::Pass) } } diff --git a/src/validate/rift.rs b/src/validate/rift.rs new file mode 100644 index 00000000..b8cc3d58 --- /dev/null +++ b/src/validate/rift.rs @@ -0,0 +1,34 @@ +use crate::validate::{filter_out_packs, SupportedGameVersions, ValidationError, ValidationResult}; +use std::io::Cursor; +use zip::ZipArchive; + +pub struct RiftValidator; + +impl super::Validator for RiftValidator { + fn get_file_extensions(&self) -> &[&str] { + &["jar"] + } + + fn get_supported_loaders(&self) -> &[&str] { + &["rift"] + } + + fn get_supported_game_versions(&self) -> SupportedGameVersions { + SupportedGameVersions::All + } + + fn validate( + &self, + archive: &mut ZipArchive>, + ) -> Result { + if archive.by_name("riftmod.json").is_err() { + return Ok(ValidationResult::Warning( + "No riftmod.json present for Rift file.", + )); + } + + filter_out_packs(archive)?; + + Ok(ValidationResult::Pass) + } +} diff --git a/tests/common/dummy_data.rs b/tests/common/dummy_data.rs index b2cdcb0c..853d08b4 100644 --- a/tests/common/dummy_data.rs +++ b/tests/common/dummy_data.rs @@ -102,6 +102,14 @@ impl TestFile { ) .unwrap(); zip.write_all(fabric_mod_json.as_bytes()).unwrap(); + + zip.start_file( + "META-INF/mods.toml", + FileOptions::default().compression_method(CompressionMethod::Stored), + ) + .unwrap(); + zip.write_all(fabric_mod_json.as_bytes()).unwrap(); + zip.finish().unwrap(); } let bytes = cursor.into_inner(); @@ -117,7 +125,23 @@ impl TestFile { "game": "minecraft", "versionId": "1.20.1-9.6", "name": filename, - "files": [], + "files": [ + { + "path": "mods/animatica-0.6+1.20.jar", + "hashes": { + "sha1": "3bcb19c759f313e69d3f7848b03c48f15167b88d", + "sha512": "7d50f3f34479f8b052bfb9e2482603b4906b8984039777dc2513ecf18e9af2b599c9d094e88cec774f8525345859e721a394c8cd7c14a789c9538d2533c71d65" + }, + "env": { + "client": "required", + "server": "required" + }, + "downloads": [ + "https://cdn.modrinth.com/data/PRN43VSY/versions/uNgEPb10/animatica-0.6%2B1.20.jar" + ], + "fileSize": 69810 + } + ], "dependencies": { "fabric-loader": "0.14.22", "minecraft": "1.20.1"