mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
fix(daemon): preserve backslashes in parseCommandLine on Windows (#15642)
* fix(daemon): preserve backslashes in parseCommandLine on Windows Only treat backslash as escape when followed by a quote or another backslash. Bare backslashes are kept as-is so Windows paths survive. Fixes #15587 * fix(daemon): preserve UNC backslashes in schtasks parsing (#15642) (thanks @arosstale) --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Agents/Image tool: cap image-analysis completion `maxTokens` by model capability (`min(4096, model.maxTokens)`) to avoid over-limit provider failures while still preventing truncation. (#11770) Thanks @detecti1.
|
||||
- TUI/Streaming: preserve richer streamed assistant text when final payload drops pre-tool-call text blocks, while keeping non-empty final payload authoritative for plain-text updates. (#15452) Thanks @TsekaLuk.
|
||||
- Inbound/Web UI: preserve literal `\n` sequences when normalizing inbound text so Windows paths like `C:\\Work\\nxxx\\README.md` are not corrupted. (#11547) Thanks @mcaxtr.
|
||||
- Daemon/Windows: preserve literal backslashes in `gateway.cmd` command parsing so drive and UNC paths are not corrupted in runtime checks and doctor entrypoint comparisons. (#15642) Thanks @arosstale.
|
||||
- Security/Canvas: serve A2UI assets via the shared safe-open path (`openFileWithinRoot`) to close traversal/TOCTOU gaps, with traversal and symlink regression coverage. (#10525) Thanks @abdelsfane.
|
||||
- Security/Gateway: breaking default-behavior change - canvas IP-based auth fallback now only accepts machine-scoped addresses (RFC1918, link-local, ULA IPv6, CGNAT); public-source IP matches now require bearer token auth. (#14661) Thanks @sumleo.
|
||||
- Security/Gateway: sanitize and truncate untrusted WebSocket header values in pre-handshake close logs to reduce log-poisoning risk. Thanks @thewilloftheshadow.
|
||||
|
||||
@@ -245,4 +245,63 @@ describe("readScheduledTaskCommand", () => {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
it("parses command with Windows backslash paths", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-schtasks-test-"));
|
||||
try {
|
||||
const scriptPath = path.join(tmpDir, ".openclaw", "gateway.cmd");
|
||||
await fs.mkdir(path.dirname(scriptPath), { recursive: true });
|
||||
await fs.writeFile(
|
||||
scriptPath,
|
||||
[
|
||||
"@echo off",
|
||||
'"C:\\Program Files\\nodejs\\node.exe" C:\\Users\\test\\AppData\\Roaming\\npm\\node_modules\\openclaw\\dist\\index.js gateway --port 18789',
|
||||
].join("\r\n"),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const env = { USERPROFILE: tmpDir, OPENCLAW_PROFILE: "default" };
|
||||
const result = await readScheduledTaskCommand(env);
|
||||
expect(result).toEqual({
|
||||
programArguments: [
|
||||
"C:\\Program Files\\nodejs\\node.exe",
|
||||
"C:\\Users\\test\\AppData\\Roaming\\npm\\node_modules\\openclaw\\dist\\index.js",
|
||||
"gateway",
|
||||
"--port",
|
||||
"18789",
|
||||
],
|
||||
});
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("preserves UNC paths in command arguments", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-schtasks-test-"));
|
||||
try {
|
||||
const scriptPath = path.join(tmpDir, ".openclaw", "gateway.cmd");
|
||||
await fs.mkdir(path.dirname(scriptPath), { recursive: true });
|
||||
await fs.writeFile(
|
||||
scriptPath,
|
||||
[
|
||||
"@echo off",
|
||||
'"\\\\fileserver\\OpenClaw Share\\node.exe" "\\\\fileserver\\OpenClaw Share\\dist\\index.js" gateway --port 18789',
|
||||
].join("\r\n"),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const env = { USERPROFILE: tmpDir, OPENCLAW_PROFILE: "default" };
|
||||
const result = await readScheduledTaskCommand(env);
|
||||
expect(result).toEqual({
|
||||
programArguments: [
|
||||
"\\\\fileserver\\OpenClaw Share\\node.exe",
|
||||
"\\\\fileserver\\OpenClaw Share\\dist\\index.js",
|
||||
"gateway",
|
||||
"--port",
|
||||
"18789",
|
||||
],
|
||||
});
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,16 +59,14 @@ function parseCommandLine(value: string): string[] {
|
||||
const args: string[] = [];
|
||||
let current = "";
|
||||
let inQuotes = false;
|
||||
let escapeNext = false;
|
||||
|
||||
for (const char of value) {
|
||||
if (escapeNext) {
|
||||
current += char;
|
||||
escapeNext = false;
|
||||
continue;
|
||||
}
|
||||
if (char === "\\") {
|
||||
escapeNext = true;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const char = value[i];
|
||||
// `buildTaskScript` only escapes quotes (`\"`).
|
||||
// Keep all other backslashes literal so drive and UNC paths are preserved.
|
||||
if (char === "\\" && i + 1 < value.length && value[i + 1] === '"') {
|
||||
current += value[i + 1];
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (char === '"') {
|
||||
|
||||
Reference in New Issue
Block a user