@orangecheck/auth-client 2.17.2 → 2.19.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/dist/index.d.mts +18 -2
- package/dist/index.d.ts +18 -2
- package/dist/index.js +306 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +298 -73
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -31,6 +31,7 @@ interface OcSessionState {
|
|
|
31
31
|
status: OcSessionStatus;
|
|
32
32
|
account: OcAccount | null;
|
|
33
33
|
roster: OcAccountSummary[];
|
|
34
|
+
tabPinned: boolean;
|
|
34
35
|
error: Error | null;
|
|
35
36
|
refresh: () => Promise<void>;
|
|
36
37
|
signOut: (opts?: {
|
|
@@ -124,6 +125,7 @@ interface OcSignInProps {
|
|
|
124
125
|
resolveReturnTo?: (account: OcAccount) => string | Promise<string>;
|
|
125
126
|
authOrigin?: string;
|
|
126
127
|
initialPath?: 'wallet' | 'email';
|
|
128
|
+
providersFirst?: boolean;
|
|
127
129
|
paths?: {
|
|
128
130
|
wallet?: boolean;
|
|
129
131
|
email?: boolean;
|
|
@@ -132,7 +134,7 @@ interface OcSignInProps {
|
|
|
132
134
|
add?: boolean;
|
|
133
135
|
className?: string;
|
|
134
136
|
}
|
|
135
|
-
declare function OcSignIn({ audience, returnTo, onSuccess, resolveReturnTo, linkPrompt, add: addProp, authOrigin, initialPath, paths, className, }: OcSignInProps): React.ReactElement;
|
|
137
|
+
declare function OcSignIn({ audience, returnTo, onSuccess, resolveReturnTo, linkPrompt, add: addProp, authOrigin, initialPath, providersFirst, paths, className, }: OcSignInProps): React.ReactElement;
|
|
136
138
|
|
|
137
139
|
interface OcLinkedIdentity {
|
|
138
140
|
id: string;
|
|
@@ -152,6 +154,20 @@ interface OcLinkedIdentitiesProps {
|
|
|
152
154
|
}
|
|
153
155
|
declare function OcLinkedIdentities({ authOrigin, className, onChange, }: OcLinkedIdentitiesProps): React.ReactElement;
|
|
154
156
|
|
|
157
|
+
declare const TAB_SESSION_HEADER = "x-oc-tab-session";
|
|
158
|
+
declare const TAB_SESSION_STORAGE_KEY = "oc_tab_session";
|
|
159
|
+
declare const TAB_ADOPT_HASH = "#oc-adopt";
|
|
160
|
+
interface OcTabSession {
|
|
161
|
+
token: string;
|
|
162
|
+
didOc: string;
|
|
163
|
+
}
|
|
164
|
+
declare function readTabSession(): OcTabSession | null;
|
|
165
|
+
declare function writeTabSession(session: OcTabSession): void;
|
|
166
|
+
declare function clearTabSession(): void;
|
|
167
|
+
declare function tabSessionHeader(): Record<string, string>;
|
|
168
|
+
declare function installTabFetchInterceptor(authOrigin: string): () => void;
|
|
169
|
+
declare function consumeTabAdoptMarker(): boolean;
|
|
170
|
+
|
|
155
171
|
interface WebAuthnCredentialPublic {
|
|
156
172
|
id: string;
|
|
157
173
|
label: string;
|
|
@@ -234,4 +250,4 @@ declare function handleSudoRequired(body: {
|
|
|
234
250
|
returnTo?: string;
|
|
235
251
|
}): boolean;
|
|
236
252
|
|
|
237
|
-
export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, type DisplayIdentity, type DisplayIdentityKind, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, type OcAccountSummary, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcLinkedIdentities, type OcLinkedIdentitiesProps, type OcLinkedIdentity, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignIn, OcSignInButton, type OcSignInButtonProps, type OcSignInProps, type OcSignOutScope, type RedirectToSudoArgs, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, type UseStepUpAuthReturn, type UseWebAuthnListReturn, type UseWebAuthnRegisterReturn, type WebAuthnAssertionStatus, type WebAuthnCredentialPublic, type WebAuthnListStatus, type WebAuthnRegisterResult, type WebAuthnRegisterStatus, type WebAuthnRemoveResult, type WebAuthnRenameResult, type WebAuthnStepUpResult, buildAddAccountUrl, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
|
|
253
|
+
export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, type DisplayIdentity, type DisplayIdentityKind, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, type OcAccountSummary, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcLinkedIdentities, type OcLinkedIdentitiesProps, type OcLinkedIdentity, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignIn, OcSignInButton, type OcSignInButtonProps, type OcSignInProps, type OcSignOutScope, type OcTabSession, type RedirectToSudoArgs, TAB_ADOPT_HASH, TAB_SESSION_HEADER, TAB_SESSION_STORAGE_KEY, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, type UseStepUpAuthReturn, type UseWebAuthnListReturn, type UseWebAuthnRegisterReturn, type WebAuthnAssertionStatus, type WebAuthnCredentialPublic, type WebAuthnListStatus, type WebAuthnRegisterResult, type WebAuthnRegisterStatus, type WebAuthnRemoveResult, type WebAuthnRenameResult, type WebAuthnStepUpResult, buildAddAccountUrl, buildSignInUrl, clearTabSession, consumeTabAdoptMarker, fetchOcLinkedIdentities, handleSudoRequired, installTabFetchInterceptor, readTabSession, redirectToSudo, tabSessionHeader, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister, writeTabSession };
|
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ interface OcSessionState {
|
|
|
31
31
|
status: OcSessionStatus;
|
|
32
32
|
account: OcAccount | null;
|
|
33
33
|
roster: OcAccountSummary[];
|
|
34
|
+
tabPinned: boolean;
|
|
34
35
|
error: Error | null;
|
|
35
36
|
refresh: () => Promise<void>;
|
|
36
37
|
signOut: (opts?: {
|
|
@@ -124,6 +125,7 @@ interface OcSignInProps {
|
|
|
124
125
|
resolveReturnTo?: (account: OcAccount) => string | Promise<string>;
|
|
125
126
|
authOrigin?: string;
|
|
126
127
|
initialPath?: 'wallet' | 'email';
|
|
128
|
+
providersFirst?: boolean;
|
|
127
129
|
paths?: {
|
|
128
130
|
wallet?: boolean;
|
|
129
131
|
email?: boolean;
|
|
@@ -132,7 +134,7 @@ interface OcSignInProps {
|
|
|
132
134
|
add?: boolean;
|
|
133
135
|
className?: string;
|
|
134
136
|
}
|
|
135
|
-
declare function OcSignIn({ audience, returnTo, onSuccess, resolveReturnTo, linkPrompt, add: addProp, authOrigin, initialPath, paths, className, }: OcSignInProps): React.ReactElement;
|
|
137
|
+
declare function OcSignIn({ audience, returnTo, onSuccess, resolveReturnTo, linkPrompt, add: addProp, authOrigin, initialPath, providersFirst, paths, className, }: OcSignInProps): React.ReactElement;
|
|
136
138
|
|
|
137
139
|
interface OcLinkedIdentity {
|
|
138
140
|
id: string;
|
|
@@ -152,6 +154,20 @@ interface OcLinkedIdentitiesProps {
|
|
|
152
154
|
}
|
|
153
155
|
declare function OcLinkedIdentities({ authOrigin, className, onChange, }: OcLinkedIdentitiesProps): React.ReactElement;
|
|
154
156
|
|
|
157
|
+
declare const TAB_SESSION_HEADER = "x-oc-tab-session";
|
|
158
|
+
declare const TAB_SESSION_STORAGE_KEY = "oc_tab_session";
|
|
159
|
+
declare const TAB_ADOPT_HASH = "#oc-adopt";
|
|
160
|
+
interface OcTabSession {
|
|
161
|
+
token: string;
|
|
162
|
+
didOc: string;
|
|
163
|
+
}
|
|
164
|
+
declare function readTabSession(): OcTabSession | null;
|
|
165
|
+
declare function writeTabSession(session: OcTabSession): void;
|
|
166
|
+
declare function clearTabSession(): void;
|
|
167
|
+
declare function tabSessionHeader(): Record<string, string>;
|
|
168
|
+
declare function installTabFetchInterceptor(authOrigin: string): () => void;
|
|
169
|
+
declare function consumeTabAdoptMarker(): boolean;
|
|
170
|
+
|
|
155
171
|
interface WebAuthnCredentialPublic {
|
|
156
172
|
id: string;
|
|
157
173
|
label: string;
|
|
@@ -234,4 +250,4 @@ declare function handleSudoRequired(body: {
|
|
|
234
250
|
returnTo?: string;
|
|
235
251
|
}): boolean;
|
|
236
252
|
|
|
237
|
-
export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, type DisplayIdentity, type DisplayIdentityKind, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, type OcAccountSummary, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcLinkedIdentities, type OcLinkedIdentitiesProps, type OcLinkedIdentity, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignIn, OcSignInButton, type OcSignInButtonProps, type OcSignInProps, type OcSignOutScope, type RedirectToSudoArgs, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, type UseStepUpAuthReturn, type UseWebAuthnListReturn, type UseWebAuthnRegisterReturn, type WebAuthnAssertionStatus, type WebAuthnCredentialPublic, type WebAuthnListStatus, type WebAuthnRegisterResult, type WebAuthnRegisterStatus, type WebAuthnRemoveResult, type WebAuthnRenameResult, type WebAuthnStepUpResult, buildAddAccountUrl, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
|
|
253
|
+
export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, type DisplayIdentity, type DisplayIdentityKind, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, type OcAccountSummary, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcLinkedIdentities, type OcLinkedIdentitiesProps, type OcLinkedIdentity, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignIn, OcSignInButton, type OcSignInButtonProps, type OcSignInProps, type OcSignOutScope, type OcTabSession, type RedirectToSudoArgs, TAB_ADOPT_HASH, TAB_SESSION_HEADER, TAB_SESSION_STORAGE_KEY, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, type UseStepUpAuthReturn, type UseWebAuthnListReturn, type UseWebAuthnRegisterReturn, type WebAuthnAssertionStatus, type WebAuthnCredentialPublic, type WebAuthnListStatus, type WebAuthnRegisterResult, type WebAuthnRegisterStatus, type WebAuthnRemoveResult, type WebAuthnRenameResult, type WebAuthnStepUpResult, buildAddAccountUrl, buildSignInUrl, clearTabSession, consumeTabAdoptMarker, fetchOcLinkedIdentities, handleSudoRequired, installTabFetchInterceptor, readTabSession, redirectToSudo, tabSessionHeader, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister, writeTabSession };
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,91 @@ function buildAddAccountUrl(cfg, returnTo) {
|
|
|
49
49
|
u.searchParams.set("add", "1");
|
|
50
50
|
return u.toString();
|
|
51
51
|
}
|
|
52
|
+
|
|
53
|
+
// src/tab-session.ts
|
|
54
|
+
var TAB_SESSION_HEADER = "x-oc-tab-session";
|
|
55
|
+
var TAB_SESSION_STORAGE_KEY = "oc_tab_session";
|
|
56
|
+
var TAB_ADOPT_HASH = "#oc-adopt";
|
|
57
|
+
function readTabSession() {
|
|
58
|
+
if (typeof window === "undefined") return null;
|
|
59
|
+
try {
|
|
60
|
+
const raw = window.sessionStorage.getItem(TAB_SESSION_STORAGE_KEY);
|
|
61
|
+
if (!raw) return null;
|
|
62
|
+
const parsed = JSON.parse(raw);
|
|
63
|
+
if (typeof parsed.token !== "string" || parsed.token.length === 0) return null;
|
|
64
|
+
if (typeof parsed.didOc !== "string" || parsed.didOc.length === 0) return null;
|
|
65
|
+
return { token: parsed.token, didOc: parsed.didOc };
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function writeTabSession(session) {
|
|
71
|
+
if (typeof window === "undefined") return;
|
|
72
|
+
try {
|
|
73
|
+
window.sessionStorage.setItem(TAB_SESSION_STORAGE_KEY, JSON.stringify(session));
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function clearTabSession() {
|
|
78
|
+
if (typeof window === "undefined") return;
|
|
79
|
+
try {
|
|
80
|
+
window.sessionStorage.removeItem(TAB_SESSION_STORAGE_KEY);
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function tabSessionHeader() {
|
|
85
|
+
const pin = readTabSession();
|
|
86
|
+
return pin ? { [TAB_SESSION_HEADER]: pin.token } : {};
|
|
87
|
+
}
|
|
88
|
+
function isPinnableUrl(url, authOrigin) {
|
|
89
|
+
if (typeof window === "undefined") return false;
|
|
90
|
+
try {
|
|
91
|
+
const u = new URL(url, window.location.href);
|
|
92
|
+
return u.origin === window.location.origin || u.origin === authOrigin;
|
|
93
|
+
} catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function installTabFetchInterceptor(authOrigin) {
|
|
98
|
+
if (typeof window === "undefined") return () => {
|
|
99
|
+
};
|
|
100
|
+
const original = window.fetch;
|
|
101
|
+
const wrapped = (input, init) => {
|
|
102
|
+
try {
|
|
103
|
+
const pin = readTabSession();
|
|
104
|
+
if (pin) {
|
|
105
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
106
|
+
if (isPinnableUrl(url, authOrigin)) {
|
|
107
|
+
const headers = new Headers(
|
|
108
|
+
init?.headers ?? (input instanceof Request ? input.headers : void 0)
|
|
109
|
+
);
|
|
110
|
+
if (!headers.has("authorization") && !headers.has(TAB_SESSION_HEADER)) {
|
|
111
|
+
headers.set(TAB_SESSION_HEADER, pin.token);
|
|
112
|
+
init = { ...init, headers };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
return original.call(window, input, init);
|
|
119
|
+
};
|
|
120
|
+
window.fetch = wrapped;
|
|
121
|
+
return () => {
|
|
122
|
+
if (window.fetch === wrapped) window.fetch = original;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function consumeTabAdoptMarker() {
|
|
126
|
+
if (typeof window === "undefined") return false;
|
|
127
|
+
if (!window.location.hash.includes(TAB_ADOPT_HASH.slice(1))) return false;
|
|
128
|
+
clearTabSession();
|
|
129
|
+
try {
|
|
130
|
+
const url = new URL(window.location.href);
|
|
131
|
+
url.hash = "";
|
|
132
|
+
window.history.replaceState(window.history.state, "", url.toString());
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
52
137
|
var SessionContext = React3__namespace.createContext(null);
|
|
53
138
|
function normalizeDisplayIdentity(raw, didOc) {
|
|
54
139
|
const di = raw.display_identity ?? raw.displayIdentity;
|
|
@@ -75,7 +160,7 @@ async function fetchHostRoster(cfg) {
|
|
|
75
160
|
const res = await fetch(`${cfg.authOrigin}${cfg.mePath}`, {
|
|
76
161
|
method: "GET",
|
|
77
162
|
credentials: "include",
|
|
78
|
-
headers: { Accept: "application/json" }
|
|
163
|
+
headers: { Accept: "application/json", ...tabSessionHeader() }
|
|
79
164
|
});
|
|
80
165
|
if (!res.ok) return [];
|
|
81
166
|
const body = await res.json();
|
|
@@ -112,14 +197,50 @@ function OcSessionProvider({
|
|
|
112
197
|
const [roster, setRoster] = React3__namespace.useState([]);
|
|
113
198
|
const [status, setStatus] = React3__namespace.useState("loading");
|
|
114
199
|
const [error, setError] = React3__namespace.useState(null);
|
|
200
|
+
const [tabPinned, setTabPinned] = React3__namespace.useState(false);
|
|
201
|
+
const pinInFlightRef = React3__namespace.useRef(false);
|
|
202
|
+
const pinThisTab = React3__namespace.useCallback(
|
|
203
|
+
async (didOc) => {
|
|
204
|
+
if (pinInFlightRef.current || readTabSession()) return;
|
|
205
|
+
pinInFlightRef.current = true;
|
|
206
|
+
try {
|
|
207
|
+
const res = await fetch(`${cfg.authOrigin}/api/auth/tab`, {
|
|
208
|
+
method: "POST",
|
|
209
|
+
credentials: "include",
|
|
210
|
+
headers: { Accept: "application/json" }
|
|
211
|
+
});
|
|
212
|
+
if (!res.ok) return;
|
|
213
|
+
const body = await res.json();
|
|
214
|
+
if (body.ok && typeof body.token === "string" && body.account?.did_oc === didOc) {
|
|
215
|
+
writeTabSession({ token: body.token, didOc });
|
|
216
|
+
setTabPinned(true);
|
|
217
|
+
}
|
|
218
|
+
} catch {
|
|
219
|
+
} finally {
|
|
220
|
+
pinInFlightRef.current = false;
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
[cfg.authOrigin]
|
|
224
|
+
);
|
|
115
225
|
const refresh = React3__namespace.useCallback(async () => {
|
|
116
226
|
if (typeof window === "undefined") return;
|
|
117
227
|
try {
|
|
118
|
-
|
|
228
|
+
let pin = readTabSession();
|
|
229
|
+
let res = await fetch(cfg.mePath, {
|
|
119
230
|
method: "GET",
|
|
120
231
|
credentials: "include",
|
|
121
|
-
headers: { Accept: "application/json" }
|
|
232
|
+
headers: { Accept: "application/json", ...tabSessionHeader() }
|
|
122
233
|
});
|
|
234
|
+
if (res.status === 401 && pin) {
|
|
235
|
+
clearTabSession();
|
|
236
|
+
pin = null;
|
|
237
|
+
setTabPinned(false);
|
|
238
|
+
res = await fetch(cfg.mePath, {
|
|
239
|
+
method: "GET",
|
|
240
|
+
credentials: "include",
|
|
241
|
+
headers: { Accept: "application/json" }
|
|
242
|
+
});
|
|
243
|
+
}
|
|
123
244
|
if (res.status === 401) {
|
|
124
245
|
setAccount(null);
|
|
125
246
|
setRoster([]);
|
|
@@ -134,11 +255,17 @@ function OcSessionProvider({
|
|
|
134
255
|
}
|
|
135
256
|
const body = await res.json();
|
|
136
257
|
const acct = normalizeAccount(body.account);
|
|
258
|
+
if (acct && pin && acct.didOc !== pin.didOc) {
|
|
259
|
+
clearTabSession();
|
|
260
|
+
pin = null;
|
|
261
|
+
}
|
|
262
|
+
setTabPinned(pin !== null);
|
|
137
263
|
const rosterEntries = Array.isArray(body.roster) ? body.roster.map(normalizeRosterEntry).filter((r) => r !== null) : [];
|
|
138
264
|
setAccount(acct);
|
|
139
265
|
setRoster(rosterEntries);
|
|
140
266
|
setStatus(acct ? "authenticated" : "anonymous");
|
|
141
267
|
setError(null);
|
|
268
|
+
if (acct && !pin) void pinThisTab(acct.didOc);
|
|
142
269
|
const currentOrigin = typeof window !== "undefined" ? window.location.origin : null;
|
|
143
270
|
if (acct && rosterEntries.length === 0 && currentOrigin !== null && !cfg.authOrigin.startsWith(currentOrigin)) {
|
|
144
271
|
const peers = await fetchHostRoster(cfg);
|
|
@@ -148,10 +275,12 @@ function OcSessionProvider({
|
|
|
148
275
|
setStatus("error");
|
|
149
276
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
150
277
|
}
|
|
151
|
-
}, [cfg]);
|
|
278
|
+
}, [cfg, pinThisTab]);
|
|
152
279
|
React3__namespace.useEffect(() => {
|
|
280
|
+
consumeTabAdoptMarker();
|
|
153
281
|
void refresh();
|
|
154
282
|
}, [refresh]);
|
|
283
|
+
React3__namespace.useEffect(() => installTabFetchInterceptor(cfg.authOrigin), [cfg.authOrigin]);
|
|
155
284
|
const signOut = React3__namespace.useCallback(
|
|
156
285
|
async (opts) => {
|
|
157
286
|
const scope = opts?.scope ?? "all";
|
|
@@ -161,6 +290,10 @@ function OcSessionProvider({
|
|
|
161
290
|
const res = await fetch(url.toString(), {
|
|
162
291
|
method: "POST",
|
|
163
292
|
credentials: "include",
|
|
293
|
+
// Per-tab · carry the pin so scope='current' signs out
|
|
294
|
+
// the account THIS tab is operating as, not whichever
|
|
295
|
+
// account the shared cookie happens to point at.
|
|
296
|
+
headers: { ...tabSessionHeader() },
|
|
164
297
|
// `keepalive` lets the logout round-trip complete even if
|
|
165
298
|
// the caller hard-navigates away in the same tick (e.g.
|
|
166
299
|
// `<OcAccountMenu>` redirects home immediately on sign-out).
|
|
@@ -168,11 +301,15 @@ function OcSessionProvider({
|
|
|
168
301
|
// and the `.ochk.io` cookie may never get cleared.
|
|
169
302
|
keepalive: true
|
|
170
303
|
});
|
|
304
|
+
clearTabSession();
|
|
305
|
+
setTabPinned(false);
|
|
171
306
|
if (scope === "current" && res.ok) {
|
|
172
307
|
await refresh();
|
|
173
308
|
return;
|
|
174
309
|
}
|
|
175
310
|
} catch {
|
|
311
|
+
clearTabSession();
|
|
312
|
+
setTabPinned(false);
|
|
176
313
|
}
|
|
177
314
|
setAccount(null);
|
|
178
315
|
setRoster([]);
|
|
@@ -186,7 +323,7 @@ function OcSessionProvider({
|
|
|
186
323
|
const res = await fetch(`${cfg.authOrigin}/api/auth/switch`, {
|
|
187
324
|
method: "POST",
|
|
188
325
|
credentials: "include",
|
|
189
|
-
headers: { "Content-Type": "application/json" },
|
|
326
|
+
headers: { "Content-Type": "application/json", ...tabSessionHeader() },
|
|
190
327
|
body: JSON.stringify({ did_oc: didOc })
|
|
191
328
|
});
|
|
192
329
|
if (!res.ok) {
|
|
@@ -198,6 +335,14 @@ function OcSessionProvider({
|
|
|
198
335
|
}
|
|
199
336
|
throw new Error(`[@orangecheck/auth-client] switchAccount failed: ${reason}`);
|
|
200
337
|
}
|
|
338
|
+
try {
|
|
339
|
+
const body = await res.json();
|
|
340
|
+
if (typeof body.token === "string" && body.account?.did_oc) {
|
|
341
|
+
writeTabSession({ token: body.token, didOc: body.account.did_oc });
|
|
342
|
+
setTabPinned(true);
|
|
343
|
+
}
|
|
344
|
+
} catch {
|
|
345
|
+
}
|
|
201
346
|
await refresh();
|
|
202
347
|
},
|
|
203
348
|
[cfg.authOrigin, refresh]
|
|
@@ -215,7 +360,7 @@ function OcSessionProvider({
|
|
|
215
360
|
const res = await fetch(`${cfg.authOrigin}/api/auth/account`, {
|
|
216
361
|
method: "PATCH",
|
|
217
362
|
credentials: "include",
|
|
218
|
-
headers: { "Content-Type": "application/json" },
|
|
363
|
+
headers: { "Content-Type": "application/json", ...tabSessionHeader() },
|
|
219
364
|
body: JSON.stringify({ display_identity: kind })
|
|
220
365
|
});
|
|
221
366
|
if (!res.ok) {
|
|
@@ -227,6 +372,14 @@ function OcSessionProvider({
|
|
|
227
372
|
}
|
|
228
373
|
throw new Error(`[@orangecheck/auth-client] setDisplayIdentity failed: ${reason}`);
|
|
229
374
|
}
|
|
375
|
+
try {
|
|
376
|
+
const body = await res.json();
|
|
377
|
+
const pin = readTabSession();
|
|
378
|
+
if (pin && typeof body.token === "string" && body.account?.did_oc === pin.didOc) {
|
|
379
|
+
writeTabSession({ token: body.token, didOc: pin.didOc });
|
|
380
|
+
}
|
|
381
|
+
} catch {
|
|
382
|
+
}
|
|
230
383
|
await refresh();
|
|
231
384
|
},
|
|
232
385
|
[cfg.authOrigin, refresh]
|
|
@@ -237,6 +390,7 @@ function OcSessionProvider({
|
|
|
237
390
|
status,
|
|
238
391
|
account,
|
|
239
392
|
roster,
|
|
393
|
+
tabPinned,
|
|
240
394
|
error,
|
|
241
395
|
refresh,
|
|
242
396
|
signOut,
|
|
@@ -249,6 +403,7 @@ function OcSessionProvider({
|
|
|
249
403
|
status,
|
|
250
404
|
account,
|
|
251
405
|
roster,
|
|
406
|
+
tabPinned,
|
|
252
407
|
error,
|
|
253
408
|
refresh,
|
|
254
409
|
signOut,
|
|
@@ -1774,6 +1929,18 @@ function safeReturnTo(input) {
|
|
|
1774
1929
|
if (!candidate.startsWith("/") || candidate.startsWith("//")) return "/";
|
|
1775
1930
|
return candidate;
|
|
1776
1931
|
}
|
|
1932
|
+
function familyReturnTarget(input) {
|
|
1933
|
+
if (typeof input !== "string" || input.length === 0) return void 0;
|
|
1934
|
+
if (input.startsWith("/") && !input.startsWith("//")) return input;
|
|
1935
|
+
try {
|
|
1936
|
+
const u = new URL(input);
|
|
1937
|
+
if (u.protocol !== "https:") return void 0;
|
|
1938
|
+
const host = u.hostname.toLowerCase();
|
|
1939
|
+
if (host === "ochk.io" || host.endsWith(".ochk.io")) return u.toString();
|
|
1940
|
+
} catch {
|
|
1941
|
+
}
|
|
1942
|
+
return void 0;
|
|
1943
|
+
}
|
|
1777
1944
|
function hardNavigate(target) {
|
|
1778
1945
|
if (typeof window === "undefined") return;
|
|
1779
1946
|
window.location.assign(target);
|
|
@@ -1786,13 +1953,27 @@ function OcSignIn({
|
|
|
1786
1953
|
linkPrompt = true,
|
|
1787
1954
|
add: addProp,
|
|
1788
1955
|
authOrigin = "https://ochk.io",
|
|
1789
|
-
initialPath
|
|
1956
|
+
initialPath,
|
|
1957
|
+
providersFirst = false,
|
|
1790
1958
|
paths,
|
|
1791
1959
|
className
|
|
1792
1960
|
}) {
|
|
1793
1961
|
const walletEnabled = paths?.wallet ?? true;
|
|
1794
1962
|
const emailEnabled = paths?.email ?? true;
|
|
1795
|
-
const
|
|
1963
|
+
const [resolvedReturn, setResolvedReturn] = React3__namespace.useState(
|
|
1964
|
+
() => familyReturnTarget(returnTo) ?? safeReturnTo(returnTo)
|
|
1965
|
+
);
|
|
1966
|
+
React3__namespace.useEffect(() => {
|
|
1967
|
+
const fromProp = familyReturnTarget(returnTo);
|
|
1968
|
+
if (fromProp) {
|
|
1969
|
+
setResolvedReturn(fromProp);
|
|
1970
|
+
return;
|
|
1971
|
+
}
|
|
1972
|
+
if (typeof window === "undefined") return;
|
|
1973
|
+
const q = new URLSearchParams(window.location.search);
|
|
1974
|
+
const fromQuery = familyReturnTarget(q.get("return_to")) ?? familyReturnTarget(q.get("next"));
|
|
1975
|
+
setResolvedReturn(fromQuery ?? "/");
|
|
1976
|
+
}, [returnTo]);
|
|
1796
1977
|
const [addMode, setAddMode] = React3__namespace.useState(Boolean(addProp));
|
|
1797
1978
|
React3__namespace.useEffect(() => {
|
|
1798
1979
|
if (typeof window === "undefined") return;
|
|
@@ -1802,7 +1983,9 @@ function OcSignIn({
|
|
|
1802
1983
|
}
|
|
1803
1984
|
setAddMode(new URLSearchParams(window.location.search).get("add") === "1");
|
|
1804
1985
|
}, [addProp]);
|
|
1805
|
-
const [path, setPath] = React3__namespace.useState(
|
|
1986
|
+
const [path, setPath] = React3__namespace.useState(
|
|
1987
|
+
initialPath ?? (providersFirst ? "email" : "wallet")
|
|
1988
|
+
);
|
|
1806
1989
|
const [signedIn, setSignedIn] = React3__namespace.useState(null);
|
|
1807
1990
|
const [linkAlso, setLinkAlso] = React3__namespace.useState(false);
|
|
1808
1991
|
const [oauthError, setOauthError] = React3__namespace.useState(false);
|
|
@@ -1816,18 +1999,20 @@ function OcSignIn({
|
|
|
1816
1999
|
async (account) => {
|
|
1817
2000
|
if (resolveReturnTo) {
|
|
1818
2001
|
try {
|
|
1819
|
-
|
|
2002
|
+
const resolved = familyReturnTarget(await resolveReturnTo(account));
|
|
2003
|
+
hardNavigate(resolved ?? resolvedReturn);
|
|
1820
2004
|
return;
|
|
1821
2005
|
} catch {
|
|
1822
2006
|
}
|
|
1823
2007
|
}
|
|
1824
|
-
hardNavigate(
|
|
2008
|
+
hardNavigate(resolvedReturn);
|
|
1825
2009
|
},
|
|
1826
|
-
[resolveReturnTo,
|
|
2010
|
+
[resolveReturnTo, resolvedReturn]
|
|
1827
2011
|
);
|
|
1828
2012
|
const handleSuccess = React3__namespace.useCallback(
|
|
1829
2013
|
async (account, token, via) => {
|
|
1830
2014
|
const proceed = () => {
|
|
2015
|
+
clearTabSession();
|
|
1831
2016
|
if (onSuccess) onSuccess(account, token);
|
|
1832
2017
|
else void navigate(account);
|
|
1833
2018
|
};
|
|
@@ -1948,7 +2133,16 @@ function OcSignIn({
|
|
|
1948
2133
|
]
|
|
1949
2134
|
}
|
|
1950
2135
|
),
|
|
1951
|
-
|
|
2136
|
+
providersFirst && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2137
|
+
ProviderSignIn,
|
|
2138
|
+
{
|
|
2139
|
+
authOrigin,
|
|
2140
|
+
returnTo: resolvedReturn,
|
|
2141
|
+
add: addMode,
|
|
2142
|
+
first: true
|
|
2143
|
+
}
|
|
2144
|
+
),
|
|
2145
|
+
bothEnabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1952
2146
|
"div",
|
|
1953
2147
|
{
|
|
1954
2148
|
role: "tablist",
|
|
@@ -1960,7 +2154,24 @@ function OcSignIn({
|
|
|
1960
2154
|
marginBottom: 16,
|
|
1961
2155
|
borderBottom: "1px solid var(--border, #27272a)"
|
|
1962
2156
|
},
|
|
1963
|
-
children: [
|
|
2157
|
+
children: providersFirst ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2158
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2159
|
+
SigninTab,
|
|
2160
|
+
{
|
|
2161
|
+
active: path === "email",
|
|
2162
|
+
onClick: () => setPath("email"),
|
|
2163
|
+
children: "email + otp"
|
|
2164
|
+
}
|
|
2165
|
+
),
|
|
2166
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2167
|
+
SigninTab,
|
|
2168
|
+
{
|
|
2169
|
+
active: path === "wallet",
|
|
2170
|
+
onClick: () => setPath("wallet"),
|
|
2171
|
+
children: "bitcoin \xB7 self-custody"
|
|
2172
|
+
}
|
|
2173
|
+
)
|
|
2174
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1964
2175
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1965
2176
|
SigninTab,
|
|
1966
2177
|
{
|
|
@@ -1969,8 +2180,15 @@ function OcSignIn({
|
|
|
1969
2180
|
children: "bitcoin wallet"
|
|
1970
2181
|
}
|
|
1971
2182
|
),
|
|
1972
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1973
|
-
|
|
2183
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2184
|
+
SigninTab,
|
|
2185
|
+
{
|
|
2186
|
+
active: path === "email",
|
|
2187
|
+
onClick: () => setPath("email"),
|
|
2188
|
+
children: "email + otp"
|
|
2189
|
+
}
|
|
2190
|
+
)
|
|
2191
|
+
] })
|
|
1974
2192
|
}
|
|
1975
2193
|
),
|
|
1976
2194
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-oc-signin-panel": "", role: "tabpanel", children: [
|
|
@@ -1992,7 +2210,7 @@ function OcSignIn({
|
|
|
1992
2210
|
}
|
|
1993
2211
|
)
|
|
1994
2212
|
] }),
|
|
1995
|
-
/* @__PURE__ */ jsxRuntime.jsx(ProviderSignIn, { authOrigin, returnTo:
|
|
2213
|
+
!providersFirst && /* @__PURE__ */ jsxRuntime.jsx(ProviderSignIn, { authOrigin, returnTo: resolvedReturn, add: addMode }),
|
|
1996
2214
|
linkPrompt && /* @__PURE__ */ jsxRuntime.jsxs("label", { "data-oc-signin-linkalso": "", style: linkAlsoStyle, children: [
|
|
1997
2215
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1998
2216
|
"input",
|
|
@@ -2062,7 +2280,9 @@ function ProviderIcon({ id }) {
|
|
|
2062
2280
|
}
|
|
2063
2281
|
function ProviderSignIn({
|
|
2064
2282
|
authOrigin,
|
|
2065
|
-
returnTo
|
|
2283
|
+
returnTo,
|
|
2284
|
+
add,
|
|
2285
|
+
first = false
|
|
2066
2286
|
}) {
|
|
2067
2287
|
const [providers, setProviders] = React3__namespace.useState([]);
|
|
2068
2288
|
const [origin, setOrigin] = React3__namespace.useState("");
|
|
@@ -2078,62 +2298,67 @@ function ProviderSignIn({
|
|
|
2078
2298
|
};
|
|
2079
2299
|
}, [authOrigin]);
|
|
2080
2300
|
if (providers.length === 0) return null;
|
|
2081
|
-
const providerReturnTo = origin ? `${origin}${returnTo}` : returnTo;
|
|
2301
|
+
const providerReturnTo = returnTo.startsWith("/") ? origin ? `${origin}${returnTo}` : returnTo : returnTo;
|
|
2082
2302
|
const line = { flex: 1, height: 1, background: "var(--border, #27272a)" };
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
{
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
textTransform: "uppercase"
|
|
2097
|
-
},
|
|
2098
|
-
children: [
|
|
2099
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: line }),
|
|
2100
|
-
"or",
|
|
2101
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: line })
|
|
2102
|
-
]
|
|
2103
|
-
}
|
|
2104
|
-
),
|
|
2105
|
-
providers.map((p, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2106
|
-
"a",
|
|
2107
|
-
{
|
|
2108
|
-
href: `${authOrigin}/api/auth/${p.id}/start?return_to=${encodeURIComponent(
|
|
2109
|
-
providerReturnTo
|
|
2110
|
-
)}`,
|
|
2111
|
-
"data-oc-signin-provider": p.id,
|
|
2112
|
-
style: {
|
|
2113
|
-
display: "flex",
|
|
2114
|
-
alignItems: "center",
|
|
2115
|
-
justifyContent: "center",
|
|
2116
|
-
gap: 10,
|
|
2117
|
-
boxSizing: "border-box",
|
|
2118
|
-
width: "100%",
|
|
2119
|
-
marginTop: i === 0 ? 0 : 8,
|
|
2120
|
-
padding: "0.6rem 0.875rem",
|
|
2121
|
-
border: "1px solid var(--border, #27272a)",
|
|
2122
|
-
borderRadius: 6,
|
|
2123
|
-
background: "transparent",
|
|
2124
|
-
color: "var(--muted-foreground, #a1a1aa)",
|
|
2125
|
-
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
2126
|
-
fontSize: 12,
|
|
2127
|
-
textDecoration: "none"
|
|
2128
|
-
},
|
|
2129
|
-
children: [
|
|
2130
|
-
/* @__PURE__ */ jsxRuntime.jsx(ProviderIcon, { id: p.id }),
|
|
2131
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: p.label })
|
|
2132
|
-
]
|
|
2303
|
+
const divider = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2304
|
+
"div",
|
|
2305
|
+
{
|
|
2306
|
+
style: {
|
|
2307
|
+
display: "flex",
|
|
2308
|
+
alignItems: "center",
|
|
2309
|
+
gap: 10,
|
|
2310
|
+
margin: first ? "14px 0 4px" : "4px 0 12px",
|
|
2311
|
+
color: "var(--muted-foreground, #a1a1aa)",
|
|
2312
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
2313
|
+
fontSize: 10,
|
|
2314
|
+
letterSpacing: "0.16em",
|
|
2315
|
+
textTransform: "uppercase"
|
|
2133
2316
|
},
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2317
|
+
children: [
|
|
2318
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: line }),
|
|
2319
|
+
"or",
|
|
2320
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: line })
|
|
2321
|
+
]
|
|
2322
|
+
}
|
|
2323
|
+
);
|
|
2324
|
+
const buttons = providers.map((p, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2325
|
+
"a",
|
|
2326
|
+
{
|
|
2327
|
+
href: `${authOrigin}/api/auth/${p.id}/start?return_to=${encodeURIComponent(
|
|
2328
|
+
providerReturnTo
|
|
2329
|
+
)}${add ? "&add=1" : ""}`,
|
|
2330
|
+
"data-oc-signin-provider": p.id,
|
|
2331
|
+
style: {
|
|
2332
|
+
display: "flex",
|
|
2333
|
+
alignItems: "center",
|
|
2334
|
+
justifyContent: "center",
|
|
2335
|
+
gap: 10,
|
|
2336
|
+
boxSizing: "border-box",
|
|
2337
|
+
width: "100%",
|
|
2338
|
+
marginTop: i === 0 ? 0 : 8,
|
|
2339
|
+
padding: "0.6rem 0.875rem",
|
|
2340
|
+
border: "1px solid var(--border, #27272a)",
|
|
2341
|
+
borderRadius: 6,
|
|
2342
|
+
background: "transparent",
|
|
2343
|
+
color: "var(--muted-foreground, #a1a1aa)",
|
|
2344
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
2345
|
+
fontSize: 12,
|
|
2346
|
+
textDecoration: "none"
|
|
2347
|
+
},
|
|
2348
|
+
children: [
|
|
2349
|
+
/* @__PURE__ */ jsxRuntime.jsx(ProviderIcon, { id: p.id }),
|
|
2350
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: p.label })
|
|
2351
|
+
]
|
|
2352
|
+
},
|
|
2353
|
+
p.id
|
|
2354
|
+
));
|
|
2355
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-oc-signin-providers": "", style: first ? { marginBottom: 4 } : { marginTop: 20 }, children: first ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2356
|
+
buttons,
|
|
2357
|
+
divider
|
|
2358
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2359
|
+
divider,
|
|
2360
|
+
buttons
|
|
2361
|
+
] }) });
|
|
2137
2362
|
}
|
|
2138
2363
|
function WalletFlow({ authOrigin, audience, add, onSuccess }) {
|
|
2139
2364
|
const [address, setAddress] = React3__namespace.useState("");
|
|
@@ -2797,16 +3022,25 @@ exports.OcLinkedIdentities = OcLinkedIdentities;
|
|
|
2797
3022
|
exports.OcSessionProvider = OcSessionProvider;
|
|
2798
3023
|
exports.OcSignIn = OcSignIn;
|
|
2799
3024
|
exports.OcSignInButton = OcSignInButton;
|
|
3025
|
+
exports.TAB_ADOPT_HASH = TAB_ADOPT_HASH;
|
|
3026
|
+
exports.TAB_SESSION_HEADER = TAB_SESSION_HEADER;
|
|
3027
|
+
exports.TAB_SESSION_STORAGE_KEY = TAB_SESSION_STORAGE_KEY;
|
|
2800
3028
|
exports.buildAddAccountUrl = buildAddAccountUrl;
|
|
2801
3029
|
exports.buildSignInUrl = buildSignInUrl;
|
|
3030
|
+
exports.clearTabSession = clearTabSession;
|
|
3031
|
+
exports.consumeTabAdoptMarker = consumeTabAdoptMarker;
|
|
2802
3032
|
exports.fetchOcLinkedIdentities = fetchOcLinkedIdentities;
|
|
2803
3033
|
exports.handleSudoRequired = handleSudoRequired;
|
|
3034
|
+
exports.installTabFetchInterceptor = installTabFetchInterceptor;
|
|
3035
|
+
exports.readTabSession = readTabSession;
|
|
2804
3036
|
exports.redirectToSudo = redirectToSudo;
|
|
3037
|
+
exports.tabSessionHeader = tabSessionHeader;
|
|
2805
3038
|
exports.useOcAddressSuggestion = useOcAddressSuggestion;
|
|
2806
3039
|
exports.useOcSession = useOcSession;
|
|
2807
3040
|
exports.useOptionalOcSession = useOptionalOcSession;
|
|
2808
3041
|
exports.useStepUpAuth = useStepUpAuth;
|
|
2809
3042
|
exports.useWebAuthnList = useWebAuthnList;
|
|
2810
3043
|
exports.useWebAuthnRegister = useWebAuthnRegister;
|
|
3044
|
+
exports.writeTabSession = writeTabSession;
|
|
2811
3045
|
//# sourceMappingURL=index.js.map
|
|
2812
3046
|
//# sourceMappingURL=index.js.map
|