@orangecheck/auth-client 2.36.0 → 2.37.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/address.mjs +7 -0
- package/dist/address.mjs.map +1 -0
- package/dist/bond.mjs +3 -2
- package/dist/{chunk-HOCQ722N.mjs → chunk-BMMNHG74.mjs} +5 -2
- package/dist/chunk-BMMNHG74.mjs.map +1 -0
- package/dist/{chunk-NCJZBLNF.mjs → chunk-EFMTFRCS.mjs} +6 -3
- package/dist/chunk-EFMTFRCS.mjs.map +1 -0
- package/dist/chunk-U7IUGDLW.mjs +10 -0
- package/dist/chunk-U7IUGDLW.mjs.map +1 -0
- package/dist/{chunk-FZ6RPWWR.mjs → chunk-VOO5KQQW.mjs} +25 -10
- package/dist/chunk-VOO5KQQW.mjs.map +1 -0
- package/dist/index.js +26 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13 -12
- package/dist/linked-identities.mjs +2 -1
- package/dist/signin.mjs +3 -2
- package/package.json +2 -1
- package/dist/chunk-FZ6RPWWR.mjs.map +0 -1
- package/dist/chunk-HOCQ722N.mjs.map +0 -1
- package/dist/chunk-NCJZBLNF.mjs.map +0 -1
package/dist/address.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/bond.mjs
CHANGED
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
bondFloorsText,
|
|
5
5
|
bondRefusal,
|
|
6
6
|
fetchOcBond
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-EFMTFRCS.mjs";
|
|
8
|
+
import "./chunk-BMMNHG74.mjs";
|
|
9
9
|
import "./chunk-XCZVSE7M.mjs";
|
|
10
|
+
import "./chunk-U7IUGDLW.mjs";
|
|
10
11
|
import "./chunk-H2TXOCXH.mjs";
|
|
11
12
|
import "./chunk-VRLFZAGK.mjs";
|
|
12
13
|
import "./chunk-CYR7J4UY.mjs";
|
|
@@ -3,6 +3,9 @@ import {
|
|
|
3
3
|
handleSudoRequired,
|
|
4
4
|
isSudoAccountMismatch
|
|
5
5
|
} from "./chunk-XCZVSE7M.mjs";
|
|
6
|
+
import {
|
|
7
|
+
addressInputValue
|
|
8
|
+
} from "./chunk-U7IUGDLW.mjs";
|
|
6
9
|
import {
|
|
7
10
|
SIGNIN_BUTTON_RADIUS,
|
|
8
11
|
SIGNIN_CASE,
|
|
@@ -622,7 +625,7 @@ function BtcLinkForm({
|
|
|
622
625
|
"data-oca-field": "",
|
|
623
626
|
type: "text",
|
|
624
627
|
value: addr,
|
|
625
|
-
onChange: (e) => setAddr(e.target.value.trim()),
|
|
628
|
+
onChange: (e) => setAddr(addressInputValue(e.target.value.trim())),
|
|
626
629
|
placeholder: "bc1q\u2026",
|
|
627
630
|
autoCapitalize: "none",
|
|
628
631
|
spellCheck: false,
|
|
@@ -913,4 +916,4 @@ export {
|
|
|
913
916
|
ghostBtnStyle,
|
|
914
917
|
dangerBtnStyle
|
|
915
918
|
};
|
|
916
|
-
//# sourceMappingURL=chunk-
|
|
919
|
+
//# sourceMappingURL=chunk-BMMNHG74.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/linked-identities.tsx"],"sourcesContent":["'use client';\n\n/**\n * @orangecheck/auth-client · OcLinkedIdentities\n *\n * The shared linked-identities management surface for every `X.ochk.io`\n * consumer. A signed-in user sees their linked email + Bitcoin address,\n * can reveal/hide each raw value, unlink a non-primary identity, and\n * link a new one. Linking a Bitcoin address that's already on another\n * OC account offers a dual-proof transfer; the same is now true for\n * email (auth host F4). Consolidated (`merged_from`) accounts render in\n * a tombstone panel.\n *\n * This generalizes me.ochk.io's bespoke `LinkedIdentitiesPanel` so\n * linking is no longer a single-product, one-tab feature — any family\n * site can drop in `<OcLinkedIdentities />`. See AUTH-PLAN.md §5.\n *\n * All endpoints live on the auth host (`ochk.io`); calls are\n * cross-origin with `credentials: 'include'` and rely on the auth\n * host's family-CORS — the same posture `OcSignIn` uses. No local\n * proxy route is needed (AUTH-AUDIT.md F6: direct-to-host is the\n * intended design).\n *\n * Style: inline, CSS-variable-themed (same approach as `OcSignIn`), so\n * the component carries zero CSS dependency and themes to each site.\n * Every block carries a `data-oc-li-*` attribute so a site may\n * override via its own stylesheet.\n */\n\nimport * as React from 'react';\nimport {\n handleSudoRequired,\n isSudoAccountMismatch,\n SUDO_ACCOUNT_MISMATCH_MESSAGE,\n} from './sudo';\n\nimport {\n SIGNIN_BUTTON_RADIUS,\n SIGNIN_CASE,\n SIGNIN_FONT,\n signinRadius,\n signinSize,\n signinTracking,\n} from './appearance';\nimport { addressInputValue } from './address';\nimport { tabSessionHeader } from './tab-session';\n\nconst DEFAULT_AUTH_ORIGIN = 'https://ochk.io';\n\n/* --- types --- */\n\nexport interface OcLinkedIdentity {\n id: string;\n kind: 'email' | 'btc';\n /** Raw value · null when the identity is pending recovery. */\n value: string | null;\n verified_at: string | null;\n verification_method: 'email-otp' | 'bip322' | null;\n /** The signup-time identity for its kind · cannot be unlinked here. */\n is_primary: boolean;\n}\n\ninterface MergedFromEntry {\n did_oc: string;\n created_at: string;\n last_signed_in_at: string | null;\n}\n\ninterface IdentitiesResp {\n ok: boolean;\n account_id?: string;\n did_oc?: string | null;\n linked?: OcLinkedIdentity[];\n merged_from?: MergedFromEntry[];\n reason?: string;\n}\n\n/**\n * Fetch the signed-in user's linked identities from the auth host —\n * the same data `<OcLinkedIdentities>` renders, exposed as a plain\n * function for surfaces that need the list without the full\n * management UI (notably `<OcAccountMenu>`'s badge-identity promote\n * list). Returns `[]` when anonymous; throws on network / server\n * error so the caller can show a deferred state.\n */\nexport async function fetchOcLinkedIdentities(opts?: {\n authOrigin?: string;\n}): Promise<OcLinkedIdentity[]> {\n const authOrigin = opts?.authOrigin ?? DEFAULT_AUTH_ORIGIN;\n // Per-tab pinning: forward the tab's session JWT so the host resolves\n // the SAME account this tab displays (its chip reads /api/auth/me\n // tab-aware). Without this, a pinned tab's show-as list is the shared\n // cookie account's identities — a menu that disagrees with itself.\n // Unpinned tabs send no header → unchanged cookie-default behavior.\n const r = await fetch(`${authOrigin}/api/auth/identities`, {\n credentials: 'include',\n headers: { ...tabSessionHeader() },\n });\n if (r.status === 401) return [];\n if (!r.ok) throw new Error(`identities fetch failed: http_${r.status}`);\n const body = (await r.json()) as IdentitiesResp;\n return body.linked ?? [];\n}\n\nexport interface OcLinkedIdentitiesProps {\n /** Auth host origin. Defaults to `https://ochk.io`. */\n authOrigin?: string;\n /** Outer container className. */\n className?: string;\n /** Called after every successful link / unlink / transfer. */\n onChange?: () => void;\n /**\n * Show the \"portable attestation\" card that links out to attest.ochk.io.\n * Defaults to `true`. Pass `false` on a page that already hosts its own\n * attestation builder (ochk.io's dashboard), or the same action is offered\n * twice, one panel apart.\n */\n attestationLink?: boolean;\n}\n\n/* --- main --- */\n\nexport function OcLinkedIdentities({\n authOrigin = DEFAULT_AUTH_ORIGIN,\n className,\n onChange,\n attestationLink = true,\n}: OcLinkedIdentitiesProps): React.ReactElement {\n const [resp, setResp] = React.useState<IdentitiesResp | null>(null);\n const [error, setError] = React.useState<string | null>(null);\n const [showEmailLink, setShowEmailLink] = React.useState(false);\n const [showBtcLink, setShowBtcLink] = React.useState(false);\n\n const refresh = React.useCallback(async () => {\n setError(null);\n try {\n const r = await fetch(`${authOrigin}/api/auth/identities`, {\n credentials: 'include',\n headers: { ...tabSessionHeader() },\n });\n if (!r.ok) {\n if (r.status === 401) {\n setError('not signed in');\n return;\n }\n throw new Error(`http_${r.status}`);\n }\n setResp((await r.json()) as IdentitiesResp);\n } catch (e) {\n setError(e instanceof Error ? e.message : 'load failed');\n }\n }, [authOrigin]);\n\n React.useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const afterChange = React.useCallback(() => {\n setShowEmailLink(false);\n setShowBtcLink(false);\n void refresh();\n onChange?.();\n }, [refresh, onChange]);\n\n if (error) {\n return (\n <div className={className} data-oc-li=\"\" style={panelStyle('warn')} role=\"alert\">\n <SectionLabel tone=\"warn\">§ identities · load deferred</SectionLabel>\n <p style={bodyStyle}>\n Couldn't reach the auth host ({error}). Linking is temporarily\n unavailable; your signed-in identity still works as normal.\n </p>\n <button type=\"button\" onClick={() => void refresh()} style={ghostBtnStyle(false)}>\n retry\n </button>\n </div>\n );\n }\n\n if (!resp) {\n return (\n <div className={className} data-oc-li=\"\" style={panelStyle()}>\n <span style={hintStyle}>loading…</span>\n </div>\n );\n }\n\n const linked = resp.linked ?? [];\n const emailRows = linked.filter((i) => i.kind === 'email');\n const btcRows = linked.filter((i) => i.kind === 'btc');\n const hasEmail = emailRows.some((i) => i.value);\n const hasBtc = btcRows.some((i) => i.value);\n const mergedFrom = resp.merged_from ?? [];\n\n return (\n <div className={className} data-oc-li=\"\" style={{ display: 'grid', gap: 16 }}>\n <div style={panelStyle()}>\n <SectionLabel>§ what this is</SectionLabel>\n <p style={bodyStyle}>\n These are the ways you can sign in to this account. An app you sign in to\n sees one only if you grant it. Linking a second one is also your way back\n in: lose one, and the other still signs you in.\n </p>\n </div>\n\n {mergedFrom.length > 0 && <ConsolidationPanel entries={mergedFrom} />}\n\n <div style={panelStyle('plain')} data-oc-li-rows=\"\">\n <IdentityGroup\n kind=\"email\"\n title=\"email\"\n rows={emailRows}\n authOrigin={authOrigin}\n onChange={afterChange}\n addCta={hasEmail ? null : 'link an email'}\n onAdd={() => {\n setShowEmailLink((v) => !v);\n setShowBtcLink(false);\n }}\n />\n <div style={{ borderTop: `1px solid ${V.border}` }} />\n <IdentityGroup\n kind=\"btc\"\n title=\"bitcoin address\"\n rows={btcRows}\n authOrigin={authOrigin}\n onChange={afterChange}\n addCta={hasBtc ? null : 'link a Bitcoin address'}\n onAdd={() => {\n setShowBtcLink((v) => !v);\n setShowEmailLink(false);\n }}\n />\n </div>\n\n {showEmailLink && (\n <EmailLinkForm\n authOrigin={authOrigin}\n onDone={afterChange}\n onCancel={() => setShowEmailLink(false)}\n />\n )}\n {showBtcLink && (\n <BtcLinkForm\n authOrigin={authOrigin}\n didOc={resp.did_oc ?? null}\n onDone={afterChange}\n onCancel={() => setShowBtcLink(false)}\n />\n )}\n\n {hasBtc && attestationLink && <AttestationLink />}\n </div>\n );\n}\n\n/* --- identity group (rows for one kind, or an empty-state add CTA) --- */\n\nfunction IdentityGroup({\n kind,\n title,\n rows,\n authOrigin,\n onChange,\n addCta,\n onAdd,\n}: {\n kind: 'email' | 'btc';\n title: string;\n rows: OcLinkedIdentity[];\n authOrigin: string;\n onChange: () => void;\n addCta: string | null;\n onAdd: () => void;\n}): React.ReactElement {\n if (rows.length === 0) {\n return (\n <div style={rowStyle}>\n <div>\n <div style={rowLabelStyle}>§ {title}</div>\n <div style={{ ...bodyStyle, marginTop: 4 }}>none linked</div>\n </div>\n {addCta && (\n <button type=\"button\" onClick={onAdd} style={primaryChipStyle}>\n + {addCta}\n </button>\n )}\n </div>\n );\n }\n return (\n <>\n {rows.map((r) => (\n <IdentityRow\n key={r.id}\n row={r}\n kind={kind}\n authOrigin={authOrigin}\n onChange={onChange}\n />\n ))}\n </>\n );\n}\n\n/* --- single identity row --- */\n\nfunction IdentityRow({\n row,\n kind,\n authOrigin,\n onChange,\n}: {\n row: OcLinkedIdentity;\n kind: 'email' | 'btc';\n authOrigin: string;\n onChange: () => void;\n}): React.ReactElement {\n const [shown, setShown] = React.useState(false);\n const [confirming, setConfirming] = React.useState(false);\n const [busy, setBusy] = React.useState(false);\n const [err, setErr] = React.useState<string | null>(null);\n\n const masked = row.value ? mask(row.value, kind) : '— pending recovery —';\n const display = shown && row.value ? row.value : masked;\n\n async function unlink(): Promise<void> {\n if (row.is_primary) return;\n setBusy(true);\n setErr(null);\n try {\n const r = await fetch(\n `${authOrigin}/api/auth/identities?id=${encodeURIComponent(row.id)}`,\n { method: 'DELETE', credentials: 'include' }\n );\n if (!r.ok) {\n const j = (await r.json().catch(() => ({}))) as { reason?: string };\n throw new Error(j.reason ?? `http_${r.status}`);\n }\n onChange();\n } catch (e) {\n setErr(e instanceof Error ? e.message : 'unlink failed');\n setBusy(false);\n setConfirming(false);\n }\n }\n\n return (\n <div style={rowStyle} data-oc-li-row={kind}>\n <div style={{ minWidth: 0, flex: 1 }}>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px 12px' }}>\n <span style={rowLabelStyle}>\n § {kind === 'email' ? 'email' : 'bitcoin address'}\n </span>\n {row.is_primary && (\n <span style={{ ...rowLabelStyle, color: V.primary }}>\n primary · signup-time\n </span>\n )}\n </div>\n <div\n style={{\n marginTop: 4,\n color: V.foreground,\n fontFamily: SIGNIN_FONT,\n fontSize: signinSize(12),\n wordBreak: 'break-all',\n }}\n >\n {display}\n </div>\n {row.verified_at && (\n <div style={{ ...hintStyle, marginTop: 4 }}>\n verified · {new Date(row.verified_at).toUTCString()}\n </div>\n )}\n {err && <ErrorLine>{err}</ErrorLine>}\n </div>\n <div style={{ display: 'flex', flexShrink: 0, gap: 8, flexWrap: 'wrap' }}>\n {row.value && (\n <button\n type=\"button\"\n onClick={() => setShown((s) => !s)}\n style={ghostBtnStyle(false)}\n >\n {shown ? 'hide' : 'show'}\n </button>\n )}\n {!row.is_primary && !confirming && (\n <button\n type=\"button\"\n onClick={() => setConfirming(true)}\n style={dangerBtnStyle(false)}\n >\n unlink\n </button>\n )}\n {!row.is_primary && confirming && (\n <>\n <button\n type=\"button\"\n onClick={() => void unlink()}\n disabled={busy}\n style={dangerBtnStyle(busy)}\n >\n {busy ? 'unlinking…' : 'confirm unlink'}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirming(false)}\n disabled={busy}\n style={ghostBtnStyle(busy)}\n >\n cancel\n </button>\n </>\n )}\n </div>\n </div>\n );\n}\n\n/* --- consolidated-accounts tombstone panel --- */\n\nfunction ConsolidationPanel({ entries }: { entries: MergedFromEntry[] }): React.ReactElement {\n return (\n <div style={panelStyle('success')} data-oc-li-consolidated=\"\">\n <SectionLabel tone=\"success\">\n § consolidated accounts · {entries.length}\n </SectionLabel>\n <p style={bodyStyle}>\n {entries.length === 1 ? 'A previous OC account' : 'Previous OC accounts'} you\n signed up with, folded into this one under dual proof of control. Historical\n activity is unioned into this account automatically;{' '}\n {entries.length === 1 ? 'it' : 'they'} can no longer sign in.\n </p>\n <ul style={{ listStyle: 'none', margin: '12px 0 0', padding: 0 }}>\n {entries.map((e) => (\n <li\n key={e.did_oc}\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: 8,\n padding: '8px 0',\n borderTop: `1px solid ${V.border}`,\n fontFamily: SIGNIN_FONT,\n fontSize: signinSize(11),\n }}\n >\n <code style={{ color: V.foreground, wordBreak: 'break-all' }}>\n {e.did_oc}\n </code>\n <span style={{ ...hintStyle, marginLeft: 'auto' }}>\n created {new Date(e.created_at).toLocaleDateString()}\n </span>\n </li>\n ))}\n </ul>\n </div>\n );\n}\n\n/* --- portable-attestation pointer --- */\n\n/**\n * A thin pointer to the OC Attest builder. The portable, self-sovereign\n * form of identity linking is a standard OrangeCheck attestation — one\n * BIP-322 signature by the Bitcoin address binding it to its handles,\n * published to Nostr. That ceremony already lives at\n * `attest.ochk.io/create` (which pre-fills the address from the signed-in\n * session); this panel routes the user there rather than re-implementing\n * it. Shown once the account has a linked Bitcoin address to attest with.\n */\nfunction AttestationLink(): React.ReactElement {\n return (\n <div style={panelStyle()} data-oc-li-attest=\"\">\n <SectionLabel>§ portable attestation</SectionLabel>\n <p style={bodyStyle}>\n Make your identity links portable: publish a standard OrangeCheck\n attestation — one Bitcoin-wallet signature (BIP-322) binding your address\n to your handles (Nostr, GitHub, …). It is published to Nostr and verifies\n with zero trust in OrangeCheck, so it outlives any single service.\n </p>\n <a\n href=\"https://attest.ochk.io/create\"\n target=\"_blank\"\n rel=\"noreferrer\"\n style={{ ...primaryChipStyle, textDecoration: 'none', display: 'inline-block' }}\n data-oc-li-attest-link=\"\"\n >\n open the attestation builder ↗\n </a>\n </div>\n );\n}\n\n/* --- post-sign-in link prompt (used by OcSignIn) --- */\n\n/** Where the ways to sign in are managed: ochk.app, which replaces me.ochk.io's pages. */\nconst ACCOUNT_WAYS_URL = 'https://ochk.app/me/account#ways';\n\n/**\n * Shown by `<OcSignIn>` after a successful sign-in *when the user ticked\n * the \"also link my other identity\" checkbox on the sign-in form*. It runs\n * the complementary identity's link ceremony inline — BIP-322 for a\n * Bitcoin address, OTP for an email.\n *\n * Skipping is first-class: even though the user opted in at the form, they\n * may change their mind here — an explicit \"skip, I'll do this later\"\n * control exits cleanly and tells them where to link later. `onResolved`\n * (linked, or skipped) hands control back to OcSignIn's post-sign-in\n * navigation.\n */\nexport function LinkPromptStep({\n method,\n didOc,\n authOrigin,\n onResolved,\n}: {\n /** The complementary identity to link — the opposite of the sign-in method. */\n method: 'btc' | 'email';\n didOc: string;\n authOrigin: string;\n /** Called once the user has linked the identity, or skipped. */\n onResolved: () => void;\n}): React.ReactElement {\n const what = method === 'btc' ? 'a Bitcoin address' : 'an email';\n return (\n <div data-oc-linkprompt={method}>\n <div style={{ ...panelStyle('success'), marginBottom: 16 }}>\n <SectionLabel tone=\"success\">§ signed in</SectionLabel>\n <p style={{ ...bodyStyle, margin: 0 }}>\n You chose to also link {what}. Complete it below — or skip for now; it is\n entirely optional and changes nothing about the sign-in you just completed.\n </p>\n </div>\n {method === 'btc' ? (\n <BtcLinkForm\n authOrigin={authOrigin}\n didOc={didOc}\n onDone={onResolved}\n onCancel={onResolved}\n />\n ) : (\n <EmailLinkForm authOrigin={authOrigin} onDone={onResolved} onCancel={onResolved} />\n )}\n <div\n data-oc-linkprompt-skip=\"\"\n style={{ marginTop: 14, paddingTop: 14, borderTop: `1px solid ${V.border}` }}\n >\n <button type=\"button\" onClick={onResolved} style={ghostBtnStyle(false)}>\n skip — I'll do this later\n </button>\n <p style={{ ...hintStyle, marginTop: 8 }}>\n Changed your mind? Skipping continues you straight on — your sign-in is\n unaffected. You can link {what} anytime later from your account page,{' '}\n <a\n href={ACCOUNT_WAYS_URL}\n target=\"_blank\"\n rel=\"noreferrer\"\n style={{ color: 'inherit' }}\n data-oc-linkprompt-account=\"\"\n >\n ochk.app/me/account\n </a>\n .\n </p>\n </div>\n </div>\n );\n}\n\n/* --- email link form --- */\n\nfunction EmailLinkForm({\n authOrigin,\n onDone,\n onCancel,\n}: {\n authOrigin: string;\n onDone: () => void;\n onCancel: () => void;\n}): React.ReactElement {\n const [step, setStep] = React.useState<'email' | 'code'>('email');\n const [email, setEmail] = React.useState('');\n const [code, setCode] = React.useState('');\n const [token, setToken] = React.useState('');\n const [busy, setBusy] = React.useState(false);\n const [err, setErr] = React.useState<string | null>(null);\n // Set when the auth host reports the email is linked elsewhere — the\n // user can confirm a dual-proof transfer (session + verified OTP).\n const [transfer, setTransfer] = React.useState(false);\n\n async function start(): Promise<void> {\n setBusy(true);\n setErr(null);\n try {\n const r = await fetch(`${authOrigin}/api/auth/email-otp/start`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email.trim().toLowerCase() }),\n });\n const j = (await r.json()) as { ok?: boolean; token?: string; reason?: string };\n if (!r.ok || !j.token) throw new Error(j.reason ?? `http_${r.status}`);\n setToken(j.token);\n setStep('code');\n } catch (e) {\n setErr(e instanceof Error ? e.message : 'could not send code');\n } finally {\n setBusy(false);\n }\n }\n\n async function verify(confirmTransfer: boolean): Promise<void> {\n setBusy(true);\n setErr(null);\n try {\n const r = await fetch(`${authOrigin}/api/auth/link/email`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: email.trim().toLowerCase(),\n code: code.trim(),\n token,\n ...(confirmTransfer ? { confirm_transfer: true } : {}),\n }),\n });\n const j = (await r.json()) as { ok?: boolean; reason?: string };\n if (r.status === 409 && j.reason === 'email_linked_elsewhere') {\n setTransfer(true);\n setBusy(false);\n return;\n }\n if (handleSudoRequired(j, { purpose: 'link an email' })) return;\n if (isSudoAccountMismatch(j)) {\n setErr(SUDO_ACCOUNT_MISMATCH_MESSAGE);\n setBusy(false);\n return;\n }\n if (!r.ok || !j.ok) throw new Error(j.reason ?? `http_${r.status}`);\n onDone();\n } catch (e) {\n setErr(e instanceof Error ? e.message : 'link failed');\n setBusy(false);\n }\n }\n\n return (\n <div style={panelStyle('accent')} data-oc-li-form=\"email\">\n <SectionLabel>§ link an email</SectionLabel>\n {step === 'email' ? (\n <>\n <input\n data-oca-field=\"\"\n type=\"email\"\n autoComplete=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"you@example.com\"\n style={inputStyle}\n />\n {err && <ErrorLine>{err}</ErrorLine>}\n <FormButtons>\n <button\n type=\"button\"\n onClick={() => void start()}\n disabled={busy || email.trim().length < 5}\n style={primaryBtnStyle(busy || email.trim().length < 5)}\n >\n {busy ? 'sending…' : 'send code'}\n </button>\n <button type=\"button\" onClick={onCancel} style={ghostBtnStyle(busy)}>\n cancel\n </button>\n </FormButtons>\n </>\n ) : transfer ? (\n <TransferConfirm\n what=\"email\"\n busy={busy}\n onConfirm={() => void verify(true)}\n onCancel={onCancel}\n err={err}\n />\n ) : (\n <>\n <p style={bodyStyle}>Enter the 6-digit code sent to {email}.</p>\n <input\n data-oca-field=\"\"\n type=\"text\"\n inputMode=\"numeric\"\n autoComplete=\"one-time-code\"\n maxLength={6}\n value={code}\n onChange={(e) => setCode(e.target.value.replace(/\\D/g, '').slice(0, 6))}\n placeholder=\"123456\"\n style={{ ...inputStyle, letterSpacing: '0.3em' }}\n />\n {err && <ErrorLine>{err}</ErrorLine>}\n <FormButtons>\n <button\n type=\"button\"\n onClick={() => void verify(false)}\n disabled={busy || code.length !== 6}\n style={primaryBtnStyle(busy || code.length !== 6)}\n >\n {busy ? 'linking…' : 'verify + link'}\n </button>\n <button\n type=\"button\"\n onClick={() => setStep('email')}\n disabled={busy}\n style={ghostBtnStyle(busy)}\n >\n back\n </button>\n </FormButtons>\n </>\n )}\n </div>\n );\n}\n\n/* --- btc link form --- */\n\nfunction BtcLinkForm({\n authOrigin,\n didOc,\n onDone,\n onCancel,\n}: {\n authOrigin: string;\n didOc: string | null;\n onDone: () => void;\n onCancel: () => void;\n}): React.ReactElement {\n const [step, setStep] = React.useState<'request' | 'sign'>('request');\n const [addr, setAddr] = React.useState('');\n const [challenge, setChallenge] = React.useState('');\n const [busy, setBusy] = React.useState(false);\n const [err, setErr] = React.useState<string | null>(null);\n // Holds the signature awaiting transfer confirmation when the\n // address is already linked to another account.\n const [pendingSig, setPendingSig] = React.useState<string | null>(null);\n\n async function getChallenge(): Promise<void> {\n if (!didOc) {\n setErr('session not loaded yet · refresh and retry');\n return;\n }\n setBusy(true);\n setErr(null);\n try {\n // /api/challenge is a public primitive — no session needed.\n // audience MUST be the caller's did_oc: the link endpoint\n // verifies expectedAudience=session.did_oc, so a signature\n // obtained here can't be replayed against another account.\n const r = await fetch(\n `${authOrigin}/api/challenge?addr=${encodeURIComponent(addr)}` +\n `&purpose=link&audience=${encodeURIComponent(didOc)}`\n );\n const j = (await r.json()) as { message?: string; reason?: string };\n if (!r.ok || !j.message) throw new Error(j.reason ?? `http_${r.status}`);\n setChallenge(j.message);\n setStep('sign');\n } catch (e) {\n setErr(e instanceof Error ? e.message : 'challenge failed');\n } finally {\n setBusy(false);\n }\n }\n\n async function postLink(sig: string, confirmTransfer: boolean): Promise<void> {\n setBusy(true);\n setErr(null);\n try {\n const r = await fetch(`${authOrigin}/api/auth/link/btc`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: challenge,\n signature: sig,\n ...(confirmTransfer ? { confirm_transfer: true } : {}),\n }),\n });\n const j = (await r.json()) as { ok?: boolean; reason?: string };\n if (r.status === 409 && j.reason === 'address_linked_elsewhere') {\n setPendingSig(sig);\n setBusy(false);\n return;\n }\n if (handleSudoRequired(j, { purpose: 'link a Bitcoin address' })) return;\n if (isSudoAccountMismatch(j)) {\n setErr(SUDO_ACCOUNT_MISMATCH_MESSAGE);\n setBusy(false);\n return;\n }\n if (!r.ok || !j.ok) throw new Error(j.reason ?? `http_${r.status}`);\n onDone();\n } catch (e) {\n setErr(e instanceof Error ? e.message : 'link failed');\n setBusy(false);\n }\n }\n\n return (\n <div style={panelStyle('accent')} data-oc-li-form=\"btc\">\n <SectionLabel>§ link a Bitcoin address</SectionLabel>\n {step === 'request' ? (\n <>\n <p style={bodyStyle}>\n Enter a Bitcoin address you control. We generate a challenge and your\n wallet signs it (BIP-322).\n </p>\n <input\n data-oca-field=\"\"\n type=\"text\"\n value={addr}\n onChange={(e) => setAddr(addressInputValue(e.target.value.trim()))}\n placeholder=\"bc1q…\"\n autoCapitalize=\"none\"\n spellCheck={false}\n style={{ ...inputStyle, fontFamily: SIGNIN_FONT }}\n />\n {err && <ErrorLine>{err}</ErrorLine>}\n <FormButtons>\n <button\n type=\"button\"\n onClick={() => void getChallenge()}\n disabled={busy || addr.length < 14}\n style={primaryBtnStyle(busy || addr.length < 14)}\n >\n {busy ? 'requesting…' : 'get challenge'}\n </button>\n <button type=\"button\" onClick={onCancel} style={ghostBtnStyle(busy)}>\n cancel\n </button>\n </FormButtons>\n </>\n ) : pendingSig ? (\n <TransferConfirm\n what=\"bitcoin address\"\n busy={busy}\n onConfirm={() => void postLink(pendingSig, true)}\n onCancel={onCancel}\n err={err}\n />\n ) : (\n <>\n <p style={bodyStyle}>\n Sign the challenge with the wallet that controls{' '}\n <span style={{ fontFamily: SIGNIN_FONT, wordBreak: 'break-all' }}>{addr}</span>.\n </p>\n <LazyWalletButton\n address={addr}\n message={challenge}\n showManual\n layout=\"list\"\n heading={null}\n onSigned={(sig: string) => void postLink(sig, false)}\n onError={(e: { message?: string }) =>\n setErr(e?.message ?? 'wallet rejected')\n }\n />\n {err && <ErrorLine>{err}</ErrorLine>}\n <FormButtons>\n <button\n type=\"button\"\n onClick={() => {\n setStep('request');\n setErr(null);\n }}\n disabled={busy}\n style={ghostBtnStyle(busy)}\n >\n back\n </button>\n </FormButtons>\n </>\n )}\n </div>\n );\n}\n\n/* --- transfer-under-dual-proof confirm --- */\n\nfunction TransferConfirm({\n what,\n busy,\n onConfirm,\n onCancel,\n err,\n}: {\n what: string;\n busy: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n err: string | null;\n}): React.ReactElement {\n return (\n <>\n <p style={bodyStyle}>\n This {what} is already linked to another OrangeCheck account. You've just\n proven control of it — you can transfer the link to this account under dual proof\n of control. The other account loses this sign-in path; its history stays\n verifiable. Continue?\n </p>\n {err && <ErrorLine>{err}</ErrorLine>}\n <FormButtons>\n <button\n type=\"button\"\n onClick={onConfirm}\n disabled={busy}\n style={dangerBtnStyle(busy)}\n >\n {busy ? 'transferring…' : 'transfer link here'}\n </button>\n <button type=\"button\" onClick={onCancel} disabled={busy} style={ghostBtnStyle(busy)}>\n cancel\n </button>\n </FormButtons>\n </>\n );\n}\n\n/* --- lazy wallet button · wallet-adapter loads on demand, not with the page --- */\n\ninterface WalletButtonProps {\n address: string;\n message: string;\n showManual?: boolean;\n layout?: string;\n heading?: React.ReactNode;\n onSigned: (sig: string) => void;\n onError: (err: { message?: string }, walletId?: string) => void;\n}\n\nexport function LazyWalletButton(props: WalletButtonProps): React.ReactElement {\n const [Comp, setComp] = React.useState<React.ComponentType<WalletButtonProps> | null>(null);\n const [failed, setFailed] = React.useState(false);\n\n React.useEffect(() => {\n let alive = true;\n // A bundler resolves this specifier at build time, so wallet-adapter\n // is a real dependency; only the chunk is deferred.\n import('@orangecheck/wallet-adapter/react')\n .then((m) => {\n if (alive) {\n setComp(\n () => (m as { OcWalletButton: React.ComponentType<WalletButtonProps> })\n .OcWalletButton\n );\n }\n })\n .catch(() => {\n if (alive) setFailed(true);\n });\n return () => {\n alive = false;\n };\n }, []);\n\n if (failed) {\n return (\n <ErrorLine>\n could not load wallet support · refresh to try again\n </ErrorLine>\n );\n }\n if (!Comp) return <span style={hintStyle}>loading wallet options…</span>;\n return <Comp {...props} />;\n}\n\n/* --- helpers --- */\n\nfunction mask(value: string, kind: 'email' | 'btc'): string {\n if (kind === 'email') {\n const [user, host] = value.split('@');\n if (!user || !host) return '••••';\n const m =\n user.length <= 2\n ? '•'.repeat(user.length)\n : user[0] + '•'.repeat(user.length - 2) + user.slice(-1);\n return `${m}@${host}`;\n }\n if (value.length <= 12) return '•'.repeat(value.length);\n return `${value.slice(0, 6)}…${value.slice(-4)}`;\n}\n\n/* --- presentational atoms · also used by bond.tsx; not re-exported from index --- */\n\nexport function SectionLabel({\n children,\n tone = 'primary',\n}: {\n children: React.ReactNode;\n tone?: 'primary' | 'success' | 'warn';\n}): React.ReactElement {\n const color = tone === 'success' ? V.success : tone === 'warn' ? V.warn : V.primary;\n return (\n <div\n style={{\n color,\n fontFamily: SIGNIN_FONT,\n fontSize: signinSize(10),\n letterSpacing: signinTracking('0.18em'),\n textTransform: SIGNIN_CASE,\n marginBottom: 8,\n }}\n >\n {children}\n </div>\n );\n}\n\nexport function ErrorLine({ children }: { children: React.ReactNode }): React.ReactElement {\n return (\n <p\n role=\"alert\"\n style={{\n margin: '8px 0 0',\n color: V.destructive,\n fontFamily: SIGNIN_FONT,\n fontSize: signinSize(11),\n }}\n >\n {children}\n </p>\n );\n}\n\nexport function FormButtons({ children }: { children: React.ReactNode }): React.ReactElement {\n return (\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 12 }}>{children}</div>\n );\n}\n\n/* --- style tokens (CSS-variable-themed, same approach as OcSignIn) --- */\n\n\nexport const V = {\n primary: 'var(--primary, #f97316)',\n foreground: 'var(--foreground, #fafafa)',\n muted: 'var(--muted-foreground, #a1a1aa)',\n background: 'var(--background, #0a0a0a)',\n card: 'var(--card, #111113)',\n border: 'var(--border, #27272a)',\n destructive: 'var(--destructive, #ef4444)',\n success: 'var(--success, #22c55e)',\n warn: 'var(--warning, #eab308)',\n} as const;\n\nexport function panelStyle(tone: 'plain' | 'accent' | 'success' | 'warn' | 'default' = 'default'): React.CSSProperties {\n const base: React.CSSProperties = {\n background: V.card,\n border: `1px solid ${V.border}`,\n padding: '1.25rem',\n };\n if (tone === 'plain') return { ...base, padding: 0 };\n if (tone === 'accent') return { ...base, borderColor: V.primary, background: 'var(--card, #111113)' };\n if (tone === 'success') return { ...base, borderColor: V.success };\n if (tone === 'warn') return { ...base, borderColor: V.warn };\n return base;\n}\n\nexport const bodyStyle: React.CSSProperties = {\n color: V.muted,\n fontSize: 13,\n lineHeight: 1.55,\n margin: '0 0 12px',\n};\n\nexport const hintStyle: React.CSSProperties = {\n color: V.muted,\n fontFamily: SIGNIN_FONT,\n fontSize: signinSize(10.5),\n opacity: 0.8,\n};\n\nconst rowStyle: React.CSSProperties = {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n padding: '1rem',\n};\n\nconst rowLabelStyle: React.CSSProperties = {\n color: V.foreground,\n fontFamily: SIGNIN_FONT,\n fontSize: signinSize(10.5),\n letterSpacing: signinTracking('0.12em'),\n textTransform: SIGNIN_CASE,\n opacity: 0.8,\n};\n\nexport const inputStyle: React.CSSProperties = {\n width: '100%',\n padding: '0.55rem 0.75rem',\n background: V.background,\n color: V.foreground,\n border: `1px solid ${V.border}`,\n borderRadius: signinRadius(6),\n fontFamily: SIGNIN_FONT,\n // 16px — never lower · suppresses iOS Safari focus auto-zoom.\n fontSize: 16,\n boxSizing: 'border-box',\n};\n\nfunction btnBase(disabled: boolean): React.CSSProperties {\n return {\n padding: '0.5rem 0.875rem',\n borderRadius: SIGNIN_BUTTON_RADIUS,\n fontFamily: SIGNIN_FONT,\n fontSize: signinSize(10.5),\n letterSpacing: signinTracking('0.12em'),\n textTransform: SIGNIN_CASE,\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n };\n}\n\nexport function primaryBtnStyle(disabled: boolean): React.CSSProperties {\n return {\n ...btnBase(disabled),\n background: V.primary,\n color: 'var(--primary-foreground, #0a0a0a)',\n border: `1px solid ${V.primary}`,\n fontWeight: 600,\n };\n}\n\nexport function ghostBtnStyle(disabled: boolean): React.CSSProperties {\n return {\n ...btnBase(disabled),\n background: V.background,\n color: V.foreground,\n border: `1px solid ${V.border}`,\n };\n}\n\nexport function dangerBtnStyle(disabled: boolean): React.CSSProperties {\n return {\n ...btnBase(disabled),\n background: 'transparent',\n color: V.destructive,\n border: `1px solid ${V.destructive}`,\n };\n}\n\nconst primaryChipStyle: React.CSSProperties = {\n ...btnBase(false),\n background: 'transparent',\n color: V.primary,\n border: `1px solid ${V.primary}`,\n};\n"],"mappings":"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","names":[]}
|
|
@@ -11,7 +11,10 @@ import {
|
|
|
11
11
|
inputStyle,
|
|
12
12
|
panelStyle,
|
|
13
13
|
primaryBtnStyle
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-BMMNHG74.mjs";
|
|
15
|
+
import {
|
|
16
|
+
addressInputValue
|
|
17
|
+
} from "./chunk-U7IUGDLW.mjs";
|
|
15
18
|
import {
|
|
16
19
|
SIGNIN_FONT
|
|
17
20
|
} from "./chunk-H2TXOCXH.mjs";
|
|
@@ -452,7 +455,7 @@ function BondForm({
|
|
|
452
455
|
"aria-describedby": `${id}-advice`,
|
|
453
456
|
style: inputStyle,
|
|
454
457
|
value: address,
|
|
455
|
-
onChange: (e) => setAddress(e.target.value),
|
|
458
|
+
onChange: (e) => setAddress(addressInputValue(e.target.value)),
|
|
456
459
|
placeholder: "bc1q\u2026",
|
|
457
460
|
spellCheck: false,
|
|
458
461
|
autoComplete: "off",
|
|
@@ -488,4 +491,4 @@ export {
|
|
|
488
491
|
fetchOcBond,
|
|
489
492
|
OcBond
|
|
490
493
|
};
|
|
491
|
-
//# sourceMappingURL=chunk-
|
|
494
|
+
//# sourceMappingURL=chunk-EFMTFRCS.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bond.tsx"],"sourcesContent":["'use client';\n\n/**\n * OcBond · back the signed-in account with bitcoin (oc-attest-protocol\n * BOND.md). The person signs for one coin they hold. It stays in their wallet,\n * and spending it ends the backing. Apps they sign in to see floors and a\n * number unique to that app, never the coin. Optional: every account signs in\n * without one.\n *\n * Runs against the auth host's /api/auth/bond with the family cookie, like\n * OcLinkedIdentities, so any *.ochk.io site can mount it. A change re-mints\n * the session there, and a tab pinned to this account re-pins with the fresh\n * token; `onChange` lets the site refresh its session view.\n */\nimport * as React from 'react';\n\nimport { addressInputValue } from './address';\nimport { SIGNIN_FONT } from './appearance';\nimport {\n bodyStyle,\n dangerBtnStyle,\n ErrorLine,\n FormButtons,\n ghostBtnStyle,\n hintStyle,\n inputStyle,\n LazyWalletButton,\n panelStyle,\n primaryBtnStyle,\n SectionLabel,\n V,\n} from './linked-identities';\nimport { readTabSession, writeTabSession } from './tab-session';\n\nconst DEFAULT_AUTH_ORIGIN = 'https://ochk.io';\nconst MIN_CONFIRMATIONS = 6;\n/** Smaller coins meet no floor, so the auth host refuses them (`coin_too_small`). */\nconst MIN_SATS = 1_000;\n\ninterface Floors {\n sats_floor: number;\n days_floor: number;\n}\n\n/** The account's bond as the auth host shows it to the account itself. */\nexport interface OcBondView extends Floors {\n address: string;\n outpoint: string;\n sats: number;\n confirmed_height: number;\n checked_at: string;\n checked_height: number;\n created_at: string;\n}\n\ninterface Coin extends Floors {\n outpoint: string;\n sats: number;\n age_blocks: number;\n}\n\nexport interface OcBondProps {\n /** The auth host. Default https://ochk.io; pass the current origin on ochk.io itself. */\n authOrigin?: string;\n /** After a bond is made or released, so the site can refresh its session. */\n onChange?: (bond: OcBondView | null) => void;\n className?: string;\n}\n\nconst n = (v: number) => v.toLocaleString('en-US');\n\n/** \"at least 100,000 sats, held 90 days or more\". */\nexport function bondFloorsText(f: Floors): string {\n const sats = f.sats_floor > 0 ? `at least ${n(f.sats_floor)} sats` : 'under 1,000 sats';\n const days = f.days_floor > 0 ? `held ${f.days_floor} days or more` : 'held under 7 days';\n return `${sats}, ${days}`;\n}\n\nconst short = (outpoint: string) => {\n const [txid = '', vout = ''] = outpoint.split(':');\n return `${txid.slice(0, 8)}…${txid.slice(-4)}:${vout}`;\n};\n\nconst usable = (c: Coin) => c.sats >= MIN_SATS && c.age_blocks >= MIN_CONFIRMATIONS;\n\nconst dustText = (count: number) =>\n `${n(count)} ${count === 1 ? 'coin' : 'coins'} under ${n(MIN_SATS)} sats, ` +\n 'too small to back an account';\n\nconst REFUSAL: Record<string, string> = {\n invalid_address: \"that isn't a Bitcoin address we can read\",\n chain_unavailable: \"couldn't read the chain just now · nothing changed, try again in a minute\",\n sig_invalid:\n \"that signature isn't from this coin's address · sign with the wallet that holds it\",\n bond_expired: 'the message expired · start again',\n bond_not_yet_valid: \"your device's clock looks wrong · check it and start again\",\n bond_subject_mismatch: 'that message was for another account · start again',\n bond_malformed: 'the signed message changed on the way · start again',\n bond_window_too_long: \"that message's signing window is too long · start again\",\n coin_not_found: \"that coin doesn't exist on-chain\",\n coin_address_mismatch: \"that coin isn't at this address\",\n coin_unconfirmed: \"that coin isn't confirmed yet\",\n coin_too_recent: 'that coin needs six confirmations first, about an hour',\n coin_spent: 'that coin has been spent · pick one still in your wallet',\n coin_too_small: `that coin is under ${n(MIN_SATS)} sats, too small to back an account`,\n coin_backs_another_account: 'that coin already backs another orangecheck account',\n coin_backed_another_recently:\n 'that coin backed another account until recently · ' +\n 'it can back this one 30 days after it was released',\n not_authenticated: 'your session ended · sign in again',\n rate_limited: 'too many tries · wait a minute, then try again',\n};\n\n/** A refusal from /api/auth/bond, in the component's voice. Not exported from the index. */\nexport const bondRefusal = (reason?: string): string =>\n (reason && REFUSAL[reason]) || \"your backing didn't save · nothing changed, try again\";\n\n/* Small print stays legible: 12px or more, and never dimmed below the muted tone. */\nconst smallStyle: React.CSSProperties = { ...bodyStyle, fontSize: 12, margin: 0 };\nconst explainerStyle: React.CSSProperties = {\n ...hintStyle,\n fontSize: 12,\n lineHeight: 1.55,\n opacity: 1,\n margin: 0,\n};\nconst fieldLabelStyle: React.CSSProperties = {\n display: 'block',\n color: V.foreground,\n fontSize: 13,\n fontWeight: 500,\n margin: '0 0 4px',\n};\nconst addressStyle: React.CSSProperties = { wordBreak: 'break-all', color: V.foreground };\n\nfunction coinStyle(picked: boolean, young: boolean): React.CSSProperties {\n return {\n background: V.card,\n border: `1px ${young ? 'dashed' : 'solid'} ${picked ? V.primary : V.border}`,\n padding: '0.75rem',\n display: 'flex',\n gap: 10,\n alignItems: 'flex-start',\n cursor: young ? 'not-allowed' : 'pointer',\n };\n}\n\n/** The account's bond, or null. Throws when the auth host can't be read. */\nexport async function fetchOcBond(opts?: { authOrigin?: string }): Promise<OcBondView | null> {\n const r = await fetch(`${opts?.authOrigin ?? DEFAULT_AUTH_ORIGIN}/api/auth/bond`, {\n credentials: 'include',\n });\n const j = (await r.json().catch(() => ({}))) as { ok?: boolean; bond?: OcBondView | null };\n if (!r.ok || !j.ok) throw new Error(`http_${r.status}`);\n return j.bond ?? null;\n}\n\nexport function OcBond({\n authOrigin = DEFAULT_AUTH_ORIGIN,\n onChange,\n className,\n}: OcBondProps): React.ReactElement {\n const [bond, setBond] = React.useState<OcBondView | null | undefined>(undefined);\n const [loadErr, setLoadErr] = React.useState(false);\n const [nonce, setNonce] = React.useState(0);\n const [adding, setAdding] = React.useState(false);\n const [confirming, setConfirming] = React.useState(false);\n const [busy, setBusy] = React.useState(false);\n const [err, setErr] = React.useState<string | null>(null);\n\n React.useEffect(() => {\n let alive = true;\n fetchOcBond({ authOrigin }).then(\n (b) => alive && setBond(b),\n () => alive && setLoadErr(true)\n );\n return () => {\n alive = false;\n };\n }, [authOrigin, nonce]);\n\n const call = React.useCallback(\n async (method: string, body?: unknown) => {\n const r = await fetch(`${authOrigin}/api/auth/bond`, {\n method,\n credentials: 'include',\n headers: body ? { 'Content-Type': 'application/json' } : undefined,\n body: body ? JSON.stringify(body) : undefined,\n });\n const j = (await r.json().catch(() => ({}))) as Record<string, unknown> & {\n ok?: boolean;\n reason?: string;\n token?: unknown;\n };\n // The host minted for the account this tab shows; keep the pin current.\n const pin = readTabSession();\n if (pin && r.ok && typeof j.token === 'string') {\n writeTabSession({ token: j.token, didOc: pin.didOc });\n }\n return { ok: r.ok && j.ok === true, ...j };\n },\n [authOrigin]\n );\n\n async function release(): Promise<void> {\n setBusy(true);\n setErr(null);\n const j = await call('DELETE').catch(() => ({ ok: false, reason: 'network' }));\n setBusy(false);\n if (!j.ok) return setErr(bondRefusal(j.reason));\n setConfirming(false);\n setBond(null);\n onChange?.(null);\n }\n\n if (loadErr) {\n return (\n <div className={className} data-oc-bond=\"\" style={panelStyle('warn')} role=\"alert\">\n <p style={bodyStyle}>couldn't read your backing · nothing was changed</p>\n <button\n type=\"button\"\n style={ghostBtnStyle(false)}\n onClick={() => {\n setLoadErr(false);\n setNonce((x) => x + 1);\n }}\n >\n try again\n </button>\n </div>\n );\n }\n if (bond === undefined) {\n return (\n <div className={className} data-oc-bond=\"\" style={panelStyle()}>\n <span style={hintStyle}>reading your backing…</span>\n </div>\n );\n }\n\n return (\n <div className={className} data-oc-bond=\"\" style={{ display: 'grid', gap: 16 }}>\n {bond && !adding ? (\n <div style={panelStyle('success')}>\n <SectionLabel tone=\"success\">§ backed by bitcoin</SectionLabel>\n <p style={{ ...bodyStyle, color: V.foreground }}>\n apps see a coin {bondFloorsText(bond)}.\n </p>\n <p style={bodyStyle}>\n coin {short(bond.outpoint)}, {n(bond.sats)} sats · last found unspent at\n block {n(bond.checked_height)} · only you and orangecheck see this line\n </p>\n {confirming ? (\n <div role=\"group\" aria-label=\"stop backing\" data-oc-bond-confirm=\"\">\n <p style={{ ...bodyStyle, color: V.foreground, margin: 0 }}>\n stop backing? apps that ask for a backed account may stop letting\n you in.\n </p>\n <FormButtons>\n <button\n type=\"button\"\n style={dangerBtnStyle(busy)}\n disabled={busy}\n onClick={() => void release()}\n >\n stop backing\n </button>\n <button\n type=\"button\"\n style={ghostBtnStyle(busy)}\n disabled={busy}\n autoFocus\n onClick={() => {\n setErr(null);\n setConfirming(false);\n }}\n >\n keep\n </button>\n </FormButtons>\n </div>\n ) : (\n <FormButtons>\n <button\n type=\"button\"\n style={ghostBtnStyle(false)}\n onClick={() => {\n setErr(null);\n setAdding(true);\n }}\n >\n use another coin\n </button>\n <button\n type=\"button\"\n style={dangerBtnStyle(false)}\n onClick={() => setConfirming(true)}\n >\n stop backing\n </button>\n </FormButtons>\n )}\n {err ? <ErrorLine>{err}</ErrorLine> : null}\n </div>\n ) : null}\n {!bond && !adding ? (\n <div style={panelStyle()}>\n <SectionLabel>§ not backed</SectionLabel>\n <p style={bodyStyle}>\n your account works everywhere as it is. some apps let in only accounts\n backed by a coin you hold. it stays in your wallet, and apps never see\n which coin.\n </p>\n <button\n type=\"button\"\n style={primaryBtnStyle(false)}\n onClick={() => setAdding(true)}\n >\n back your account\n </button>\n </div>\n ) : null}\n {adding ? (\n <BondForm\n call={call}\n onCancel={() => setAdding(false)}\n onDone={(b) => {\n setBond(b);\n setAdding(false);\n onChange?.(b);\n }}\n />\n ) : null}\n <p style={explainerStyle}>\n Apps see only rough floors, like “at least 100,000 sats, held 30 days or\n more”, and a number unique to that app. Never the coin, your address or your\n balance. An app can block that number; only moving the coin gets past it, and a\n moved coin starts its age again.\n </p>\n </div>\n );\n}\n\ntype Call = (\n method: string,\n body?: unknown\n) => Promise<Record<string, unknown> & { ok: boolean; reason?: string }>;\n\nfunction BondForm({\n call,\n onCancel,\n onDone,\n}: {\n call: Call;\n onCancel: () => void;\n onDone: (bond: OcBondView) => void;\n}): React.ReactElement {\n const [address, setAddress] = React.useState('');\n const [coins, setCoins] = React.useState<Coin[] | null>(null);\n const [chosen, setChosen] = React.useState('');\n const [message, setMessage] = React.useState<string | null>(null);\n const [busy, setBusy] = React.useState(false);\n const [err, setErr] = React.useState<string | null>(null);\n const id = React.useId();\n\n const addr = address.trim();\n const canFind = addr.length >= 14;\n\n async function run(fn: () => Promise<void>): Promise<void> {\n setBusy(true);\n setErr(null);\n try {\n await fn();\n } catch {\n setErr(bondRefusal('chain_unavailable'));\n } finally {\n setBusy(false);\n }\n }\n\n const findCoins = () =>\n run(async () => {\n const j = await call('POST', { action: 'coins', address: addr });\n if (!j.ok) return setErr(bondRefusal(j.reason));\n const list = (j.coins as Coin[]) ?? [];\n setCoins(list);\n setChosen(list.find(usable)?.outpoint ?? '');\n });\n\n const getMessage = () =>\n run(async () => {\n const j = await call('POST', { action: 'message', address: addr, outpoint: chosen });\n if (!j.ok || typeof j.message !== 'string') return setErr(bondRefusal(j.reason));\n setMessage(j.message);\n });\n\n const submit = (signature: string) =>\n run(async () => {\n const j = await call('POST', { action: 'bond', message, signature });\n if (!j.ok || !j.bond) return setErr(bondRefusal(j.reason));\n onDone(j.bond as OcBondView);\n });\n\n /** Back one step: from signing to the coin list, or from the coins to the address. */\n function back(): void {\n setErr(null);\n if (message) setMessage(null);\n else setCoins(null);\n }\n\n const error = err ? <ErrorLine>{err}</ErrorLine> : null;\n const backButton = (\n <button type=\"button\" style={ghostBtnStyle(busy)} disabled={busy} onClick={back}>\n back\n </button>\n );\n const cancelButton = (\n <button type=\"button\" style={ghostBtnStyle(busy)} disabled={busy} onClick={onCancel}>\n cancel\n </button>\n );\n\n let step: React.ReactNode;\n if (message) {\n step = (\n <>\n <p style={bodyStyle}>\n sign with the wallet that holds <span style={addressStyle}>{addr}</span>.\n signing spends nothing, and the coin stays in your wallet.\n </p>\n <LazyWalletButton\n address={addr}\n message={message}\n showManual\n onSigned={(sig) => void submit(sig)}\n onError={(e) => setErr(e.message ?? 'the wallet refused to sign')}\n />\n {error}\n <FormButtons>\n {backButton}\n {cancelButton}\n </FormButtons>\n </>\n );\n } else if (coins) {\n const eligible = coins.filter((c) => c.sats >= MIN_SATS);\n const dust = coins.length - eligible.length;\n step = (\n <>\n {coins.length === 0 ? (\n <p style={bodyStyle}>\n no confirmed coins at that address · send at least {n(MIN_SATS)} sats\n there and wait for six confirmations, about an hour. the longer a coin\n sits, the more it says.\n </p>\n ) : eligible.length === 0 ? (\n <>\n <p style={{ ...bodyStyle, color: V.foreground }}>{dustText(dust)}</p>\n <p style={bodyStyle}>\n send at least {n(MIN_SATS)} sats there in one payment and wait for six\n confirmations, about an hour. coins aren't added together.\n </p>\n </>\n ) : (\n <>\n <p id={`${id}-pick`} style={bodyStyle}>\n pick one coin · coins aren't added together\n </p>\n <div\n role=\"radiogroup\"\n aria-labelledby={`${id}-pick`}\n style={{ display: 'grid', gap: 8 }}\n >\n {eligible.map((c) => {\n const young = c.age_blocks < MIN_CONFIRMATIONS;\n return (\n <label\n key={c.outpoint}\n style={coinStyle(chosen === c.outpoint, young)}\n >\n <input\n type=\"radio\"\n name=\"oc-bond-coin\"\n value={c.outpoint}\n checked={chosen === c.outpoint}\n disabled={young}\n onChange={() => setChosen(c.outpoint)}\n style={{ accentColor: V.primary, margin: '2px 0 0' }}\n />\n <span style={{ display: 'grid', gap: 2, minWidth: 0 }}>\n <span\n style={{\n color: young ? V.muted : V.foreground,\n fontSize: 13,\n }}\n >\n {n(c.sats)} sats, held{' '}\n {Math.floor(c.age_blocks / 144)} days\n </span>\n <span style={smallStyle}>\n {young\n ? 'too recent: needs six confirmations'\n : `apps would see ${bondFloorsText(c)}`}\n </span>\n <span\n style={{\n ...smallStyle,\n fontFamily: SIGNIN_FONT,\n wordBreak: 'break-all',\n }}\n >\n {short(c.outpoint)}\n </span>\n </span>\n </label>\n );\n })}\n </div>\n {dust > 0 ? (\n <p style={{ ...smallStyle, marginTop: 8 }}>{dustText(dust)}</p>\n ) : null}\n </>\n )}\n {error}\n <FormButtons>\n {eligible.length > 0 ? (\n <button\n type=\"button\"\n style={primaryBtnStyle(busy || !chosen)}\n disabled={busy || !chosen}\n onClick={() => void getMessage()}\n >\n continue\n </button>\n ) : null}\n {backButton}\n {cancelButton}\n </FormButtons>\n </>\n );\n } else {\n step = (\n <form\n style={{ margin: 0 }}\n onSubmit={(e) => {\n e.preventDefault();\n if (canFind && !busy) void findCoins();\n }}\n >\n <label htmlFor={`${id}-address`} style={fieldLabelStyle}>\n bitcoin address that holds the coin\n </label>\n <p id={`${id}-advice`} style={{ ...bodyStyle, margin: '0 0 8px' }}>\n use one that holds nothing else of yours: orangecheck learns its address and\n amount. apps never do.\n </p>\n <input\n data-oca-field=\"\"\n id={`${id}-address`}\n aria-describedby={`${id}-advice`}\n style={inputStyle}\n value={address}\n onChange={(e) => setAddress(addressInputValue(e.target.value))}\n placeholder=\"bc1q…\"\n spellCheck={false}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n />\n {error}\n <FormButtons>\n <button\n type=\"submit\"\n style={primaryBtnStyle(busy || !canFind)}\n disabled={busy || !canFind}\n >\n find its coins\n </button>\n {cancelButton}\n </FormButtons>\n </form>\n );\n }\n\n return (\n <div style={panelStyle('accent')} data-oc-bond-form=\"\">\n <SectionLabel>§ back your account</SectionLabel>\n {step}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/address.ts"],"sourcesContent":["import { normalizeAddress } from '@orangecheck/bip322';\n\n/**\n * What an address field holds after an edit: a whole address in the one\n * spelling that verifies (a QR code's capitals lowercased, BIP-173), otherwise\n * the text as typed, so partial input stays editable. A challenge fetched for\n * the field then names the address the account is keyed by.\n */\nexport function addressInputValue(raw: string): string {\n return normalizeAddress(raw) ?? raw;\n}\n"],"mappings":";AAAA,SAAS,wBAAwB;AAQ1B,SAAS,kBAAkB,KAAqB;AACnD,SAAO,iBAAiB,GAAG,KAAK;AACpC;","names":[]}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LinkPromptStep
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BMMNHG74.mjs";
|
|
4
|
+
import {
|
|
5
|
+
addressInputValue
|
|
6
|
+
} from "./chunk-U7IUGDLW.mjs";
|
|
4
7
|
import {
|
|
5
8
|
SIGNIN_ARROW,
|
|
6
9
|
SIGNIN_BUTTON_RADIUS,
|
|
@@ -105,7 +108,18 @@ var BECH32_ADDRESS = /^(bc1|tb1|bcrt1)[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{8,87}$/
|
|
|
105
108
|
var BASE58_ADDRESS = /^[123mn][1-9A-HJ-NP-Za-km-z]{25,34}$/;
|
|
106
109
|
function looksLikeBitcoinAddress(input) {
|
|
107
110
|
const s = input.trim();
|
|
108
|
-
|
|
111
|
+
if (BECH32_ADDRESS.test(s)) return s === s.toLowerCase() || s === s.toUpperCase();
|
|
112
|
+
return BASE58_ADDRESS.test(s);
|
|
113
|
+
}
|
|
114
|
+
var OAUTH_EMAIL_CODE_REASONS = /* @__PURE__ */ new Set(["email_code_required", "account_mismatch"]);
|
|
115
|
+
function oauthErrorText(reason) {
|
|
116
|
+
if (reason === "email_code_required") {
|
|
117
|
+
return "This email already has an orangecheck account. Sign in to it with an email code below.";
|
|
118
|
+
}
|
|
119
|
+
if (reason === "account_mismatch") {
|
|
120
|
+
return "A different Google or GitHub account is already linked to this email. Use that one, or sign in with an email code below.";
|
|
121
|
+
}
|
|
122
|
+
return "That sign-in didn't finish. Try again, or use another way below.";
|
|
109
123
|
}
|
|
110
124
|
function OcSignIn({
|
|
111
125
|
audience,
|
|
@@ -172,13 +186,14 @@ function OcSignIn({
|
|
|
172
186
|
};
|
|
173
187
|
const [signedIn, setSignedIn] = React.useState(null);
|
|
174
188
|
const [linkAlso, setLinkAlso] = React.useState(false);
|
|
175
|
-
const [oauthError, setOauthError] = React.useState(
|
|
189
|
+
const [oauthError, setOauthError] = React.useState(null);
|
|
176
190
|
React.useEffect(() => {
|
|
177
191
|
if (typeof window === "undefined") return;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
192
|
+
const reason = new URLSearchParams(window.location.search).get("oauth_error");
|
|
193
|
+
if (reason === null) return;
|
|
194
|
+
setOauthError(reason);
|
|
195
|
+
if (OAUTH_EMAIL_CODE_REASONS.has(reason) && emailEnabled) setPath("email");
|
|
196
|
+
}, [emailEnabled]);
|
|
182
197
|
const navigate = React.useCallback(
|
|
183
198
|
async (account) => {
|
|
184
199
|
if (resolveReturnTo) {
|
|
@@ -279,7 +294,7 @@ function OcSignIn({
|
|
|
279
294
|
fontFamily: SIGNIN_FONT,
|
|
280
295
|
fontSize: signinRoleSize("text", signinSize(11))
|
|
281
296
|
},
|
|
282
|
-
children:
|
|
297
|
+
children: oauthErrorText(oauthError)
|
|
283
298
|
}
|
|
284
299
|
),
|
|
285
300
|
addMode && /* @__PURE__ */ jsxs(
|
|
@@ -809,7 +824,7 @@ function WalletFlow({
|
|
|
809
824
|
type: "text",
|
|
810
825
|
value: address,
|
|
811
826
|
onChange: (e) => {
|
|
812
|
-
setAddress(e.target.value);
|
|
827
|
+
setAddress(addressInputValue(e.target.value));
|
|
813
828
|
if (error) setError(null);
|
|
814
829
|
},
|
|
815
830
|
placeholder: "bc1q\u2026 \xB7 3\u2026 \xB7 1\u2026",
|
|
@@ -1193,4 +1208,4 @@ export {
|
|
|
1193
1208
|
looksLikeBitcoinAddress,
|
|
1194
1209
|
OcSignIn
|
|
1195
1210
|
};
|
|
1196
|
-
//# sourceMappingURL=chunk-
|
|
1211
|
+
//# sourceMappingURL=chunk-VOO5KQQW.mjs.map
|