From a53d6641c9803608e33f5a188ead68ae7c25ee4d Mon Sep 17 00:00:00 2001 From: Angelo Ashmore Date: Wed, 15 Apr 2020 18:29:13 -1000 Subject: [PATCH 1/3] feat: s param and optional URL signing --- src/index.ts | 22 +++++++++++++++++++++- src/tests.ts | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 7146151..c28db44 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,7 @@ // tslint:disable-next-line match-default-export-name +import { createHash } from 'crypto'; import { ParsedUrlQueryInput } from 'querystring'; +import * as urlHelpers from 'url'; import { addQueryToUrl } from 'url-transformers'; import { pickBy } from './helpers'; import { catMaybesDictionary, mapValueIfDefined } from './helpers/maybe'; @@ -71,6 +73,7 @@ export type ImgixUrlQueryParams = { cs?: ImgixColorSpace; faceindex?: number; facepad?: number; + s?: string; }; const pickTrueInObject = (obj: Record): Partial> => @@ -87,6 +90,21 @@ const serializeImgixUrlQueryParamListValue = pipe( joinWithComma, undefinedIfEmptyString, ); +const addImgixUrlQueryParamSignature = (url: string, token?: string) => ( + query: ParsedUrlQueryInput, +) => { + if (token === undefined || query.hasOwnProperty('s')) return query; + + const formattedQuery = urlHelpers.format({ query }); + const { pathname } = new urlHelpers.URL(url); + + const signatureBase = token + pathname + formattedQuery; + const signature = createHash('md5') + .update(signatureBase) + .digest('hex'); + + return { ...query, s: signature }; +}; const mapToSerializedListValueIfDefined = mapValueIfDefined(serializeImgixUrlQueryParamListValue); @@ -110,12 +128,14 @@ const serializeImgixUrlQueryParamValues = (query: ImgixUrlQueryParams): ParsedUr blur: query.blur, faceindex: query.faceindex, facepad: query.facepad, + s: query.s, }), catMaybesDictionary, )({}); -export const buildImgixUrl = (url: string) => +export const buildImgixUrl = (url: string, token?: string) => pipe( serializeImgixUrlQueryParamValues, + addImgixUrlQueryParamSignature(url, token), query => addQueryToUrl({ url })({ queryToAppend: query }), ); diff --git a/src/tests.ts b/src/tests.ts index 6b4c0c9..fb6b6ec 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -10,3 +10,24 @@ assert.strictEqual( }), 'https://foo.com/?auto=format&w=300', ); + +assert.strictEqual( + buildImgixUrl('https://foo.com')({ + auto: { + format: true, + }, + w: 300, + s: 'signature', + }), + 'https://foo.com/?auto=format&w=300&s=signature', +); + +assert.strictEqual( + buildImgixUrl('https://foo.com', 'token')({ + auto: { + format: true, + }, + w: 300, + }), + 'https://foo.com/?auto=format&w=300&s=d82d76f9f31379083b452f98bcd7f670', +); From 57611f589dd55ed710a8af142e90b8b7a8c86add Mon Sep 17 00:00:00 2001 From: Angelo Ashmore Date: Wed, 15 Apr 2020 18:39:55 -1000 Subject: [PATCH 2/3] docs: add link to imgix-blueprint on url signing --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index c28db44..47fc9f9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -98,6 +98,7 @@ const addImgixUrlQueryParamSignature = (url: string, token?: string) => ( const formattedQuery = urlHelpers.format({ query }); const { pathname } = new urlHelpers.URL(url); + // https://github.com/imgix/imgix-blueprint#securing-urls const signatureBase = token + pathname + formattedQuery; const signature = createHash('md5') .update(signatureBase) From 3ba8004fbb927e0416dcbb20facf71e30fe78936 Mon Sep 17 00:00:00 2001 From: Angelo Ashmore Date: Wed, 15 Apr 2020 18:52:14 -1000 Subject: [PATCH 3/3] test: add token to signature passthrough test --- src/tests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests.ts b/src/tests.ts index fb6b6ec..b9e43b2 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -12,7 +12,7 @@ assert.strictEqual( ); assert.strictEqual( - buildImgixUrl('https://foo.com')({ + buildImgixUrl('https://foo.com', 'token')({ auto: { format: true, },