mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-13 21:26:07 +00:00
fix(cli): reject noncanonical trajectory export requests (#105557)
* fix(cli): reject noncanonical trajectory export requests * fix(cli): preserve encoded request bytes * style(cli): format trajectory alias tests * chore: keep trajectory note in PR context --------- Co-authored-by: Peter Steinberger <peter@steipete.me> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -85,6 +85,27 @@ describe("exportTrajectoryCommand", () => {
|
||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["a discarded suffix", (encoded: string) => `${encoded}A`, "x"],
|
||||
["nonzero padding bits", (encoded: string) => `${encoded.slice(0, -1)}R`, "xy"],
|
||||
["surrounding whitespace", (encoded: string) => ` ${encoded} `, "xyz"],
|
||||
])(
|
||||
"rejects a non-canonical base64url request with %s before looking up its session",
|
||||
async (_case, makeNonCanonical, sessionKey) => {
|
||||
const runtime = createRuntime();
|
||||
const canonical = Buffer.from(JSON.stringify({ sessionKey }), "utf8").toString("base64url");
|
||||
const requestJsonBase64 = makeNonCanonical(canonical);
|
||||
|
||||
await exportTrajectoryCommand({ requestJsonBase64 }, runtime);
|
||||
|
||||
expect(runtime.error).toHaveBeenCalledWith(
|
||||
"Failed to decode trajectory export request: Encoded trajectory export request is invalid",
|
||||
);
|
||||
expect(mocks.loadSessionEntry).not.toHaveBeenCalled();
|
||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||
},
|
||||
);
|
||||
|
||||
it("preserves direct options when an encoded request omits them", async () => {
|
||||
const runtime = createRuntime();
|
||||
const requestJsonBase64 = Buffer.from(
|
||||
|
||||
@@ -43,13 +43,16 @@ function readOptionalString(value: unknown): string | undefined {
|
||||
}
|
||||
|
||||
function decodeExportTrajectoryRequest(encoded: string): Partial<ExportTrajectoryCommandOptions> {
|
||||
const trimmed = encoded.trim();
|
||||
if (!ENCODED_EXPORT_REQUEST_RE.test(trimmed)) {
|
||||
if (!ENCODED_EXPORT_REQUEST_RE.test(encoded)) {
|
||||
throw new Error("Encoded trajectory export request is invalid");
|
||||
}
|
||||
const bytes = Buffer.from(encoded, "base64url");
|
||||
if (bytes.toString("base64url") !== encoded) {
|
||||
throw new Error("Encoded trajectory export request is invalid");
|
||||
}
|
||||
let decoded: unknown;
|
||||
try {
|
||||
decoded = JSON.parse(Buffer.from(trimmed, "base64url").toString("utf8")) as unknown;
|
||||
decoded = JSON.parse(bytes.toString("utf8")) as unknown;
|
||||
} catch {
|
||||
throw new Error("Encoded trajectory export request is invalid JSON");
|
||||
}
|
||||
@@ -84,8 +87,8 @@ function decodeExportTrajectoryRequest(encoded: string): Partial<ExportTrajector
|
||||
function resolveExportTrajectoryOptions(
|
||||
opts: ExportTrajectoryCommandOptions,
|
||||
): ExportTrajectoryCommandOptions {
|
||||
const encoded = opts.requestJsonBase64?.trim();
|
||||
if (!encoded) {
|
||||
const encoded = opts.requestJsonBase64;
|
||||
if (encoded === undefined || encoded.length === 0) {
|
||||
return opts;
|
||||
}
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user