From cdfd46f19110061f7783161c389365c9da844955 Mon Sep 17 00:00:00 2001 From: Jon Koops Date: Thu, 26 Sep 2024 15:06:32 +0200 Subject: [PATCH] Strip remaining dependencies from Keycloak JS (#33295) Closes #33277 Signed-off-by: Jon Koops --- js/libs/keycloak-js/package.json | 7 --- js/libs/keycloak-js/rollup.config.ts | 37 +++++-------- js/libs/keycloak-js/src/keycloak.js | 80 ++++++++++++++++++++++++---- pnpm-lock.yaml | 44 --------------- 4 files changed, 83 insertions(+), 85 deletions(-) diff --git a/js/libs/keycloak-js/package.json b/js/libs/keycloak-js/package.json index c688fa6322..f78879a5e4 100644 --- a/js/libs/keycloak-js/package.json +++ b/js/libs/keycloak-js/package.json @@ -68,16 +68,9 @@ "authentication" ], "devDependencies": { - "@rollup/plugin-commonjs": "^26.0.1", - "@rollup/plugin-inject": "^5.0.5", - "@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^12.1.0", - "es6-promise": "^4.2.8", "rollup": "^4.22.4", "shx": "^0.3.4" - }, - "dependencies": { - "jwt-decode": "^4.0.0" } } diff --git a/js/libs/keycloak-js/rollup.config.ts b/js/libs/keycloak-js/rollup.config.ts index 6912731d4b..a34acf036e 100644 --- a/js/libs/keycloak-js/rollup.config.ts +++ b/js/libs/keycloak-js/rollup.config.ts @@ -1,7 +1,4 @@ -import commonjs from "@rollup/plugin-commonjs"; -import inject from "@rollup/plugin-inject"; -import { nodeResolve } from "@rollup/plugin-node-resolve"; -import terser from '@rollup/plugin-terser'; +import terser from "@rollup/plugin-terser"; import path from "node:path"; import type { OutputOptions, RollupOptions } from "rollup"; import { defineConfig } from "rollup"; @@ -12,18 +9,15 @@ interface DefineOptionsArgs { amdId: string; } +const sourceFile = (file: string) => path.join("src", file); +const targetFile = (file: string) => path.join("dist", file); + function defineOptions({ file, name, amdId, }: DefineOptionsArgs): RollupOptions[] { - const sourceDir = "src"; - const targetDir = "dist"; - const commonOptions = { - input: path.join(sourceDir, `${file}.js`), - plugins: [commonjs(), nodeResolve()], - } satisfies RollupOptions; - + const input = sourceFile(`${file}.js`); const umdOutput: OutputOptions = { format: "umd", name, @@ -31,38 +25,31 @@ function defineOptions({ }; return [ - // Modern ES module variant, with externalized dependencies. + // Modern ES module variant. { - ...commonOptions, + input, output: [ { - file: path.join(targetDir, `${file}.mjs`), + file: targetFile(`${file}.mjs`), }, ], - external: ["jwt-decode"], }, - // Legacy Universal Module Definition, or “UMD”, with inlined dependencies. + // Legacy Universal Module Definition, or “UMD”. { - ...commonOptions, + input, output: [ { ...umdOutput, - file: path.join(targetDir, `${file}.js`), + file: targetFile(`${file}.js`), }, { ...umdOutput, - file: path.join(targetDir, `${file}.min.js`), + file: targetFile(`${file}.min.js`), sourcemap: true, sourcemapExcludeSources: true, plugins: [terser()], }, ], - plugins: [ - ...commonOptions.plugins, - inject({ - Promise: ["es6-promise/dist/es6-promise.min.js", "Promise"], - }), - ], }, ]; } diff --git a/js/libs/keycloak-js/src/keycloak.js b/js/libs/keycloak-js/src/keycloak.js index 485ab18126..02a54dce31 100755 --- a/js/libs/keycloak-js/src/keycloak.js +++ b/js/libs/keycloak-js/src/keycloak.js @@ -14,12 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { jwtDecode } from 'jwt-decode'; - -if (typeof Promise === 'undefined') { - throw Error('Keycloak requires an environment that supports Promises. Make sure that you include the appropriate polyfill.'); -} - function Keycloak (config) { if (!(this instanceof Keycloak)) { throw new Error("The 'Keycloak' constructor must be invoked with 'new'.") @@ -983,7 +977,7 @@ function Keycloak (config) { if (refreshToken) { kc.refreshToken = refreshToken; - kc.refreshTokenParsed = jwtDecode(refreshToken); + kc.refreshTokenParsed = decodeToken(refreshToken); } else { delete kc.refreshToken; delete kc.refreshTokenParsed; @@ -991,7 +985,7 @@ function Keycloak (config) { if (idToken) { kc.idToken = idToken; - kc.idTokenParsed = jwtDecode(idToken); + kc.idTokenParsed = decodeToken(idToken); } else { delete kc.idToken; delete kc.idTokenParsed; @@ -999,7 +993,7 @@ function Keycloak (config) { if (token) { kc.token = token; - kc.tokenParsed = jwtDecode(token); + kc.tokenParsed = decodeToken(token); kc.sessionId = kc.tokenParsed.sid; kc.authenticated = true; kc.subject = kc.tokenParsed.sub; @@ -1770,3 +1764,71 @@ async function sha256Digest(message) { const hash = await crypto.subtle.digest("SHA-256", data); return hash; } + +/** + * @param {string} token + */ +function decodeToken(token) { + const [header, payload] = token.split("."); + + if (typeof payload !== "string") { + throw new Error("Unable to decode token, payload not found."); + } + + let decoded; + + try { + decoded = base64UrlDecode(payload); + } catch (error) { + throw new Error("Unable to decode token, payload is not a valid Base64URL value.", { cause: error }); + } + + try { + return JSON.parse(decoded); + } catch (error) { + throw new Error("Unable to decode token, payload is not a valid JSON value.", { cause: error }); + } +} + +/** + * @param {string} input + */ +function base64UrlDecode(input) { + let output = input + .replaceAll("-", "+") + .replaceAll("_", "/"); + + switch (output.length % 4) { + case 0: + break; + case 2: + output += "=="; + break; + case 3: + output += "="; + break; + default: + throw new Error("Input is not of the correct length."); + } + + try { + return b64DecodeUnicode(output); + } catch (error) { + return atob(output); + } +} + +/** + * @param {string} input + */ +function b64DecodeUnicode(input) { + return decodeURIComponent(atob(input).replace(/(.)/g, (m, p) => { + let code = p.charCodeAt(0).toString(16).toUpperCase(); + + if (code.length < 2) { + code = "0" + code; + } + + return "%" + code; + })); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d2d163fd3..d1ad7688fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -379,29 +379,13 @@ importers: version: 10.9.2(@swc/core@1.7.22)(@types/node@22.7.2)(typescript@5.6.2) js/libs/keycloak-js: - dependencies: - jwt-decode: - specifier: ^4.0.0 - version: 4.0.0 devDependencies: - '@rollup/plugin-commonjs': - specifier: ^26.0.1 - version: 26.0.1(rollup@4.22.4) - '@rollup/plugin-inject': - specifier: ^5.0.5 - version: 5.0.5(rollup@4.22.4) - '@rollup/plugin-node-resolve': - specifier: ^15.3.0 - version: 15.3.0(rollup@4.22.4) '@rollup/plugin-terser': specifier: ^0.4.4 version: 0.4.4(rollup@4.22.4) '@rollup/plugin-typescript': specifier: ^12.1.0 version: 12.1.0(rollup@4.22.4)(tslib@2.7.0)(typescript@5.6.2) - es6-promise: - specifier: ^4.2.8 - version: 4.2.8 rollup: specifier: ^4.22.4 version: 4.22.4 @@ -1255,15 +1239,6 @@ packages: rollup: optional: true - '@rollup/plugin-inject@5.0.5': - resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - '@rollup/plugin-node-resolve@15.3.0': resolution: {integrity: sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==} engines: {node: '>=14.0.0'} @@ -2608,9 +2583,6 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} - es6-promise@4.2.8: - resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -3440,10 +3412,6 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} - jwt-decode@4.0.0: - resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} - engines: {node: '>=18'} - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -5803,14 +5771,6 @@ snapshots: optionalDependencies: rollup: 4.22.4 - '@rollup/plugin-inject@5.0.5(rollup@4.22.4)': - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.22.4) - estree-walker: 2.0.2 - magic-string: 0.30.11 - optionalDependencies: - rollup: 4.22.4 - '@rollup/plugin-node-resolve@15.3.0(rollup@4.22.4)': dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.22.4) @@ -7316,8 +7276,6 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 - es6-promise@4.2.8: {} - esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -8241,8 +8199,6 @@ snapshots: object.assign: 4.1.5 object.values: 1.2.0 - jwt-decode@4.0.0: {} - keyv@4.5.4: dependencies: json-buffer: 3.0.1