oidc-spa 8.2.12 → 8.3.0
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 +19 -5
- package/core/createOidc.js +9 -2
- package/core/createOidc.js.map +1 -1
- package/core/earlyInit.d.ts +6 -2
- package/core/earlyInit.js +156 -31
- package/core/earlyInit.js.map +1 -1
- package/core/loginSilent.js +7 -42
- package/core/loginSilent.js.map +1 -1
- package/esm/core/createOidc.js +9 -2
- package/esm/core/createOidc.js.map +1 -1
- package/esm/core/earlyInit.d.ts +6 -2
- package/esm/core/earlyInit.js +155 -31
- package/esm/core/earlyInit.js.map +1 -1
- package/esm/core/loginSilent.js +7 -42
- package/esm/core/loginSilent.js.map +1 -1
- package/esm/tools/Evt.js +18 -10
- package/esm/tools/Evt.js.map +1 -1
- package/package.json +2 -2
- package/src/core/createOidc.ts +8 -1
- package/src/core/earlyInit.ts +205 -40
- package/src/core/loginSilent.ts +18 -79
- package/src/tools/Evt.ts +17 -16
- package/src/vite-plugin/handleClientEntrypoint.ts +4 -6
- package/tools/Evt.js +18 -10
- package/tools/Evt.js.map +1 -1
- package/vite-plugin/handleClientEntrypoint.js +3 -1
- package/vite-plugin/handleClientEntrypoint.js.map +1 -1
- package/core/iframeMessageProtection.d.ts +0 -32
- package/core/iframeMessageProtection.js +0 -154
- package/core/iframeMessageProtection.js.map +0 -1
- package/esm/core/iframeMessageProtection.d.ts +0 -32
- package/esm/core/iframeMessageProtection.js +0 -149
- package/esm/core/iframeMessageProtection.js.map +0 -1
- package/esm/tools/asymmetricEncryption.d.ts +0 -18
- package/esm/tools/asymmetricEncryption.js +0 -85
- package/esm/tools/asymmetricEncryption.js.map +0 -1
- package/src/core/iframeMessageProtection.ts +0 -219
- package/src/tools/asymmetricEncryption.ts +0 -184
- package/tools/asymmetricEncryption.d.ts +0 -18
- package/tools/asymmetricEncryption.js +0 -90
- package/tools/asymmetricEncryption.js.map +0 -1
package/esm/core/loginSilent.js
CHANGED
|
@@ -6,8 +6,8 @@ import { getStateData, clearStateStore } from "./StateData";
|
|
|
6
6
|
import { getDownlinkAndRtt } from "../tools/getDownlinkAndRtt";
|
|
7
7
|
import { getIsDev } from "../tools/isDev";
|
|
8
8
|
import { addOrUpdateSearchParam } from "../tools/urlSearchParams";
|
|
9
|
-
import { initIframeMessageProtection } from "./iframeMessageProtection";
|
|
10
9
|
import { getIsOnline } from "../tools/getIsOnline";
|
|
10
|
+
import { getEvtIframeAuthResponse } from "./earlyInit";
|
|
11
11
|
export async function loginSilent(params) {
|
|
12
12
|
const { oidcClientTsUserManager, stateUrlParamValue_instance, configId, transformUrlBeforeRedirect, getExtraQueryParams, getExtraTokenParams, autoLogin, log } = params;
|
|
13
13
|
delay_until_online: {
|
|
@@ -33,9 +33,6 @@ export async function loginSilent(params) {
|
|
|
33
33
|
const dynamicDelay = rtt * 2.5 + BASE_DELAY_MS / (downlink + 1);
|
|
34
34
|
return Math.max(BASE_DELAY_MS, dynamicDelay);
|
|
35
35
|
})();
|
|
36
|
-
const { getIsReadyToReadPublicKeyMessage, startSessionStoragePublicKeyMaliciousWriteDetection, setSessionStoragePublicKey, decodeEncryptedAuth, getIsEncryptedAuthResponse, clearSessionStoragePublicKey } = await initIframeMessageProtection({
|
|
37
|
-
stateUrlParamValue: stateUrlParamValue_instance
|
|
38
|
-
});
|
|
39
36
|
let clearTimeouts;
|
|
40
37
|
{
|
|
41
38
|
let hasLoggedWarningMessage = false;
|
|
@@ -65,41 +62,11 @@ export async function loginSilent(params) {
|
|
|
65
62
|
}
|
|
66
63
|
};
|
|
67
64
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (event.origin !== window.location.origin) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (!getIsReadyToReadPublicKeyMessage({
|
|
74
|
-
stateUrlParamValue: stateUrlParamValue_instance,
|
|
75
|
-
message: event.data
|
|
76
|
-
})) {
|
|
65
|
+
const { unsubscribe: unsubscribe_evtIframeAuthResponse } = getEvtIframeAuthResponse().subscribe(authResponse => {
|
|
66
|
+
if (authResponse.state !== stateUrlParamValue_instance) {
|
|
77
67
|
return;
|
|
78
68
|
}
|
|
79
|
-
|
|
80
|
-
setSessionStoragePublicKey();
|
|
81
|
-
const dEncryptedAuthResponse = new Deferred();
|
|
82
|
-
listener = event => {
|
|
83
|
-
if (event.origin !== window.location.origin) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const message = event.data;
|
|
87
|
-
if (!getIsEncryptedAuthResponse({
|
|
88
|
-
stateUrlParamValue: stateUrlParamValue_instance,
|
|
89
|
-
message
|
|
90
|
-
})) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
window.removeEventListener("message", listener);
|
|
94
|
-
// NOTE: Acknowledge that we're also doing it later but
|
|
95
|
-
// since there's a aggressive write protection in place
|
|
96
|
-
// it's good to clear the key ASAP.
|
|
97
|
-
clearSessionStoragePublicKey();
|
|
98
|
-
dEncryptedAuthResponse.resolve(message);
|
|
99
|
-
};
|
|
100
|
-
window.addEventListener("message", listener, false);
|
|
101
|
-
const encryptedAuthResponse = await dEncryptedAuthResponse.pr;
|
|
102
|
-
const { authResponse } = await decodeEncryptedAuth({ encryptedAuthResponse });
|
|
69
|
+
unsubscribe_evtIframeAuthResponse();
|
|
103
70
|
const stateData = getStateData({ stateUrlParamValue: authResponse.state });
|
|
104
71
|
assert(stateData !== undefined, "765645");
|
|
105
72
|
assert(stateData.context === "iframe", "250711");
|
|
@@ -109,8 +76,7 @@ export async function loginSilent(params) {
|
|
|
109
76
|
outcome: "got auth response from iframe",
|
|
110
77
|
authResponse
|
|
111
78
|
});
|
|
112
|
-
};
|
|
113
|
-
window.addEventListener("message", listener, false);
|
|
79
|
+
});
|
|
114
80
|
const transformUrl_oidcClientTs = (url) => {
|
|
115
81
|
add_extra_query_params: {
|
|
116
82
|
if (getExtraQueryParams === undefined) {
|
|
@@ -132,7 +98,6 @@ export async function loginSilent(params) {
|
|
|
132
98
|
}
|
|
133
99
|
return url;
|
|
134
100
|
};
|
|
135
|
-
startSessionStoragePublicKeyMaliciousWriteDetection();
|
|
136
101
|
oidcClientTsUserManager
|
|
137
102
|
.signinSilent({
|
|
138
103
|
state: id({
|
|
@@ -146,7 +111,7 @@ export async function loginSilent(params) {
|
|
|
146
111
|
.then(oidcClientTsUser => {
|
|
147
112
|
assert(oidcClientTsUser !== null, "oidcClientTsUser is not supposed to be null here");
|
|
148
113
|
clearTimeouts({ wasSuccess: true });
|
|
149
|
-
|
|
114
|
+
unsubscribe_evtIframeAuthResponse();
|
|
150
115
|
dResult.resolve({
|
|
151
116
|
outcome: "token refreshed using refresh token",
|
|
152
117
|
oidcClientTsUser
|
|
@@ -156,9 +121,9 @@ export async function loginSilent(params) {
|
|
|
156
121
|
// error than timeout so we fail silently and let the timeout expire.
|
|
157
122
|
});
|
|
158
123
|
dResult.pr.then(result => {
|
|
159
|
-
clearSessionStoragePublicKey();
|
|
160
124
|
if (result.outcome === "timeout") {
|
|
161
125
|
clearStateStore({ stateUrlParamValue: stateUrlParamValue_instance });
|
|
126
|
+
unsubscribe_evtIframeAuthResponse();
|
|
162
127
|
}
|
|
163
128
|
});
|
|
164
129
|
return dResult.pr;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loginSilent.js","sourceRoot":"","sources":["../../src/core/loginSilent.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAkB,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"loginSilent.js","sourceRoot":"","sources":["../../src/core/loginSilent.ts"],"names":[],"mappings":"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"}
|
package/esm/tools/Evt.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { Deferred } from "./Deferred";
|
|
2
|
-
import { assert, is } from "../tools/tsafe/assert";
|
|
3
2
|
export function createEvt() {
|
|
4
|
-
const
|
|
5
|
-
const KEY = "event";
|
|
3
|
+
const listeners = [];
|
|
6
4
|
let postCount = 0;
|
|
7
5
|
const evt = {
|
|
8
6
|
subscribe: next => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
next(e.detail);
|
|
12
|
-
};
|
|
13
|
-
eventTarget.addEventListener(KEY, listener);
|
|
7
|
+
listeners.push(next);
|
|
8
|
+
let isActive = true;
|
|
14
9
|
return {
|
|
15
10
|
unsubscribe: () => {
|
|
16
|
-
|
|
11
|
+
if (!isActive) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
isActive = false;
|
|
15
|
+
const i = listeners.indexOf(next);
|
|
16
|
+
if (i >= 0) {
|
|
17
|
+
listeners.splice(i, 1);
|
|
18
|
+
}
|
|
17
19
|
}
|
|
18
20
|
};
|
|
19
21
|
},
|
|
@@ -27,7 +29,13 @@ export function createEvt() {
|
|
|
27
29
|
},
|
|
28
30
|
post: (data) => {
|
|
29
31
|
postCount++;
|
|
30
|
-
|
|
32
|
+
const snapshot = listeners.slice();
|
|
33
|
+
for (const l of snapshot) {
|
|
34
|
+
try {
|
|
35
|
+
l(data);
|
|
36
|
+
}
|
|
37
|
+
catch { }
|
|
38
|
+
}
|
|
31
39
|
},
|
|
32
40
|
get postCount() {
|
|
33
41
|
return postCount;
|
package/esm/tools/Evt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Evt.js","sourceRoot":"","sources":["../../src/tools/Evt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"Evt.js","sourceRoot":"","sources":["../../src/tools/Evt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAYtC,MAAM,UAAU,SAAS;IACrB,MAAM,SAAS,GAA6B,EAAE,CAAC;IAC/C,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,MAAM,GAAG,GAAW;QAChB,SAAS,EAAE,IAAI,CAAC,EAAE;YACd,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,IAAI,QAAQ,GAAG,IAAI,CAAC;YACpB,OAAO;gBACH,WAAW,EAAE,GAAG,EAAE;oBACd,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACZ,OAAO;oBACX,CAAC;oBACD,QAAQ,GAAG,KAAK,CAAC;oBACjB,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBAClC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBACT,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBAC3B,CAAC;gBACL,CAAC;aACJ,CAAC;QACN,CAAC;QACD,OAAO,EAAE,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,IAAI,QAAQ,EAAK,CAAC;YAC5B,MAAM,EAAE,WAAW,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;gBACzC,WAAW,EAAE,CAAC;gBACd,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC,CAAC,CAAC;YACH,OAAO,CAAC,CAAC,EAAE,CAAC;QAChB,CAAC;QACD,IAAI,EAAE,CAAC,IAAO,EAAE,EAAE;YACd,SAAS,EAAE,CAAC;YACZ,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;YACnC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACvB,IAAI,CAAC;oBACD,CAAC,CAAC,IAAI,CAAC,CAAC;gBACZ,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YACd,CAAC;QACL,CAAC;QACD,IAAI,SAAS;YACT,OAAO,SAAS,CAAC;QACrB,CAAC;KACJ,CAAC;IAEF,OAAO,GAAG,CAAC;AACf,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oidc-spa",
|
|
3
|
-
"version": "8.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "8.3.0",
|
|
4
|
+
"description": "OIDC Client for Client Centric Web Applications",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git://github.com/keycloakify/oidc-spa.git"
|
package/src/core/createOidc.ts
CHANGED
|
@@ -748,7 +748,14 @@ export async function createOidc_nonMemoized<
|
|
|
748
748
|
{
|
|
749
749
|
log?.(
|
|
750
750
|
`Handling login redirect auth response ${JSON.stringify(
|
|
751
|
-
|
|
751
|
+
{
|
|
752
|
+
...authResponse,
|
|
753
|
+
...(authResponse.code === undefined
|
|
754
|
+
? undefined
|
|
755
|
+
: {
|
|
756
|
+
code: authResponse.code.slice(0, 20) + "..."
|
|
757
|
+
})
|
|
758
|
+
},
|
|
752
759
|
null,
|
|
753
760
|
2
|
|
754
761
|
)}`
|
package/src/core/earlyInit.ts
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { getStateData, getIsStatQueryParamValue } from "./StateData";
|
|
2
2
|
import { assert, type Equals } from "../tools/tsafe/assert";
|
|
3
3
|
import type { AuthResponse } from "./AuthResponse";
|
|
4
|
-
import {
|
|
5
|
-
iframeMessageProtection_captureAndLockBuiltins,
|
|
6
|
-
postEncryptedAuthResponseToParent
|
|
7
|
-
} from "./iframeMessageProtection";
|
|
8
4
|
import { setOidcRequiredPostHydrationReplaceNavigationUrl } from "./requiredPostHydrationReplaceNavigationUrl";
|
|
9
5
|
import { setBASE_URL } from "./BASE_URL";
|
|
10
6
|
import { resolvePrShouldLoadApp } from "./prShouldLoadApp";
|
|
11
7
|
import { isBrowser } from "../tools/isBrowser";
|
|
8
|
+
import { createEvt, type Evt } from "../tools/Evt";
|
|
12
9
|
|
|
13
10
|
let hasEarlyInitBeenCalled = false;
|
|
14
11
|
|
|
12
|
+
const IFRAME_MESSAGE_PREFIX = "oidc-spa:cross-window-messaging:";
|
|
13
|
+
|
|
15
14
|
export function oidcEarlyInit(params: {
|
|
16
|
-
freezeFetch
|
|
17
|
-
freezeXMLHttpRequest
|
|
18
|
-
// NOTE: Made optional just to avoid breaking change.
|
|
19
|
-
// Will be made mandatory next major.
|
|
15
|
+
freezeFetch?: boolean;
|
|
16
|
+
freezeXMLHttpRequest?: boolean;
|
|
20
17
|
freezeWebSocket?: boolean;
|
|
18
|
+
freezePromise?: boolean;
|
|
19
|
+
safeMode?: boolean;
|
|
21
20
|
isPostLoginRedirectManual?: boolean;
|
|
22
21
|
BASE_URL?: string;
|
|
23
22
|
}) {
|
|
@@ -34,7 +33,9 @@ export function oidcEarlyInit(params: {
|
|
|
34
33
|
const {
|
|
35
34
|
freezeFetch,
|
|
36
35
|
freezeXMLHttpRequest,
|
|
37
|
-
freezeWebSocket
|
|
36
|
+
freezeWebSocket,
|
|
37
|
+
freezePromise,
|
|
38
|
+
safeMode = false,
|
|
38
39
|
isPostLoginRedirectManual = false,
|
|
39
40
|
BASE_URL
|
|
40
41
|
} = params;
|
|
@@ -42,52 +43,198 @@ export function oidcEarlyInit(params: {
|
|
|
42
43
|
const { shouldLoadApp } = handleOidcCallback({ isPostLoginRedirectManual });
|
|
43
44
|
|
|
44
45
|
if (shouldLoadApp) {
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
const createWriteError = (target: string) =>
|
|
47
|
+
new Error(
|
|
48
|
+
[
|
|
49
|
+
`oidc-spa: ${target} has been frozen for security reasons.`,
|
|
50
|
+
"Set `safeMode: false` in oidcEarlyInit() or in the Vite plugin configuration",
|
|
51
|
+
"to disable this restriction at the cost of security.",
|
|
52
|
+
"If you think this restriction is overzealous please open an issue at",
|
|
53
|
+
"https://github.com/keycloakify/oidc-spa"
|
|
54
|
+
].join(" ")
|
|
55
|
+
);
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
for (const name of [
|
|
58
|
+
"fetch",
|
|
59
|
+
"XMLHttpRequest",
|
|
60
|
+
"WebSocket",
|
|
61
|
+
"String",
|
|
62
|
+
"Object",
|
|
63
|
+
"Promise",
|
|
64
|
+
"Array",
|
|
65
|
+
"RegExp",
|
|
66
|
+
"TextEncoder",
|
|
67
|
+
"Uint8Array",
|
|
68
|
+
"Uint32Array",
|
|
69
|
+
"Response",
|
|
70
|
+
"Reflect",
|
|
71
|
+
"JSON",
|
|
72
|
+
"encodeURIComponent",
|
|
73
|
+
"decodeURIComponent",
|
|
74
|
+
"atob",
|
|
75
|
+
"btoa"
|
|
76
|
+
] as const) {
|
|
77
|
+
const doSkip = (() => {
|
|
78
|
+
switch (name) {
|
|
79
|
+
case "XMLHttpRequest":
|
|
80
|
+
if (freezeXMLHttpRequest !== undefined) {
|
|
81
|
+
return !freezeXMLHttpRequest;
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
case "fetch":
|
|
85
|
+
if (freezeFetch !== undefined) {
|
|
86
|
+
return !freezeFetch;
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
case "WebSocket":
|
|
90
|
+
if (freezeWebSocket !== undefined) {
|
|
91
|
+
return !freezeWebSocket;
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case "Promise":
|
|
95
|
+
if (freezePromise !== undefined) {
|
|
96
|
+
return !freezePromise;
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
50
100
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
}
|
|
101
|
+
return !safeMode;
|
|
102
|
+
})();
|
|
103
|
+
|
|
104
|
+
if (doSkip) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
58
107
|
|
|
59
|
-
|
|
60
|
-
|
|
108
|
+
const original = window[name];
|
|
109
|
+
|
|
110
|
+
if ("prototype" in original) {
|
|
111
|
+
for (const propertyName of Object.getOwnPropertyNames(original.prototype)) {
|
|
112
|
+
if (name === "Object" && propertyName === "toString") {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const pd = Object.getOwnPropertyDescriptor(original.prototype, propertyName);
|
|
117
|
+
|
|
118
|
+
assert(pd !== undefined);
|
|
119
|
+
|
|
120
|
+
if (!pd.configurable) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
Object.defineProperty(original.prototype, propertyName, {
|
|
125
|
+
enumerable: pd.enumerable,
|
|
126
|
+
configurable: false,
|
|
127
|
+
...("value" in pd
|
|
128
|
+
? {
|
|
129
|
+
get: () => pd.value,
|
|
130
|
+
set: () => {
|
|
131
|
+
throw createWriteError(`window.${name}.prototype.${propertyName}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
: {
|
|
135
|
+
get: pd.get,
|
|
136
|
+
set:
|
|
137
|
+
pd.set ??
|
|
138
|
+
(() => {
|
|
139
|
+
throw createWriteError(
|
|
140
|
+
`window.${name}.prototype.${propertyName}`
|
|
141
|
+
);
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
61
147
|
|
|
62
|
-
Object.freeze(
|
|
148
|
+
Object.freeze(original);
|
|
63
149
|
|
|
64
|
-
Object.defineProperty(
|
|
150
|
+
Object.defineProperty(window, name, {
|
|
65
151
|
configurable: false,
|
|
66
|
-
writable: false,
|
|
67
152
|
enumerable: true,
|
|
68
|
-
|
|
153
|
+
get: () => original,
|
|
154
|
+
set: () => {
|
|
155
|
+
throw createWriteError(`window.${name}`);
|
|
156
|
+
}
|
|
69
157
|
});
|
|
70
158
|
}
|
|
71
159
|
|
|
72
|
-
if (
|
|
73
|
-
const
|
|
160
|
+
if (safeMode) {
|
|
161
|
+
for (const name of ["call", "apply", "bind"] as const) {
|
|
162
|
+
const original = Function.prototype[name];
|
|
163
|
+
|
|
164
|
+
Object.defineProperty(Function.prototype, name, {
|
|
165
|
+
configurable: false,
|
|
166
|
+
enumerable: true,
|
|
167
|
+
get: () => original,
|
|
168
|
+
set: () => {
|
|
169
|
+
throw createWriteError(`window.Function.prototype.${name});`);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
74
174
|
|
|
75
|
-
|
|
76
|
-
Object.
|
|
175
|
+
const _MessageEvent_prototype_data_get = (() => {
|
|
176
|
+
const pd = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
|
|
77
177
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
178
|
+
assert(pd !== undefined);
|
|
179
|
+
|
|
180
|
+
const { get } = pd;
|
|
181
|
+
|
|
182
|
+
assert(get !== undefined);
|
|
183
|
+
|
|
184
|
+
return get;
|
|
185
|
+
})();
|
|
186
|
+
|
|
187
|
+
const _MessageEvent_prototype_origin_get = (() => {
|
|
188
|
+
const pd = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "origin");
|
|
189
|
+
|
|
190
|
+
assert(pd !== undefined);
|
|
191
|
+
|
|
192
|
+
const { get } = pd;
|
|
193
|
+
|
|
194
|
+
assert(get !== undefined);
|
|
195
|
+
|
|
196
|
+
return get;
|
|
197
|
+
})();
|
|
198
|
+
|
|
199
|
+
const _Event_prototype_stopImmediatePropagation_value = Event.prototype.stopImmediatePropagation;
|
|
200
|
+
|
|
201
|
+
const origin = window.location.origin;
|
|
202
|
+
|
|
203
|
+
window.addEventListener(
|
|
204
|
+
"message",
|
|
205
|
+
event => {
|
|
206
|
+
if (_MessageEvent_prototype_origin_get.call(event) !== origin) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const eventData: unknown = _MessageEvent_prototype_data_get.call(event);
|
|
211
|
+
|
|
212
|
+
if (typeof eventData !== "string") {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (!eventData.startsWith(IFRAME_MESSAGE_PREFIX)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
_Event_prototype_stopImmediatePropagation_value.call(event);
|
|
221
|
+
|
|
222
|
+
const authResponse: AuthResponse = JSON.parse(
|
|
223
|
+
eventData.slice(IFRAME_MESSAGE_PREFIX.length)
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
(evtIframeAuthResponse ??= createEvt()).post(authResponse);
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
capture: true,
|
|
230
|
+
once: false,
|
|
231
|
+
passive: false
|
|
232
|
+
}
|
|
233
|
+
);
|
|
85
234
|
|
|
86
235
|
if (BASE_URL !== undefined) {
|
|
87
236
|
setBASE_URL({ BASE_URL });
|
|
88
237
|
}
|
|
89
|
-
|
|
90
|
-
iframeMessageProtection_captureAndLockBuiltins();
|
|
91
238
|
}
|
|
92
239
|
|
|
93
240
|
resolvePrShouldLoadApp({ shouldLoadApp });
|
|
@@ -95,6 +242,12 @@ export function oidcEarlyInit(params: {
|
|
|
95
242
|
return { shouldLoadApp };
|
|
96
243
|
}
|
|
97
244
|
|
|
245
|
+
let evtIframeAuthResponse: Evt<AuthResponse> | undefined = undefined;
|
|
246
|
+
|
|
247
|
+
export function getEvtIframeAuthResponse() {
|
|
248
|
+
return (evtIframeAuthResponse ??= createEvt());
|
|
249
|
+
}
|
|
250
|
+
|
|
98
251
|
let redirectAuthResponse: AuthResponse | undefined = undefined;
|
|
99
252
|
|
|
100
253
|
export function getRedirectAuthResponse():
|
|
@@ -208,7 +361,19 @@ function handleOidcCallback(params: { isPostLoginRedirectManual?: boolean }): {
|
|
|
208
361
|
|
|
209
362
|
switch (stateData.context) {
|
|
210
363
|
case "iframe":
|
|
211
|
-
|
|
364
|
+
if (parent !== top) {
|
|
365
|
+
const errorMessage = [
|
|
366
|
+
"oidc-spa: For security reasons, refusing to post the auth response.",
|
|
367
|
+
"If you want your app to be framable use sessionRestorationMethod: 'full page redirect'."
|
|
368
|
+
].join(" ");
|
|
369
|
+
alert(errorMessage);
|
|
370
|
+
|
|
371
|
+
throw new Error(errorMessage);
|
|
372
|
+
}
|
|
373
|
+
parent.postMessage(
|
|
374
|
+
`${IFRAME_MESSAGE_PREFIX}${JSON.stringify(authResponse)}`,
|
|
375
|
+
location.origin
|
|
376
|
+
);
|
|
212
377
|
return { shouldLoadApp: false };
|
|
213
378
|
case "redirect": {
|
|
214
379
|
redirectAuthResponse = authResponse;
|
package/src/core/loginSilent.ts
CHANGED
|
@@ -11,8 +11,8 @@ import { getDownlinkAndRtt } from "../tools/getDownlinkAndRtt";
|
|
|
11
11
|
import { getIsDev } from "../tools/isDev";
|
|
12
12
|
import { type AuthResponse } from "./AuthResponse";
|
|
13
13
|
import { addOrUpdateSearchParam } from "../tools/urlSearchParams";
|
|
14
|
-
import { initIframeMessageProtection } from "./iframeMessageProtection";
|
|
15
14
|
import { getIsOnline } from "../tools/getIsOnline";
|
|
15
|
+
import { getEvtIframeAuthResponse } from "./earlyInit";
|
|
16
16
|
|
|
17
17
|
type ResultOfLoginSilent =
|
|
18
18
|
| {
|
|
@@ -87,17 +87,6 @@ export async function loginSilent(params: {
|
|
|
87
87
|
return Math.max(BASE_DELAY_MS, dynamicDelay);
|
|
88
88
|
})();
|
|
89
89
|
|
|
90
|
-
const {
|
|
91
|
-
getIsReadyToReadPublicKeyMessage,
|
|
92
|
-
startSessionStoragePublicKeyMaliciousWriteDetection,
|
|
93
|
-
setSessionStoragePublicKey,
|
|
94
|
-
decodeEncryptedAuth,
|
|
95
|
-
getIsEncryptedAuthResponse,
|
|
96
|
-
clearSessionStoragePublicKey
|
|
97
|
-
} = await initIframeMessageProtection({
|
|
98
|
-
stateUrlParamValue: stateUrlParamValue_instance
|
|
99
|
-
});
|
|
100
|
-
|
|
101
90
|
let clearTimeouts: (params: { wasSuccess: boolean }) => void;
|
|
102
91
|
{
|
|
103
92
|
let hasLoggedWarningMessage = false;
|
|
@@ -136,75 +125,28 @@ export async function loginSilent(params: {
|
|
|
136
125
|
};
|
|
137
126
|
}
|
|
138
127
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (event.origin !== window.location.origin) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
!getIsReadyToReadPublicKeyMessage({
|
|
148
|
-
stateUrlParamValue: stateUrlParamValue_instance,
|
|
149
|
-
message: event.data
|
|
150
|
-
})
|
|
151
|
-
) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
window.removeEventListener("message", listener, false);
|
|
156
|
-
|
|
157
|
-
setSessionStoragePublicKey();
|
|
158
|
-
|
|
159
|
-
const dEncryptedAuthResponse = new Deferred<string>();
|
|
160
|
-
|
|
161
|
-
listener = event => {
|
|
162
|
-
if (event.origin !== window.location.origin) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const message = event.data;
|
|
167
|
-
|
|
168
|
-
if (
|
|
169
|
-
!getIsEncryptedAuthResponse({
|
|
170
|
-
stateUrlParamValue: stateUrlParamValue_instance,
|
|
171
|
-
message
|
|
172
|
-
})
|
|
173
|
-
) {
|
|
128
|
+
const { unsubscribe: unsubscribe_evtIframeAuthResponse } = getEvtIframeAuthResponse().subscribe(
|
|
129
|
+
authResponse => {
|
|
130
|
+
if (authResponse.state !== stateUrlParamValue_instance) {
|
|
174
131
|
return;
|
|
175
132
|
}
|
|
176
133
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// NOTE: Acknowledge that we're also doing it later but
|
|
180
|
-
// since there's a aggressive write protection in place
|
|
181
|
-
// it's good to clear the key ASAP.
|
|
182
|
-
clearSessionStoragePublicKey();
|
|
183
|
-
|
|
184
|
-
dEncryptedAuthResponse.resolve(message);
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
window.addEventListener("message", listener, false);
|
|
188
|
-
|
|
189
|
-
const encryptedAuthResponse = await dEncryptedAuthResponse.pr;
|
|
134
|
+
unsubscribe_evtIframeAuthResponse();
|
|
190
135
|
|
|
191
|
-
|
|
136
|
+
const stateData = getStateData({ stateUrlParamValue: authResponse.state });
|
|
192
137
|
|
|
193
|
-
|
|
138
|
+
assert(stateData !== undefined, "765645");
|
|
139
|
+
assert(stateData.context === "iframe", "250711");
|
|
140
|
+
assert(stateData.configId === configId, "4922732");
|
|
194
141
|
|
|
195
|
-
|
|
196
|
-
assert(stateData.context === "iframe", "250711");
|
|
197
|
-
assert(stateData.configId === configId, "4922732");
|
|
142
|
+
clearTimeouts({ wasSuccess: true });
|
|
198
143
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
window.addEventListener("message", listener, false);
|
|
144
|
+
dResult.resolve({
|
|
145
|
+
outcome: "got auth response from iframe",
|
|
146
|
+
authResponse
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
);
|
|
208
150
|
|
|
209
151
|
const transformUrl_oidcClientTs = (url: string) => {
|
|
210
152
|
add_extra_query_params: {
|
|
@@ -232,8 +174,6 @@ export async function loginSilent(params: {
|
|
|
232
174
|
return url;
|
|
233
175
|
};
|
|
234
176
|
|
|
235
|
-
startSessionStoragePublicKeyMaliciousWriteDetection();
|
|
236
|
-
|
|
237
177
|
oidcClientTsUserManager
|
|
238
178
|
.signinSilent({
|
|
239
179
|
state: id<StateData.IFrame>({
|
|
@@ -250,7 +190,7 @@ export async function loginSilent(params: {
|
|
|
250
190
|
assert(oidcClientTsUser !== null, "oidcClientTsUser is not supposed to be null here");
|
|
251
191
|
|
|
252
192
|
clearTimeouts({ wasSuccess: true });
|
|
253
|
-
|
|
193
|
+
unsubscribe_evtIframeAuthResponse();
|
|
254
194
|
|
|
255
195
|
dResult.resolve({
|
|
256
196
|
outcome: "token refreshed using refresh token",
|
|
@@ -264,10 +204,9 @@ export async function loginSilent(params: {
|
|
|
264
204
|
);
|
|
265
205
|
|
|
266
206
|
dResult.pr.then(result => {
|
|
267
|
-
clearSessionStoragePublicKey();
|
|
268
|
-
|
|
269
207
|
if (result.outcome === "timeout") {
|
|
270
208
|
clearStateStore({ stateUrlParamValue: stateUrlParamValue_instance });
|
|
209
|
+
unsubscribe_evtIframeAuthResponse();
|
|
271
210
|
}
|
|
272
211
|
});
|
|
273
212
|
|