mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
fix(pdf): reject unsafe page numbers before analysis (#105315)
* fix(pdf): reject unsafe page numbers before analysis * test(pdf): bound unsafe page range regression
This commit is contained in:
@@ -79,6 +79,17 @@ describe("parsePageRange", () => {
|
||||
expect(() => parsePageRange("1,2.5", 20)).toThrow('Invalid page number: "2.5"');
|
||||
});
|
||||
|
||||
it("throws on unsafe integer page numbers and ranges", () => {
|
||||
const unsafePage = String(Number.MAX_SAFE_INTEGER + 1);
|
||||
const maxPages = 20;
|
||||
expect(() => parsePageRange(unsafePage, maxPages)).toThrow(
|
||||
`Invalid page number: "${unsafePage}"`,
|
||||
);
|
||||
expect(() => parsePageRange(`1-${unsafePage}`, maxPages)).toThrow(
|
||||
`Invalid page range: "${unsafePage}"`,
|
||||
);
|
||||
});
|
||||
|
||||
it("throws on invalid range (start > end)", () => {
|
||||
expect(() => parsePageRange("5-3", 20)).toThrow("Invalid page range");
|
||||
});
|
||||
|
||||
@@ -47,6 +47,14 @@ export function providerSupportsNativePdf(provider: string): boolean {
|
||||
}
|
||||
|
||||
/** Parses a page range string into sorted, unique, 1-based page numbers within `maxPages`. */
|
||||
function readPageNumber(value: string, errorLabel: string): number {
|
||||
const parsed = Number(value);
|
||||
if (!Number.isSafeInteger(parsed) || parsed < 1) {
|
||||
throw new Error(`${errorLabel}: "${value}"`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
export function parsePageRange(range: string, maxPages: number): number[] {
|
||||
const pages = new Set<number>();
|
||||
const parts = range.split(",").map((p) => p.trim());
|
||||
@@ -56,9 +64,9 @@ export function parsePageRange(range: string, maxPages: number): number[] {
|
||||
}
|
||||
const dashMatch = /^(\d+)\s*-\s*(\d+)$/.exec(part);
|
||||
if (dashMatch) {
|
||||
const start = Number(dashMatch[1]);
|
||||
const end = Number(dashMatch[2]);
|
||||
if (!Number.isFinite(start) || !Number.isFinite(end) || start < 1 || end < start) {
|
||||
const start = readPageNumber(dashMatch[1] ?? "", "Invalid page range");
|
||||
const end = readPageNumber(dashMatch[2] ?? "", "Invalid page range");
|
||||
if (end < start) {
|
||||
throw new Error(`Invalid page range: "${part}"`);
|
||||
}
|
||||
for (let i = start; i <= Math.min(end, maxPages); i++) {
|
||||
@@ -68,10 +76,7 @@ export function parsePageRange(range: string, maxPages: number): number[] {
|
||||
if (!/^\d+$/.test(part)) {
|
||||
throw new Error(`Invalid page number: "${part}"`);
|
||||
}
|
||||
const num = Number(part);
|
||||
if (!Number.isFinite(num) || num < 1) {
|
||||
throw new Error(`Invalid page number: "${part}"`);
|
||||
}
|
||||
const num = readPageNumber(part, "Invalid page number");
|
||||
if (num <= maxPages) {
|
||||
pages.add(num);
|
||||
}
|
||||
|
||||
@@ -625,8 +625,9 @@ describe("createPdfTool", () => {
|
||||
it.each([
|
||||
["1.5", "1.5"],
|
||||
["1,2.5", "2.5"],
|
||||
[`1,${String(Number.MAX_SAFE_INTEGER + 1)}`, String(Number.MAX_SAFE_INTEGER + 1)],
|
||||
])(
|
||||
"rejects fractional page selection %s before loading or fallback extraction",
|
||||
"rejects invalid page selection %s before loading or fallback extraction",
|
||||
async (pages, invalidPage) => {
|
||||
await withTempPdfAgentDir(async (agentDir) => {
|
||||
const { loadSpy } = await stubPdfToolInfra(agentDir, {
|
||||
|
||||
Reference in New Issue
Block a user