diff --git a/crates/coa-core/src/custom_races.rs b/crates/coa-core/src/custom_races.rs index a96e5cb..1675c7f 100644 --- a/crates/coa-core/src/custom_races.rs +++ b/crates/coa-core/src/custom_races.rs @@ -192,6 +192,8 @@ fn patch_files(client: &Path) -> Result> { include_str!("custom_races_hashes_1_7.json") } else if manifest.lines().any(|line| line == "# CoA Custom 1.8") { include_str!("custom_races_hashes_1_8.json") + } else if manifest.lines().any(|line| line == "# CoA Custom 1.8.3") { + include_str!("custom_races_hashes_1_8_3.json") } else { include_str!("custom_races_hashes.json") }; @@ -206,11 +208,6 @@ fn patch_files(client: &Path) -> Result> { } Some(format!("Data/{name}")) } else if let Some(name) = line.strip_prefix("ROOT:") { - if name.contains(['/', '\\']) { - return Err(Error::Invalid( - "Invalid custom races patch manifest.".into(), - )); - } Some(name.to_string()) } else { line.strip_prefix("ADDON:") @@ -1061,6 +1058,33 @@ mod tests { fs::remove_dir(link).unwrap(); } + #[test] + fn nested_root_manifest_remains_valid_and_rejects_traversal() { + let temp = tempfile::tempdir().unwrap(); + let relative = "Data/Retail/Assets/EquipmentFitting/60-0.bin"; + fs::write( + temp.path().join(MANIFEST_FILENAME), + format!("# CoA Custom {CLIENT_VERSION}\nROOT:{relative}\n"), + ) + .unwrap(); + assert_eq!(patch_files(temp.path()).unwrap()[0].path, relative); + fs::write(temp.path().join(MANIFEST_FILENAME), "ROOT:../outside.bin\n").unwrap(); + assert!(patch_files(temp.path()).is_err()); + } + + #[test] + fn previous_split_release_retains_its_original_hash_inventory() { + let temp = tempfile::tempdir().unwrap(); + fs::write(temp.path().join(MANIFEST_FILENAME), "# CoA Custom 1.8.3\n").unwrap(); + let old: std::collections::BTreeMap = + serde_json::from_str(include_str!("custom_races_hashes_1_8_3.json")).unwrap(); + let files = patch_files(temp.path()).unwrap(); + assert_eq!(files.len(), old.len()); + assert!(files + .iter() + .all(|file| old.get(&file.path) == Some(&file.sha256))); + } + #[test] fn root_assets_preserve_nested_paths_and_reject_traversal() { let temp = tempfile::tempdir().unwrap(); diff --git a/crates/coa-core/src/custom_races_hashes_1_8_3.json b/crates/coa-core/src/custom_races_hashes_1_8_3.json new file mode 100644 index 0000000..f58dec3 --- /dev/null +++ b/crates/coa-core/src/custom_races_hashes_1_8_3.json @@ -0,0 +1,73 @@ +{ + "Ascension.exe": "e2c347019d554a59639e5978fd68e50e906973ab313c6573cc56ca82e8e3c547", + "Data/patch-T.MPQ": "fe597138ab7f56881b5f4f27d6dc9d81bb278b483ca0d91b7207ffd4a5ae7bfd", + "Data/patch-ZE1.MPQ": "69d79dbbea54ec0312c37770debc79c7bc9ce2e21eedef99c03cd8d911955283", + "Data/patch-ZE2.MPQ": "1a41cae77ad730e9cf69e8d63fd12ae3a579418bb550d351fff469573a97ac3c", + "Data/patch-ZE3.MPQ": "b587202c21b6f580682b601b7c2e905fbfa766276e74733db55c1bddbffb7f87", + "Data/patch-ZE5.MPQ": "476b5a1fcf69f64fdb281e3b445362b936d016066ccd12f897acfcf200d6c0cf", + "Data/patch-ZE6.MPQ": "762592c9ed950b4a7b6c7d85d45050b30fa3f35d53e348ee1e1516fdbb7e5484", + "Data/patch-ZE7.MPQ": "de54b0189d242763d2872223419a259b6b8a4b380c24b50a2ef9c6fa44466248", + "Data/patch-ZE8.MPQ": "1bc5691fb84a84f3e7a0a70baaa9192a97b4ec5906ee37c85838ffe08adef934", + "Data/patch-ZE9.MPQ": "d49c94463e9548e76378ce2c0454d8f204f0745c8c0de32b6dce7f0b0fd67c4a", + "Data/patch-ZEA.MPQ": "78fd10ec5262ae2417eba9700d2172553bbc1e5cfb0b597aada8f1753ca46d9d", + "Data/patch-ZES.MPQ": "a2d9348f917f745c7aa25b2eed96efa312f7b2d2f62cb86a4f2eaabc2dfa895f", + "Data/patch-ZG.MPQ": "48979e1fda775f8deb47bffa48e0a468595d4c71286fee518f51dc5801c5ca39", + "Data/patch-ZH.MPQ": "5e1d2fe287053abba703d7af381e10096c6525ba477ffed3971c2fc4f93e919c", + "Data/patch-ZHA.MPQ": "0fc6ebeafe1d14192dc64bafc90bde3c49230df1297f98bf65900a3bcf953617", + "Data/patch-ZHM.MPQ": "317d3ae00f0bd674b358af07544976acb7804aa6d8b19d1788ad96030e8c9bf0", + "Data/patch-ZJ.MPQ": "f821e99add86ef68d108c5ec466328c97677d3ed52f7944e200f3fe38c13b4de", + "Data/patch-ZK.MPQ": "444d0ecb72c1e990509d53e3cfa5b7634c816733533e8a97e5d7f5653ee32cce", + "Data/patch-ZM.MPQ": "424ab1978986e854551633983a94bd15beba6328aabea8c02f98eaa32f6f0b61", + "Data/patch-ZVU.MPQ": "c679b85a2e97344395756b54d2cf6abefe4e80e74944cb55b6e573ad17b7d020", + "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-ZZX.MPQ": "4c12608089cfe356f7c8882d66db90239ed3ec8ddd980d91d7a3a488680f3c88", + "Data/patch-ZZZ.MPQ": "566aaadf501af42e29a828b1bc2edbd36d436288fb309fe423bd74b9619bf593", + "Data/patch-ZZZC.MPQ": "691a53f6325c2615a64ced0802f18bc4d96e99c62aaa606fc930f9406ee74cdf", + "Data/patch-ZZZD.MPQ": "e4ce9d8b363eb609d0d6d92627eb53454fa2e03e4dbc1795b3573a22b7d009c8", + "EsteriaAppearance.bin": "90d9cfaeaf6de10f014f1d1610ea10453ec9b240255759aea99513cac488a3ec", + "EsteriaAppearance.dll": "196a82f24dd287653e2b2fc4d12bfc796f8ee3f6687ca8308905a5ab528a51a9", + "EsteriaAppearanceGeometry.bin": "19de5b4b4f79778ea5316659efc2f66c6edb6b5149c46efa47c46bfa4ec6904c", + "EsteriaAppearanceMaterials.bin": "f72f027f54a55c05aa0f76b457b97b484fe0e1aedc0e068cc0e0ca53e1878cba", + "EsteriaCosmeticWings.bin": "57352c28459d073a29b3014d33b70f3b3756afa37fa9583ef6b30d503422ac3f", + "EsteriaDrakonid.bin": "95440ee9c065ef20bb7fed6158d20623d68745291cedc2726fc746ff54601f95", + "EsteriaDrakonidCoverage.bin": "9cdc227f08329e1245d2b864a996e7a772c96ecdbe5d81925f4d60cdbe4fa11e", + "EsteriaDrakonidTextures.bin": "1ba9133a75dad291d98a068b2dcde01f31a897a1764cd7f3e2c316c288a8f605", + "EsteriaEarthen.bin": "8a0db93ba2d5c756b44ed84f2f7bc7c15eef13be6a7d87baf1383c6c0c624e02", + "EsteriaGnoll.bin": "cfacc8e681bb8e54a4f01ee9c12a91bf0bd23a23527bb548d4dc21ec1b33eea2", + "EsteriaGnollTextures.bin": "1ba9133a75dad291d98a068b2dcde01f31a897a1764cd7f3e2c316c288a8f605", + "EsteriaHaranir.bin": "59f31d00e372fd2646e1cf0d9d3d5d671b31edd60ff7b862f8d1ce7e53ba1f2f", + "EsteriaHaranirTextures.bin": "99948ca570be2d376f0c67e3b8088739b6fa9f9d2c73985e19f68df77689a229", + "EsteriaHighmountain.bin": "e83349252ad2687ac23fcfc5623db7401cf32e5faf47a5a7be20c2f94b014938", + "EsteriaNaga.bin": "e87547cff5d09500c294f8b06935d134cdd0bbb962e294a72de09404505bd8b3", + "EsteriaNagaTextures.bin": "57ec560f99c1d48ac1e8f6a797c156513b99e7d349e3071afe405f812d159ae3", + "EsteriaSaberon.bin": "7735c9325c807c5125760d87f323d6b7d4162fb542c1d8b5f435ea2d6b9a4daa", + "EsteriaSaberonCoverage.bin": "9cdc227f08329e1245d2b864a996e7a772c96ecdbe5d81925f4d60cdbe4fa11e", + "EsteriaSaberonTextures.bin": "1ba9133a75dad291d98a068b2dcde01f31a897a1764cd7f3e2c316c288a8f605", + "EsteriaSethrak.bin": "bd14857a8c11fdf8027128763293701586b2102f9a6539d33a727014789fd606", + "EsteriaSethrakTextures.bin": "d2b2cf58087a391f00198008fe871edd400ddf28d54a3a05674df74c5198528a", + "EsteriaTarasek.bin": "f718444d5ec36f7aff018883486ae1981151fe6e01f5b7781d68d74e9fadfa47", + "EsteriaTarasekTextures.bin": "1ba9133a75dad291d98a068b2dcde01f31a897a1764cd7f3e2c316c288a8f605", + "EsteriaThinHuman.bin": "75794d192ea0c228b3da7bf7d0bdff1119f79d3f9bfef6650cd5e1a2b5d106eb", + "EsteriaThinHumanTextures.bin": "02aeb4c05893d06125b8b58fdb7c2a56fe3d66a7d094706a44b43cb503d1731e", + "EsteriaTuskarr.bin": "ecbe7ef490ba67eca029a57639192db61238522618491549766fe38529914387", + "EsteriaTuskarrTextures.bin": "e2116c2c83adea079126fd5da765d20da24f044d4f161c4124e4368cb3d6bc71", + "EsteriaVrykul.bin": "39e2b7b4c67997dbbd34bae840bd606a59290f7f2fc82565a0ba00090335415c", + "EsteriaVrykulTextures.bin": "46098750a0e235724c6e9cc8d9d4e26550aa47bef95fd5f0f82efe5e945bf296", + "EsteriaVulpera.bin": "c5434993b9af4a17d881965e4735cd2ac379e39c7142aac9844adff9528562d4", + "EsteriaVulperaTextures.bin": "1ab844e74684aced2b069f1b91cd563aade45e05bd5e23f866a6c0c301cb098e", + "Interface/AddOns/CoAHideArmor/CoAHideArmor.lua": "8c1c7403524fc9bd56c0809b4101b141da700ba163701209bf1420f2ef106aa7", + "Interface/AddOns/CoAHideArmor/CoAHideArmor.toc": "123580d92fd5ceee258e96296f42c359b7e83cdff151af49c50c6c4e2059677c", + "Interface/AddOns/CoAWC2Cursor/CoAWC2Cursor.lua": "1cf9537ff5f10b77250fea4407aea1008da690afe102ed6ed2dac21f79638cfa", + "Interface/AddOns/CoAWC2Cursor/CoAWC2Cursor.toc": "48ce695dce712b3643ebe13a77e318d623c964acc69479b8fc8cc675099801bf", + "Interface/AddOns/CoA_TalentReset/CoA_TalentReset.lua": "827d756d5948ef918fafaf8b869290b3a1faa4e4cc21b19b512a00d4509f3d41", + "Interface/AddOns/CoA_TalentReset/CoA_TalentReset.toc": "16298c04af68e68d6445e7a11f42aee525dd4145f85d2771ff434fb7c6e95a85", + "dinput8.dll": "f8de78606c241fb3911dce22faf68f5b9f9885b142b183c1e2c09ddc8f7e380c", + "wc2_human.cur": "f609736e29596bb386ef1597b157d211e01a86d32c2a929e256c581c37d71791", + "wc2_orc.cur": "baa512c9b9045762ba35b6e0d35b8f79c54b7649f35cc9c0e0cc8c168a1e5a97" +}