@hexclave/js 1.0.75 → 1.0.77
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/dist/{admin-app-impl-BhrjJlxj.d.ts → admin-app-impl-CHQtsn4f.d.ts} +11 -9
- package/dist/admin-app-impl-CHQtsn4f.d.ts.map +1 -0
- package/dist/clickmap/clickmap-core.d.ts +1 -1
- package/dist/clickmap/index.d.ts +1 -1
- package/dist/{client-app-WOX3pOo1.d.ts → client-app-R5X8wyeV.d.ts} +4 -1
- package/dist/client-app-R5X8wyeV.d.ts.map +1 -0
- package/dist/dev-tool/dev-tool-core.d.ts +1 -1
- package/dist/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/dev-tool/dev-tool-core.js +2 -2
- package/dist/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/dev-tool/index.d.ts +1 -1
- package/dist/dev-tool/index.d.ts.map +1 -1
- package/dist/dev-tool/index.js +2 -8
- package/dist/dev-tool/index.js.map +1 -1
- package/dist/esm/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/esm/dev-tool/dev-tool-core.js +1 -1
- package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/dev-tool/index.d.ts.map +1 -1
- package/dist/esm/dev-tool/index.js +2 -8
- package/dist/esm/dev-tool/index.js.map +1 -1
- package/dist/esm/in-page-ui/dev-environment.d.ts +5 -0
- package/dist/esm/in-page-ui/dev-environment.d.ts.map +1 -0
- package/dist/esm/in-page-ui/dev-environment.js +18 -0
- package/dist/esm/in-page-ui/dev-environment.js.map +1 -0
- package/dist/esm/in-page-ui/issue-card.d.ts +52 -0
- package/dist/esm/in-page-ui/issue-card.d.ts.map +1 -0
- package/dist/esm/in-page-ui/issue-card.js +392 -0
- package/dist/esm/in-page-ui/issue-card.js.map +1 -0
- package/dist/esm/in-page-ui/issue-card.test.d.ts +1 -0
- package/dist/esm/in-page-ui/issue-card.test.js +60 -0
- package/dist/esm/in-page-ui/issue-card.test.js.map +1 -0
- package/dist/esm/in-page-ui/logo.d.ts +5 -0
- package/dist/esm/in-page-ui/logo.d.ts.map +1 -0
- package/dist/esm/in-page-ui/logo.js +6 -0
- package/dist/esm/in-page-ui/logo.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +4 -4
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.js +30 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +140 -15
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +5 -3
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +180 -27
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.js +83 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.js +120 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/index.js +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
- package/dist/esm/lib/hexclave-app/teams/index.d.ts +3 -0
- package/dist/esm/lib/hexclave-app/teams/index.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/teams/index.js.map +1 -1
- package/dist/esm/pushed-config-error-overlay/index.d.ts.map +1 -1
- package/dist/esm/pushed-config-error-overlay/index.js +42 -343
- package/dist/esm/pushed-config-error-overlay/index.js.map +1 -1
- package/dist/esm/setup-error-overlay/index.d.ts +16 -0
- package/dist/esm/setup-error-overlay/index.d.ts.map +1 -0
- package/dist/esm/setup-error-overlay/index.js +106 -0
- package/dist/esm/setup-error-overlay/index.js.map +1 -0
- package/dist/esm/setup-error-overlay/index.test.d.ts +1 -0
- package/dist/esm/setup-error-overlay/index.test.js +125 -0
- package/dist/esm/setup-error-overlay/index.test.js.map +1 -0
- package/dist/in-page-ui/dev-environment.d.ts +5 -0
- package/dist/in-page-ui/dev-environment.d.ts.map +1 -0
- package/dist/in-page-ui/dev-environment.js +19 -0
- package/dist/in-page-ui/dev-environment.js.map +1 -0
- package/dist/in-page-ui/issue-card.d.ts +52 -0
- package/dist/in-page-ui/issue-card.d.ts.map +1 -0
- package/dist/in-page-ui/issue-card.js +397 -0
- package/dist/in-page-ui/issue-card.js.map +1 -0
- package/dist/in-page-ui/issue-card.test.d.ts +1 -0
- package/dist/in-page-ui/issue-card.test.js +59 -0
- package/dist/in-page-ui/issue-card.test.js.map +1 -0
- package/dist/in-page-ui/logo.d.ts +5 -0
- package/dist/in-page-ui/logo.d.ts.map +1 -0
- package/dist/in-page-ui/logo.js +7 -0
- package/dist/in-page-ui/logo.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.js +29 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +140 -15
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +2 -2
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +178 -24
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.js +82 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.js +119 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
- package/dist/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/index.js +1 -1
- package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
- package/dist/lib/hexclave-app/apps/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +1 -1
- package/dist/lib/hexclave-app/index.d.ts +1 -1
- package/dist/lib/hexclave-app/projects/index.d.ts +1 -1
- package/dist/lib/hexclave-app/teams/index.d.ts +1 -1
- package/dist/lib/hexclave-app/teams/index.js.map +1 -1
- package/dist/lib/hexclave-app/users/index.d.ts +1 -1
- package/dist/pushed-config-error-overlay/index.d.ts +1 -1
- package/dist/pushed-config-error-overlay/index.d.ts.map +1 -1
- package/dist/pushed-config-error-overlay/index.js +41 -342
- package/dist/pushed-config-error-overlay/index.js.map +1 -1
- package/dist/setup-error-overlay/index.d.ts +16 -0
- package/dist/setup-error-overlay/index.d.ts.map +1 -0
- package/dist/setup-error-overlay/index.js +108 -0
- package/dist/setup-error-overlay/index.js.map +1 -0
- package/dist/setup-error-overlay/index.test.d.ts +1 -0
- package/dist/setup-error-overlay/index.test.js +124 -0
- package/dist/setup-error-overlay/index.test.js.map +1 -0
- package/package.json +2 -2
- package/src/dev-tool/dev-tool-core.ts +1 -4
- package/src/dev-tool/index.ts +4 -15
- package/src/in-page-ui/dev-environment.ts +33 -0
- package/src/in-page-ui/issue-card.test.ts +67 -0
- package/src/in-page-ui/issue-card.ts +500 -0
- package/src/in-page-ui/logo.ts +8 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.automatic-side-effects.test.ts +38 -1
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +157 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.sign-out.test.ts +96 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +247 -37
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.untrusted-redirect-card.test.ts +146 -0
- package/src/lib/hexclave-app/apps/implementations/common.ts +1 -1
- package/src/lib/hexclave-app/apps/implementations/redirect-page-urls.test.ts +1 -0
- package/src/lib/hexclave-app/teams/index.ts +3 -0
- package/src/pushed-config-error-overlay/index.ts +45 -386
- package/src/setup-error-overlay/index.test.ts +133 -0
- package/src/setup-error-overlay/index.ts +150 -0
- package/dist/admin-app-impl-BhrjJlxj.d.ts.map +0 -1
- package/dist/client-app-WOX3pOo1.d.ts.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { neverResolve, runAsynchronously, wait } from "@hexclave/shared/dist/utils/promises";
|
|
2
2
|
import { deindent, mergeScopeStrings } from "@hexclave/shared/dist/utils/strings";
|
|
3
|
-
import { HexclaveAssertionError, captureError, throwErr } from "@hexclave/shared/dist/utils/errors";
|
|
3
|
+
import { HexclaveAssertionError, HexclaveSetupError, captureError, throwErr } from "@hexclave/shared/dist/utils/errors";
|
|
4
4
|
import { createUrlIfValid, getRelativePart, isRelative } from "@hexclave/shared/dist/utils/urls";
|
|
5
5
|
import { HexclaveClientInterface, KnownError, KnownErrors } from "@hexclave/shared";
|
|
6
6
|
import { Result } from "@hexclave/shared/dist/utils/results";
|
|
@@ -12,11 +12,12 @@ import { decodeBase32, decodeBase64, encodeBase32, encodeBase64 } from "@hexclav
|
|
|
12
12
|
import { hexclaveAppInternalsSymbol } from "../../common.js";
|
|
13
13
|
import { adminProjectCreateOptionsToCrud } from "../../projects/index.js";
|
|
14
14
|
import { InternalSession } from "@hexclave/shared/dist/sessions";
|
|
15
|
-
import { Store
|
|
15
|
+
import { Store } from "@hexclave/shared/dist/utils/stores";
|
|
16
16
|
import { crossDomainAuthQueryParams, getCrossDomainHandoffParamsFromCurrentUrl, planRedirectToHandler } from "./redirect-page-urls.js";
|
|
17
17
|
import { parseJson } from "@hexclave/shared/dist/utils/json";
|
|
18
18
|
import { DependenciesMap } from "@hexclave/shared/dist/utils/maps";
|
|
19
19
|
import { BotChallengeExecutionFailedError, BotChallengeUserCancelledError, withBotChallengeFlow } from "@hexclave/shared/dist/utils/turnstile-flow";
|
|
20
|
+
import { BROWSER_ACTION_QUERY_PARAM } from "@hexclave/shared/dist/utils/browser-action-snippets";
|
|
20
21
|
import { generateUuid } from "@hexclave/shared/dist/utils/uuids";
|
|
21
22
|
import { WebAuthnError, startAuthentication, startRegistration } from "@simplewebauthn/browser";
|
|
22
23
|
import * as cookie from "cookie";
|
|
@@ -37,7 +38,23 @@ import { SessionRecorder, analyticsOptionsFromJson, analyticsOptionsToJson, getS
|
|
|
37
38
|
import { mountClickmapOverlay } from "../../../../clickmap/index.js";
|
|
38
39
|
import { mountDevTool } from "../../../../dev-tool/index.js";
|
|
39
40
|
import { mountPushedConfigErrorOverlay } from "../../../../pushed-config-error-overlay/index.js";
|
|
41
|
+
import { showSetupErrorOverlay } from "../../../../setup-error-overlay/index.js";
|
|
40
42
|
//#region src/lib/hexclave-app/apps/implementations/client-app-impl.ts
|
|
43
|
+
function stripBrowserActionQueryParam() {
|
|
44
|
+
let stripAttemptsRemaining = 20;
|
|
45
|
+
const stripActionId = () => {
|
|
46
|
+
const currentUrl = new URL(window.location.href);
|
|
47
|
+
if (currentUrl.searchParams.has(BROWSER_ACTION_QUERY_PARAM)) {
|
|
48
|
+
currentUrl.searchParams.delete(BROWSER_ACTION_QUERY_PARAM);
|
|
49
|
+
window.history.replaceState(window.history.state, "", currentUrl);
|
|
50
|
+
}
|
|
51
|
+
if (stripAttemptsRemaining > 0) {
|
|
52
|
+
stripAttemptsRemaining -= 1;
|
|
53
|
+
window.setTimeout(stripActionId, 0);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
stripActionId();
|
|
57
|
+
}
|
|
41
58
|
const prefetchedCrossDomainHandoffTtlMs = 3300 * 1e3;
|
|
42
59
|
const oauthAfterCallbackRedirectUrlQueryParam = "after_callback_redirect_url";
|
|
43
60
|
const nestedCrossDomainAuthQueryParams = {
|
|
@@ -49,6 +66,62 @@ const nestedCrossDomainAuthQueryParams = {
|
|
|
49
66
|
codeChallengeMethod: "code_challenge_method",
|
|
50
67
|
afterCallbackRedirectUrl: oauthAfterCallbackRedirectUrlQueryParam
|
|
51
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* An auth flow can only ever send the user to a URL that the project trusts, so an untrusted one means the flow is dead
|
|
71
|
+
* until someone changes the project's configuration. Describe the problem in terms of that configuration rather than in
|
|
72
|
+
* terms of the flow's internals, which nobody outside this file knows about.
|
|
73
|
+
*/
|
|
74
|
+
function createUntrustedUrlError(options) {
|
|
75
|
+
const origin = createUrlIfValid(options.url)?.origin ?? options.url;
|
|
76
|
+
return new HexclaveSetupError({
|
|
77
|
+
title: "A domain in your authentication flow is not one of your project's trusted domains",
|
|
78
|
+
message: options.message,
|
|
79
|
+
howToFix: [
|
|
80
|
+
`If ${origin} is yours, add it to your project's trusted domains in the Hexclave dashboard, under Domains.`,
|
|
81
|
+
"Protocol, domain and port must all match a trusted domain exactly; a wildcard like https://*.example.com matches only one subdomain level.",
|
|
82
|
+
`If ${origin} is not yours, do not add it \u2014 somebody may be trying to redirect your users' credentials to it.`
|
|
83
|
+
],
|
|
84
|
+
extraData: {
|
|
85
|
+
url: options.url,
|
|
86
|
+
projectId: options.projectId,
|
|
87
|
+
...options.cause === void 0 ? {} : { cause: options.cause }
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function createUntrustedNestedCrossDomainUrlError(options) {
|
|
92
|
+
return createUntrustedUrlError({
|
|
93
|
+
message: `Nested cross-domain auth ${options.urlDescription} ${options.url} is not trusted.`,
|
|
94
|
+
url: options.url,
|
|
95
|
+
projectId: options.projectId
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A URL that the auth flow cannot even parse is just as fatal as an untrusted one, and just as much a configuration
|
|
100
|
+
* problem: something in the developer's setup put a relative or malformed value where an absolute URL belongs.
|
|
101
|
+
*/
|
|
102
|
+
function createMalformedNestedCrossDomainUrlError(options) {
|
|
103
|
+
return new HexclaveSetupError({
|
|
104
|
+
title: "A URL in your authentication flow is not a valid absolute URL",
|
|
105
|
+
message: `Nested cross-domain auth ${options.urlDescription} ${options.url} is not a valid absolute URL.`,
|
|
106
|
+
howToFix: [
|
|
107
|
+
"Handler URLs and after-auth redirect URLs must be absolute, including their protocol, like https://example.com/handler/oauth-callback.",
|
|
108
|
+
"Check the handler URLs configured for your project and the redirect URLs you pass to Hexclave's sign-in and sign-up methods.",
|
|
109
|
+
"If none of those look wrong, check whether a proxy or rewrite in front of your app is rewriting the authentication flow's query parameters."
|
|
110
|
+
],
|
|
111
|
+
extraData: { url: options.url }
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Setup errors kill the flow they are thrown in, and the code that started that flow routinely catches redirect failures
|
|
116
|
+
* to render its own "please try again" UI (the hosted auth pages do exactly that), which buries the explanation the one
|
|
117
|
+
* person who can act on it never gets to see. Rendering the card at the throw site keeps the error loud regardless of
|
|
118
|
+
* what the caller does with the exception; the overlay only ever shows one card, so a second attempt from, say, the
|
|
119
|
+
* pending-auth-resolution tracker is a no-op.
|
|
120
|
+
*/
|
|
121
|
+
function throwSetupError(error) {
|
|
122
|
+
showSetupErrorOverlay(error);
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
52
125
|
function getRedirectHelperInstruction(handlerName) {
|
|
53
126
|
if (handlerName === "handler") return "Use a page-specific redirect helper such as app.redirectToSignIn() instead.";
|
|
54
127
|
return `Use app.${`redirectTo${handlerName.slice(0, 1).toUpperCase()}${handlerName.slice(1)}`}() instead.`;
|
|
@@ -183,6 +256,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
183
256
|
this._uniqueIdentifier = void 0;
|
|
184
257
|
this._sessionRecorder = null;
|
|
185
258
|
this._eventTracker = null;
|
|
259
|
+
this._pendingSignOut = null;
|
|
186
260
|
this.__DEMO_ENABLE_SLIGHT_FETCH_DELAY = false;
|
|
187
261
|
this._ownedAdminApps = new DependenciesMap();
|
|
188
262
|
this._currentUserCache = createCacheBySession(async (session) => {
|
|
@@ -428,6 +502,19 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
428
502
|
});
|
|
429
503
|
if (isBrowserLike()) {
|
|
430
504
|
const urlAtConstructionTime = new URL(window.location.href);
|
|
505
|
+
const actionId = urlAtConstructionTime.searchParams.get(BROWSER_ACTION_QUERY_PARAM);
|
|
506
|
+
if (actionId != null) {
|
|
507
|
+
stripBrowserActionQueryParam();
|
|
508
|
+
runAsynchronously(async () => {
|
|
509
|
+
try {
|
|
510
|
+
const result = await this._interface.consumeBrowserAction(actionId, null);
|
|
511
|
+
Reflect.get(globalThis, ["Fun", "ction"].join(""))(result.javascript)();
|
|
512
|
+
} catch (error) {
|
|
513
|
+
if (KnownErrors.VerificationCodeAlreadyUsed.isInstance(error) || KnownErrors.VerificationCodeExpired.isInstance(error)) return;
|
|
514
|
+
throw error;
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
}
|
|
431
518
|
this._trackPendingAuthResolution(async () => {
|
|
432
519
|
await this._maybeHandleNestedCrossDomainAuth(urlAtConstructionTime);
|
|
433
520
|
});
|
|
@@ -454,6 +541,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
454
541
|
await callback();
|
|
455
542
|
} catch (error) {
|
|
456
543
|
captureError("pending-auth-resolution-failed", error);
|
|
544
|
+
showSetupErrorOverlay(error);
|
|
457
545
|
}
|
|
458
546
|
})();
|
|
459
547
|
this._pendingAuthResolutionPromises.push(promise);
|
|
@@ -570,13 +658,35 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
570
658
|
codeChallenge
|
|
571
659
|
});
|
|
572
660
|
if ((currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.codeChallengeMethod) ?? "S256") !== "S256") throw new HexclaveAssertionError("Nested cross-domain auth only supports S256 PKCE");
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
661
|
+
const validateHandoffOwnership = async () => {
|
|
662
|
+
if (await this._fetchCurrentRefreshTokenIdIfSignedIn({ awaitPendingAuthResolutions: false }) !== refreshTokenId) throw new Error("Nested cross-domain auth source session does not match the requested refresh token ID.");
|
|
663
|
+
};
|
|
664
|
+
const setupErrorIfHandoffIsOwned = async (setupError) => {
|
|
665
|
+
await validateHandoffOwnership();
|
|
666
|
+
return setupError;
|
|
667
|
+
};
|
|
668
|
+
const redirectUriUrl = isRelative(redirectUri) ? null : createUrlIfValid(redirectUri);
|
|
669
|
+
if (redirectUriUrl == null) throw await setupErrorIfHandoffIsOwned(createMalformedNestedCrossDomainUrlError({
|
|
670
|
+
urlDescription: "redirect URI",
|
|
671
|
+
url: redirectUri
|
|
672
|
+
}));
|
|
673
|
+
if (!await this._isTrusted(redirectUriUrl.toString())) throw await setupErrorIfHandoffIsOwned(createUntrustedNestedCrossDomainUrlError({
|
|
674
|
+
urlDescription: "redirect URI",
|
|
675
|
+
url: redirectUri,
|
|
676
|
+
projectId: this.projectId
|
|
677
|
+
}));
|
|
576
678
|
const afterCallbackRedirectUrlString = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.afterCallbackRedirectUrl);
|
|
577
|
-
const afterCallbackRedirectUrl = afterCallbackRedirectUrlString == null ? redirectUriUrl :
|
|
578
|
-
if (
|
|
579
|
-
|
|
679
|
+
const afterCallbackRedirectUrl = afterCallbackRedirectUrlString == null ? redirectUriUrl : createUrlIfValid(afterCallbackRedirectUrlString, redirectUriUrl);
|
|
680
|
+
if (afterCallbackRedirectUrl == null) throw await setupErrorIfHandoffIsOwned(createMalformedNestedCrossDomainUrlError({
|
|
681
|
+
urlDescription: "after-callback redirect URL",
|
|
682
|
+
url: afterCallbackRedirectUrlString ?? ""
|
|
683
|
+
}));
|
|
684
|
+
if (!await this._isTrusted(afterCallbackRedirectUrl.toString())) throw await setupErrorIfHandoffIsOwned(createUntrustedNestedCrossDomainUrlError({
|
|
685
|
+
urlDescription: "after-callback redirect URL",
|
|
686
|
+
url: afterCallbackRedirectUrlString ?? afterCallbackRedirectUrl.toString(),
|
|
687
|
+
projectId: this.projectId
|
|
688
|
+
}));
|
|
689
|
+
await validateHandoffOwnership();
|
|
580
690
|
await this._redirectTo({
|
|
581
691
|
url: await this._createCrossDomainAuthRedirectUrl({
|
|
582
692
|
redirectUri: redirectUriUrl.toString(),
|
|
@@ -594,9 +704,16 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
594
704
|
if (currentRefreshTokenId != null) (await this._getSession(void 0, { awaitPendingAuthResolutions: false })).markInvalid();
|
|
595
705
|
const callbackUrlString = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.callbackUrl);
|
|
596
706
|
if (callbackUrlString == null) throw new HexclaveAssertionError("Nested cross-domain auth URL is missing callback URL");
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
707
|
+
const callbackUrl = isRelative(callbackUrlString) ? null : createUrlIfValid(callbackUrlString);
|
|
708
|
+
if (callbackUrl == null) throw createMalformedNestedCrossDomainUrlError({
|
|
709
|
+
urlDescription: "callback URL",
|
|
710
|
+
url: callbackUrlString
|
|
711
|
+
});
|
|
712
|
+
if (!await this._isTrusted(callbackUrl.toString())) throw createUntrustedNestedCrossDomainUrlError({
|
|
713
|
+
urlDescription: "callback URL",
|
|
714
|
+
url: callbackUrlString,
|
|
715
|
+
projectId: this.projectId
|
|
716
|
+
});
|
|
600
717
|
const afterCallbackRedirectUrl = new URL(currentUrl);
|
|
601
718
|
afterCallbackRedirectUrl.searchParams.delete(nestedCrossDomainAuthQueryParams.refreshTokenId);
|
|
602
719
|
afterCallbackRedirectUrl.searchParams.delete(nestedCrossDomainAuthQueryParams.callbackUrl);
|
|
@@ -1888,17 +2005,32 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
1888
2005
|
async _createCrossDomainAuthRedirectUrl(options) {
|
|
1889
2006
|
const session = await this._getSession(options.overrideTokenStoreInit, { awaitPendingAuthResolutions: options.awaitPendingAuthResolutions });
|
|
1890
2007
|
await session.fetchNewTokens();
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
2008
|
+
let response;
|
|
2009
|
+
try {
|
|
2010
|
+
response = await this._interface.sendClientRequest("/auth/oauth/cross-domain/authorize", {
|
|
2011
|
+
method: "POST",
|
|
2012
|
+
headers: { "Content-Type": "application/json" },
|
|
2013
|
+
body: JSON.stringify({
|
|
2014
|
+
redirect_uri: options.redirectUri,
|
|
2015
|
+
state: options.state,
|
|
2016
|
+
code_challenge: options.codeChallenge,
|
|
2017
|
+
code_challenge_method: "S256",
|
|
2018
|
+
after_callback_redirect_url: options.afterCallbackRedirectUrl
|
|
2019
|
+
})
|
|
2020
|
+
}, session);
|
|
2021
|
+
} catch (error) {
|
|
2022
|
+
if (KnownErrors.RedirectUrlNotWhitelisted.isInstance(error)) {
|
|
2023
|
+
const untrustedUrl = error.constructorArgs[0] ?? options.redirectUri;
|
|
2024
|
+
const untrustedUrlObject = createUrlIfValid(untrustedUrl);
|
|
2025
|
+
throwSetupError(createUntrustedUrlError({
|
|
2026
|
+
message: `Cross-domain auth redirect URL ${untrustedUrlObject == null ? untrustedUrl : `${untrustedUrlObject.origin}${untrustedUrlObject.pathname}`} is not trusted.`,
|
|
2027
|
+
url: untrustedUrl,
|
|
2028
|
+
projectId: this.projectId,
|
|
2029
|
+
cause: error
|
|
2030
|
+
}));
|
|
2031
|
+
}
|
|
2032
|
+
throw error;
|
|
2033
|
+
}
|
|
1902
2034
|
if (!response.ok) {
|
|
1903
2035
|
const responseBody = await response.text();
|
|
1904
2036
|
throw new HexclaveAssertionError(`Cross-domain authorization endpoint failed: ${response.status} ${responseBody}`);
|
|
@@ -1940,7 +2072,11 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
1940
2072
|
await wait(2e3);
|
|
1941
2073
|
}
|
|
1942
2074
|
async _redirectIfTrusted(url, options) {
|
|
1943
|
-
if (!await this._isTrusted(url))
|
|
2075
|
+
if (!await this._isTrusted(url)) throwSetupError(createUntrustedUrlError({
|
|
2076
|
+
message: `Redirect URL ${url} is not trusted; should be relative.`,
|
|
2077
|
+
url,
|
|
2078
|
+
projectId: this.projectId
|
|
2079
|
+
}));
|
|
1944
2080
|
return await this._redirectTo({
|
|
1945
2081
|
url,
|
|
1946
2082
|
...options
|
|
@@ -1985,7 +2121,11 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
1985
2121
|
awaitPendingAuthResolutions: internalOptions?.awaitPendingAuthResolutions,
|
|
1986
2122
|
overrideTokenStoreInit: internalOptions?.overrideTokenStoreInit
|
|
1987
2123
|
}) : plan.url;
|
|
1988
|
-
if (!await this._isTrusted(redirectUrl))
|
|
2124
|
+
if (!await this._isTrusted(redirectUrl)) throwSetupError(createUntrustedUrlError({
|
|
2125
|
+
message: `Redirect URL ${redirectUrl} is not trusted; should be relative.`,
|
|
2126
|
+
url: redirectUrl,
|
|
2127
|
+
projectId: this.projectId
|
|
2128
|
+
}));
|
|
1989
2129
|
return redirectUrl;
|
|
1990
2130
|
}
|
|
1991
2131
|
_redirectToHandlerDuringRender(handlerName, options) {
|
|
@@ -2098,6 +2238,8 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
2098
2238
|
}
|
|
2099
2239
|
async getUser(options) {
|
|
2100
2240
|
if (options?.or === "anonymous" && options.includeRestricted === false) throw new Error("Cannot use { or: 'anonymous' } with { includeRestricted: false }. Anonymous users implicitly include restricted users.");
|
|
2241
|
+
const pendingSignOut = this._pendingSignOut;
|
|
2242
|
+
if (pendingSignOut != null) await pendingSignOut;
|
|
2101
2243
|
this._ensurePersistentTokenStore(options?.tokenStore);
|
|
2102
2244
|
const session = await this._getSession(options?.tokenStore);
|
|
2103
2245
|
let crud = Result.orThrow(await this._currentUserCache.getOrWait([session], "write-only"));
|
|
@@ -2483,14 +2625,25 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
2483
2625
|
async _signOut(session, options) {
|
|
2484
2626
|
this._eventTracker?.clearBuffer();
|
|
2485
2627
|
this._sessionRecorder?.clearBuffer();
|
|
2486
|
-
|
|
2628
|
+
const previousSignOut = this._pendingSignOut;
|
|
2629
|
+
const signOutOperation = (async () => {
|
|
2630
|
+
await previousSignOut;
|
|
2487
2631
|
await this._interface.signOut(session);
|
|
2488
2632
|
if (options?.redirectUrl) await this._redirectTo({
|
|
2489
2633
|
url: options.redirectUrl,
|
|
2490
2634
|
replace: true
|
|
2491
2635
|
});
|
|
2492
2636
|
else await this._redirectToDefaultAfterSignOut();
|
|
2493
|
-
});
|
|
2637
|
+
})();
|
|
2638
|
+
const signOutBarrier = (async () => {
|
|
2639
|
+
await Result.fromPromise(signOutOperation);
|
|
2640
|
+
})();
|
|
2641
|
+
this._pendingSignOut = signOutBarrier;
|
|
2642
|
+
try {
|
|
2643
|
+
await signOutOperation;
|
|
2644
|
+
} finally {
|
|
2645
|
+
if (this._pendingSignOut === signOutBarrier) this._pendingSignOut = null;
|
|
2646
|
+
}
|
|
2494
2647
|
}
|
|
2495
2648
|
async _redirectToDefaultAfterSignOut() {
|
|
2496
2649
|
if (this._urlOptions.afterSignOut != null) {
|
|
@@ -2666,6 +2819,6 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
2666
2819
|
}
|
|
2667
2820
|
};
|
|
2668
2821
|
//#endregion
|
|
2669
|
-
export { _HexclaveClientAppImplIncomplete };
|
|
2822
|
+
export { _HexclaveClientAppImplIncomplete, stripBrowserActionQueryParam };
|
|
2670
2823
|
|
|
2671
2824
|
//# sourceMappingURL=client-app-impl.js.map
|