diff --git a/backend/src/procedure/js_scripts.rs b/backend/src/procedure/js_scripts.rs index 800e181b1..a840d02e4 100644 --- a/backend/src/procedure/js_scripts.rs +++ b/backend/src/procedure/js_scripts.rs @@ -418,3 +418,46 @@ async fn js_action_test_deep_dir() { .unwrap() .unwrap(); } +#[tokio::test] +async fn js_action_test_deep_dir_escape() { + let js_action = JsProcedure { args: vec![] }; + let path: PathBuf = "test/js_action_execute/" + .parse::() + .unwrap() + .canonicalize() + .unwrap(); + let package_id = "test-package".parse().unwrap(); + let package_version: Version = "0.3.0.3".parse().unwrap(); + let name = ProcedureName::Action("test-deep-dir-escape".parse().unwrap()); + let volumes: Volumes = serde_json::from_value(serde_json::json!({ + "main": { + "type": "data" + }, + "compat": { + "type": "assets" + }, + "filebrowser" :{ + "package-id": "filebrowser", + "path": "data", + "readonly": true, + "type": "pointer", + "volume-id": "main", + } + })) + .unwrap(); + let input: Option = None; + let timeout = Some(Duration::from_secs(10)); + js_action + .execute::( + &path, + &package_id, + &package_version, + name, + &volumes, + input, + timeout, + ) + .await + .unwrap() + .unwrap(); +} diff --git a/backend/src/util/http_reader.rs b/backend/src/util/http_reader.rs index 3bc4d4cd9..f37d51d2d 100644 --- a/backend/src/util/http_reader.rs +++ b/backend/src/util/http_reader.rs @@ -345,7 +345,7 @@ async fn s9pk_test() { let http_url = Url::parse("https://github.com/Start9Labs/hello-world-wrapper/releases/download/v0.3.0/hello-world.s9pk").unwrap(); println!("Getting this resource: {}", http_url); - let mut test_reader = + let test_reader = BufReader::with_capacity(1024 * 1024, HttpReader::new(http_url).await.unwrap()); let mut s9pk = crate::s9pk::reader::S9pkReader::from_reader(test_reader, true) diff --git a/backend/test/js_action_execute/package-data/scripts/test-package/0.3.0.3/embassy.js b/backend/test/js_action_execute/package-data/scripts/test-package/0.3.0.3/embassy.js index cfcfddac7..aeca5a832 100644 --- a/backend/test/js_action_execute/package-data/scripts/test-package/0.3.0.3/embassy.js +++ b/backend/test/js_action_execute/package-data/scripts/test-package/0.3.0.3/embassy.js @@ -790,6 +790,7 @@ export const action = { }; }, async "test-rename"(effects, _input) { + let failed = false; await effects.writeFile({ volumeId: "main", path: "test-rename.txt", @@ -813,13 +814,17 @@ export const action = { volumeId: "main", }); + failed = false; try { await effects.removeFile({ path: "test-rename.txt", volumeId: "main", }); - assert(false, "Should not be able to remove file that doesn't exist"); - } catch (_) {} + } catch (_) { + failed = true; + } + assert(failed, "Should not be able to remove file that doesn't exist"); + return { result: { @@ -840,7 +845,6 @@ export const action = { * @returns */ async "test-deep-dir"(effects, _input) { - effects.error("Test"); await effects .removeDir({ volumeId: "main", @@ -855,6 +859,32 @@ export const action = { volumeId: "main", path: "test-deep-dir", }); + return { + result: { + copyable: false, + message: "Done", + version: "0", + qr: false, + }, + }; + }, + /** + * Found case where we could escape with the new deeper dir fix. + * @param {*} effects + * @param {*} _input + * @returns + */ + async "test-deep-dir-escape"(effects, _input) { + await effects + .removeDir({ + volumeId: "main", + path: "test-deep-dir", + }) + .catch(() => {}); + await effects.createDir({ + volumeId: "main", + path: "test-deep-dir/../../test", + }).then(_ => {throw new Error("Should not be able to create sub")}, _ => {}); return { result: { diff --git a/libs/js_engine/src/lib.rs b/libs/js_engine/src/lib.rs index 2d6b4f2f6..eeaa6619c 100644 --- a/libs/js_engine/src/lib.rs +++ b/libs/js_engine/src/lib.rs @@ -773,11 +773,18 @@ mod fns { child: impl AsRef, ) -> Result { let child = { + let mut child_count = 0; let mut child = child.as_ref(); loop { - let meta = tokio::fs::metadata(child).await; - if meta.is_ok() { - break; + if child.ends_with("..") { + child_count += 1; + } else if child_count > 0 { + child_count -= 1; + } else { + let meta = tokio::fs::metadata(child).await; + if meta.is_ok() { + break; + } } child = match child.parent() { Some(child) => child,