diff --git a/libs/url/builder.ts b/libs/url/builder.ts index 5aea385..68cb536 100644 --- a/libs/url/builder.ts +++ b/libs/url/builder.ts @@ -24,6 +24,19 @@ const SIGNATURE_PARAMETER: string = "ik-s"; const TIMESTAMP_PARAMETER: string = "ik-t"; const DEFAULT_TIMESTAMP: string = "9999999999"; +//used to check if special char is present in string (you'll need to encode it to utf-8 if it does) +const hasMoreThanAscii = (str: string) => { + return str.split('').some((char) => char.charCodeAt(0) > 127); +} + +const customEncodeURI = (str: string) => { + return str.includes("?") ? `${encodeURI(str.split("?")[0])}?${str.split("?")[1]}` : encodeURI(str); +}; + +export const encodeStringIfRequired = (str: string) => { + return hasMoreThanAscii(str) ? customEncodeURI(str) : str; +} + const buildURL = function (opts: FinalUrlOptions): string { //Create correct query parameters var parsedURL: UrlWithStringQuery; @@ -160,9 +173,10 @@ function getSignatureTimestamp(seconds: number): string { return String(currentTimestamp + sec); } -function getSignature(opts: any) { +export function getSignature(opts: any) { if (!opts.privateKey || !opts.url || !opts.urlEndpoint) return ""; var stringToSign = opts.url.replace(urlFormatter.addTrailingSlash(opts.urlEndpoint), "") + opts.expiryTimestamp; + stringToSign = encodeStringIfRequired(stringToSign); return crypto.createHmac("sha1", opts.privateKey).update(stringToSign).digest("hex"); } diff --git a/package.json b/package.json index dd24015..3754b8b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "imagekit", - "version": "5.0.0", + "version": "5.0.1", "description": "Offical NodeJS SDK for ImageKit.io integration", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/tests/url-generation.js b/tests/url-generation.js index 4664d16..4e946a4 100644 --- a/tests/url-generation.js +++ b/tests/url-generation.js @@ -3,6 +3,7 @@ const pkg = require("../package.json"); const expect = chai.expect; const initializationParams = require("./data").initializationParams import ImageKit from "../index"; +import { encodeStringIfRequired, getSignature } from "../libs/url/builder"; var imagekit = new ImageKit(initializationParams); describe("URL generation", function () { @@ -59,6 +60,84 @@ describe("URL generation", function () { expect(url).includes(`ik-s=`); }); + it("Signed URL with é in filename", function () { + const testURL = "https://ik.imagekit.io/test_url_endpoint/test_é_path_alt.jpg"; + const encodedUrl = encodeStringIfRequired(testURL); + expect(encodedUrl).equal("https://ik.imagekit.io/test_url_endpoint/test_%C3%A9_path_alt.jpg"); + const signature = getSignature({ + privateKey: "test_private_key", + url: testURL, + urlEndpoint: "https://ik.imagekit.io/test_url_endpoint", + expiryTimestamp: "9999999999", + }); + const url = imagekit.url({ + path: "/test_é_path_alt.jpg", + signed: true, + }); + expect(url).equal(`https://ik.imagekit.io/test_url_endpoint/test_é_path_alt.jpg?ik-s=${signature}`); + }); + + it("Signed URL with é in filename and path", function () { + const testURL = "https://ik.imagekit.io/test_url_endpoint/aéb/test_é_path_alt.jpg"; + const encodedUrl = encodeStringIfRequired(testURL); + expect(encodedUrl).equal("https://ik.imagekit.io/test_url_endpoint/a%C3%A9b/test_%C3%A9_path_alt.jpg"); + const signature = getSignature({ + privateKey: "test_private_key", + url: testURL, + urlEndpoint: "https://ik.imagekit.io/test_url_endpoint", + expiryTimestamp: "9999999999", + }); + const url = imagekit.url({ + path: "/aéb/test_é_path_alt.jpg", + signed: true, + }); + expect(url).equal(`https://ik.imagekit.io/test_url_endpoint/aéb/test_é_path_alt.jpg?ik-s=${signature}`); + }); + + it("Signed URL with é in filename, path and transformation as path", function () { + const testURL = "https://ik.imagekit.io/test_url_endpoint/tr:l-text,i-Imagekité,fs-50,l-end/aéb/test_é_path_alt.jpg"; + const encodedUrl = encodeStringIfRequired(testURL); + expect(encodedUrl).equal("https://ik.imagekit.io/test_url_endpoint/tr:l-text,i-Imagekit%C3%A9,fs-50,l-end/a%C3%A9b/test_%C3%A9_path_alt.jpg"); + const signature = getSignature({ + privateKey: "test_private_key", + url: testURL, + urlEndpoint: "https://ik.imagekit.io/test_url_endpoint", + expiryTimestamp: "9999999999", + }); + + const url = imagekit.url({ + path: "/aéb/test_é_path_alt.jpg", + signed: true, + transformation: [{ raw: "l-text,i-Imagekité,fs-50,l-end" }], + transformationPosition: "path", + }); + expect(url).equal( + `https://ik.imagekit.io/test_url_endpoint/tr:l-text,i-Imagekité,fs-50,l-end/aéb/test_é_path_alt.jpg?ik-s=${signature}` + ); + }); + + it("Signed URL with é in filename, path and transformation as query", function () { + const testURL = "https://ik.imagekit.io/test_url_endpoint/aéb/test_é_path_alt.jpg?tr=l-text%2Ci-Imagekit%C3%A9%2Cfs-50%2Cl-end"; + const encodedUrl = encodeStringIfRequired(testURL); + expect(encodedUrl).equal("https://ik.imagekit.io/test_url_endpoint/a%C3%A9b/test_%C3%A9_path_alt.jpg?tr=l-text%2Ci-Imagekit%C3%A9%2Cfs-50%2Cl-end"); + const signature = getSignature({ + privateKey: "test_private_key", + url: testURL, + urlEndpoint: "https://ik.imagekit.io/test_url_endpoint", + expiryTimestamp: "9999999999", + }); + const url = imagekit.url({ + path: "/aéb/test_é_path_alt.jpg", + signed: true, + transformation: [{ raw: "l-text,i-Imagekité,fs-50,l-end" }], + transformationPosition: "query", + }); + expect(url).equal( + `https://ik.imagekit.io/test_url_endpoint/aéb/test_é_path_alt.jpg?tr=l-text%2Ci-Imagekit%C3%A9%2Cfs-50%2Cl-end&ik-s=${signature}` + ); + }); + + it('should generate the correct url with path param', function () { const url = imagekit.url({ path: "/test_path.jpg",