mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
prevent ddos on img
This commit is contained in:
@@ -19,8 +19,12 @@ const FALLBACK_ASSET_PATH = '/DefaultProfileImage.jpg'
|
||||
*/
|
||||
const CACHE_CONTROL = 'public, max-age=31536000, immutable'
|
||||
|
||||
/** Upper bound on a requested output dimension; guards against abuse. */
|
||||
const MAX_DIMENSION = 4096
|
||||
/**
|
||||
* Allowed output dimensions. Restricting resizes to a small fixed set caps the
|
||||
* number of distinct variants an attacker can request, so they can't blow past
|
||||
* the edge cache and force the (expensive) WASM resize on every hit.
|
||||
*/
|
||||
const ALLOWED_DIMENSIONS = new Set([128, 256, 512, 1024])
|
||||
|
||||
/** JPEG quality used when re-encoding a resized image. */
|
||||
const RESIZE_JPEG_QUALITY = 90
|
||||
@@ -33,11 +37,11 @@ interface Transform {
|
||||
cropSquare: boolean
|
||||
}
|
||||
|
||||
/** Parse a positive-integer dimension query param, or `undefined` if invalid/absent. */
|
||||
/** Parse a dimension query param, or `undefined` if absent or not an allowed size. */
|
||||
function parseDimension(value: string | undefined): number | undefined {
|
||||
if (value === undefined) return undefined
|
||||
const n = Number(value)
|
||||
if (!Number.isInteger(n) || n <= 0 || n > MAX_DIMENSION) return undefined
|
||||
if (!Number.isInteger(n) || !ALLOWED_DIMENSIONS.has(n)) return undefined
|
||||
return n
|
||||
}
|
||||
|
||||
|
||||
@@ -196,6 +196,14 @@ describe('img endpoints', () => {
|
||||
expect(new Uint8Array(await res.arrayBuffer())).toEqual(full)
|
||||
})
|
||||
|
||||
it('ignores a ?width outside the allowed sizes and serves the original', async () => {
|
||||
const full = new Uint8Array(await (await SELF.fetch(`${ORIGIN}/RecCenter.jpg`)).arrayBuffer())
|
||||
// 300 isn't one of 128/256/512/1024, so it's rejected and the source served.
|
||||
const res = await SELF.fetch(`${ORIGIN}/RecCenter.jpg?width=300`)
|
||||
expect(res.status).toBe(200)
|
||||
expect(new Uint8Array(await res.arrayBuffer())).toEqual(full)
|
||||
})
|
||||
|
||||
it('signs the resized body with ?width and ?sig=p1', async () => {
|
||||
const res = await SELF.fetch(`${ORIGIN}/RecCenter.jpg?width=512&sig=p1`)
|
||||
expect(res.status).toBe(200)
|
||||
|
||||
Reference in New Issue
Block a user