diff --git a/package.json b/package.json index faf0ba621..df455f603 100755 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "image-meta": "^0.0.1", "ipx": "^0.4.8", "is-https": "^3.0.2", + "md5": "^2.3.0", "node-fetch": "^2.6.1", "requrl": "^3.0.2", "ufo": "^0.5.2", diff --git a/src/runtime/providers/imgix.ts b/src/runtime/providers/imgix.ts index 7868c382c..568285f46 100644 --- a/src/runtime/providers/imgix.ts +++ b/src/runtime/providers/imgix.ts @@ -1,4 +1,5 @@ import type { ProviderGetImage } from 'src' +import md5 from 'md5' import { joinURL } from 'ufo' import { createOperationsGenerator } from '~image' @@ -18,12 +19,39 @@ const operationsGenerator = createOperationsGenerator({ } }, joinWith: '&', - formatter: (key, value) => `${key}=${value}` + formatter: (key, value) => { + const encodedKey = encodeURIComponent(key) + const encodedValue = encodeURIComponent(value) + + return `${encodedKey}=${encodedValue}` + } }) -export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/' } = {}) => { +const sanitizePath = (src: string): string => { + const path = src.replace(/^\//, '') + + const encodedPath = /^https?:\/\//.test(path) + ? encodeURIComponent(path) + : encodeURI(path) + .replace(/[#?:+]/g, encodeURIComponent) + + return `/${encodedPath}` +} + +export const getImage: ProviderGetImage = (src, { options = {}, modifiers = {}, baseURL = '/' } = {}) => { + const { token } = options const operations = operationsGenerator(modifiers) + const queryString = operations ? `?${operations}` : '' + + if (!token) { + return { url: joinURL(baseURL, src + queryString) } + } + + const sanitizedPath = sanitizePath(src) + const signature = md5(token + sanitizedPath + queryString) + const delimiter = queryString ? '&' : '?' + return { - url: joinURL(baseURL, src + (operations ? ('?' + operations) : '')) + url: joinURL(baseURL, sanitizedPath + queryString + delimiter + `s=${signature}`) } } diff --git a/yarn.lock b/yarn.lock index fa59691bf..31375e77c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3399,6 +3399,11 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + check-types@^8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" @@ -4091,6 +4096,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -6589,7 +6599,7 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^1.1.5: +is-buffer@^1.1.5, is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -7901,6 +7911,15 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"