Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions library/helpers/extractStringsFromUserInput.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,32 @@ t.test("it handles deeply nested JWT without stack overflow", async () => {
t.ok(result.size > 0);
t.ok(result.has("Test'), ('Test2');--"));
});

t.test("it decodes buffers and array buffers", async () => {
const buffer = Buffer.from("Hello, world!", "utf-8");
const arrayBuffer = buffer.buffer.slice(
buffer.byteOffset,
buffer.byteOffset + buffer.byteLength
);

t.same(
extractStringsFromUserInput({
buf: buffer,
arrBuf: arrayBuffer,
}),
fromArr(["buf", "Hello, world!", "arrBuf", "Hello, world!"])
);
});

t.test("it ignores large buffers and array buffers", async () => {
process.env.AIKIDO_MAX_BODY_SIZE_MB = "1"; // 1 MB
const largeBuffer = Buffer.alloc(1024 * 1024 + 1, "a"); // 1 MB + 1 byte

t.same(
extractStringsFromUserInput({
buf: largeBuffer,
}),
fromArr(["buf"])
);
delete process.env.AIKIDO_MAX_BODY_SIZE_MB;
});
11 changes: 11 additions & 0 deletions library/helpers/extractStringsFromUserInput.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { getMaxBodySize } from "./getMaxBodySize";
import { isPlainObject } from "./isPlainObject";
import { safeDecodeURIComponent } from "./safeDecodeURIComponent";
import { tryDecodeAsJWT } from "./tryDecodeAsJWT";
import { tryDecodeBuffer } from "./tryDecodeBuffer";

type UserString = string;

Expand Down Expand Up @@ -66,5 +68,14 @@ export function extractStringsFromUserInput(
}
}

if (Buffer.isBuffer(obj) || obj instanceof ArrayBuffer) {
if (obj.byteLength < getMaxBodySize()) {
const decoded = tryDecodeBuffer(obj);
if (decoded) {
results.add(decoded);
}
}
}

return results;
}
46 changes: 46 additions & 0 deletions library/helpers/tryDecodeBuffer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as t from "tap";
import { tryDecodeBuffer } from "./tryDecodeBuffer";

t.test("tryDecodeBuffer decodes valid UTF-8 buffer", async (t) => {
const buffer = Buffer.from("Hello, world!", "utf-8");
const result = tryDecodeBuffer(buffer);
t.equal(result, "Hello, world!");
});

t.test(
"tryDecodeBuffer returns undefined for invalid UTF-8 buffer",
async (t) => {
const buffer = Buffer.from([0xff, 0xfe, 0xfd]);
const result = tryDecodeBuffer(buffer);
t.equal(result, undefined);
}
);

t.test("tryDecodeBuffer decodes valid UTF-8 ArrayBuffer", async (t) => {
const encoder = new TextEncoder();
const uint8Array = encoder.encode("Hello, ArrayBuffer!");
const arrayBuffer = uint8Array.buffer;
const result = tryDecodeBuffer(arrayBuffer);
t.equal(result, "Hello, ArrayBuffer!");
});

t.test(
"tryDecodeBuffer returns undefined for invalid UTF-8 ArrayBuffer",
async (t) => {
const invalidArray = new Uint8Array([0xff, 0xfe, 0xfd]);
const result = tryDecodeBuffer(invalidArray.buffer);
t.equal(result, undefined);
}
);

t.test("tryDecodeBuffer with different encoding", async (t) => {
const buffer = Buffer.from("48656c6c6f", "hex"); // "Hello" in hex
const result = tryDecodeBuffer(buffer, "utf-8", false);
t.equal(result, "Hello");
});

t.test("tryDecodeBuffer with utf8Only false", async (t) => {
const buffer = Buffer.from([0xff, 0xfe, 0xfd]);
const result = tryDecodeBuffer(buffer, "utf-8", false);
t.equal(result, "���"); // Should decode to replacement characters
});
15 changes: 15 additions & 0 deletions library/helpers/tryDecodeBuffer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export function tryDecodeBuffer(
data: Buffer | ArrayBuffer,
encoding = "utf-8",
fatal = true
): string | undefined {
try {
const decoder = new TextDecoder(encoding, {
fatal: fatal, // Throw error if buffer is not matching the encoding
});

return decoder.decode(data);
} catch {
return undefined;
}
}