diff --git a/README.md b/README.md index b0fba5c..911c8a0 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Resize to `200x200px` using `embed` method and change format to `webp`: ### Modifiers + | Property | Docs | Example | Comments | | -------------- | :-------------------------------------------------------------- | :--------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | width / w | [Docs](https://sharp.pixelplumbing.com/api-resize#resize) | `/width_200/buffalo.png` | @@ -88,6 +89,8 @@ Config can be customized using `IPX_*` environment variables. - Default: `[]` + - e.g.: `IPX_DOMAINS=https://avatars.githubusercontent.com, https://nuxt.com` + - `IPX_MAX_AGE` - Default: `300` @@ -100,6 +103,17 @@ Config can be customized using `IPX_*` environment variables. - Default: `{}` +- `IPX_LIMITS_MODIFIERS` + + - Default: `['width', ' w', ' height', ' h', ' resize', ' s', ' fit', ' position', ' pos', ' trim', ' extend', ' extract', ' format', ' f', ' quality', ' q', ' rotate', ' enlarge', ' flip', ' flop', ' sharpen', ' median', ' blur', ' gamma', ' negate', ' normalize', ' threshold', ' tint', ' grayscale', ' animated']` (Abbreviated modifiers will be treated as distinct variants.) + + - e.g.: `IPX_LIMITS_MODIFIERS=w, enlarge` + +- `IPX_LIMITS_MAX_DIMENSIONS` + + - Default: `8192` (px, Both width and height will use this value.) + + ## License [MIT](./LICENSE) diff --git a/src/ipx.ts b/src/ipx.ts index 0c33001..f1b6ba3 100644 --- a/src/ipx.ts +++ b/src/ipx.ts @@ -35,6 +35,10 @@ export interface IPXOptions { // TODO: Create types // https://github.com/lovell/sharp/blob/master/lib/constructor.js#L130 sharp?: SharpOptions; + limits: { + modifiers: Set; + maxDimensions: number; + }; } // https://sharp.pixelplumbing.com/#formats @@ -57,6 +61,17 @@ export function createIPX(userOptions: Partial): IPX { fetchOptions: getEnvironment("IPX_FETCH_OPTIONS", {}), maxAge: getEnvironment("IPX_MAX_AGE", 300), sharp: {}, + limits: { + modifiers: new Set( + getEnvironment( + "IPX_LIMITS_MODIFIERS", + "width, w, height, h, resize, s, fit, position, pos, trim, extend, extract, format, f, quality, q, rotate, enlarge, flip, flop, sharpen, median, blur, gamma, negate, normalize, threshold, tint, grayscale, animated" + ) + .split(",") + .map((s) => s.trim()) + ), + maxDimensions: getEnvironment("IPX_LIMITS_MAX_DIMENSIONS", 8192), + }, }; const options: IPXOptions = defu(userOptions, defaults) as IPXOptions; @@ -155,6 +170,7 @@ export function createIPX(userOptions: Partial): IPX { name, args: arguments_, })) + .filter((h) => options.limits.modifiers.has(h.name)) .filter((h) => h.handler) .sort((a, b) => { const aKey = (a.handler.order || a.name || "").toString(); @@ -165,6 +181,27 @@ export function createIPX(userOptions: Partial): IPX { // Apply handlers const handlerContext: any = { meta }; for (const h of handlers) { + switch (h.name) { + case "width": + case "w": + case "height": + case "h": + case "size": + case "s": { + const [width, height] = String(h.args).split("x").map(Number); + if ( + width > options.limits.maxDimensions || + height > options.limits.maxDimensions + ) { + throw createError( + "Request dimensions exceeds the limit.", + 416, + options.limits.maxDimensions.toString() + ); + } + break; + } + } sharp = applyHandler(handlerContext, sharp, h.handler, h.args) || sharp; }