forked from tools/josh
1
0
Fork 0

Adjust resolution semantics for security

Fixes #150.
This commit is contained in:
Florine W. Dekker 2020-12-07 14:48:19 +01:00
parent 86b07555da
commit d6d893d414
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
3 changed files with 73 additions and 51 deletions

View File

@ -1,6 +1,6 @@
{
"name": "fwdekker.com",
"version": "0.39.3",
"version": "0.39.4",
"description": "The source code of [my personal website](https://fwdekker.com/).",
"author": "Felix W. Dekker",
"browser": "dist/bundle.js",

View File

@ -93,9 +93,10 @@ export class Commands {
*
* If the target is a command, the command is parsed (but not yet invoked) and returned.
*
* Targets are resolved as follows. If the target name contains a slash, then interpret that path literally.
* Otherwise, look for the target in /bin. If no such target exists or it is not a file, then interpret it as a
* relative path.
* Targets are resolved as follows:
* If the target name contains a slash, then resolve target relatively and return the result.
* Otherwise, look for the target in /bin. If no such target exists or it is not a file, then resolve the target
* relatively but return `undefined` if it is not a directory.
*
* @param targetName the name of the target to be resolved
* @return the `Command`, `Script`, or `Directory` addressed by the target, an `Error` if the target could be found
@ -107,14 +108,17 @@ export class Commands {
let target: Node | undefined;
if (targetName.includes("/")) {
target = this.fileSystem.get(Path.interpret(cwd, targetName));
if (!(target instanceof File))
return target instanceof Directory ? target : undefined;
} else {
target = this.fileSystem.get(Path.interpret(cwd, "/bin", targetName));
if (!(target instanceof File))
target = this.fileSystem.get(Path.interpret(cwd, targetName));
}
if (!(target instanceof File))
return target instanceof Directory ? target : undefined;
if (!(target instanceof File)) {
target = this.fileSystem.get(Path.interpret(cwd, targetName));
return target instanceof Directory ? target : undefined;
}
}
const code = target.open("read").read();
try {

View File

@ -87,53 +87,13 @@ describe("commands", () => {
beforeEach(() => loadCommand("cd"));
it("navigates to an absolute directory", () => {
fileSystem.add(new Path("/dir"), new Directory(), false);
expect(execute("/dir")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/dir");
});
it("navigates to a relative directory without a slash", () => {
it("navigates to a directory without explicitly writing `cd`", () => {
fileSystem.add(new Path("/dir1/dir2"), new Directory(), true);
environment.set("cwd", "/dir1");
expect(execute("dir2")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/dir1/dir2");
});
it("navigates to a relative directory with a slash", () => {
fileSystem.add(new Path("/dir1/dir2"), new Directory(), true);
environment.set("cwd", "dir1");
expect(execute("dir2/")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/dir1/dir2");
});
it("navigates to a nested relative directory", () => {
fileSystem.add(new Path("/dir1/dir2/dir3"), new Directory(), true);
environment.set("cwd", "dir1");
expect(execute("dir2/dir3")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/dir1/dir2/dir3");
});
describe("/bin", () => {
it("cannot navigate to a directory in /bin by only typing its name if not currently in /bin", () => {
fileSystem.add(new Path("/bin/dir"), new Directory(), true);
expect(execute("dir")).to.equal(ExitCode.COMMAND_NOT_FOUND);
expect(environment.get("cwd")).to.equal("/");
});
it("navigates to a directory in /bin by only typing its name if currently in /bin", () => {
fileSystem.add(new Path("/bin/dir"), new Directory(), true);
environment.set("cwd", "/bin");
expect(execute("dir")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/bin/dir");
});
});
});
describe("scripts", () => {
@ -179,6 +139,58 @@ describe("commands", () => {
});
describe("resolve", () => {
describe("directories", () => {
beforeEach(() => loadCommand("cd"));
it("resolves an absolute directory", () => {
fileSystem.add(new Path("/dir1"), new Directory(), false);
environment.set("cwd", "/dir2");
expect(execute("/dir1")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/dir1");
});
it("resolves a relative directory without a slash", () => {
fileSystem.add(new Path("/dir1/dir2"), new Directory(), true);
environment.set("cwd", "/dir1");
expect(execute("dir2")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/dir1/dir2");
});
it("resolves a relative directory with a slash", () => {
fileSystem.add(new Path("/dir1/dir2"), new Directory(), true);
environment.set("cwd", "dir1");
expect(execute("dir2/")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/dir1/dir2");
});
it("resolves a nested relative directory", () => {
fileSystem.add(new Path("/dir1/dir2/dir3"), new Directory(), true);
environment.set("cwd", "dir1");
expect(execute("dir2/dir3")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/dir1/dir2/dir3");
});
it("does not resolve a directory in /bin by only typing its name if not currently in /bin", () => {
fileSystem.add(new Path("/bin/dir"), new Directory(), true);
expect(execute("dir")).to.equal(ExitCode.COMMAND_NOT_FOUND);
expect(environment.get("cwd")).to.equal("/");
});
it("resolves a directory in /bin by only typing its name if currently in /bin", () => {
fileSystem.add(new Path("/bin/dir"), new Directory(), true);
environment.set("cwd", "/bin");
expect(execute("dir")).to.equal(ExitCode.OK);
expect(environment.get("cwd")).to.equal("/bin/dir");
});
});
describe("/bin commands", () => {
it("resolves a command from /bin if it exists", () => {
const command = `return new Command("", "Summary", "", "", "")`;
@ -206,9 +218,15 @@ describe("commands", () => {
expect((commands.resolve("./command") as Command).summary).to.equal("Summary");
});
it("cannot resolve a command from a relative path if it does not exist", () => {
it("does not resolve a command from a relative path if it does not exist", () => {
expect(commands.resolve("./command")).to.equal(undefined);
});
it("does not resolve a relative command without using a slash", () => {
fileSystem.add(new Path("/command"), new File(`return new Command("", "Summary", "", "", "")`), true);
expect(commands.resolve("command")).to.equal(undefined);
});
});
describe("scripts", () => {