Strip remaining dependencies from Keycloak JS (#33295)

Closes #33277

Signed-off-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
Jon Koops 2024-09-26 15:06:32 +02:00 committed by GitHub
parent ccfdf9c251
commit cdfd46f191
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 83 additions and 85 deletions

View file

@ -68,16 +68,9 @@
"authentication" "authentication"
], ],
"devDependencies": { "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-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.0", "@rollup/plugin-typescript": "^12.1.0",
"es6-promise": "^4.2.8",
"rollup": "^4.22.4", "rollup": "^4.22.4",
"shx": "^0.3.4" "shx": "^0.3.4"
},
"dependencies": {
"jwt-decode": "^4.0.0"
} }
} }

View file

@ -1,7 +1,4 @@
import commonjs from "@rollup/plugin-commonjs"; import terser from "@rollup/plugin-terser";
import inject from "@rollup/plugin-inject";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import terser from '@rollup/plugin-terser';
import path from "node:path"; import path from "node:path";
import type { OutputOptions, RollupOptions } from "rollup"; import type { OutputOptions, RollupOptions } from "rollup";
import { defineConfig } from "rollup"; import { defineConfig } from "rollup";
@ -12,18 +9,15 @@ interface DefineOptionsArgs {
amdId: string; amdId: string;
} }
const sourceFile = (file: string) => path.join("src", file);
const targetFile = (file: string) => path.join("dist", file);
function defineOptions({ function defineOptions({
file, file,
name, name,
amdId, amdId,
}: DefineOptionsArgs): RollupOptions[] { }: DefineOptionsArgs): RollupOptions[] {
const sourceDir = "src"; const input = sourceFile(`${file}.js`);
const targetDir = "dist";
const commonOptions = {
input: path.join(sourceDir, `${file}.js`),
plugins: [commonjs(), nodeResolve()],
} satisfies RollupOptions;
const umdOutput: OutputOptions = { const umdOutput: OutputOptions = {
format: "umd", format: "umd",
name, name,
@ -31,38 +25,31 @@ function defineOptions({
}; };
return [ return [
// Modern ES module variant, with externalized dependencies. // Modern ES module variant.
{ {
...commonOptions, input,
output: [ 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: [ output: [
{ {
...umdOutput, ...umdOutput,
file: path.join(targetDir, `${file}.js`), file: targetFile(`${file}.js`),
}, },
{ {
...umdOutput, ...umdOutput,
file: path.join(targetDir, `${file}.min.js`), file: targetFile(`${file}.min.js`),
sourcemap: true, sourcemap: true,
sourcemapExcludeSources: true, sourcemapExcludeSources: true,
plugins: [terser()], plugins: [terser()],
}, },
], ],
plugins: [
...commonOptions.plugins,
inject({
Promise: ["es6-promise/dist/es6-promise.min.js", "Promise"],
}),
],
}, },
]; ];
} }

View file

@ -14,12 +14,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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) { function Keycloak (config) {
if (!(this instanceof Keycloak)) { if (!(this instanceof Keycloak)) {
throw new Error("The 'Keycloak' constructor must be invoked with 'new'.") throw new Error("The 'Keycloak' constructor must be invoked with 'new'.")
@ -983,7 +977,7 @@ function Keycloak (config) {
if (refreshToken) { if (refreshToken) {
kc.refreshToken = refreshToken; kc.refreshToken = refreshToken;
kc.refreshTokenParsed = jwtDecode(refreshToken); kc.refreshTokenParsed = decodeToken(refreshToken);
} else { } else {
delete kc.refreshToken; delete kc.refreshToken;
delete kc.refreshTokenParsed; delete kc.refreshTokenParsed;
@ -991,7 +985,7 @@ function Keycloak (config) {
if (idToken) { if (idToken) {
kc.idToken = idToken; kc.idToken = idToken;
kc.idTokenParsed = jwtDecode(idToken); kc.idTokenParsed = decodeToken(idToken);
} else { } else {
delete kc.idToken; delete kc.idToken;
delete kc.idTokenParsed; delete kc.idTokenParsed;
@ -999,7 +993,7 @@ function Keycloak (config) {
if (token) { if (token) {
kc.token = token; kc.token = token;
kc.tokenParsed = jwtDecode(token); kc.tokenParsed = decodeToken(token);
kc.sessionId = kc.tokenParsed.sid; kc.sessionId = kc.tokenParsed.sid;
kc.authenticated = true; kc.authenticated = true;
kc.subject = kc.tokenParsed.sub; kc.subject = kc.tokenParsed.sub;
@ -1770,3 +1764,71 @@ async function sha256Digest(message) {
const hash = await crypto.subtle.digest("SHA-256", data); const hash = await crypto.subtle.digest("SHA-256", data);
return hash; 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;
}));
}

View file

@ -379,29 +379,13 @@ importers:
version: 10.9.2(@swc/core@1.7.22)(@types/node@22.7.2)(typescript@5.6.2) version: 10.9.2(@swc/core@1.7.22)(@types/node@22.7.2)(typescript@5.6.2)
js/libs/keycloak-js: js/libs/keycloak-js:
dependencies:
jwt-decode:
specifier: ^4.0.0
version: 4.0.0
devDependencies: 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': '@rollup/plugin-terser':
specifier: ^0.4.4 specifier: ^0.4.4
version: 0.4.4(rollup@4.22.4) version: 0.4.4(rollup@4.22.4)
'@rollup/plugin-typescript': '@rollup/plugin-typescript':
specifier: ^12.1.0 specifier: ^12.1.0
version: 12.1.0(rollup@4.22.4)(tslib@2.7.0)(typescript@5.6.2) 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: rollup:
specifier: ^4.22.4 specifier: ^4.22.4
version: 4.22.4 version: 4.22.4
@ -1255,15 +1239,6 @@ packages:
rollup: rollup:
optional: true 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': '@rollup/plugin-node-resolve@15.3.0':
resolution: {integrity: sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==} resolution: {integrity: sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@ -2608,9 +2583,6 @@ packages:
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
es6-promise@4.2.8:
resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
esbuild@0.21.5: esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -3440,10 +3412,6 @@ packages:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'} engines: {node: '>=4.0'}
jwt-decode@4.0.0:
resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==}
engines: {node: '>=18'}
keyv@4.5.4: keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
@ -5803,14 +5771,6 @@ snapshots:
optionalDependencies: optionalDependencies:
rollup: 4.22.4 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)': '@rollup/plugin-node-resolve@15.3.0(rollup@4.22.4)':
dependencies: dependencies:
'@rollup/pluginutils': 5.1.0(rollup@4.22.4) '@rollup/pluginutils': 5.1.0(rollup@4.22.4)
@ -7316,8 +7276,6 @@ snapshots:
is-date-object: 1.0.5 is-date-object: 1.0.5
is-symbol: 1.0.4 is-symbol: 1.0.4
es6-promise@4.2.8: {}
esbuild@0.21.5: esbuild@0.21.5:
optionalDependencies: optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5 '@esbuild/aix-ppc64': 0.21.5
@ -8241,8 +8199,6 @@ snapshots:
object.assign: 4.1.5 object.assign: 4.1.5
object.values: 1.2.0 object.values: 1.2.0
jwt-decode@4.0.0: {}
keyv@4.5.4: keyv@4.5.4:
dependencies: dependencies:
json-buffer: 3.0.1 json-buffer: 3.0.1