oidc-spa 8.5.5 → 8.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/core/createOidc.js +18 -3
- package/core/createOidc.js.map +1 -1
- package/core/tokenExfiltrationDefense.js +17 -44
- package/core/tokenExfiltrationDefense.js.map +1 -1
- package/core/tokenPlaceholderSubstitution.d.ts +2 -5
- package/core/tokenPlaceholderSubstitution.js +73 -38
- package/core/tokenPlaceholderSubstitution.js.map +1 -1
- package/esm/core/createOidc.js +18 -3
- package/esm/core/createOidc.js.map +1 -1
- package/esm/core/tokenExfiltrationDefense.js +18 -45
- package/esm/core/tokenExfiltrationDefense.js.map +1 -1
- package/esm/core/tokenPlaceholderSubstitution.d.ts +2 -5
- package/esm/core/tokenPlaceholderSubstitution.js +72 -37
- package/esm/core/tokenPlaceholderSubstitution.js.map +1 -1
- package/esm/keycloak/keycloak-js/Keycloak.d.ts +1 -1
- package/esm/keycloak/keycloak-js/Keycloak.js +1 -1
- package/keycloak/keycloak-js/Keycloak.d.ts +1 -1
- package/keycloak/keycloak-js/Keycloak.js +1 -1
- package/package.json +1 -1
- package/src/core/createOidc.ts +20 -2
- package/src/core/tokenExfiltrationDefense.ts +18 -45
- package/src/core/tokenPlaceholderSubstitution.ts +98 -45
- package/src/keycloak/keycloak-js/Keycloak.ts +1 -1
- package/src/vite-plugin/vite-plugin.ts +1 -1
- package/vite-plugin/vite-plugin.d.ts +1 -1
- package/vite-plugin/vite-plugin.js +1 -1
- package/vite-plugin/vite-plugin.js.map +1 -1
|
@@ -2,7 +2,7 @@ import { assert } from "../tools/tsafe/assert";
|
|
|
2
2
|
|
|
3
3
|
let isTokenSubstitutionEnabled = false;
|
|
4
4
|
|
|
5
|
-
export function
|
|
5
|
+
export function markTokenSubstitutionAsEnabled() {
|
|
6
6
|
isTokenSubstitutionEnabled = true;
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -18,10 +18,61 @@ type Tokens = {
|
|
|
18
18
|
|
|
19
19
|
const entries: {
|
|
20
20
|
configId: string;
|
|
21
|
-
tokens: Tokens;
|
|
22
21
|
id: number;
|
|
22
|
+
tokens: Tokens;
|
|
23
|
+
tokens_placeholder: Tokens;
|
|
23
24
|
}[] = [];
|
|
24
25
|
|
|
26
|
+
function generatePlaceholderForToken(params: {
|
|
27
|
+
tokenType: "id_token" | "access_token" | "refresh_token";
|
|
28
|
+
token_real: string;
|
|
29
|
+
id: number;
|
|
30
|
+
}): string {
|
|
31
|
+
const { tokenType, token_real, id } = params;
|
|
32
|
+
|
|
33
|
+
const match = token_real.match(/^([A-Za-z0-9\-_]+)\.([A-Za-z0-9\-_]+)\.([A-Za-z0-9\-_]+)$/);
|
|
34
|
+
|
|
35
|
+
if (match === null) {
|
|
36
|
+
assert(tokenType !== "id_token", "39232932927");
|
|
37
|
+
return `${tokenType}_placeholder_${id}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const [, header_b64, payload_b64, signature_b64] = match;
|
|
41
|
+
|
|
42
|
+
const signatureByteLength = (() => {
|
|
43
|
+
const b64 = signature_b64
|
|
44
|
+
.replace(/-/g, "+")
|
|
45
|
+
.replace(/_/g, "/")
|
|
46
|
+
.padEnd(Math.ceil(signature_b64.length / 4) * 4, "=");
|
|
47
|
+
|
|
48
|
+
const padding = b64.endsWith("==") ? 2 : b64.endsWith("=") ? 1 : 0;
|
|
49
|
+
return (b64.length * 3) / 4 - padding;
|
|
50
|
+
})();
|
|
51
|
+
|
|
52
|
+
const targetSigB64Length = Math.ceil((signatureByteLength * 4) / 3);
|
|
53
|
+
|
|
54
|
+
const sig_placeholder = (function makeZeroPaddedBase64UrlString(
|
|
55
|
+
targetLength: number,
|
|
56
|
+
seed: string
|
|
57
|
+
): string {
|
|
58
|
+
const PAD = "A";
|
|
59
|
+
|
|
60
|
+
let out = seed.slice(0, targetLength);
|
|
61
|
+
|
|
62
|
+
if (out.length < targetLength) {
|
|
63
|
+
out = out + PAD.repeat(targetLength - out.length);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (out.length % 4 === 1) {
|
|
67
|
+
out = out.slice(0, -1) + PAD;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return out;
|
|
71
|
+
})(targetSigB64Length, `sig_placeholder_${id}_`);
|
|
72
|
+
|
|
73
|
+
return `${header_b64}.${payload_b64}.${sig_placeholder}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
25
76
|
let counter = Math.floor(Math.random() * 1_000_000) + 1_000_000;
|
|
26
77
|
|
|
27
78
|
export function getTokensPlaceholders(params: { configId: string; tokens: Tokens }): Tokens {
|
|
@@ -48,66 +99,68 @@ export function getTokensPlaceholders(params: { configId: string; tokens: Tokens
|
|
|
48
99
|
const id = counter++;
|
|
49
100
|
|
|
50
101
|
const entry_new: (typeof entries)[number] = {
|
|
51
|
-
id,
|
|
52
102
|
configId,
|
|
103
|
+
id,
|
|
53
104
|
tokens: {
|
|
54
|
-
accessToken: tokens.accessToken,
|
|
55
105
|
idToken: tokens.idToken,
|
|
106
|
+
accessToken: tokens.accessToken,
|
|
56
107
|
refreshToken: tokens.refreshToken
|
|
108
|
+
},
|
|
109
|
+
tokens_placeholder: {
|
|
110
|
+
idToken: generatePlaceholderForToken({
|
|
111
|
+
tokenType: "id_token",
|
|
112
|
+
id,
|
|
113
|
+
token_real: tokens.idToken
|
|
114
|
+
}),
|
|
115
|
+
accessToken: generatePlaceholderForToken({
|
|
116
|
+
tokenType: "access_token",
|
|
117
|
+
id,
|
|
118
|
+
token_real: tokens.accessToken
|
|
119
|
+
}),
|
|
120
|
+
refreshToken:
|
|
121
|
+
tokens.refreshToken === undefined
|
|
122
|
+
? undefined
|
|
123
|
+
: generatePlaceholderForToken({
|
|
124
|
+
tokenType: "refresh_token",
|
|
125
|
+
id,
|
|
126
|
+
token_real: tokens.refreshToken
|
|
127
|
+
})
|
|
57
128
|
}
|
|
58
129
|
};
|
|
59
130
|
|
|
60
131
|
entries.push(entry_new);
|
|
61
132
|
|
|
62
|
-
return
|
|
63
|
-
accessToken: `access_token_placeholder_${id}`,
|
|
64
|
-
idToken: `id_token_placeholder_${id}`,
|
|
65
|
-
refreshToken: tokens.refreshToken === undefined ? undefined : `refresh_token_placeholder_${id}`
|
|
66
|
-
};
|
|
133
|
+
return entry_new.tokens_placeholder;
|
|
67
134
|
}
|
|
68
135
|
|
|
69
|
-
export function substitutePlaceholderByRealToken(
|
|
70
|
-
text
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
const { text, doEncodeUriComponent } = params;
|
|
136
|
+
export function substitutePlaceholderByRealToken(text: string): string {
|
|
137
|
+
if (!text.includes("_placeholder_")) {
|
|
138
|
+
return text;
|
|
139
|
+
}
|
|
74
140
|
|
|
75
141
|
let text_modified = text;
|
|
76
142
|
|
|
77
|
-
for (const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
const entry = entries.find(e => e.id === id);
|
|
86
|
-
|
|
87
|
-
if (!entry) {
|
|
88
|
-
throw new Error(
|
|
89
|
-
[
|
|
90
|
-
"oidc-spa: Outdated token used to make a request.",
|
|
91
|
-
"Token should not be stored at the application level, when a token",
|
|
92
|
-
"is needed, it should be requested and used immediately."
|
|
93
|
-
].join(" ")
|
|
94
|
-
);
|
|
95
|
-
}
|
|
143
|
+
for (const entry of entries) {
|
|
144
|
+
if (!text.includes(`${entry.id}`)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for (const tokenType of ["idToken", "accessToken", "refreshToken"] as const) {
|
|
149
|
+
const placeholder = entry.tokens_placeholder[tokenType];
|
|
96
150
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return entry.tokens.accessToken;
|
|
101
|
-
case "id_token":
|
|
102
|
-
return entry.tokens.idToken;
|
|
103
|
-
case "refresh_token":
|
|
104
|
-
assert(entry.tokens.refreshToken !== undefined, "204392284");
|
|
105
|
-
return entry.tokens.refreshToken;
|
|
151
|
+
if (tokenType === "refreshToken") {
|
|
152
|
+
if (placeholder === undefined) {
|
|
153
|
+
continue;
|
|
106
154
|
}
|
|
107
|
-
}
|
|
155
|
+
}
|
|
156
|
+
assert(placeholder !== undefined, "023948092393");
|
|
157
|
+
|
|
158
|
+
const realToken = entry.tokens[tokenType];
|
|
108
159
|
|
|
109
|
-
|
|
110
|
-
|
|
160
|
+
assert(realToken !== undefined, "02394809239328");
|
|
161
|
+
|
|
162
|
+
text_modified = text_modified.split(placeholder).join(realToken);
|
|
163
|
+
}
|
|
111
164
|
}
|
|
112
165
|
|
|
113
166
|
return text_modified;
|
|
@@ -71,7 +71,7 @@ type ConstructorParams = KeycloakServerConfig & {
|
|
|
71
71
|
* This module provides a drop-in replacement for `keycloak-js`,
|
|
72
72
|
* designed for teams migrating to `oidc-spa` with minimal changes.
|
|
73
73
|
*
|
|
74
|
-
*
|
|
74
|
+
* While the import path is `oidc-spa/keycloak-js`, this is *not* a re-export or patch —
|
|
75
75
|
* it is a full alternative implementation aligned with the `keycloak-js` API.
|
|
76
76
|
*/
|
|
77
77
|
export class Keycloak {
|
|
@@ -11,7 +11,7 @@ export type OidcSpaVitePluginParams =
|
|
|
11
11
|
| Omit<ParamsOfEarlyInit, "BASE_URL">
|
|
12
12
|
| Omit<ParamsOfEarlyInit_legacy, "BASE_URL">;
|
|
13
13
|
|
|
14
|
-
export function oidcSpa(params: OidcSpaVitePluginParams) {
|
|
14
|
+
export function oidcSpa(params: OidcSpaVitePluginParams = {}) {
|
|
15
15
|
let load_handleClientEntrypoint:
|
|
16
16
|
| ReturnType<typeof createHandleClientEntrypoint>["load_handleClientEntrypoint"]
|
|
17
17
|
| undefined = undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
import type { ParamsOfEarlyInit, ParamsOfEarlyInit_legacy } from "../core/earlyInit";
|
|
3
3
|
export type OidcSpaVitePluginParams = Omit<ParamsOfEarlyInit, "BASE_URL"> | Omit<ParamsOfEarlyInit_legacy, "BASE_URL">;
|
|
4
|
-
export declare function oidcSpa(params
|
|
4
|
+
export declare function oidcSpa(params?: OidcSpaVitePluginParams): Plugin<any>;
|
|
@@ -7,7 +7,7 @@ const handleServerEntrypoint_1 = require("./handleServerEntrypoint");
|
|
|
7
7
|
const manageOptimizedDeps_1 = require("./manageOptimizedDeps");
|
|
8
8
|
const transformTanstackRouterCreateFileRoute_1 = require("./transformTanstackRouterCreateFileRoute");
|
|
9
9
|
const projectType_1 = require("./projectType");
|
|
10
|
-
function oidcSpa(params) {
|
|
10
|
+
function oidcSpa(params = {}) {
|
|
11
11
|
let load_handleClientEntrypoint = undefined;
|
|
12
12
|
let load_handleServerEntrypoint = undefined;
|
|
13
13
|
let projectType = undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-plugin.js","sourceRoot":"","sources":["../src/vite-plugin/vite-plugin.ts"],"names":[],"mappings":";;AAaA,0BA4FC;AAxGD,kDAA+C;AAE/C,qEAAwE;AACxE,qEAAwE;AACxE,+DAA4D;AAC5D,qGAAoF;AACpF,+CAAiE;AAMjE,SAAgB,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"vite-plugin.js","sourceRoot":"","sources":["../src/vite-plugin/vite-plugin.ts"],"names":[],"mappings":";;AAaA,0BA4FC;AAxGD,kDAA+C;AAE/C,qEAAwE;AACxE,qEAAwE;AACxE,+DAA4D;AAC5D,qGAAoF;AACpF,+CAAiE;AAMjE,SAAgB,OAAO,CAAC,SAAkC,EAAE;IACxD,IAAI,2BAA2B,GAEb,SAAS,CAAC;IAC5B,IAAI,2BAA2B,GAEb,SAAS,CAAC;IAE5B,IAAI,WAAW,GAA4B,SAAS,CAAC;IAErD,MAAM,MAAM,GAAW;QACnB,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,KAAK;QACd,MAAM,CAAC,UAAU;YACb,MAAM,WAAW,GAAG,IAAA,4BAAc,EAAC;gBAC/B,WAAW,EACP,UAAU,CAAC,OAAO;oBACd,EAAE,IAAI,EAAE;qBACP,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,YAAY,MAAM,CAAC;qBAC1C,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,MAAM,CAAC;qBAClC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;aAC5C,CAAC,CAAC;YAEH,UAAU,GAAG,IAAA,yCAAmB,EAAC,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;YAC9D,OAAO,UAAU,CAAC;QACtB,CAAC;QACD,cAAc,CAAC,cAAc;YACzB,WAAW,GAAG,IAAA,4BAAc,EAAC;gBACzB,WAAW,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;aAC9D,CAAC,CAAC;YAEH,2BAA2B,GAAG,IAAA,qDAA4B,EAAC;gBACvD,uBAAuB,EAAE,MAAM;gBAC/B,cAAc;gBACd,WAAW;aACd,CAAC,CAAC,2BAA2B,CAAC;YAE/B,2BAA2B,GAAG,IAAA,qDAA4B,EAAC;gBACvD,cAAc;gBACd,WAAW;aACd,CAAC,CAAC,2BAA2B,CAAC;QACnC,CAAC;QACD,SAAS,CAAC,IAAI,EAAE,EAAE;YACd,IAAI,WAAW,GAA2B,IAAI,CAAC;YAE/C,IAAA,eAAM,EAAC,WAAW,KAAK,SAAS,CAAC,CAAC;YAElC,uCAAuC,EAAE,CAAC;gBACtC,IAAI,WAAW,KAAK,gBAAgB,EAAE,CAAC;oBACnC,MAAM,uCAAuC,CAAC;gBAClD,CAAC;gBAED,WAAW,GAAG,IAAA,iEAAwB,EAAC;oBACnC,IAAI;oBACJ,EAAE;iBACL,CAAC,CAAC;YACP,CAAC;YAED,OAAO,WAAW,CAAC;QACvB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE;YACT,CAAC;gBACG,IAAA,eAAM,EAAC,2BAA2B,KAAK,SAAS,CAAC,CAAC;gBAElD,MAAM,CAAC,GAAG,MAAM,2BAA2B,CAAC;oBACxC,EAAE;oBACF,aAAa,EAAE,IAAI;iBACtB,CAAC,CAAC;gBAEH,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;oBACb,OAAO,CAAC,CAAC;gBACb,CAAC;YACL,CAAC;YAED,CAAC;gBACG,IAAA,eAAM,EAAC,2BAA2B,KAAK,SAAS,CAAC,CAAC;gBAElD,MAAM,CAAC,GAAG,MAAM,2BAA2B,CAAC;oBACxC,EAAE;oBACF,aAAa,EAAE,IAAI;iBACtB,CAAC,CAAC;gBAEH,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;oBACb,OAAO,CAAC,CAAC;gBACb,CAAC;YACL,CAAC;YAED,OAAO,IAAI,CAAC;QAChB,CAAC;KACJ,CAAC;IAEF,OAAO,MAAM,CAAC;AAClB,CAAC"}
|