@hexclave/next 1.0.5 → 1.0.6
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/components-page/account-settings/payments/payments-panel.js +3 -3
- package/dist/components-page/account-settings/payments/payments-panel.js.map +1 -1
- package/dist/components-page/hexclave-handler-client.d.ts +13 -1
- package/dist/components-page/hexclave-handler-client.d.ts.map +1 -1
- package/dist/components-page/hexclave-handler-client.js +44 -9
- package/dist/components-page/hexclave-handler-client.js.map +1 -1
- package/dist/components-page/hexclave-handler-client.test.d.ts +1 -0
- package/dist/components-page/hexclave-handler-client.test.js +51 -0
- package/dist/components-page/hexclave-handler-client.test.js.map +1 -0
- package/dist/dev-tool/dev-tool-core.js +2 -2
- package/dist/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/components-page/account-settings/payments/payments-panel.js +2 -2
- package/dist/esm/components-page/account-settings/payments/payments-panel.js.map +1 -1
- package/dist/esm/components-page/hexclave-handler-client.d.ts +12 -1
- package/dist/esm/components-page/hexclave-handler-client.d.ts.map +1 -1
- package/dist/esm/components-page/hexclave-handler-client.js +46 -12
- package/dist/esm/components-page/hexclave-handler-client.js.map +1 -1
- package/dist/esm/components-page/hexclave-handler-client.test.d.ts +1 -0
- package/dist/esm/components-page/hexclave-handler-client.test.js +51 -0
- package/dist/esm/components-page/hexclave-handler-client.test.js.map +1 -0
- package/dist/esm/dev-tool/dev-tool-core.js +2 -2
- package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/generated/env.d.ts +26 -0
- package/dist/esm/{lib → generated}/env.d.ts.map +1 -1
- package/dist/esm/generated/env.js +67 -0
- package/dist/esm/generated/env.js.map +1 -0
- package/dist/esm/generated/quetzal-translations.d.ts +2 -2
- package/dist/esm/global.d.ts +8 -1
- package/dist/esm/global.d.ts.map +1 -0
- 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.cross-domain.test.js +263 -3
- 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 +3 -1
- 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 +53 -26
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.d.ts +8 -8
- package/dist/esm/lib/hexclave-app/apps/implementations/common.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +28 -14
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
- package/dist/esm/lib/hexclave-app/url-targets.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/url-targets.js +25 -11
- package/dist/esm/lib/hexclave-app/url-targets.js.map +1 -1
- package/dist/esm/lib/hexclave-app/url-targets.test.js +12 -0
- package/dist/esm/lib/hexclave-app/url-targets.test.js.map +1 -1
- package/dist/generated/env.d.ts +26 -0
- package/dist/{lib → generated}/env.d.ts.map +1 -1
- package/dist/generated/env.js +69 -0
- package/dist/generated/env.js.map +1 -0
- package/dist/generated/quetzal-translations.d.ts +2 -2
- package/dist/global.d.ts +8 -1
- package/dist/global.d.ts.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +263 -3
- 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 +3 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +52 -25
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.d.ts +8 -8
- package/dist/lib/hexclave-app/apps/implementations/common.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +28 -14
- package/dist/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +1 -1
- package/dist/lib/hexclave-app/url-targets.d.ts.map +1 -1
- package/dist/lib/hexclave-app/url-targets.js +25 -11
- package/dist/lib/hexclave-app/url-targets.js.map +1 -1
- package/dist/lib/hexclave-app/url-targets.test.js +12 -0
- package/dist/lib/hexclave-app/url-targets.test.js.map +1 -1
- package/package.json +9 -7
- package/src/components-page/account-settings/payments/payments-panel.tsx +2 -2
- package/src/components-page/hexclave-handler-client.test.tsx +64 -0
- package/src/components-page/hexclave-handler-client.tsx +50 -11
- package/src/dev-tool/dev-tool-core.ts +2 -2
- package/src/generated/.gitignore +1 -1
- package/src/global.d.ts +8 -1
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +316 -3
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +69 -25
- package/src/lib/hexclave-app/apps/implementations/common.ts +34 -14
- package/src/lib/hexclave-app/url-targets.test.ts +17 -0
- package/src/lib/hexclave-app/url-targets.ts +25 -7
- package/dist/esm/lib/env.d.ts +0 -42
- package/dist/esm/lib/env.js +0 -93
- package/dist/esm/lib/env.js.map +0 -1
- package/dist/lib/env.d.ts +0 -42
- package/dist/lib/env.js +0 -95
- package/dist/lib/env.js.map +0 -1
- package/src/lib/env.ts +0 -93
|
@@ -4,7 +4,7 @@ import React, { useCallback, useMemo } from "react";
|
|
|
4
4
|
import { HexclaveClientInterface, KnownErrors } from "@hexclave/shared";
|
|
5
5
|
import { suspend, suspendIfSsr, use } from "@hexclave/shared/dist/utils/react";
|
|
6
6
|
import { deepPlainEquals, omit } from "@hexclave/shared/dist/utils/objects";
|
|
7
|
-
import { createUrlIfValid, isRelative } from "@hexclave/shared/dist/utils/urls";
|
|
7
|
+
import { createUrlIfValid, getRelativePart, isRelative } from "@hexclave/shared/dist/utils/urls";
|
|
8
8
|
import * as NextNavigationUnscrambled from "next/navigation";
|
|
9
9
|
import { Result } from "@hexclave/shared/dist/utils/results";
|
|
10
10
|
import { deindent, mergeScopeStrings } from "@hexclave/shared/dist/utils/strings";
|
|
@@ -14,19 +14,19 @@ import { getTrustedParentDomain, validateRedirectUrl } from "@hexclave/shared/di
|
|
|
14
14
|
import { decodeBase32, decodeBase64, encodeBase32, encodeBase64 } from "@hexclave/shared/dist/utils/bytes";
|
|
15
15
|
import { hexclaveAppInternalsSymbol } from "../../common.js";
|
|
16
16
|
import { adminProjectCreateOptionsToCrud } from "../../projects/index.js";
|
|
17
|
-
import { WebAuthnError, startAuthentication, startRegistration } from "@simplewebauthn/browser";
|
|
18
17
|
import { InternalSession } from "@hexclave/shared/dist/sessions";
|
|
18
|
+
import { Store, storeLock } from "@hexclave/shared/dist/utils/stores";
|
|
19
|
+
import { WebAuthnError, startAuthentication, startRegistration } from "@simplewebauthn/browser";
|
|
19
20
|
import { scrambleDuringCompileTime } from "@hexclave/shared/dist/utils/compile-time";
|
|
20
21
|
import { parseJson } from "@hexclave/shared/dist/utils/json";
|
|
21
22
|
import { DependenciesMap } from "@hexclave/shared/dist/utils/maps";
|
|
22
|
-
import { Store, storeLock } from "@hexclave/shared/dist/utils/stores";
|
|
23
23
|
import { BotChallengeExecutionFailedError, BotChallengeUserCancelledError, withBotChallengeFlow } from "@hexclave/shared/dist/utils/turnstile-flow";
|
|
24
24
|
import { generateUuid } from "@hexclave/shared/dist/utils/uuids";
|
|
25
25
|
import * as cookie from "cookie";
|
|
26
26
|
import { constructRedirectUrl } from "../../../../utils/url.js";
|
|
27
27
|
import { callOAuthCallback, getNewOAuthProviderOrScopeUrl } from "../../../auth.js";
|
|
28
28
|
import { createBrowserCookieHelper, createCookieHelper, createPlaceholderCookieHelper, deleteCookie, deleteCookieClient, getCookieClient, isSecure, saveVerifierAndState, setOrDeleteCookie, setOrDeleteCookieClient } from "../../../cookie.js";
|
|
29
|
-
import { envVars } from "
|
|
29
|
+
import { envVars } from "../../../../generated/env.js";
|
|
30
30
|
import { apiKeyCreationOptionsToCrud } from "../../api-keys/index.js";
|
|
31
31
|
import { contactChannelCreateOptionsToCrud, contactChannelUpdateOptionsToCrud } from "../../contact-channels/index.js";
|
|
32
32
|
import { teamCreateOptionsToCrud, teamUpdateOptionsToCrud } from "../../teams/index.js";
|
|
@@ -505,15 +505,15 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
505
505
|
for (const param of oauthCallbackResponseQueryParams) currentUrl.searchParams.delete(param);
|
|
506
506
|
return currentUrl.toString();
|
|
507
507
|
}
|
|
508
|
-
async
|
|
509
|
-
const tokens = await (await this._getSession(options?.overrideTokenStoreInit, options)).
|
|
508
|
+
async _fetchCurrentRefreshTokenIdIfSignedIn(options) {
|
|
509
|
+
const tokens = await (await this._getSession(options?.overrideTokenStoreInit, options)).fetchNewTokens();
|
|
510
510
|
if (tokens?.refreshToken == null) return null;
|
|
511
511
|
return tokens.accessToken.payload.refresh_token_id;
|
|
512
512
|
}
|
|
513
513
|
async _addNestedCrossDomainAuthParamsToRedirectUrl(options) {
|
|
514
514
|
const targetUrl = new URL(options.url, options.currentUrl);
|
|
515
515
|
if (targetUrl.origin === options.currentUrl.origin) return options.url;
|
|
516
|
-
const refreshTokenId = await this.
|
|
516
|
+
const refreshTokenId = await this._fetchCurrentRefreshTokenIdIfSignedIn({
|
|
517
517
|
awaitPendingAuthResolutions: options.awaitPendingAuthResolutions,
|
|
518
518
|
overrideTokenStoreInit: options.overrideTokenStoreInit
|
|
519
519
|
});
|
|
@@ -544,7 +544,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
544
544
|
const afterCallbackRedirectUrlString = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.afterCallbackRedirectUrl);
|
|
545
545
|
const afterCallbackRedirectUrl = afterCallbackRedirectUrlString == null ? redirectUriUrl : new URL(afterCallbackRedirectUrlString, redirectUriUrl);
|
|
546
546
|
if (!await this._isTrusted(afterCallbackRedirectUrl.toString())) throw new Error(`Nested cross-domain auth after-callback redirect URL ${afterCallbackRedirectUrlString} is not trusted.`);
|
|
547
|
-
if (await this.
|
|
547
|
+
if (await this._fetchCurrentRefreshTokenIdIfSignedIn({ awaitPendingAuthResolutions: false }) !== refreshTokenId) throw new Error("Nested cross-domain auth source session does not match the requested refresh token ID.");
|
|
548
548
|
await this._redirectTo({
|
|
549
549
|
url: await this._createCrossDomainAuthRedirectUrl({
|
|
550
550
|
redirectUri: redirectUriUrl.toString(),
|
|
@@ -557,7 +557,9 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
557
557
|
});
|
|
558
558
|
return true;
|
|
559
559
|
}
|
|
560
|
-
|
|
560
|
+
const currentRefreshTokenId = await this._fetchCurrentRefreshTokenIdIfSignedIn({ awaitPendingAuthResolutions: false });
|
|
561
|
+
if (currentRefreshTokenId === refreshTokenId) return false;
|
|
562
|
+
if (currentRefreshTokenId != null) (await this._getSession(void 0, { awaitPendingAuthResolutions: false })).markInvalid();
|
|
561
563
|
const callbackUrlString = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.callbackUrl);
|
|
562
564
|
if (callbackUrlString == null) throw new HexclaveAssertionError("Nested cross-domain auth URL is missing callback URL");
|
|
563
565
|
if (isRelative(callbackUrlString)) throw new Error("Nested cross-domain auth callback URL must be absolute.");
|
|
@@ -710,6 +712,13 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
710
712
|
accessToken
|
|
711
713
|
};
|
|
712
714
|
}
|
|
715
|
+
_getCurrentBrowserCookieTokenStoreValue(old) {
|
|
716
|
+
const tokens = this._getTokensFromCookies(this._getAllBrowserCookies());
|
|
717
|
+
return {
|
|
718
|
+
refreshToken: tokens.refreshToken,
|
|
719
|
+
accessToken: tokens.accessToken ?? (old?.refreshToken === tokens.refreshToken ? old.accessToken : null)
|
|
720
|
+
};
|
|
721
|
+
}
|
|
713
722
|
get _accessTokenCookieName() {
|
|
714
723
|
return `hexclave-access`;
|
|
715
724
|
}
|
|
@@ -814,19 +823,12 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
814
823
|
_getBrowserCookieTokenStore() {
|
|
815
824
|
if (!isBrowserLike()) throw new Error("Cannot use cookie token store on the server!");
|
|
816
825
|
if (this._storedBrowserCookieTokenStore === null) {
|
|
817
|
-
|
|
818
|
-
const tokens = this._getTokensFromCookies(this._getAllBrowserCookies());
|
|
819
|
-
return {
|
|
820
|
-
refreshToken: tokens.refreshToken,
|
|
821
|
-
accessToken: tokens.accessToken ?? (old?.refreshToken === tokens.refreshToken ? old.accessToken : null)
|
|
822
|
-
};
|
|
823
|
-
};
|
|
824
|
-
this._storedBrowserCookieTokenStore = new Store(getCurrentValue(null));
|
|
826
|
+
this._storedBrowserCookieTokenStore = new Store(this._getCurrentBrowserCookieTokenStoreValue(null));
|
|
825
827
|
let hasSucceededInWriting = true;
|
|
826
828
|
setInterval(() => {
|
|
827
829
|
if (hasSucceededInWriting) {
|
|
828
830
|
const oldValue = this._storedBrowserCookieTokenStore.get();
|
|
829
|
-
const currentValue =
|
|
831
|
+
const currentValue = this._getCurrentBrowserCookieTokenStoreValue(oldValue);
|
|
830
832
|
if (!deepPlainEquals(currentValue, oldValue)) this._storedBrowserCookieTokenStore.set(currentValue);
|
|
831
833
|
}
|
|
832
834
|
}, 100);
|
|
@@ -852,6 +854,10 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
852
854
|
else throw e;
|
|
853
855
|
}
|
|
854
856
|
});
|
|
857
|
+
} else {
|
|
858
|
+
const oldValue = this._storedBrowserCookieTokenStore.get();
|
|
859
|
+
const currentValue = this._getCurrentBrowserCookieTokenStoreValue(oldValue);
|
|
860
|
+
if (!deepPlainEquals(currentValue, oldValue)) this._storedBrowserCookieTokenStore.set(currentValue);
|
|
855
861
|
}
|
|
856
862
|
return this._storedBrowserCookieTokenStore;
|
|
857
863
|
}
|
|
@@ -946,17 +952,17 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
946
952
|
accessToken: tokenObj.accessToken
|
|
947
953
|
});
|
|
948
954
|
session.onAccessTokenChange((newAccessToken) => {
|
|
949
|
-
tokenStore.update((old) => ({
|
|
955
|
+
tokenStore.update((old) => InternalSession.calculateSessionKey(old) === sessionKey ? {
|
|
950
956
|
...old,
|
|
951
957
|
accessToken: newAccessToken?.token ?? null
|
|
952
|
-
})
|
|
958
|
+
} : old);
|
|
953
959
|
});
|
|
954
960
|
session.onInvalidate(() => {
|
|
955
|
-
tokenStore.update((old) => ({
|
|
961
|
+
tokenStore.update((old) => InternalSession.calculateSessionKey(old) === sessionKey ? {
|
|
956
962
|
...old,
|
|
957
963
|
accessToken: null,
|
|
958
964
|
refreshToken: null
|
|
959
|
-
})
|
|
965
|
+
} : old);
|
|
960
966
|
});
|
|
961
967
|
let sessionsBySessionKey = this._sessionsByTokenStoreAndSessionKey.get(tokenStore) ?? /* @__PURE__ */ new Map();
|
|
962
968
|
this._sessionsByTokenStoreAndSessionKey.set(tokenStore, sessionsBySessionKey);
|
|
@@ -1905,17 +1911,17 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
1905
1911
|
}
|
|
1906
1912
|
_getBotChallengeSiteKeys() {
|
|
1907
1913
|
if (!isBrowserLike()) return null;
|
|
1908
|
-
const visibleSiteKey = envVars.
|
|
1914
|
+
const visibleSiteKey = envVars.HEXCLAVE_BOT_CHALLENGE_SITE_KEY;
|
|
1909
1915
|
if (!visibleSiteKey) {
|
|
1910
1916
|
if (!this._botChallengeSiteKeysWarned) {
|
|
1911
1917
|
this._botChallengeSiteKeysWarned = true;
|
|
1912
|
-
console.warn("[stack-auth]
|
|
1918
|
+
console.warn("[stack-auth] HEXCLAVE_BOT_CHALLENGE_SITE_KEY is not set — bot challenge fraud protection is disabled. Set the env variable to enable it.");
|
|
1913
1919
|
}
|
|
1914
1920
|
return null;
|
|
1915
1921
|
}
|
|
1916
1922
|
return {
|
|
1917
1923
|
visibleSiteKey,
|
|
1918
|
-
invisibleSiteKey: envVars.
|
|
1924
|
+
invisibleSiteKey: envVars.HEXCLAVE_BOT_CHALLENGE_INVISIBLE_SITE_KEY ?? visibleSiteKey
|
|
1919
1925
|
};
|
|
1920
1926
|
}
|
|
1921
1927
|
_getBotChallengeFlowFailure(error) {
|
|
@@ -2037,6 +2043,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
2037
2043
|
}
|
|
2038
2044
|
async _createCrossDomainAuthRedirectUrl(options) {
|
|
2039
2045
|
const session = await this._getSession(options.overrideTokenStoreInit, { awaitPendingAuthResolutions: options.awaitPendingAuthResolutions });
|
|
2046
|
+
await session.fetchNewTokens();
|
|
2040
2047
|
const response = await this._interface.sendClientRequest("/auth/oauth/cross-domain/authorize", {
|
|
2041
2048
|
method: "POST",
|
|
2042
2049
|
headers: { "Content-Type": "application/json" },
|
|
@@ -2137,6 +2144,8 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
2137
2144
|
return await this._redirectToHandler("signUp", options);
|
|
2138
2145
|
}
|
|
2139
2146
|
async redirectToSignOut(options) {
|
|
2147
|
+
const configuredSignOutTarget = this._urlOptions.signOut ?? this._urlOptions.default;
|
|
2148
|
+
if (typeof configuredSignOutTarget !== "string" && configuredSignOutTarget?.type === "hosted") return await this.signOut();
|
|
2140
2149
|
return await this._redirectToHandler("signOut", options);
|
|
2141
2150
|
}
|
|
2142
2151
|
async redirectToEmailVerification(options) {
|
|
@@ -2674,9 +2683,27 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
|
|
|
2674
2683
|
url: options.redirectUrl,
|
|
2675
2684
|
replace: true
|
|
2676
2685
|
});
|
|
2677
|
-
else await this.
|
|
2686
|
+
else await this._redirectToDefaultAfterSignOut();
|
|
2678
2687
|
});
|
|
2679
2688
|
}
|
|
2689
|
+
async _redirectToDefaultAfterSignOut() {
|
|
2690
|
+
if (this._urlOptions.afterSignOut != null) {
|
|
2691
|
+
await this.redirectToAfterSignOut({ replace: true });
|
|
2692
|
+
return;
|
|
2693
|
+
}
|
|
2694
|
+
if (this._urlOptions.home != null) {
|
|
2695
|
+
await this.redirectToHome({ replace: true });
|
|
2696
|
+
return;
|
|
2697
|
+
}
|
|
2698
|
+
if (this._urlOptions.default?.type === "hosted" && typeof window !== "undefined") {
|
|
2699
|
+
await this._redirectTo({
|
|
2700
|
+
url: getRelativePart(new URL(window.location.href)),
|
|
2701
|
+
replace: true
|
|
2702
|
+
});
|
|
2703
|
+
return;
|
|
2704
|
+
}
|
|
2705
|
+
await this.redirectToAfterSignOut({ replace: true });
|
|
2706
|
+
}
|
|
2680
2707
|
async signOut(options) {
|
|
2681
2708
|
const user = await this.getUser({ tokenStore: options?.tokenStore ?? void 0 });
|
|
2682
2709
|
if (user) await user.signOut({ redirectUrl: options?.redirectUrl });
|