@orangecheck/auth-client 2.25.3 → 2.26.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 +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +485 -252
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +484 -251
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React4 = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var browser = require('@simplewebauthn/browser');
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ function _interopNamespace(e) {
|
|
|
22
22
|
return Object.freeze(n);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
var
|
|
25
|
+
var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
|
|
26
26
|
|
|
27
27
|
// src/provider.tsx
|
|
28
28
|
|
|
@@ -221,7 +221,7 @@ async function consumeTabAccountHint(authOrigin) {
|
|
|
221
221
|
}
|
|
222
222
|
return null;
|
|
223
223
|
}
|
|
224
|
-
var SessionContext =
|
|
224
|
+
var SessionContext = React4__namespace.createContext(null);
|
|
225
225
|
function normalizeDisplayIdentity(raw, didOc) {
|
|
226
226
|
const di = raw.display_identity ?? raw.displayIdentity;
|
|
227
227
|
if (di && typeof di === "object" && typeof di.value === "string" && di.value.length > 0 && typeof di.kind === "string" && DISPLAY_IDENTITY_KINDS.includes(di.kind)) {
|
|
@@ -279,14 +279,14 @@ function OcSessionProvider({
|
|
|
279
279
|
config,
|
|
280
280
|
defaultReturnTo
|
|
281
281
|
}) {
|
|
282
|
-
const cfg =
|
|
283
|
-
const [account, setAccount] =
|
|
284
|
-
const [roster, setRoster] =
|
|
285
|
-
const [status, setStatus] =
|
|
286
|
-
const [error, setError] =
|
|
287
|
-
const [tabPinned, setTabPinned] =
|
|
288
|
-
const pinInFlightRef =
|
|
289
|
-
const pinThisTab =
|
|
282
|
+
const cfg = React4__namespace.useMemo(() => resolveConfig(config), [config]);
|
|
283
|
+
const [account, setAccount] = React4__namespace.useState(null);
|
|
284
|
+
const [roster, setRoster] = React4__namespace.useState([]);
|
|
285
|
+
const [status, setStatus] = React4__namespace.useState("loading");
|
|
286
|
+
const [error, setError] = React4__namespace.useState(null);
|
|
287
|
+
const [tabPinned, setTabPinned] = React4__namespace.useState(false);
|
|
288
|
+
const pinInFlightRef = React4__namespace.useRef(false);
|
|
289
|
+
const pinThisTab = React4__namespace.useCallback(
|
|
290
290
|
async (didOc) => {
|
|
291
291
|
if (pinInFlightRef.current || readTabSession()) return;
|
|
292
292
|
pinInFlightRef.current = true;
|
|
@@ -309,7 +309,7 @@ function OcSessionProvider({
|
|
|
309
309
|
},
|
|
310
310
|
[cfg.authOrigin]
|
|
311
311
|
);
|
|
312
|
-
const refresh =
|
|
312
|
+
const refresh = React4__namespace.useCallback(async () => {
|
|
313
313
|
if (typeof window === "undefined") return;
|
|
314
314
|
try {
|
|
315
315
|
let pin = readTabSession();
|
|
@@ -363,7 +363,7 @@ function OcSessionProvider({
|
|
|
363
363
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
364
364
|
}
|
|
365
365
|
}, [cfg, pinThisTab]);
|
|
366
|
-
|
|
366
|
+
React4__namespace.useEffect(() => {
|
|
367
367
|
let cancelled = false;
|
|
368
368
|
consumeTabAdoptMarker();
|
|
369
369
|
void (async () => {
|
|
@@ -374,9 +374,9 @@ function OcSessionProvider({
|
|
|
374
374
|
cancelled = true;
|
|
375
375
|
};
|
|
376
376
|
}, [refresh, cfg.authOrigin]);
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const signOut =
|
|
377
|
+
React4__namespace.useEffect(() => installTabFetchInterceptor(cfg.authOrigin), [cfg.authOrigin]);
|
|
378
|
+
React4__namespace.useEffect(() => installTabLinkDecorator(cfg.authOrigin), [cfg.authOrigin]);
|
|
379
|
+
const signOut = React4__namespace.useCallback(
|
|
380
380
|
async (opts) => {
|
|
381
381
|
const scope = opts?.scope ?? "all";
|
|
382
382
|
try {
|
|
@@ -412,7 +412,7 @@ function OcSessionProvider({
|
|
|
412
412
|
},
|
|
413
413
|
[cfg.authOrigin, cfg.logoutPath, refresh]
|
|
414
414
|
);
|
|
415
|
-
const switchAccount =
|
|
415
|
+
const switchAccount = React4__namespace.useCallback(
|
|
416
416
|
async (didOc) => {
|
|
417
417
|
if (typeof window === "undefined") return;
|
|
418
418
|
const res = await fetch(`${cfg.authOrigin}/api/auth/switch`, {
|
|
@@ -442,14 +442,14 @@ function OcSessionProvider({
|
|
|
442
442
|
},
|
|
443
443
|
[cfg.authOrigin, refresh]
|
|
444
444
|
);
|
|
445
|
-
const addAccountUrl =
|
|
445
|
+
const addAccountUrl = React4__namespace.useCallback(
|
|
446
446
|
(returnTo) => {
|
|
447
447
|
const rt = returnTo ?? (typeof window !== "undefined" ? window.location.href : void 0);
|
|
448
448
|
return buildAddAccountUrl(cfg, rt);
|
|
449
449
|
},
|
|
450
450
|
[cfg]
|
|
451
451
|
);
|
|
452
|
-
const setDisplayIdentity =
|
|
452
|
+
const setDisplayIdentity = React4__namespace.useCallback(
|
|
453
453
|
async (kind) => {
|
|
454
454
|
if (typeof window === "undefined") return;
|
|
455
455
|
const res = await fetch(`${cfg.authOrigin}/api/auth/account`, {
|
|
@@ -479,7 +479,7 @@ function OcSessionProvider({
|
|
|
479
479
|
},
|
|
480
480
|
[cfg.authOrigin, refresh]
|
|
481
481
|
);
|
|
482
|
-
const value =
|
|
482
|
+
const value = React4__namespace.useMemo(() => {
|
|
483
483
|
const returnTo = defaultReturnTo ?? (typeof window !== "undefined" ? window.location.href : void 0);
|
|
484
484
|
return {
|
|
485
485
|
status,
|
|
@@ -511,7 +511,7 @@ function OcSessionProvider({
|
|
|
511
511
|
return /* @__PURE__ */ jsxRuntime.jsx(SessionContext.Provider, { value, children });
|
|
512
512
|
}
|
|
513
513
|
function useOcSession() {
|
|
514
|
-
const ctx =
|
|
514
|
+
const ctx = React4__namespace.useContext(SessionContext);
|
|
515
515
|
if (!ctx) {
|
|
516
516
|
throw new Error(
|
|
517
517
|
"[@orangecheck/auth-client] useOcSession() must be called inside <OcSessionProvider>"
|
|
@@ -520,7 +520,7 @@ function useOcSession() {
|
|
|
520
520
|
return ctx;
|
|
521
521
|
}
|
|
522
522
|
function useOptionalOcSession() {
|
|
523
|
-
return
|
|
523
|
+
return React4__namespace.useContext(SessionContext);
|
|
524
524
|
}
|
|
525
525
|
function shortenAddress(addr) {
|
|
526
526
|
if (addr.length <= 12) return addr;
|
|
@@ -535,7 +535,7 @@ function isPrefixOf(value, target) {
|
|
|
535
535
|
}
|
|
536
536
|
var listboxIdCounter = 0;
|
|
537
537
|
function useUniqueId(prefix) {
|
|
538
|
-
const [id] =
|
|
538
|
+
const [id] = React4__namespace.useState(() => `${prefix}-${++listboxIdCounter}`);
|
|
539
539
|
return id;
|
|
540
540
|
}
|
|
541
541
|
function OcAccountChip({
|
|
@@ -549,9 +549,9 @@ function OcAccountChip({
|
|
|
549
549
|
}) {
|
|
550
550
|
const { status, account, signInUrl: sessionSignInUrl, signOut } = useOcSession();
|
|
551
551
|
const signInUrl = signInUrlOverride ?? sessionSignInUrl;
|
|
552
|
-
const [open, setOpen] =
|
|
553
|
-
const wrapRef =
|
|
554
|
-
|
|
552
|
+
const [open, setOpen] = React4__namespace.useState(false);
|
|
553
|
+
const wrapRef = React4__namespace.useRef(null);
|
|
554
|
+
React4__namespace.useEffect(() => {
|
|
555
555
|
if (!open) return;
|
|
556
556
|
function handleClickOutside(e) {
|
|
557
557
|
if (wrapRef.current && !wrapRef.current.contains(e.target)) {
|
|
@@ -874,9 +874,9 @@ function useOcAddressSuggestion(options) {
|
|
|
874
874
|
} = options;
|
|
875
875
|
const { status, account } = useOcSession();
|
|
876
876
|
const sessionAddress = status === "authenticated" ? account?.primaryBtc ?? null : null;
|
|
877
|
-
const [open, setOpen] =
|
|
878
|
-
const [highlighted, setHighlighted] =
|
|
879
|
-
const blurTimer =
|
|
877
|
+
const [open, setOpen] = React4__namespace.useState(false);
|
|
878
|
+
const [highlighted, setHighlighted] = React4__namespace.useState(false);
|
|
879
|
+
const blurTimer = React4__namespace.useRef(null);
|
|
880
880
|
const listboxId = useUniqueId("oc-addr-listbox");
|
|
881
881
|
const optionId = `${listboxId}-opt`;
|
|
882
882
|
const valueMatchesSession = sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();
|
|
@@ -888,7 +888,7 @@ function useOcAddressSuggestion(options) {
|
|
|
888
888
|
setOpen(false);
|
|
889
889
|
setHighlighted(false);
|
|
890
890
|
}
|
|
891
|
-
|
|
891
|
+
React4__namespace.useEffect(() => {
|
|
892
892
|
return () => {
|
|
893
893
|
if (blurTimer.current != null) window.clearTimeout(blurTimer.current);
|
|
894
894
|
};
|
|
@@ -991,7 +991,7 @@ function useOcAddressSuggestion(options) {
|
|
|
991
991
|
) : null;
|
|
992
992
|
return { inputProps, popover };
|
|
993
993
|
}
|
|
994
|
-
var OcAddressInput =
|
|
994
|
+
var OcAddressInput = React4__namespace.forwardRef(
|
|
995
995
|
function OcAddressInput2({
|
|
996
996
|
value,
|
|
997
997
|
onValueChange,
|
|
@@ -1006,15 +1006,15 @@ var OcAddressInput = React3__namespace.forwardRef(
|
|
|
1006
1006
|
}, forwardedRef) {
|
|
1007
1007
|
const { status, account } = useOcSession();
|
|
1008
1008
|
const sessionAddress = status === "authenticated" ? account?.primaryBtc ?? null : null;
|
|
1009
|
-
const [open, setOpen] =
|
|
1010
|
-
const [highlighted, setHighlighted] =
|
|
1011
|
-
const innerRef =
|
|
1009
|
+
const [open, setOpen] = React4__namespace.useState(false);
|
|
1010
|
+
const [highlighted, setHighlighted] = React4__namespace.useState(false);
|
|
1011
|
+
const innerRef = React4__namespace.useRef(null);
|
|
1012
1012
|
const setRef = (node) => {
|
|
1013
1013
|
innerRef.current = node;
|
|
1014
1014
|
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
1015
1015
|
else if (forwardedRef) forwardedRef.current = node;
|
|
1016
1016
|
};
|
|
1017
|
-
const blurTimer =
|
|
1017
|
+
const blurTimer = React4__namespace.useRef(null);
|
|
1018
1018
|
const listboxId = useUniqueId("oc-addr-listbox");
|
|
1019
1019
|
const optionId = `${listboxId}-opt`;
|
|
1020
1020
|
const valueMatchesSession = sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();
|
|
@@ -1061,7 +1061,7 @@ var OcAddressInput = React3__namespace.forwardRef(
|
|
|
1061
1061
|
}
|
|
1062
1062
|
onKeyDown?.(e);
|
|
1063
1063
|
}
|
|
1064
|
-
|
|
1064
|
+
React4__namespace.useEffect(() => {
|
|
1065
1065
|
return () => {
|
|
1066
1066
|
if (blurTimer.current != null) window.clearTimeout(blurTimer.current);
|
|
1067
1067
|
};
|
|
@@ -1195,13 +1195,14 @@ async function fetchOcLinkedIdentities(opts) {
|
|
|
1195
1195
|
function OcLinkedIdentities({
|
|
1196
1196
|
authOrigin = DEFAULT_AUTH_ORIGIN,
|
|
1197
1197
|
className,
|
|
1198
|
-
onChange
|
|
1198
|
+
onChange,
|
|
1199
|
+
attestationLink = true
|
|
1199
1200
|
}) {
|
|
1200
|
-
const [resp, setResp] =
|
|
1201
|
-
const [error, setError] =
|
|
1202
|
-
const [showEmailLink, setShowEmailLink] =
|
|
1203
|
-
const [showBtcLink, setShowBtcLink] =
|
|
1204
|
-
const refresh =
|
|
1201
|
+
const [resp, setResp] = React4__namespace.useState(null);
|
|
1202
|
+
const [error, setError] = React4__namespace.useState(null);
|
|
1203
|
+
const [showEmailLink, setShowEmailLink] = React4__namespace.useState(false);
|
|
1204
|
+
const [showBtcLink, setShowBtcLink] = React4__namespace.useState(false);
|
|
1205
|
+
const refresh = React4__namespace.useCallback(async () => {
|
|
1205
1206
|
setError(null);
|
|
1206
1207
|
try {
|
|
1207
1208
|
const r = await fetch(`${authOrigin}/api/auth/identities`, {
|
|
@@ -1220,10 +1221,10 @@ function OcLinkedIdentities({
|
|
|
1220
1221
|
setError(e instanceof Error ? e.message : "load failed");
|
|
1221
1222
|
}
|
|
1222
1223
|
}, [authOrigin]);
|
|
1223
|
-
|
|
1224
|
+
React4__namespace.useEffect(() => {
|
|
1224
1225
|
void refresh();
|
|
1225
1226
|
}, [refresh]);
|
|
1226
|
-
const afterChange =
|
|
1227
|
+
const afterChange = React4__namespace.useCallback(() => {
|
|
1227
1228
|
setShowEmailLink(false);
|
|
1228
1229
|
setShowBtcLink(false);
|
|
1229
1230
|
void refresh();
|
|
@@ -1255,11 +1256,7 @@ function OcLinkedIdentities({
|
|
|
1255
1256
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-oc-li": "", style: { display: "grid", gap: 16 }, children: [
|
|
1256
1257
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyle(), children: [
|
|
1257
1258
|
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "\xA7 what this is" }),
|
|
1258
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1259
|
-
"Your public identity is the opaque ",
|
|
1260
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { style: codeStyle, children: "did:oc:" }),
|
|
1261
|
-
" DID. Below it sit your private linked identities \u2014 your email and your Bitcoin address. They never appear in dashboard chrome and never reach an integrator unless you grant the matching scope. Linking a second identity is also your account-recovery path: if you lose one, the other still signs you in."
|
|
1262
|
-
] })
|
|
1259
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: bodyStyle, children: "These are the ways you can sign in to this account. An app you sign in to sees one only if you grant it. Linking a second one is also your way back in: lose one, and the other still signs you in." })
|
|
1263
1260
|
] }),
|
|
1264
1261
|
mergedFrom.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ConsolidationPanel, { entries: mergedFrom }),
|
|
1265
1262
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyle("plain"), "data-oc-li-rows": "", children: [
|
|
@@ -1312,7 +1309,7 @@ function OcLinkedIdentities({
|
|
|
1312
1309
|
onCancel: () => setShowBtcLink(false)
|
|
1313
1310
|
}
|
|
1314
1311
|
),
|
|
1315
|
-
hasBtc && /* @__PURE__ */ jsxRuntime.jsx(AttestationLink, {})
|
|
1312
|
+
hasBtc && attestationLink && /* @__PURE__ */ jsxRuntime.jsx(AttestationLink, {})
|
|
1316
1313
|
] });
|
|
1317
1314
|
}
|
|
1318
1315
|
function IdentityGroup({
|
|
@@ -1356,10 +1353,10 @@ function IdentityRow({
|
|
|
1356
1353
|
authOrigin,
|
|
1357
1354
|
onChange
|
|
1358
1355
|
}) {
|
|
1359
|
-
const [shown, setShown] =
|
|
1360
|
-
const [confirming, setConfirming] =
|
|
1361
|
-
const [busy, setBusy] =
|
|
1362
|
-
const [err, setErr] =
|
|
1356
|
+
const [shown, setShown] = React4__namespace.useState(false);
|
|
1357
|
+
const [confirming, setConfirming] = React4__namespace.useState(false);
|
|
1358
|
+
const [busy, setBusy] = React4__namespace.useState(false);
|
|
1359
|
+
const [err, setErr] = React4__namespace.useState(null);
|
|
1363
1360
|
const masked = row.value ? mask(row.value, kind) : "\u2014 pending recovery \u2014";
|
|
1364
1361
|
const display = shown && row.value ? row.value : masked;
|
|
1365
1362
|
async function unlink() {
|
|
@@ -1558,13 +1555,13 @@ function EmailLinkForm({
|
|
|
1558
1555
|
onDone,
|
|
1559
1556
|
onCancel
|
|
1560
1557
|
}) {
|
|
1561
|
-
const [step, setStep] =
|
|
1562
|
-
const [email, setEmail] =
|
|
1563
|
-
const [code, setCode] =
|
|
1564
|
-
const [token, setToken] =
|
|
1565
|
-
const [busy, setBusy] =
|
|
1566
|
-
const [err, setErr] =
|
|
1567
|
-
const [transfer, setTransfer] =
|
|
1558
|
+
const [step, setStep] = React4__namespace.useState("email");
|
|
1559
|
+
const [email, setEmail] = React4__namespace.useState("");
|
|
1560
|
+
const [code, setCode] = React4__namespace.useState("");
|
|
1561
|
+
const [token, setToken] = React4__namespace.useState("");
|
|
1562
|
+
const [busy, setBusy] = React4__namespace.useState(false);
|
|
1563
|
+
const [err, setErr] = React4__namespace.useState(null);
|
|
1564
|
+
const [transfer, setTransfer] = React4__namespace.useState(false);
|
|
1568
1565
|
async function start() {
|
|
1569
1566
|
setBusy(true);
|
|
1570
1567
|
setErr(null);
|
|
@@ -1707,12 +1704,12 @@ function BtcLinkForm({
|
|
|
1707
1704
|
onDone,
|
|
1708
1705
|
onCancel
|
|
1709
1706
|
}) {
|
|
1710
|
-
const [step, setStep] =
|
|
1711
|
-
const [addr, setAddr] =
|
|
1712
|
-
const [challenge, setChallenge] =
|
|
1713
|
-
const [busy, setBusy] =
|
|
1714
|
-
const [err, setErr] =
|
|
1715
|
-
const [pendingSig, setPendingSig] =
|
|
1707
|
+
const [step, setStep] = React4__namespace.useState("request");
|
|
1708
|
+
const [addr, setAddr] = React4__namespace.useState("");
|
|
1709
|
+
const [challenge, setChallenge] = React4__namespace.useState("");
|
|
1710
|
+
const [busy, setBusy] = React4__namespace.useState(false);
|
|
1711
|
+
const [err, setErr] = React4__namespace.useState(null);
|
|
1712
|
+
const [pendingSig, setPendingSig] = React4__namespace.useState(null);
|
|
1716
1713
|
async function getChallenge() {
|
|
1717
1714
|
if (!didOc) {
|
|
1718
1715
|
setErr("session not loaded yet \xB7 refresh and retry");
|
|
@@ -1872,9 +1869,9 @@ function TransferConfirm({
|
|
|
1872
1869
|
] });
|
|
1873
1870
|
}
|
|
1874
1871
|
function LazyWalletButton(props) {
|
|
1875
|
-
const [Comp, setComp] =
|
|
1876
|
-
const [failed, setFailed] =
|
|
1877
|
-
|
|
1872
|
+
const [Comp, setComp] = React4__namespace.useState(null);
|
|
1873
|
+
const [failed, setFailed] = React4__namespace.useState(false);
|
|
1874
|
+
React4__namespace.useEffect(() => {
|
|
1878
1875
|
let alive = true;
|
|
1879
1876
|
import('@orangecheck/wallet-adapter/react').then((m) => {
|
|
1880
1877
|
if (alive) {
|
|
@@ -1982,10 +1979,6 @@ var hintStyle = {
|
|
|
1982
1979
|
fontSize: 10.5,
|
|
1983
1980
|
opacity: 0.8
|
|
1984
1981
|
};
|
|
1985
|
-
var codeStyle = {
|
|
1986
|
-
fontFamily: MONO,
|
|
1987
|
-
color: V.foreground
|
|
1988
|
-
};
|
|
1989
1982
|
var rowStyle = {
|
|
1990
1983
|
display: "flex",
|
|
1991
1984
|
flexWrap: "wrap",
|
|
@@ -2092,6 +2085,50 @@ function hardNavigate(target) {
|
|
|
2092
2085
|
if (typeof window === "undefined") return;
|
|
2093
2086
|
window.location.assign(target);
|
|
2094
2087
|
}
|
|
2088
|
+
var SIGNIN_ERRORS = {
|
|
2089
|
+
bad_request: "That doesn't look like a Bitcoin address.",
|
|
2090
|
+
invalid_challenge: "That signature doesn't match this address. Sign with the wallet that holds it.",
|
|
2091
|
+
sig_invalid: "That signature doesn't match this address. Sign with the wallet that holds it.",
|
|
2092
|
+
sig_unsupported_scheme: "We can't check this wallet's signature format yet. Try another wallet, or use email.",
|
|
2093
|
+
expired: "That request timed out. Try again for a fresh one.",
|
|
2094
|
+
not_yet_valid: "That request is not valid yet. Check your device clock, then try again.",
|
|
2095
|
+
nonce_mismatch: "That request didn't match. Try again for a fresh one.",
|
|
2096
|
+
audience_mismatch: "That request didn't match this site. Reload the page and try again.",
|
|
2097
|
+
purpose_mismatch: "That request didn't match. Try again for a fresh one.",
|
|
2098
|
+
malformed: "That signature couldn't be read. Copy it again, whole.",
|
|
2099
|
+
cross_site_blocked: "Your browser blocked this request. Reload the page and try again.",
|
|
2100
|
+
rate_limited: "Too many tries. Wait a minute, then try again.",
|
|
2101
|
+
invalid_email: "That email address doesn't look right.",
|
|
2102
|
+
mailer_unavailable: "We couldn't send the email right now. Try again in a minute.",
|
|
2103
|
+
mailer_error: "We couldn't send the email right now. Try again in a minute.",
|
|
2104
|
+
wrong_code: "That code isn't right. Check the newest email from us.",
|
|
2105
|
+
replay: "That code was already used. Send a new one.",
|
|
2106
|
+
invalid_token: "That code is no longer valid. Send a new one.",
|
|
2107
|
+
email_mismatch: "That code was sent to a different address. Send a new one."
|
|
2108
|
+
};
|
|
2109
|
+
var EMAIL_ERRORS = {
|
|
2110
|
+
expired: "That code expired. Send a new one."
|
|
2111
|
+
};
|
|
2112
|
+
var SUBMIT_ERRORS = {
|
|
2113
|
+
bad_request: "That signature couldn't be read. Copy it again, whole."
|
|
2114
|
+
};
|
|
2115
|
+
var NETWORK_ERROR = "We couldn't reach the server. Check your connection and try again.";
|
|
2116
|
+
function humanSigninError(reason, path, step = "challenge") {
|
|
2117
|
+
if (!/^[a-z0-9_]+$/.test(reason)) return reason;
|
|
2118
|
+
if (path === "wallet" && step === "submit" && SUBMIT_ERRORS[reason]) return SUBMIT_ERRORS[reason];
|
|
2119
|
+
if (path === "email" && EMAIL_ERRORS[reason]) return EMAIL_ERRORS[reason];
|
|
2120
|
+
return SIGNIN_ERRORS[reason] ?? (path === "email" ? "That didn't work. Try again, or send a new code." : "That didn't work. Try again.");
|
|
2121
|
+
}
|
|
2122
|
+
function failureMessage(err, path, step) {
|
|
2123
|
+
if (err instanceof TypeError || err instanceof SyntaxError) return NETWORK_ERROR;
|
|
2124
|
+
return humanSigninError(err instanceof Error ? err.message : "failed", path, step);
|
|
2125
|
+
}
|
|
2126
|
+
var BECH32_ADDRESS = /^(bc1|tb1|bcrt1)[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{8,87}$/i;
|
|
2127
|
+
var BASE58_ADDRESS = /^[123mn][1-9A-HJ-NP-Za-km-z]{25,34}$/;
|
|
2128
|
+
function looksLikeBitcoinAddress(input) {
|
|
2129
|
+
const s = input.trim();
|
|
2130
|
+
return BECH32_ADDRESS.test(s) || BASE58_ADDRESS.test(s);
|
|
2131
|
+
}
|
|
2095
2132
|
function OcSignIn({
|
|
2096
2133
|
audience,
|
|
2097
2134
|
returnTo,
|
|
@@ -2107,10 +2144,10 @@ function OcSignIn({
|
|
|
2107
2144
|
}) {
|
|
2108
2145
|
const walletEnabled = paths?.wallet ?? true;
|
|
2109
2146
|
const emailEnabled = paths?.email ?? true;
|
|
2110
|
-
const [resolvedReturn, setResolvedReturn] =
|
|
2147
|
+
const [resolvedReturn, setResolvedReturn] = React4__namespace.useState(
|
|
2111
2148
|
() => familyReturnTarget(returnTo) ?? safeReturnTo(returnTo)
|
|
2112
2149
|
);
|
|
2113
|
-
|
|
2150
|
+
React4__namespace.useEffect(() => {
|
|
2114
2151
|
const fromProp = familyReturnTarget(returnTo);
|
|
2115
2152
|
if (fromProp) {
|
|
2116
2153
|
setResolvedReturn(fromProp);
|
|
@@ -2121,8 +2158,8 @@ function OcSignIn({
|
|
|
2121
2158
|
const fromQuery = familyReturnTarget(q.get("return_to")) ?? familyReturnTarget(q.get("next"));
|
|
2122
2159
|
setResolvedReturn(fromQuery ?? "/");
|
|
2123
2160
|
}, [returnTo]);
|
|
2124
|
-
const [addMode, setAddMode] =
|
|
2125
|
-
|
|
2161
|
+
const [addMode, setAddMode] = React4__namespace.useState(Boolean(addProp));
|
|
2162
|
+
React4__namespace.useEffect(() => {
|
|
2126
2163
|
if (typeof window === "undefined") return;
|
|
2127
2164
|
if (addProp !== void 0) {
|
|
2128
2165
|
setAddMode(Boolean(addProp));
|
|
@@ -2130,19 +2167,19 @@ function OcSignIn({
|
|
|
2130
2167
|
}
|
|
2131
2168
|
setAddMode(new URLSearchParams(window.location.search).get("add") === "1");
|
|
2132
2169
|
}, [addProp]);
|
|
2133
|
-
const [path, setPath] =
|
|
2170
|
+
const [path, setPath] = React4__namespace.useState(
|
|
2134
2171
|
initialPath ?? (providersFirst ? "email" : "wallet")
|
|
2135
2172
|
);
|
|
2136
|
-
const [signedIn, setSignedIn] =
|
|
2137
|
-
const [linkAlso, setLinkAlso] =
|
|
2138
|
-
const [oauthError, setOauthError] =
|
|
2139
|
-
|
|
2173
|
+
const [signedIn, setSignedIn] = React4__namespace.useState(null);
|
|
2174
|
+
const [linkAlso, setLinkAlso] = React4__namespace.useState(false);
|
|
2175
|
+
const [oauthError, setOauthError] = React4__namespace.useState(false);
|
|
2176
|
+
React4__namespace.useEffect(() => {
|
|
2140
2177
|
if (typeof window === "undefined") return;
|
|
2141
2178
|
if (new URLSearchParams(window.location.search).has("oauth_error")) {
|
|
2142
2179
|
setOauthError(true);
|
|
2143
2180
|
}
|
|
2144
2181
|
}, []);
|
|
2145
|
-
const navigate =
|
|
2182
|
+
const navigate = React4__namespace.useCallback(
|
|
2146
2183
|
async (account) => {
|
|
2147
2184
|
if (resolveReturnTo) {
|
|
2148
2185
|
try {
|
|
@@ -2156,7 +2193,7 @@ function OcSignIn({
|
|
|
2156
2193
|
},
|
|
2157
2194
|
[resolveReturnTo, resolvedReturn]
|
|
2158
2195
|
);
|
|
2159
|
-
const handleSuccess =
|
|
2196
|
+
const handleSuccess = React4__namespace.useCallback(
|
|
2160
2197
|
async (account, token, via) => {
|
|
2161
2198
|
const proceed = () => {
|
|
2162
2199
|
clearTabSession();
|
|
@@ -2242,7 +2279,7 @@ function OcSignIn({
|
|
|
2242
2279
|
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
2243
2280
|
fontSize: 11
|
|
2244
2281
|
},
|
|
2245
|
-
children: "That sign-in didn't
|
|
2282
|
+
children: "That sign-in didn't finish. Try again, or use another way below."
|
|
2246
2283
|
}
|
|
2247
2284
|
),
|
|
2248
2285
|
addMode && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -2307,7 +2344,7 @@ function OcSignIn({
|
|
|
2307
2344
|
{
|
|
2308
2345
|
active: path === "email",
|
|
2309
2346
|
onClick: () => setPath("email"),
|
|
2310
|
-
children: "email
|
|
2347
|
+
children: "email"
|
|
2311
2348
|
}
|
|
2312
2349
|
),
|
|
2313
2350
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2315,7 +2352,7 @@ function OcSignIn({
|
|
|
2315
2352
|
{
|
|
2316
2353
|
active: path === "wallet",
|
|
2317
2354
|
onClick: () => setPath("wallet"),
|
|
2318
|
-
children: "bitcoin
|
|
2355
|
+
children: "bitcoin wallet"
|
|
2319
2356
|
}
|
|
2320
2357
|
)
|
|
2321
2358
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -2332,7 +2369,7 @@ function OcSignIn({
|
|
|
2332
2369
|
{
|
|
2333
2370
|
active: path === "email",
|
|
2334
2371
|
onClick: () => setPath("email"),
|
|
2335
|
-
children: "email
|
|
2372
|
+
children: "email"
|
|
2336
2373
|
}
|
|
2337
2374
|
)
|
|
2338
2375
|
] })
|
|
@@ -2365,7 +2402,7 @@ function OcSignIn({
|
|
|
2365
2402
|
type: "checkbox",
|
|
2366
2403
|
checked: linkAlso,
|
|
2367
2404
|
onChange: (e) => setLinkAlso(e.target.checked),
|
|
2368
|
-
style: {
|
|
2405
|
+
style: { margin: 0, accentColor: "var(--primary, #f97316)" }
|
|
2369
2406
|
}
|
|
2370
2407
|
),
|
|
2371
2408
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
@@ -2373,7 +2410,7 @@ function OcSignIn({
|
|
|
2373
2410
|
" ",
|
|
2374
2411
|
activeMethod === "email" ? "a Bitcoin wallet" : "an email",
|
|
2375
2412
|
" ",
|
|
2376
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
2413
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u2014 optional, one more signature." })
|
|
2377
2414
|
] })
|
|
2378
2415
|
] })
|
|
2379
2416
|
] });
|
|
@@ -2392,6 +2429,7 @@ function SigninTab({
|
|
|
2392
2429
|
onClick,
|
|
2393
2430
|
"data-oc-signin-tab": active ? "active" : "inactive",
|
|
2394
2431
|
style: {
|
|
2432
|
+
minHeight: 44,
|
|
2395
2433
|
padding: "0.6rem 0.875rem",
|
|
2396
2434
|
background: "transparent",
|
|
2397
2435
|
border: "none",
|
|
@@ -2431,20 +2469,21 @@ function ProviderSignIn({
|
|
|
2431
2469
|
add,
|
|
2432
2470
|
first = false
|
|
2433
2471
|
}) {
|
|
2434
|
-
const [providers, setProviders] =
|
|
2435
|
-
const [origin, setOrigin] =
|
|
2436
|
-
|
|
2472
|
+
const [providers, setProviders] = React4__namespace.useState(null);
|
|
2473
|
+
const [origin, setOrigin] = React4__namespace.useState("");
|
|
2474
|
+
React4__namespace.useEffect(() => {
|
|
2437
2475
|
setOrigin(window.location.origin);
|
|
2438
2476
|
let cancelled = false;
|
|
2439
2477
|
fetch(`${authOrigin}/api/auth/providers`, { credentials: "include" }).then((r) => r.ok ? r.json() : null).then((body) => {
|
|
2440
|
-
if (!cancelled
|
|
2478
|
+
if (!cancelled) setProviders(body?.providers ?? []);
|
|
2441
2479
|
}).catch(() => {
|
|
2480
|
+
if (!cancelled) setProviders([]);
|
|
2442
2481
|
});
|
|
2443
2482
|
return () => {
|
|
2444
2483
|
cancelled = true;
|
|
2445
2484
|
};
|
|
2446
2485
|
}, [authOrigin]);
|
|
2447
|
-
if (providers.length === 0) return null;
|
|
2486
|
+
if (providers !== null && providers.length === 0) return null;
|
|
2448
2487
|
const providerReturnTo = returnTo.startsWith("/") ? origin ? `${origin}${returnTo}` : returnTo : returnTo;
|
|
2449
2488
|
const line = { flex: 1, height: 1, background: "var(--border, #27272a)" };
|
|
2450
2489
|
const BLOCK_GAP = 16;
|
|
@@ -2473,6 +2512,31 @@ function ProviderSignIn({
|
|
|
2473
2512
|
]
|
|
2474
2513
|
}
|
|
2475
2514
|
);
|
|
2515
|
+
const buttonStyle = (i) => ({
|
|
2516
|
+
display: "flex",
|
|
2517
|
+
alignItems: "center",
|
|
2518
|
+
justifyContent: "center",
|
|
2519
|
+
gap: 10,
|
|
2520
|
+
boxSizing: "border-box",
|
|
2521
|
+
width: "100%",
|
|
2522
|
+
minHeight: 44,
|
|
2523
|
+
marginTop: i === 0 ? 0 : BUTTON_GAP,
|
|
2524
|
+
padding: "0.6rem 0.875rem",
|
|
2525
|
+
border: "1px solid var(--border, #27272a)",
|
|
2526
|
+
borderRadius: 6,
|
|
2527
|
+
background: "transparent",
|
|
2528
|
+
color: "var(--muted-foreground, #a1a1aa)",
|
|
2529
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
2530
|
+
fontSize: 12,
|
|
2531
|
+
textDecoration: "none"
|
|
2532
|
+
});
|
|
2533
|
+
if (providers === null) {
|
|
2534
|
+
if (!first) return null;
|
|
2535
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-oc-signin-providers": "", "aria-hidden": "true", children: [
|
|
2536
|
+
[0, 1].map((i) => /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...buttonStyle(i), visibility: "hidden" }, children: "\xA0" }, i)),
|
|
2537
|
+
divider
|
|
2538
|
+
] });
|
|
2539
|
+
}
|
|
2476
2540
|
const buttons = providers.map((p, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2477
2541
|
"a",
|
|
2478
2542
|
{
|
|
@@ -2480,23 +2544,7 @@ function ProviderSignIn({
|
|
|
2480
2544
|
providerReturnTo
|
|
2481
2545
|
)}${add ? "&add=1" : ""}`,
|
|
2482
2546
|
"data-oc-signin-provider": p.id,
|
|
2483
|
-
style:
|
|
2484
|
-
display: "flex",
|
|
2485
|
-
alignItems: "center",
|
|
2486
|
-
justifyContent: "center",
|
|
2487
|
-
gap: 10,
|
|
2488
|
-
boxSizing: "border-box",
|
|
2489
|
-
width: "100%",
|
|
2490
|
-
marginTop: i === 0 ? 0 : BUTTON_GAP,
|
|
2491
|
-
padding: "0.6rem 0.875rem",
|
|
2492
|
-
border: "1px solid var(--border, #27272a)",
|
|
2493
|
-
borderRadius: 6,
|
|
2494
|
-
background: "transparent",
|
|
2495
|
-
color: "var(--muted-foreground, #a1a1aa)",
|
|
2496
|
-
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
2497
|
-
fontSize: 12,
|
|
2498
|
-
textDecoration: "none"
|
|
2499
|
-
},
|
|
2547
|
+
style: buttonStyle(i),
|
|
2500
2548
|
children: [
|
|
2501
2549
|
/* @__PURE__ */ jsxRuntime.jsx(ProviderIcon, { id: p.id }),
|
|
2502
2550
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: p.label })
|
|
@@ -2519,82 +2567,214 @@ function ProviderSignIn({
|
|
|
2519
2567
|
}
|
|
2520
2568
|
);
|
|
2521
2569
|
}
|
|
2570
|
+
async function loadAdapter() {
|
|
2571
|
+
return await import('@orangecheck/wallet-adapter');
|
|
2572
|
+
}
|
|
2573
|
+
async function detectBrowserWallets() {
|
|
2574
|
+
return (await loadAdapter()).detectWallets().filter((w) => w.detected && w.id !== "manual").map((w) => ({ id: w.id, name: w.name }));
|
|
2575
|
+
}
|
|
2522
2576
|
function WalletFlow({ authOrigin, audience, add, onSuccess }) {
|
|
2523
|
-
const
|
|
2524
|
-
const
|
|
2525
|
-
|
|
2526
|
-
|
|
2577
|
+
const uid = React4__namespace.useId();
|
|
2578
|
+
const ids = {
|
|
2579
|
+
address: `${uid}-address`,
|
|
2580
|
+
wallet: `${uid}-wallet`,
|
|
2581
|
+
message: `${uid}-message`,
|
|
2582
|
+
signature: `${uid}-signature`
|
|
2583
|
+
};
|
|
2584
|
+
const [address, setAddress] = React4__namespace.useState("");
|
|
2585
|
+
const [error, setError] = React4__namespace.useState(null);
|
|
2586
|
+
const [submitting, setSubmitting] = React4__namespace.useState(false);
|
|
2587
|
+
const [wallets, setWallets] = React4__namespace.useState(null);
|
|
2588
|
+
const [walletId, setWalletId] = React4__namespace.useState(null);
|
|
2589
|
+
const [manual, setManual] = React4__namespace.useState(null);
|
|
2590
|
+
const [pasted, setPasted] = React4__namespace.useState("");
|
|
2591
|
+
const [copied, setCopied] = React4__namespace.useState("idle");
|
|
2592
|
+
React4__namespace.useEffect(() => {
|
|
2593
|
+
let cancelled = false;
|
|
2594
|
+
detectBrowserWallets().then((found) => {
|
|
2595
|
+
if (cancelled) return;
|
|
2596
|
+
setWallets(found);
|
|
2597
|
+
setWalletId(found[0]?.id ?? null);
|
|
2598
|
+
}).catch(() => {
|
|
2599
|
+
if (!cancelled) setWallets([]);
|
|
2600
|
+
});
|
|
2601
|
+
return () => {
|
|
2602
|
+
cancelled = true;
|
|
2603
|
+
};
|
|
2604
|
+
}, []);
|
|
2605
|
+
async function fetchChallenge(addr) {
|
|
2606
|
+
const res = await fetch(
|
|
2607
|
+
`${authOrigin}/api/challenge?addr=${encodeURIComponent(addr)}&audience=${encodeURIComponent(audience)}&purpose=login`
|
|
2608
|
+
);
|
|
2609
|
+
const json = await res.json();
|
|
2610
|
+
if (!res.ok || !json.message || !json.nonce) {
|
|
2611
|
+
throw new Error(json.error ?? "challenge_failed");
|
|
2612
|
+
}
|
|
2613
|
+
return { message: json.message, nonce: json.nonce };
|
|
2614
|
+
}
|
|
2615
|
+
async function submitSignature(message, nonce, signature, scheme) {
|
|
2616
|
+
const res = await fetch(`${authOrigin}/api/auth/signin`, {
|
|
2617
|
+
method: "POST",
|
|
2618
|
+
credentials: "include",
|
|
2619
|
+
headers: { "Content-Type": "application/json" },
|
|
2620
|
+
body: JSON.stringify({
|
|
2621
|
+
message,
|
|
2622
|
+
signature,
|
|
2623
|
+
...scheme ? { scheme } : {},
|
|
2624
|
+
expectedNonce: nonce,
|
|
2625
|
+
expectedAudience: audience,
|
|
2626
|
+
expectedPurpose: "login",
|
|
2627
|
+
// Multi-account add-mode · the auth host preserves the current
|
|
2628
|
+
// roster_id when set, instead of minting a fresh one.
|
|
2629
|
+
...add ? { add: true } : {}
|
|
2630
|
+
})
|
|
2631
|
+
});
|
|
2632
|
+
const json = await res.json();
|
|
2633
|
+
if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
|
|
2634
|
+
throw new Error(
|
|
2635
|
+
"reason" in json && json.reason || "error" in json && json.error || "verify_failed"
|
|
2636
|
+
);
|
|
2637
|
+
}
|
|
2638
|
+
onSuccess(json.account, json.token);
|
|
2639
|
+
}
|
|
2527
2640
|
async function signIn(e) {
|
|
2528
2641
|
e.preventDefault();
|
|
2529
2642
|
const addr = address.trim();
|
|
2530
2643
|
if (!addr) {
|
|
2531
|
-
setError("
|
|
2644
|
+
setError("Paste your Bitcoin address.");
|
|
2645
|
+
return;
|
|
2646
|
+
}
|
|
2647
|
+
if (!looksLikeBitcoinAddress(addr)) {
|
|
2648
|
+
setError(humanSigninError("bad_request", "wallet"));
|
|
2532
2649
|
return;
|
|
2533
2650
|
}
|
|
2534
2651
|
setError(null);
|
|
2535
2652
|
setSubmitting(true);
|
|
2536
|
-
|
|
2653
|
+
let step = "challenge";
|
|
2537
2654
|
try {
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2655
|
+
let id = walletId;
|
|
2656
|
+
if (wallets === null) {
|
|
2657
|
+
const found = await detectBrowserWallets().catch(() => []);
|
|
2658
|
+
setWallets(found);
|
|
2659
|
+
id = found[0]?.id ?? null;
|
|
2660
|
+
setWalletId(id);
|
|
2544
2661
|
}
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
"could not load wallet support \xB7 refresh to try again"
|
|
2551
|
-
);
|
|
2552
|
-
}
|
|
2553
|
-
const wallets = adapter.detectWallets().filter((w) => w.detected && w.id !== "manual");
|
|
2554
|
-
if (wallets.length === 0) {
|
|
2555
|
-
throw new Error("no BIP-322 wallet extension detected \xB7 install one and refresh");
|
|
2662
|
+
const challenge = await fetchChallenge(addr);
|
|
2663
|
+
if (!id) {
|
|
2664
|
+
setManual(challenge);
|
|
2665
|
+
setSubmitting(false);
|
|
2666
|
+
return;
|
|
2556
2667
|
}
|
|
2557
|
-
const
|
|
2558
|
-
const signer = adapter.getSigner(wallet.id, { address: addr });
|
|
2668
|
+
const signer = (await loadAdapter()).getSigner(id, { address: addr });
|
|
2559
2669
|
const signature = await signer(challenge.message);
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
credentials: "include",
|
|
2563
|
-
headers: { "Content-Type": "application/json" },
|
|
2564
|
-
body: JSON.stringify({
|
|
2565
|
-
message: challenge.message,
|
|
2566
|
-
signature,
|
|
2567
|
-
scheme: "bip322",
|
|
2568
|
-
expectedNonce: challenge.nonce,
|
|
2569
|
-
expectedAudience: audience,
|
|
2570
|
-
expectedPurpose: "login",
|
|
2571
|
-
// Multi-account add-mode · the auth host preserves
|
|
2572
|
-
// the current roster_id when set, instead of minting
|
|
2573
|
-
// a fresh one. Hosts that haven't deployed the
|
|
2574
|
-
// multi-account migration silently ignore the field.
|
|
2575
|
-
...add ? { add: true } : {}
|
|
2576
|
-
})
|
|
2577
|
-
});
|
|
2578
|
-
const json = await res.json();
|
|
2579
|
-
if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
|
|
2580
|
-
throw new Error(
|
|
2581
|
-
"reason" in json && json.reason || "error" in json && json.error || `verify_failed_${res.status}`
|
|
2582
|
-
);
|
|
2583
|
-
}
|
|
2584
|
-
onSuccess(json.account, json.token);
|
|
2670
|
+
step = "submit";
|
|
2671
|
+
await submitSignature(challenge.message, challenge.nonce, signature, "bip322");
|
|
2585
2672
|
} catch (err) {
|
|
2586
|
-
|
|
2587
|
-
setError(msg);
|
|
2673
|
+
setError(failureMessage(err, "wallet", step));
|
|
2588
2674
|
setSubmitting(false);
|
|
2589
|
-
setStage("enter");
|
|
2590
2675
|
}
|
|
2591
2676
|
}
|
|
2677
|
+
async function signInManual(e) {
|
|
2678
|
+
e.preventDefault();
|
|
2679
|
+
if (!manual) return;
|
|
2680
|
+
const sig = pasted.trim();
|
|
2681
|
+
if (!sig) {
|
|
2682
|
+
setError("Paste the signature your wallet gave you.");
|
|
2683
|
+
return;
|
|
2684
|
+
}
|
|
2685
|
+
setError(null);
|
|
2686
|
+
setSubmitting(true);
|
|
2687
|
+
try {
|
|
2688
|
+
await submitSignature(manual.message, manual.nonce, sig, void 0);
|
|
2689
|
+
} catch (err) {
|
|
2690
|
+
setError(failureMessage(err, "wallet", "submit"));
|
|
2691
|
+
setSubmitting(false);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
async function copyMessage() {
|
|
2695
|
+
if (!manual) return;
|
|
2696
|
+
try {
|
|
2697
|
+
await navigator.clipboard.writeText(manual.message);
|
|
2698
|
+
setCopied("copied");
|
|
2699
|
+
} catch {
|
|
2700
|
+
setCopied("failed");
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
if (manual) {
|
|
2704
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: signInManual, "data-oc-signin-wallet-manual": "", children: [
|
|
2705
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FlowHeader, { children: [
|
|
2706
|
+
"In your wallet, use \u201Csign message\u201D (BIP-322) with ",
|
|
2707
|
+
address.trim(),
|
|
2708
|
+
", sign the text below, and paste the signature back here. Nothing is spent."
|
|
2709
|
+
] }),
|
|
2710
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: ids.message, children: "message to sign" }),
|
|
2711
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2712
|
+
"textarea",
|
|
2713
|
+
{
|
|
2714
|
+
id: ids.message,
|
|
2715
|
+
readOnly: true,
|
|
2716
|
+
value: manual.message,
|
|
2717
|
+
rows: 5,
|
|
2718
|
+
onFocus: (e) => e.currentTarget.select(),
|
|
2719
|
+
style: { ...inputStyle2, resize: "vertical" }
|
|
2720
|
+
}
|
|
2721
|
+
),
|
|
2722
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => void copyMessage(), style: linkButtonStyle, children: copied === "copied" ? "copied" : "copy message" }),
|
|
2723
|
+
copied === "failed" && /* @__PURE__ */ jsxRuntime.jsx(Hint, { children: "Couldn't copy here. Select the text above and copy it." }),
|
|
2724
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: 14 }, children: [
|
|
2725
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: ids.signature, children: "signature" }),
|
|
2726
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2727
|
+
"textarea",
|
|
2728
|
+
{
|
|
2729
|
+
id: ids.signature,
|
|
2730
|
+
value: pasted,
|
|
2731
|
+
onChange: (e) => {
|
|
2732
|
+
setPasted(e.target.value);
|
|
2733
|
+
if (error) setError(null);
|
|
2734
|
+
},
|
|
2735
|
+
rows: 3,
|
|
2736
|
+
placeholder: "paste the signature",
|
|
2737
|
+
spellCheck: false,
|
|
2738
|
+
autoFocus: true,
|
|
2739
|
+
"aria-invalid": error ? true : void 0,
|
|
2740
|
+
style: { ...inputStyle2, resize: "vertical" }
|
|
2741
|
+
}
|
|
2742
|
+
)
|
|
2743
|
+
] }),
|
|
2744
|
+
error && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine2, { children: error }),
|
|
2745
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2746
|
+
"button",
|
|
2747
|
+
{
|
|
2748
|
+
type: "submit",
|
|
2749
|
+
disabled: submitting || !pasted.trim(),
|
|
2750
|
+
style: submitStyle(submitting || !pasted.trim()),
|
|
2751
|
+
children: submitting ? "checking\u2026" : "sign me in \u2192"
|
|
2752
|
+
}
|
|
2753
|
+
),
|
|
2754
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2755
|
+
"button",
|
|
2756
|
+
{
|
|
2757
|
+
type: "button",
|
|
2758
|
+
onClick: () => {
|
|
2759
|
+
setManual(null);
|
|
2760
|
+
setPasted("");
|
|
2761
|
+
setError(null);
|
|
2762
|
+
setCopied("idle");
|
|
2763
|
+
},
|
|
2764
|
+
style: linkButtonStyle,
|
|
2765
|
+
children: "use a different address"
|
|
2766
|
+
}
|
|
2767
|
+
)
|
|
2768
|
+
] });
|
|
2769
|
+
}
|
|
2770
|
+
const noBrowserWallet = wallets !== null && wallets.length === 0;
|
|
2592
2771
|
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: signIn, "data-oc-signin-wallet": "", children: [
|
|
2593
|
-
/* @__PURE__ */ jsxRuntime.jsx(FlowHeader, {
|
|
2594
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "bitcoin address" }),
|
|
2772
|
+
/* @__PURE__ */ jsxRuntime.jsx(FlowHeader, { children: "Your wallet signs a short message to prove you hold the address. Nothing is spent and your key never leaves the wallet. Works with browser wallets, or any wallet that can sign a message, like Sparrow." }),
|
|
2773
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: ids.address, children: "bitcoin address" }),
|
|
2595
2774
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2596
2775
|
"input",
|
|
2597
2776
|
{
|
|
2777
|
+
id: ids.address,
|
|
2598
2778
|
type: "text",
|
|
2599
2779
|
value: address,
|
|
2600
2780
|
onChange: (e) => {
|
|
@@ -2610,6 +2790,19 @@ function WalletFlow({ authOrigin, audience, add, onSuccess }) {
|
|
|
2610
2790
|
style: inputStyle2
|
|
2611
2791
|
}
|
|
2612
2792
|
),
|
|
2793
|
+
wallets && wallets.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: 12 }, children: [
|
|
2794
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: ids.wallet, children: "sign with" }),
|
|
2795
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2796
|
+
"select",
|
|
2797
|
+
{
|
|
2798
|
+
id: ids.wallet,
|
|
2799
|
+
value: walletId ?? "",
|
|
2800
|
+
onChange: (e) => setWalletId(e.target.value),
|
|
2801
|
+
style: inputStyle2,
|
|
2802
|
+
children: wallets.map((w) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: w.id, children: w.name }, w.id))
|
|
2803
|
+
}
|
|
2804
|
+
)
|
|
2805
|
+
] }),
|
|
2613
2806
|
error && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine2, { children: error }),
|
|
2614
2807
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2615
2808
|
"button",
|
|
@@ -2617,54 +2810,71 @@ function WalletFlow({ authOrigin, audience, add, onSuccess }) {
|
|
|
2617
2810
|
type: "submit",
|
|
2618
2811
|
disabled: submitting || !address.trim(),
|
|
2619
2812
|
style: submitStyle(submitting || !address.trim()),
|
|
2620
|
-
children:
|
|
2813
|
+
children: submitting ? "waiting for wallet\u2026" : noBrowserWallet ? "get the message to sign \u2192" : "sign in with wallet \u2192"
|
|
2621
2814
|
}
|
|
2622
2815
|
),
|
|
2623
|
-
/* @__PURE__ */ jsxRuntime.jsx(Hint, { children: "
|
|
2816
|
+
noBrowserWallet && /* @__PURE__ */ jsxRuntime.jsx(Hint, { children: "No browser wallet found here. You can sign with any wallet and paste." })
|
|
2624
2817
|
] });
|
|
2625
2818
|
}
|
|
2626
2819
|
function EmailFlow({ authOrigin, add, onSuccess }) {
|
|
2627
|
-
const
|
|
2628
|
-
const [
|
|
2629
|
-
const [
|
|
2630
|
-
const [
|
|
2631
|
-
const [
|
|
2632
|
-
const [
|
|
2633
|
-
const [
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
if (!trimmed || !/.+@.+\..+/.test(trimmed)) {
|
|
2638
|
-
setEmailError("enter a valid email");
|
|
2639
|
-
return;
|
|
2640
|
-
}
|
|
2641
|
-
setEmailError(null);
|
|
2642
|
-
setSubmitting(true);
|
|
2820
|
+
const uid = React4__namespace.useId();
|
|
2821
|
+
const [stage, setStage] = React4__namespace.useState("enter");
|
|
2822
|
+
const [email, setEmail] = React4__namespace.useState("");
|
|
2823
|
+
const [emailError, setEmailError] = React4__namespace.useState(null);
|
|
2824
|
+
const [code, setCode] = React4__namespace.useState("");
|
|
2825
|
+
const [codeError, setCodeError] = React4__namespace.useState(null);
|
|
2826
|
+
const [token, setToken] = React4__namespace.useState(null);
|
|
2827
|
+
const [submitting, setSubmitting] = React4__namespace.useState(false);
|
|
2828
|
+
const [resent, setResent] = React4__namespace.useState(false);
|
|
2829
|
+
async function sendCode(address) {
|
|
2643
2830
|
try {
|
|
2644
2831
|
const res = await fetch(`${authOrigin}/api/auth/email-otp/start`, {
|
|
2645
2832
|
method: "POST",
|
|
2646
2833
|
credentials: "include",
|
|
2647
2834
|
headers: { "Content-Type": "application/json" },
|
|
2648
|
-
body: JSON.stringify({ email:
|
|
2835
|
+
body: JSON.stringify({ email: address })
|
|
2649
2836
|
});
|
|
2650
2837
|
const json = await res.json();
|
|
2651
|
-
if (!res.ok || !json.token)
|
|
2652
|
-
throw new Error(json.reason ?? `start failed (${res.status})`);
|
|
2653
|
-
}
|
|
2838
|
+
if (!res.ok || !json.token) return humanSigninError(json.reason ?? "server_error", "email");
|
|
2654
2839
|
setToken(json.token);
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2840
|
+
return null;
|
|
2841
|
+
} catch {
|
|
2842
|
+
return NETWORK_ERROR;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
async function start(e) {
|
|
2846
|
+
e.preventDefault();
|
|
2847
|
+
const trimmed = email.trim().toLowerCase();
|
|
2848
|
+
if (!trimmed || !/.+@.+\..+/.test(trimmed)) {
|
|
2849
|
+
setEmailError(humanSigninError("invalid_email", "email"));
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
setEmailError(null);
|
|
2853
|
+
setSubmitting(true);
|
|
2854
|
+
const err = await sendCode(trimmed);
|
|
2855
|
+
setSubmitting(false);
|
|
2856
|
+
if (err) {
|
|
2857
|
+
setEmailError(err);
|
|
2858
|
+
return;
|
|
2661
2859
|
}
|
|
2860
|
+
setEmail(trimmed);
|
|
2861
|
+
setStage("code");
|
|
2862
|
+
}
|
|
2863
|
+
async function resend() {
|
|
2864
|
+
setCodeError(null);
|
|
2865
|
+
setResent(false);
|
|
2866
|
+
setSubmitting(true);
|
|
2867
|
+
const err = await sendCode(email);
|
|
2868
|
+
setSubmitting(false);
|
|
2869
|
+
setCode("");
|
|
2870
|
+
if (err) setCodeError(err);
|
|
2871
|
+
else setResent(true);
|
|
2662
2872
|
}
|
|
2663
2873
|
async function verify(e) {
|
|
2664
2874
|
e.preventDefault();
|
|
2665
2875
|
if (!token) return;
|
|
2666
2876
|
if (code.length !== 6) {
|
|
2667
|
-
setCodeError("6 digits");
|
|
2877
|
+
setCodeError("The code is 6 digits.");
|
|
2668
2878
|
return;
|
|
2669
2879
|
}
|
|
2670
2880
|
setCodeError(null);
|
|
@@ -2685,23 +2895,24 @@ function EmailFlow({ authOrigin, add, onSuccess }) {
|
|
|
2685
2895
|
const json = await res.json();
|
|
2686
2896
|
if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
|
|
2687
2897
|
throw new Error(
|
|
2688
|
-
"reason" in json && json.reason || "error" in json && json.error ||
|
|
2898
|
+
"reason" in json && json.reason || "error" in json && json.error || "server_error"
|
|
2689
2899
|
);
|
|
2690
2900
|
}
|
|
2691
2901
|
onSuccess(json.account, json.token);
|
|
2692
2902
|
} catch (err) {
|
|
2693
|
-
setCodeError(err
|
|
2903
|
+
setCodeError(failureMessage(err, "email", "submit"));
|
|
2694
2904
|
} finally {
|
|
2695
2905
|
setSubmitting(false);
|
|
2696
2906
|
}
|
|
2697
2907
|
}
|
|
2698
2908
|
if (stage === "enter") {
|
|
2699
2909
|
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: start, "data-oc-signin-email": "", children: [
|
|
2700
|
-
/* @__PURE__ */ jsxRuntime.jsx(FlowHeader, {
|
|
2701
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "email" }),
|
|
2910
|
+
/* @__PURE__ */ jsxRuntime.jsx(FlowHeader, { children: "We email you a 6-digit code. No password, and no wallet needed to start. Link a Bitcoin address any time \u2014 that is the identity you hold yourself." }),
|
|
2911
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `${uid}-email`, children: "email" }),
|
|
2702
2912
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2703
2913
|
"input",
|
|
2704
2914
|
{
|
|
2915
|
+
id: `${uid}-email`,
|
|
2705
2916
|
type: "email",
|
|
2706
2917
|
autoComplete: "email",
|
|
2707
2918
|
value: email,
|
|
@@ -2716,20 +2927,20 @@ function EmailFlow({ authOrigin, add, onSuccess }) {
|
|
|
2716
2927
|
}
|
|
2717
2928
|
),
|
|
2718
2929
|
emailError && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine2, { children: emailError }),
|
|
2719
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: submitting, style: submitStyle(submitting), children: submitting ? "sending\u2026" : "send one-time code \u2192" })
|
|
2720
|
-
/* @__PURE__ */ jsxRuntime.jsx(Hint, { children: "Codes come from the auth host, expire in 10 minutes, and work once." })
|
|
2930
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: submitting, style: submitStyle(submitting), children: submitting ? "sending\u2026" : "send one-time code \u2192" })
|
|
2721
2931
|
] });
|
|
2722
2932
|
}
|
|
2723
2933
|
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: verify, "data-oc-signin-email-verify": "", children: [
|
|
2724
|
-
/* @__PURE__ */ jsxRuntime.jsxs(FlowHeader, {
|
|
2725
|
-
"Sent a 6-digit code to ",
|
|
2934
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FlowHeader, { children: [
|
|
2935
|
+
resent ? "Sent a new code to " : "Sent a 6-digit code to ",
|
|
2726
2936
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--foreground, #fafafa)" }, children: email }),
|
|
2727
|
-
".
|
|
2937
|
+
". It expires in 10 minutes."
|
|
2728
2938
|
] }),
|
|
2729
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "one-time code" }),
|
|
2939
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `${uid}-code`, children: "one-time code" }),
|
|
2730
2940
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2731
2941
|
"input",
|
|
2732
2942
|
{
|
|
2943
|
+
id: `${uid}-code`,
|
|
2733
2944
|
type: "text",
|
|
2734
2945
|
inputMode: "numeric",
|
|
2735
2946
|
pattern: "\\d{6}",
|
|
@@ -2757,31 +2968,32 @@ function EmailFlow({ authOrigin, add, onSuccess }) {
|
|
|
2757
2968
|
children: submitting ? "verifying\u2026" : "verify \xB7 sign me in \u2192"
|
|
2758
2969
|
}
|
|
2759
2970
|
),
|
|
2760
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2971
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2972
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2973
|
+
"button",
|
|
2974
|
+
{
|
|
2975
|
+
type: "button",
|
|
2976
|
+
onClick: () => void resend(),
|
|
2977
|
+
disabled: submitting,
|
|
2978
|
+
style: linkButtonStyle,
|
|
2979
|
+
children: "send a new code"
|
|
2980
|
+
}
|
|
2981
|
+
),
|
|
2982
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2983
|
+
"button",
|
|
2984
|
+
{
|
|
2985
|
+
type: "button",
|
|
2986
|
+
onClick: () => {
|
|
2987
|
+
setStage("enter");
|
|
2988
|
+
setCode("");
|
|
2989
|
+
setToken(null);
|
|
2990
|
+
setResent(false);
|
|
2991
|
+
},
|
|
2992
|
+
style: linkButtonStyle,
|
|
2993
|
+
children: "use a different email"
|
|
2994
|
+
}
|
|
2995
|
+
)
|
|
2996
|
+
] })
|
|
2785
2997
|
] });
|
|
2786
2998
|
}
|
|
2787
2999
|
function FlowHeader({
|
|
@@ -2789,7 +3001,7 @@ function FlowHeader({
|
|
|
2789
3001
|
children
|
|
2790
3002
|
}) {
|
|
2791
3003
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 16 }, children: [
|
|
2792
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3004
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2793
3005
|
"div",
|
|
2794
3006
|
{
|
|
2795
3007
|
style: {
|
|
@@ -2817,10 +3029,30 @@ function FlowHeader({
|
|
|
2817
3029
|
)
|
|
2818
3030
|
] });
|
|
2819
3031
|
}
|
|
2820
|
-
|
|
3032
|
+
var linkButtonStyle = {
|
|
3033
|
+
display: "inline-flex",
|
|
3034
|
+
alignItems: "center",
|
|
3035
|
+
minHeight: 44,
|
|
3036
|
+
marginTop: 4,
|
|
3037
|
+
marginRight: 16,
|
|
3038
|
+
background: "transparent",
|
|
3039
|
+
border: "none",
|
|
3040
|
+
color: "var(--muted-foreground, #a1a1aa)",
|
|
3041
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
3042
|
+
fontSize: 11,
|
|
3043
|
+
letterSpacing: "0.12em",
|
|
3044
|
+
textTransform: "uppercase",
|
|
3045
|
+
cursor: "pointer",
|
|
3046
|
+
padding: 0
|
|
3047
|
+
};
|
|
3048
|
+
function Label({
|
|
3049
|
+
htmlFor,
|
|
3050
|
+
children
|
|
3051
|
+
}) {
|
|
2821
3052
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2822
3053
|
"label",
|
|
2823
3054
|
{
|
|
3055
|
+
htmlFor,
|
|
2824
3056
|
style: {
|
|
2825
3057
|
display: "block",
|
|
2826
3058
|
color: "var(--foreground, #fafafa)",
|
|
@@ -2850,7 +3082,9 @@ var inputStyle2 = {
|
|
|
2850
3082
|
};
|
|
2851
3083
|
var linkAlsoStyle = {
|
|
2852
3084
|
display: "flex",
|
|
2853
|
-
alignItems: "
|
|
3085
|
+
alignItems: "center",
|
|
3086
|
+
// The whole row is the checkbox's hit area; the 13px box alone was not.
|
|
3087
|
+
minHeight: 44,
|
|
2854
3088
|
gap: 8,
|
|
2855
3089
|
marginTop: 16,
|
|
2856
3090
|
paddingTop: 14,
|
|
@@ -2906,8 +3140,7 @@ function Hint({ children }) {
|
|
|
2906
3140
|
color: "var(--muted-foreground, #a1a1aa)",
|
|
2907
3141
|
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
2908
3142
|
fontSize: 10.5,
|
|
2909
|
-
lineHeight: 1.55
|
|
2910
|
-
opacity: 0.7
|
|
3143
|
+
lineHeight: 1.55
|
|
2911
3144
|
},
|
|
2912
3145
|
children: [
|
|
2913
3146
|
"> ",
|
|
@@ -2926,13 +3159,13 @@ function isAbortError(err) {
|
|
|
2926
3159
|
}
|
|
2927
3160
|
function useWebAuthnRegister(opts) {
|
|
2928
3161
|
const authOrigin = resolveAuthOrigin(opts);
|
|
2929
|
-
const [status, setStatus] =
|
|
2930
|
-
const [error, setError] =
|
|
2931
|
-
const reset =
|
|
3162
|
+
const [status, setStatus] = React4__namespace.useState("idle");
|
|
3163
|
+
const [error, setError] = React4__namespace.useState(null);
|
|
3164
|
+
const reset = React4__namespace.useCallback(() => {
|
|
2932
3165
|
setStatus("idle");
|
|
2933
3166
|
setError(null);
|
|
2934
3167
|
}, []);
|
|
2935
|
-
const register =
|
|
3168
|
+
const register = React4__namespace.useCallback(
|
|
2936
3169
|
async (args) => {
|
|
2937
3170
|
setError(null);
|
|
2938
3171
|
setStatus("requesting-options");
|
|
@@ -2994,10 +3227,10 @@ function useWebAuthnRegister(opts) {
|
|
|
2994
3227
|
function useWebAuthnList(opts) {
|
|
2995
3228
|
const authOrigin = resolveAuthOrigin(opts);
|
|
2996
3229
|
const { status: sessionStatus } = useOcSession();
|
|
2997
|
-
const [credentials, setCredentials] =
|
|
2998
|
-
const [status, setStatus] =
|
|
2999
|
-
const [error, setError] =
|
|
3000
|
-
const refetch =
|
|
3230
|
+
const [credentials, setCredentials] = React4__namespace.useState([]);
|
|
3231
|
+
const [status, setStatus] = React4__namespace.useState("loading");
|
|
3232
|
+
const [error, setError] = React4__namespace.useState(null);
|
|
3233
|
+
const refetch = React4__namespace.useCallback(async () => {
|
|
3001
3234
|
setError(null);
|
|
3002
3235
|
if (sessionStatus !== "authenticated") {
|
|
3003
3236
|
setCredentials([]);
|
|
@@ -3025,10 +3258,10 @@ function useWebAuthnList(opts) {
|
|
|
3025
3258
|
setStatus("error");
|
|
3026
3259
|
}
|
|
3027
3260
|
}, [authOrigin, sessionStatus]);
|
|
3028
|
-
|
|
3261
|
+
React4__namespace.useEffect(() => {
|
|
3029
3262
|
void refetch();
|
|
3030
3263
|
}, [refetch]);
|
|
3031
|
-
const rename =
|
|
3264
|
+
const rename = React4__namespace.useCallback(
|
|
3032
3265
|
async (id, label) => {
|
|
3033
3266
|
try {
|
|
3034
3267
|
const r = await fetch(`${authOrigin}/api/auth/webauthn/credentials/${id}`, {
|
|
@@ -3053,7 +3286,7 @@ function useWebAuthnList(opts) {
|
|
|
3053
3286
|
},
|
|
3054
3287
|
[authOrigin, refetch]
|
|
3055
3288
|
);
|
|
3056
|
-
const remove =
|
|
3289
|
+
const remove = React4__namespace.useCallback(
|
|
3057
3290
|
async (id) => {
|
|
3058
3291
|
try {
|
|
3059
3292
|
const r = await fetch(`${authOrigin}/api/auth/webauthn/credentials/${id}`, {
|
|
@@ -3081,13 +3314,13 @@ function useWebAuthnList(opts) {
|
|
|
3081
3314
|
function useStepUpAuth(opts) {
|
|
3082
3315
|
const authOrigin = resolveAuthOrigin(opts);
|
|
3083
3316
|
const { refresh } = useOcSession();
|
|
3084
|
-
const [status, setStatus] =
|
|
3085
|
-
const [error, setError] =
|
|
3086
|
-
const reset =
|
|
3317
|
+
const [status, setStatus] = React4__namespace.useState("idle");
|
|
3318
|
+
const [error, setError] = React4__namespace.useState(null);
|
|
3319
|
+
const reset = React4__namespace.useCallback(() => {
|
|
3087
3320
|
setStatus("idle");
|
|
3088
3321
|
setError(null);
|
|
3089
3322
|
}, []);
|
|
3090
|
-
const stepUp =
|
|
3323
|
+
const stepUp = React4__namespace.useCallback(
|
|
3091
3324
|
async (args) => {
|
|
3092
3325
|
setError(null);
|
|
3093
3326
|
setStatus("requesting-options");
|