diff --git a/Cargo.lock b/Cargo.lock index 03bcd55..9f04a82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -586,7 +586,7 @@ dependencies = [ [[package]] name = "coa-core" -version = "0.8.0" +version = "0.8.1" dependencies = [ "base64 0.22.1", "chrono", @@ -634,7 +634,7 @@ dependencies = [ [[package]] name = "coa-release" -version = "0.8.0" +version = "0.8.1" dependencies = [ "chrono", "coa-core", @@ -643,7 +643,7 @@ dependencies = [ [[package]] name = "coa-server-manager" -version = "0.8.0" +version = "0.8.1" dependencies = [ "coa-control-proto", "coa-core", diff --git a/Cargo.toml b/Cargo.toml index ea6cc93..14c1de1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = ["crates/coa-core", "crates/coa-release", "crates/coa-registry-proto", exclude = ["services/coa-registry", "services/coa-registry-e2e", "services/coa-coordinator", "services/coa-relay"] [workspace.package] -version = "0.8.0" +version = "0.8.1" edition = "2021" license = "AGPL-3.0-only" diff --git a/changelog.d/20261025-custom-races-191.md b/changelog.d/20261025-custom-races-191.md new file mode 100644 index 0000000..b299466 --- /dev/null +++ b/changelog.d/20261025-custom-races-191.md @@ -0,0 +1,7 @@ +--- +area: client +type: changed +audience: players +title: Install the matching CoA Custom 1.9.1 client files +--- +The races installer verifies and installs all five client archives, including the new races and appearance corrections. diff --git a/crates/coa-core/src/custom_races.rs b/crates/coa-core/src/custom_races.rs index a7dd5a0..a96e5cb 100644 --- a/crates/coa-core/src/custom_races.rs +++ b/crates/coa-core/src/custom_races.rs @@ -14,12 +14,14 @@ use crate::download::Cancel; use crate::error::{Error, Result}; use crate::fsx; -pub const CLIENT_VERSION: &str = "1.8.3"; +pub const CLIENT_VERSION: &str = "1.9.1"; pub const MANIFEST_FILENAME: &str = "custom_races_patch_manifest.txt"; pub const ARCHIVES: &[(&str, &str)] = &[ - ("CoA-Custom-1.8.3-Client-1.zip", "https://github.com/ilusixn/azerothcore-wotlk-coa/releases/download/coa-custom-1.8.3/CoA-Custom-1.8.3-Client-1.zip"), - ("CoA-Custom-1.8.3-Client-2.zip", "https://github.com/ilusixn/azerothcore-wotlk-coa/releases/download/coa-custom-1.8.3/CoA-Custom-1.8.3-Client-2.zip"), - ("CoA-Custom-1.8.3-Client-3.zip", "https://github.com/ilusixn/azerothcore-wotlk-coa/releases/download/coa-custom-1.8.3/CoA-Custom-1.8.3-Client-3.zip"), + ("CoA-Custom-1.9.1-Client-1.zip", "https://github.com/ilusixn/azerothcore-wotlk-coa/releases/download/coa-custom-1.9.1/CoA-Custom-1.9.1-Client-1.zip"), + ("CoA-Custom-1.9.1-Client-2.zip", "https://github.com/ilusixn/azerothcore-wotlk-coa/releases/download/coa-custom-1.9.1/CoA-Custom-1.9.1-Client-2.zip"), + ("CoA-Custom-1.9.1-Client-3.zip", "https://github.com/ilusixn/azerothcore-wotlk-coa/releases/download/coa-custom-1.9.1/CoA-Custom-1.9.1-Client-3.zip"), + ("CoA-Custom-1.9.1-Client-4.zip", "https://github.com/ilusixn/azerothcore-wotlk-coa/releases/download/coa-custom-1.9.1/CoA-Custom-1.9.1-Client-4.zip"), + ("CoA-Custom-1.9.1-Client-5.zip", "https://github.com/ilusixn/azerothcore-wotlk-coa/releases/download/coa-custom-1.9.1/CoA-Custom-1.9.1-Client-5.zip"), ]; pub const RACE_MPQS: &[&str] = &[ @@ -53,6 +55,10 @@ pub const RACE_MPQS: &[&str] = &[ "patch-ZZX.MPQ", "patch-ZZZC.MPQ", "patch-ZZZD.MPQ", + "patch-ZZZA.MPQ", + "patch-ZZZE.MPQ", + "patch-ZZZF.MPQ", + "patch-ZZZZ.MPQ", ]; pub const RACE_ADDONS: &[&str] = &[ @@ -624,16 +630,37 @@ pub fn uninstall_client_patches(client: &Path) -> Result<()> { tx.finish() } +fn stage_root_asset(staging: &Path, relative: &str, reader: &mut impl Read) -> Result { + let dest = fsx::safe_join(staging, relative)?; + fs::create_dir_all( + dest.parent() + .ok_or_else(|| Error::Invalid("Invalid client asset path.".into()))?, + )?; + let mut output = File::create(&dest)?; + io::copy(reader, &mut output)?; + let disabled = PathBuf::from(format!("{}.disabled", dest.display())); + if disabled.is_file() { + fs::remove_file(disabled)?; + } + Ok(relative.to_string()) +} + fn verify_archive(path: &Path, filename: &str) -> Result<()> { let expected = match filename { - "CoA-Custom-1.8.3-Client-1.zip" => { + "CoA-Custom-1.9.1-Client-1.zip" => { "a9dd51ed2d90fb048d549602f40f5429d56e2df0df5606a38781b358fa369568" } - "CoA-Custom-1.8.3-Client-2.zip" => { + "CoA-Custom-1.9.1-Client-2.zip" => { "ab084a55509ccbcc2977a06dd0c01fa879973a1892baaacaeb3ff52f3dfc750e" } - "CoA-Custom-1.8.3-Client-3.zip" => { - "270c7b306624bf9e5c3fe577e3bd058601221df223dd9e449ff7c25de70b9461" + "CoA-Custom-1.9.1-Client-3.zip" => { + "907e267f0ee7038807e626c3c1eca5e12db6c88b747137a23c5fb52eaa1a358e" + } + "CoA-Custom-1.9.1-Client-4.zip" => { + "e0bd87172af989fa50a8e2b08ba4321c72b6265047482f051a1db3b80d55bcaa" + } + "CoA-Custom-1.9.1-Client-5.zip" => { + "ffd75421af78957e53f586efb174c213e939b8dd346de981bdfc8e6d9deb9bc0" } _ => return Err(Error::Invalid("Unknown custom races archive.".into())), }; @@ -867,22 +894,8 @@ pub fn install_client_patches( let mut out = File::create(&dest)?; io::copy(&mut zfile, &mut out)?; installed_roots.push(relative); - } else if zname_norm.contains("files/client_root/") { - let base = Path::new(&zname_norm) - .file_name() - .map(|n| n.to_string_lossy().into_owned()) - .unwrap_or_default(); - - if !base.is_empty() { - let dest = staging.path().join(&base); - let mut out = File::create(&dest)?; - io::copy(&mut zfile, &mut out)?; - let disabled = staging.path().join(format!("{base}.disabled")); - if disabled.is_file() { - fs::remove_file(disabled)?; - } - installed_roots.push(base); - } + } else if let Some(relative) = zname_norm.split("files/client_root/").nth(1) { + installed_roots.push(stage_root_asset(staging.path(), relative, &mut zfile)?); } } } @@ -1048,6 +1061,17 @@ mod tests { fs::remove_dir(link).unwrap(); } + #[test] + fn root_assets_preserve_nested_paths_and_reject_traversal() { + let temp = tempfile::tempdir().unwrap(); + let relative = "Data/Retail/Assets/EquipmentFitting/60-0.bin"; + let result = stage_root_asset(temp.path(), relative, &mut &b"fitting"[..]).unwrap(); + assert_eq!(result, relative); + assert_eq!(fs::read(temp.path().join(relative)).unwrap(), b"fitting"); + assert!(!temp.path().join("60-0.bin").exists()); + assert!(stage_root_asset(temp.path(), "../outside.bin", &mut &b"bad"[..]).is_err()); + } + #[test] #[cfg(windows)] fn shared_addons_junction_supports_install_switch_and_rollback() { diff --git a/crates/coa-core/src/custom_races_hashes.json b/crates/coa-core/src/custom_races_hashes.json index f58dec3..6b2e822 100644 --- a/crates/coa-core/src/custom_races_hashes.json +++ b/crates/coa-core/src/custom_races_hashes.json @@ -1,5 +1,20 @@ { "Ascension.exe": "e2c347019d554a59639e5978fd68e50e906973ab313c6573cc56ca82e8e3c547", + "Data/Retail/Assets/EquipmentFitting/1068-1.bin": "332d2c38b037a118f262bbb3096a01ebfb33c5347e96bbfb64157437b300281b", + "Data/Retail/Assets/EquipmentFitting/60-0.bin": "ffbf6efc9ea09b0c442f048c5bc7b4c5975258045cfddedd9a77a93363312b5e", + "Data/Retail/Assets/EquipmentFitting/60-1.bin": "36ceed2a55756f3322e018938809acea5124351161405058ef27d100173778da", + "Data/Retail/Assets/EquipmentFitting/61-0.bin": "3b302a4055d1e795c451b02e38dfe8007527ee1bc5f926ebcd6ef17f433cd232", + "Data/Retail/Assets/EquipmentFitting/61-1.bin": "c42df399ed99be3c7ce1b5fdb95a873711011713a4cd867bc226a14b1ce0e8ca", + "Data/Retail/Assets/EquipmentFitting/65-0.bin": "8ce3f884ae197d14dff0f955c2cf05abb716742c8aff79f7af1cec5cf7225f04", + "Data/Retail/Assets/EquipmentFitting/68-0.bin": "f1d878f0f943cbdb8025af8daac4a38c1d1e159bd961d9d76f225931c11648ac", + "Data/Retail/Assets/EquipmentFitting/68-1.bin": "2ccbae634384200340c0cc3dca36a7a014a8ddad110598e4470ff1b266576465", + "Data/Retail/Assets/EquipmentFitting/73-0.bin": "5530882678f677ad47987ce906e851338a35f7d9737e3f9d829938027b8af67f", + "Data/Retail/Assets/EquipmentFitting/74-0.bin": "53a7be86b3bfdd6995406c706df3ca091484206d8141cebb39113c714500384a", + "Data/Retail/Assets/EquipmentFitting/74-1.bin": "e688c55a355231978d42480a003c26d379460f5931c2469c119ecb073ea153e1", + "Data/Retail/Assets/EquipmentFitting/75-0.bin": "289abc71c6df0e031a64d62a40e658eaefd37e45373a062ca52f08fbe803500c", + "Data/Retail/Assets/EquipmentFitting/76-0.bin": "63a493e70b91f59ff49f1942d959df986062bd267fe2ba589f344963df771021", + "Data/Retail/Assets/EquipmentFitting/77-0.bin": "b1366ce0dc4f31cb8c8c9705be2da565df4b905224af04b6b88f8c8e9c87e3c9", + "Data/Retail/Assets/EquipmentFitting/78-0.bin": "7b0031fb12ab19020005bdccacca2dd3991349c36949a58b035992585b4134db", "Data/patch-T.MPQ": "fe597138ab7f56881b5f4f27d6dc9d81bb278b483ca0d91b7207ffd4a5ae7bfd", "Data/patch-ZE1.MPQ": "69d79dbbea54ec0312c37770debc79c7bc9ce2e21eedef99c03cd8d911955283", "Data/patch-ZE2.MPQ": "1a41cae77ad730e9cf69e8d63fd12ae3a579418bb550d351fff469573a97ac3c", @@ -22,28 +37,48 @@ "Data/patch-ZZE.MPQ": "4b1e289e12c82644cb78f50170e6b5fd53918eb2de834f9e0cebddd81873a8bb", "Data/patch-ZZR.MPQ": "5a7575e592dc0c8a6913e0d946bbe06fa0ca2e4d817ef1f8548d3d13142bcbd3", "Data/patch-ZZS.MPQ": "533fd69d5784d83e872a5a28d27301dc9ab5d0cb925f8b2116926854e4a0a5b8", - "Data/patch-ZZT.MPQ": "aef3bbe4951333d62fb55224484724fbaa9c35773a19944ffb9935e250cfb59c", - "Data/patch-ZZU.MPQ": "8ee1839415b56d46c6eff7eb4dfbaf6fbafc4c6b29b39380d69f4d827d02a99e", - "Data/patch-ZZV.MPQ": "8d5e61d37008abf70478e5d5f46ec7afb0490b9a643323bd75a1c70cadd63290", - "Data/patch-ZZW.MPQ": "3689c485f8ee8fccaa6dbae1d073bc9231229f9a040f79a272d80a87486d0c33", + "Data/patch-ZZT.MPQ": "e60dab63fe5650fdf5f0846ea6d4136219293bcfdad46d9b796697faeff9ab4c", + "Data/patch-ZZU.MPQ": "0311de8f034eae7dec1bd2c92b1fe6c741cbaf53da62c7609cd12b6c37908e47", + "Data/patch-ZZV.MPQ": "3b04008905e7185d165827d68f7ca228dda8272816364f7d71874ecc83b64f0e", + "Data/patch-ZZW.MPQ": "3bbbc72901fd2d662113036485c380701e693f5a39ba9479af306bf2fa2030bd", "Data/patch-ZZX.MPQ": "4c12608089cfe356f7c8882d66db90239ed3ec8ddd980d91d7a3a488680f3c88", "Data/patch-ZZZ.MPQ": "566aaadf501af42e29a828b1bc2edbd36d436288fb309fe423bd74b9619bf593", + "Data/patch-ZZZA.MPQ": "57ccbdc0a66000767554ffd194088df6d602ddd8341a141bca8201e7d5435889", "Data/patch-ZZZC.MPQ": "691a53f6325c2615a64ced0802f18bc4d96e99c62aaa606fc930f9406ee74cdf", - "Data/patch-ZZZD.MPQ": "e4ce9d8b363eb609d0d6d92627eb53454fa2e03e4dbc1795b3573a22b7d009c8", + "Data/patch-ZZZD.MPQ": "ca893cf8129f6fd442a63f0697a8ddea88546e3ce71bde713be2cc832b892bc9", + "Data/patch-ZZZE.MPQ": "2e245ee0fe3b913087eed399062fda5843d98b04afac38024f7c64ac3bf43e18", + "Data/patch-ZZZF.MPQ": "0e0dd0b46e5308756af779803259e2ba6c99920a01b62a01505b268c20a15bbe", + "Data/patch-ZZZZ.MPQ": "ae27e2f203755c8a74f21cabf8d3ebafd076b53452b1eb9d894fa1ce9837d0ea", "EsteriaAppearance.bin": "90d9cfaeaf6de10f014f1d1610ea10453ec9b240255759aea99513cac488a3ec", - "EsteriaAppearance.dll": "196a82f24dd287653e2b2fc4d12bfc796f8ee3f6687ca8308905a5ab528a51a9", + "EsteriaAppearance.dll": "88e268d3be9eca3b0644f543d823f4bdcc04a9700a6e8ed73fd2a1260ad191af", "EsteriaAppearanceGeometry.bin": "19de5b4b4f79778ea5316659efc2f66c6edb6b5149c46efa47c46bfa4ec6904c", "EsteriaAppearanceMaterials.bin": "f72f027f54a55c05aa0f76b457b97b484fe0e1aedc0e068cc0e0ca53e1878cba", + "EsteriaBanshee.bin": "d3fe66caa6a0ecba96bddb07ac1cbdb915694e87fc1608da0fdabecdf9ffea4d", + "EsteriaBansheeTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", + "EsteriaCentaur.bin": "d63f0b7d21cee67d234d134e832fe6d55c398f2b63f9f6c191dcfa9671637185", + "EsteriaCentaurTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", "EsteriaCosmeticWings.bin": "57352c28459d073a29b3014d33b70f3b3756afa37fa9583ef6b30d503422ac3f", "EsteriaDrakonid.bin": "95440ee9c065ef20bb7fed6158d20623d68745291cedc2726fc746ff54601f95", "EsteriaDrakonidCoverage.bin": "9cdc227f08329e1245d2b864a996e7a772c96ecdbe5d81925f4d60cdbe4fa11e", "EsteriaDrakonidTextures.bin": "1ba9133a75dad291d98a068b2dcde01f31a897a1764cd7f3e2c316c288a8f605", "EsteriaEarthen.bin": "8a0db93ba2d5c756b44ed84f2f7bc7c15eef13be6a7d87baf1383c6c0c624e02", + "EsteriaEthereal.bin": "ada3b7588511a847dd5154d91e3041e9f7f193998b06bfede5e0afc32570b48c", + "EsteriaEtherealTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", + "EsteriaFaceless.bin": "1c5a1d7a6b1db6984a8e41bc4804e9f7c50d65dcdbb8c0a9d1a9e8af8c91bd8f", + "EsteriaFacelessTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", "EsteriaGnoll.bin": "cfacc8e681bb8e54a4f01ee9c12a91bf0bd23a23527bb548d4dc21ec1b33eea2", "EsteriaGnollTextures.bin": "1ba9133a75dad291d98a068b2dcde01f31a897a1764cd7f3e2c316c288a8f605", "EsteriaHaranir.bin": "59f31d00e372fd2646e1cf0d9d3d5d671b31edd60ff7b862f8d1ce7e53ba1f2f", "EsteriaHaranirTextures.bin": "99948ca570be2d376f0c67e3b8088739b6fa9f9d2c73985e19f68df77689a229", "EsteriaHighmountain.bin": "e83349252ad2687ac23fcfc5623db7401cf32e5faf47a5a7be20c2f94b014938", + "EsteriaHozen.bin": "739bc3775388976f5c09bcbf3a98b62d804dff78d545e25a41d07dd99b5fddc5", + "EsteriaHozenTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", + "EsteriaKvItems.bin": "fc5f9d86114234b38dbb0e14a6a5ec16249eaa92a73411a7fc371a950549dcce", + "EsteriaKvSkins.bin": "60b2b899f5f83137368514928f92f3b04c0fae058f534c487ddbe913ee4bec18", + "EsteriaKyrian.bin": "9329147f08805ff4003f9e062fea7c6ea8fdd8c4d6a40de63a6d228ebe1b7c9a", + "EsteriaKyrianTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", + "EsteriaMantid.bin": "71536dee6c2abd0b0e13f33bc73cad7e6fb1b0fc1f6912a95c55d57bc7ee1787", + "EsteriaMantidTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", "EsteriaNaga.bin": "e87547cff5d09500c294f8b06935d134cdd0bbb962e294a72de09404505bd8b3", "EsteriaNagaTextures.bin": "57ec560f99c1d48ac1e8f6a797c156513b99e7d349e3071afe405f812d159ae3", "EsteriaSaberon.bin": "7735c9325c807c5125760d87f323d6b7d4162fb542c1d8b5f435ea2d6b9a4daa", @@ -51,12 +86,18 @@ "EsteriaSaberonTextures.bin": "1ba9133a75dad291d98a068b2dcde01f31a897a1764cd7f3e2c316c288a8f605", "EsteriaSethrak.bin": "bd14857a8c11fdf8027128763293701586b2102f9a6539d33a727014789fd606", "EsteriaSethrakTextures.bin": "d2b2cf58087a391f00198008fe871edd400ddf28d54a3a05674df74c5198528a", + "EsteriaSlime.bin": "491e942ceb6abda83c0249afebae7c9c43af3897b35e45fa33d6f9177ecbc177", + "EsteriaSlimeTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", "EsteriaTarasek.bin": "f718444d5ec36f7aff018883486ae1981151fe6e01f5b7781d68d74e9fadfa47", "EsteriaTarasekTextures.bin": "1ba9133a75dad291d98a068b2dcde01f31a897a1764cd7f3e2c316c288a8f605", - "EsteriaThinHuman.bin": "75794d192ea0c228b3da7bf7d0bdff1119f79d3f9bfef6650cd5e1a2b5d106eb", - "EsteriaThinHumanTextures.bin": "02aeb4c05893d06125b8b58fdb7c2a56fe3d66a7d094706a44b43cb503d1731e", + "EsteriaThinHuman.bin": "bc12e5ca2c087ca0a8642ff6cd8e78fe2e1f85928518b12c19b4245a8320585d", + "EsteriaThinHumanTextures.bin": "27488a7494fa9733b53118d1d0f4acef50a9e19004f81f9c8a614b10f4c3fd5e", "EsteriaTuskarr.bin": "ecbe7ef490ba67eca029a57639192db61238522618491549766fe38529914387", "EsteriaTuskarrTextures.bin": "e2116c2c83adea079126fd5da765d20da24f044d4f161c4124e4368cb3d6bc71", + "EsteriaVenthyr.bin": "5bcf7804363e59b3c922830d06de17bbd348b9967307f39b7d72bc09f58814eb", + "EsteriaVenthyrTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", + "EsteriaVorkai.bin": "d6d2088c7e867b5db437e9afc2d323c22d830c6f84a3598415eedcaa27e2461f", + "EsteriaVorkaiTextures.bin": "837774377ca055e6a5c79c1a4cfd8151e7c1f7ce2c16990b00fd445281137433", "EsteriaVrykul.bin": "39e2b7b4c67997dbbd34bae840bd606a59290f7f2fc82565a0ba00090335415c", "EsteriaVrykulTextures.bin": "46098750a0e235724c6e9cc8d9d4e26550aa47bef95fd5f0f82efe5e945bf296", "EsteriaVulpera.bin": "c5434993b9af4a17d881965e4735cd2ac379e39c7142aac9844adff9528562d4", diff --git a/package-lock.json b/package-lock.json index 5e0b72e..a97d8bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "coa-server-manager", - "version": "0.8.0", + "version": "0.8.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "coa-server-manager", - "version": "0.8.0", + "version": "0.8.1", "dependencies": { "@tauri-apps/api": "^2.12.0", "@tauri-apps/plugin-dialog": "^2.8.0", diff --git a/package.json b/package.json index 5311bf6..43180a1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coa-server-manager", "private": true, - "version": "0.8.0", + "version": "0.8.1", "license": "AGPL-3.0-only", "type": "module", "scripts": { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index d516bee..2bdbb01 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "CoA Server Manager", - "version": "0.8.0", + "version": "0.8.1", "identifier": "com.coa.servermanager", "build": { "beforeDevCommand": "npm run dev",