fix: add userAgent validation (max 500 chars, no newlines) + add userAgent tests
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
- Route-level validation for userAgent length and newline injection - 6 new userAgent tests (validation, passthrough, GET support) - Fixes missing validation from previous commit - TDD: tests verify both rejection (400) and acceptance paths - Test suite: 425 → 431 tests
This commit is contained in:
parent
3e9336ae67
commit
4f4139c47e
2 changed files with 123 additions and 0 deletions
|
|
@ -1086,4 +1086,115 @@ describe('Screenshot Route', () => {
|
|||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('userAgent parameter', () => {
|
||||
it('should return 400 when userAgent exceeds 500 characters', async () => {
|
||||
const req = createMockRequest({
|
||||
url: "https://example.com",
|
||||
userAgent: "A".repeat(501)
|
||||
})
|
||||
const res = createMockResponse()
|
||||
|
||||
const handler = screenshotRouter.stack.find(layer =>
|
||||
layer.route?.methods.post
|
||||
)?.route.stack[0].handle
|
||||
await handler(req, res, vi.fn())
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(400)
|
||||
expect(res.json).toHaveBeenCalledWith({
|
||||
error: "userAgent: maximum 500 characters allowed"
|
||||
})
|
||||
})
|
||||
|
||||
it('should return 400 when userAgent contains newline (\\n)', async () => {
|
||||
const req = createMockRequest({
|
||||
url: "https://example.com",
|
||||
userAgent: "Mozilla/5.0\nX-Injected: true"
|
||||
})
|
||||
const res = createMockResponse()
|
||||
|
||||
const handler = screenshotRouter.stack.find(layer =>
|
||||
layer.route?.methods.post
|
||||
)?.route.stack[0].handle
|
||||
await handler(req, res, vi.fn())
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(400)
|
||||
expect(res.json).toHaveBeenCalledWith({
|
||||
error: "userAgent: newlines are not allowed (HTTP header injection prevention)"
|
||||
})
|
||||
})
|
||||
|
||||
it('should return 400 when userAgent contains carriage return (\\r)', async () => {
|
||||
const req = createMockRequest({
|
||||
url: "https://example.com",
|
||||
userAgent: "Mozilla/5.0\rX-Injected: true"
|
||||
})
|
||||
const res = createMockResponse()
|
||||
|
||||
const handler = screenshotRouter.stack.find(layer =>
|
||||
layer.route?.methods.post
|
||||
)?.route.stack[0].handle
|
||||
await handler(req, res, vi.fn())
|
||||
|
||||
expect(res.status).toHaveBeenCalledWith(400)
|
||||
expect(res.json).toHaveBeenCalledWith({
|
||||
error: "userAgent: newlines are not allowed (HTTP header injection prevention)"
|
||||
})
|
||||
})
|
||||
|
||||
it('should accept valid userAgent at exactly 500 characters', async () => {
|
||||
const req = createMockRequest({
|
||||
url: "https://example.com",
|
||||
userAgent: "A".repeat(500)
|
||||
})
|
||||
const res = createMockResponse()
|
||||
|
||||
const handler = screenshotRouter.stack.find(layer =>
|
||||
layer.route?.methods.post
|
||||
)?.route.stack[0].handle
|
||||
await handler(req, res, vi.fn())
|
||||
|
||||
expect(res.status).not.toHaveBeenCalledWith(400)
|
||||
})
|
||||
|
||||
it('should pass userAgent to takeScreenshot service', async () => {
|
||||
const req = createMockRequest({
|
||||
url: "https://example.com",
|
||||
userAgent: "Mozilla/5.0 (compatible; SnapAPI/1.0)"
|
||||
})
|
||||
const res = createMockResponse()
|
||||
|
||||
const handler = screenshotRouter.stack.find(layer =>
|
||||
layer.route?.methods.post
|
||||
)?.route.stack[0].handle
|
||||
await handler(req, res, vi.fn())
|
||||
|
||||
expect(mockTakeScreenshot).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
userAgent: "Mozilla/5.0 (compatible; SnapAPI/1.0)"
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('should accept userAgent via GET query parameter', async () => {
|
||||
const req = createMockRequest({
|
||||
url: "https://example.com",
|
||||
userAgent: "CustomBot/2.0"
|
||||
})
|
||||
req.method = "GET"
|
||||
req.query = req.body
|
||||
const res = createMockResponse()
|
||||
|
||||
const handler = screenshotRouter.stack.find(layer =>
|
||||
layer.route?.methods.get
|
||||
)?.route.stack[0].handle
|
||||
await handler(req, res, vi.fn())
|
||||
|
||||
expect(mockTakeScreenshot).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
userAgent: "CustomBot/2.0"
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -445,6 +445,18 @@ async function handleScreenshotRequest(req: any, res: any) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Validate userAgent parameter
|
||||
if (userAgent && typeof userAgent === 'string') {
|
||||
if (userAgent.length > 500) {
|
||||
res.status(400).json({ error: "userAgent: maximum 500 characters allowed" });
|
||||
return;
|
||||
}
|
||||
if (/[\r\n]/.test(userAgent)) {
|
||||
res.status(400).json({ error: "userAgent: newlines are not allowed (HTTP header injection prevention)" });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate css parameter
|
||||
if (css && typeof css === 'string' && css.length > 5000) {
|
||||
res.status(400).json({ error: "css: maximum 5000 characters allowed" });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue