mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-14 16:07:52 +00:00
fix(archive): handle multibyte ZIP paths on Windows (#2516)
zip 9.1.3's reserved-device-name check sliced entry names at byte offsets, so a WAR or tool archive with a multi-byte file name (e.g. `ZC机柜.jpg`) panicked with "end byte index is not a char boundary" on Windows. Raise zip to 9.2.3, which checks on character boundaries; this covers Tomcat WAR deployment and ZIP/VSIX tool extraction, the two enclosed_name callers. Fixes #2456 Co-authored-by: xtr-hub <242808782+xtr-hub@users.noreply.github.com>
This commit is contained in:
Generated
+3
-2
@@ -12152,14 +12152,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "9.1.3"
|
||||
version = "9.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1156b39d142a34b999c2310a50455e0cb3760bf7efad0122f796d813bee26ccb"
|
||||
checksum = "00fb4744e923442ecadfd3f85f51a5d24e03bf43d53813b81ebb4c91d02baa62"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"getrandom 0.4.3",
|
||||
"indexmap 2.14.2",
|
||||
"libc",
|
||||
"memchr",
|
||||
"nix 0.31.3",
|
||||
"typed-path",
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ trash = "5"
|
||||
blake3 = "1"
|
||||
dunce = "1"
|
||||
dirs = "6"
|
||||
zip = { version = "9", default-features = false, features = ["deflate"] }
|
||||
zip = { version = "9.2.3", default-features = false, features = ["deflate"] }
|
||||
|
||||
# search, index, language
|
||||
grep-searcher = "0.1"
|
||||
|
||||
@@ -1228,6 +1228,48 @@ mod tests {
|
||||
}
|
||||
zip.finish().unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn explodes_wars_with_multibyte_path_components() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let war = tmp.path().join("app.war");
|
||||
let entries = [
|
||||
("bdms300-front/dist/img/ZC机柜.jpg", "reported case"),
|
||||
("img/A机柜.jpg", "one ASCII byte"),
|
||||
("img/😀.jpg", "four-byte character"),
|
||||
("img/abé.jpg", "two-byte character"),
|
||||
("ZC机柜/index.jsp", "multibyte directory"),
|
||||
("img/普通.jpg", "character boundary"),
|
||||
];
|
||||
archive(&war, &entries);
|
||||
for resources_only in [false, true] {
|
||||
let destination = tmp.path().join(format!("out-{resources_only}"));
|
||||
explode(&war, &destination, resources_only).unwrap();
|
||||
for (name, text) in entries {
|
||||
assert_eq!(fs::read_to_string(destination.join(name)).unwrap(), text, "{name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_war_path_traversal() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let war = tmp.path().join("app.war");
|
||||
archive(&war, &[("../escape.txt", "outside")]);
|
||||
assert!(explode(&war, &tmp.path().join("out"), false).is_err());
|
||||
assert!(!tmp.path().join("escape.txt").exists());
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn rejects_war_reserved_device_paths() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let war = tmp.path().join("app.war");
|
||||
for name in ["CON.txt", "NUL", "COM1.txt", "LPT¹", "img/aux.jpg"] {
|
||||
archive(&war, &[(name, "device")]);
|
||||
assert!(explode(&war, &tmp.path().join("out"), false).is_err(), "{name}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keeps_the_apps_own_context_descriptor() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
||||
@@ -443,6 +443,24 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extracts_zip_with_multibyte_path_components() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let archive = tmp.path().join("tool.zip");
|
||||
let entries: &[(&str, &[u8], u32)] = &[
|
||||
("bdms300-front/dist/img/ZC机柜.jpg", b"reported case", 0o644),
|
||||
("A机柜/file", b"directory", 0o644),
|
||||
("abé.txt", b"two-byte character", 0o644),
|
||||
("😀.txt", b"four-byte character", 0o644),
|
||||
];
|
||||
zip_file(&archive, entries);
|
||||
let dest = tmp.path().join("out");
|
||||
extract(&archive, ArchiveKind::Zip, &dest, "x", &CancellationToken::new()).unwrap();
|
||||
for (name, data, _) in entries {
|
||||
assert_eq!(fs::read(dest.join(name)).unwrap(), *data, "{name}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extracts_zip_with_modes_and_nested_dirs() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user