oidc-spa 8.2.12 → 8.3.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 +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 +168 -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 +167 -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 +220 -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.1",
|
|
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,213 @@ 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: Monkey patching of ${target} has been blocked for security reasons.`,
|
|
50
|
+
"You can disable this restriction by setting `safeMode: false` in `oidcEarlyInit()`",
|
|
51
|
+
"or in your Vite plugin configuration,",
|
|
52
|
+
"but please note this will reduce security.",
|
|
53
|
+
"If you believe this restriction is too strict, please open an issue at:",
|
|
54
|
+
"https://github.com/keycloakify/oidc-spa",
|
|
55
|
+
"We're still identifying real-world blockers and can safely add exceptions where needed.",
|
|
56
|
+
"For now, we prefer to err on the side of hardening rather than exposure."
|
|
57
|
+
].join(" ")
|
|
58
|
+
);
|
|
47
59
|
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
for (const name of [
|
|
61
|
+
"fetch",
|
|
62
|
+
"XMLHttpRequest",
|
|
63
|
+
"WebSocket",
|
|
64
|
+
"String",
|
|
65
|
+
"Object",
|
|
66
|
+
"Promise",
|
|
67
|
+
"Array",
|
|
68
|
+
"RegExp",
|
|
69
|
+
"TextEncoder",
|
|
70
|
+
"Uint8Array",
|
|
71
|
+
"Uint32Array",
|
|
72
|
+
"Response",
|
|
73
|
+
"Reflect",
|
|
74
|
+
"JSON",
|
|
75
|
+
"encodeURIComponent",
|
|
76
|
+
"decodeURIComponent",
|
|
77
|
+
"atob",
|
|
78
|
+
"btoa"
|
|
79
|
+
] as const) {
|
|
80
|
+
const doSkip = (() => {
|
|
81
|
+
switch (name) {
|
|
82
|
+
case "XMLHttpRequest":
|
|
83
|
+
if (freezeXMLHttpRequest !== undefined) {
|
|
84
|
+
return !freezeXMLHttpRequest;
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
case "fetch":
|
|
88
|
+
if (freezeFetch !== undefined) {
|
|
89
|
+
return !freezeFetch;
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
case "WebSocket":
|
|
93
|
+
if (freezeWebSocket !== undefined) {
|
|
94
|
+
return !freezeWebSocket;
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
case "Promise":
|
|
98
|
+
if (freezePromise !== undefined) {
|
|
99
|
+
return !freezePromise;
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
50
103
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
}
|
|
104
|
+
return !safeMode;
|
|
105
|
+
})();
|
|
106
|
+
|
|
107
|
+
if (doSkip) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
58
110
|
|
|
59
|
-
|
|
60
|
-
|
|
111
|
+
const original = window[name];
|
|
112
|
+
|
|
113
|
+
if ("prototype" in original) {
|
|
114
|
+
for (const propertyName of Object.getOwnPropertyNames(original.prototype)) {
|
|
115
|
+
if (name === "Object") {
|
|
116
|
+
if (
|
|
117
|
+
propertyName === "toString" ||
|
|
118
|
+
propertyName === "constructor" ||
|
|
119
|
+
propertyName === "valueOf"
|
|
120
|
+
) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (name === "Array") {
|
|
126
|
+
if (propertyName === "constructor" || propertyName === "concat") {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const pd = Object.getOwnPropertyDescriptor(original.prototype, propertyName);
|
|
132
|
+
|
|
133
|
+
assert(pd !== undefined);
|
|
134
|
+
|
|
135
|
+
if (!pd.configurable) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
Object.defineProperty(original.prototype, propertyName, {
|
|
140
|
+
enumerable: pd.enumerable,
|
|
141
|
+
configurable: false,
|
|
142
|
+
...("value" in pd
|
|
143
|
+
? {
|
|
144
|
+
get: () => pd.value,
|
|
145
|
+
set: () => {
|
|
146
|
+
throw createWriteError(`window.${name}.prototype.${propertyName}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
: {
|
|
150
|
+
get: pd.get,
|
|
151
|
+
set:
|
|
152
|
+
pd.set ??
|
|
153
|
+
(() => {
|
|
154
|
+
throw createWriteError(
|
|
155
|
+
`window.${name}.prototype.${propertyName}`
|
|
156
|
+
);
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
61
162
|
|
|
62
|
-
Object.freeze(
|
|
163
|
+
Object.freeze(original);
|
|
63
164
|
|
|
64
|
-
Object.defineProperty(
|
|
165
|
+
Object.defineProperty(window, name, {
|
|
65
166
|
configurable: false,
|
|
66
|
-
writable: false,
|
|
67
167
|
enumerable: true,
|
|
68
|
-
|
|
168
|
+
get: () => original,
|
|
169
|
+
set: () => {
|
|
170
|
+
throw createWriteError(`window.${name}`);
|
|
171
|
+
}
|
|
69
172
|
});
|
|
70
173
|
}
|
|
71
174
|
|
|
72
|
-
if (
|
|
73
|
-
const
|
|
175
|
+
if (safeMode) {
|
|
176
|
+
for (const name of ["call", "apply", "bind"] as const) {
|
|
177
|
+
const original = Function.prototype[name];
|
|
178
|
+
|
|
179
|
+
Object.defineProperty(Function.prototype, name, {
|
|
180
|
+
configurable: false,
|
|
181
|
+
enumerable: true,
|
|
182
|
+
get: () => original,
|
|
183
|
+
set: () => {
|
|
184
|
+
throw createWriteError(`window.Function.prototype.${name});`);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
74
189
|
|
|
75
|
-
|
|
76
|
-
Object.
|
|
190
|
+
const _MessageEvent_prototype_data_get = (() => {
|
|
191
|
+
const pd = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
|
|
77
192
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
193
|
+
assert(pd !== undefined);
|
|
194
|
+
|
|
195
|
+
const { get } = pd;
|
|
196
|
+
|
|
197
|
+
assert(get !== undefined);
|
|
198
|
+
|
|
199
|
+
return get;
|
|
200
|
+
})();
|
|
201
|
+
|
|
202
|
+
const _MessageEvent_prototype_origin_get = (() => {
|
|
203
|
+
const pd = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "origin");
|
|
204
|
+
|
|
205
|
+
assert(pd !== undefined);
|
|
206
|
+
|
|
207
|
+
const { get } = pd;
|
|
208
|
+
|
|
209
|
+
assert(get !== undefined);
|
|
210
|
+
|
|
211
|
+
return get;
|
|
212
|
+
})();
|
|
213
|
+
|
|
214
|
+
const _Event_prototype_stopImmediatePropagation_value = Event.prototype.stopImmediatePropagation;
|
|
215
|
+
|
|
216
|
+
const origin = window.location.origin;
|
|
217
|
+
|
|
218
|
+
window.addEventListener(
|
|
219
|
+
"message",
|
|
220
|
+
event => {
|
|
221
|
+
if (_MessageEvent_prototype_origin_get.call(event) !== origin) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const eventData: unknown = _MessageEvent_prototype_data_get.call(event);
|
|
226
|
+
|
|
227
|
+
if (typeof eventData !== "string") {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (!eventData.startsWith(IFRAME_MESSAGE_PREFIX)) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
_Event_prototype_stopImmediatePropagation_value.call(event);
|
|
236
|
+
|
|
237
|
+
const authResponse: AuthResponse = JSON.parse(
|
|
238
|
+
eventData.slice(IFRAME_MESSAGE_PREFIX.length)
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
(evtIframeAuthResponse ??= createEvt()).post(authResponse);
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
capture: true,
|
|
245
|
+
once: false,
|
|
246
|
+
passive: false
|
|
247
|
+
}
|
|
248
|
+
);
|
|
85
249
|
|
|
86
250
|
if (BASE_URL !== undefined) {
|
|
87
251
|
setBASE_URL({ BASE_URL });
|
|
88
252
|
}
|
|
89
|
-
|
|
90
|
-
iframeMessageProtection_captureAndLockBuiltins();
|
|
91
253
|
}
|
|
92
254
|
|
|
93
255
|
resolvePrShouldLoadApp({ shouldLoadApp });
|
|
@@ -95,6 +257,12 @@ export function oidcEarlyInit(params: {
|
|
|
95
257
|
return { shouldLoadApp };
|
|
96
258
|
}
|
|
97
259
|
|
|
260
|
+
let evtIframeAuthResponse: Evt<AuthResponse> | undefined = undefined;
|
|
261
|
+
|
|
262
|
+
export function getEvtIframeAuthResponse() {
|
|
263
|
+
return (evtIframeAuthResponse ??= createEvt());
|
|
264
|
+
}
|
|
265
|
+
|
|
98
266
|
let redirectAuthResponse: AuthResponse | undefined = undefined;
|
|
99
267
|
|
|
100
268
|
export function getRedirectAuthResponse():
|
|
@@ -208,7 +376,19 @@ function handleOidcCallback(params: { isPostLoginRedirectManual?: boolean }): {
|
|
|
208
376
|
|
|
209
377
|
switch (stateData.context) {
|
|
210
378
|
case "iframe":
|
|
211
|
-
|
|
379
|
+
if (parent !== top) {
|
|
380
|
+
const errorMessage = [
|
|
381
|
+
"oidc-spa: For security reasons, refusing to post the auth response.",
|
|
382
|
+
"If you want your app to be framable use sessionRestorationMethod: 'full page redirect'."
|
|
383
|
+
].join(" ");
|
|
384
|
+
alert(errorMessage);
|
|
385
|
+
|
|
386
|
+
throw new Error(errorMessage);
|
|
387
|
+
}
|
|
388
|
+
parent.postMessage(
|
|
389
|
+
`${IFRAME_MESSAGE_PREFIX}${JSON.stringify(authResponse)}`,
|
|
390
|
+
location.origin
|
|
391
|
+
);
|
|
212
392
|
return { shouldLoadApp: false };
|
|
213
393
|
case "redirect": {
|
|
214
394
|
redirectAuthResponse = authResponse;
|