ftown 0.20.9 → 0.21.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.
Files changed (118) hide show
  1. package/dist/centrifugo-client.d.ts +15 -11
  2. package/dist/centrifugo-client.js +63 -70
  3. package/dist/centrifugo-client.js.map +1 -1
  4. package/dist/cli-client.d.ts +11 -1
  5. package/dist/cli-client.js +23 -3
  6. package/dist/cli-client.js.map +1 -1
  7. package/dist/command-rpc.js +4 -8
  8. package/dist/command-rpc.js.map +1 -1
  9. package/dist/identity-reset.d.ts +1 -0
  10. package/dist/identity-reset.js +31 -5
  11. package/dist/identity-reset.js.map +1 -1
  12. package/dist/index.js +184 -288
  13. package/dist/index.js.map +1 -1
  14. package/dist/ledger-pairing-client.d.ts +28 -0
  15. package/dist/ledger-pairing-client.js +152 -0
  16. package/dist/ledger-pairing-client.js.map +1 -0
  17. package/dist/ledger-relay.d.ts +124 -0
  18. package/dist/ledger-relay.js +453 -0
  19. package/dist/ledger-relay.js.map +1 -0
  20. package/dist/ledger-startup.d.ts +151 -0
  21. package/dist/ledger-startup.js +203 -0
  22. package/dist/ledger-startup.js.map +1 -0
  23. package/dist/relay-token.d.ts +39 -0
  24. package/dist/relay-token.js +130 -0
  25. package/dist/relay-token.js.map +1 -0
  26. package/dist/revocation-gating.d.ts +0 -13
  27. package/dist/revocation-gating.js +0 -16
  28. package/dist/revocation-gating.js.map +1 -1
  29. package/dist/security/bridge/identity.d.ts +2 -47
  30. package/dist/security/bridge/identity.js +3 -3
  31. package/dist/security/bridge/identity.js.map +1 -1
  32. package/dist/security/bridge/ledger-identity.d.ts +48 -0
  33. package/dist/security/bridge/ledger-identity.js +342 -0
  34. package/dist/security/bridge/ledger-identity.js.map +1 -0
  35. package/dist/security/bridge/ledger-store.d.ts +84 -0
  36. package/dist/security/bridge/ledger-store.js +485 -0
  37. package/dist/security/bridge/ledger-store.js.map +1 -0
  38. package/dist/security/bridge/metadata.d.ts +2 -2
  39. package/dist/security/bridge/permissions.js +2 -2
  40. package/dist/security/bridge/permissions.js.map +1 -1
  41. package/dist/security/bridge/policy.d.ts +42 -23
  42. package/dist/security/bridge/policy.js +214 -146
  43. package/dist/security/bridge/policy.js.map +1 -1
  44. package/dist/security/bridge/security.d.ts +84 -33
  45. package/dist/security/bridge/security.js +240 -166
  46. package/dist/security/bridge/security.js.map +1 -1
  47. package/dist/security/crypto.js +1 -1
  48. package/dist/security/crypto.js.map +1 -1
  49. package/dist/security/ledger/channels.d.ts +5 -0
  50. package/dist/security/ledger/channels.js +21 -0
  51. package/dist/security/ledger/channels.js.map +1 -0
  52. package/dist/security/ledger/ledger.d.ts +61 -0
  53. package/dist/security/ledger/ledger.js +597 -0
  54. package/dist/security/ledger/ledger.js.map +1 -0
  55. package/dist/security/ledger/pairing.d.ts +81 -0
  56. package/dist/security/ledger/pairing.js +414 -0
  57. package/dist/security/ledger/pairing.js.map +1 -0
  58. package/dist/security/ledger/proof.d.ts +24 -0
  59. package/dist/security/ledger/proof.js +161 -0
  60. package/dist/security/ledger/proof.js.map +1 -0
  61. package/dist/security/ledger/protocol.d.ts +100 -0
  62. package/dist/security/ledger/protocol.js +16 -0
  63. package/dist/security/ledger/protocol.js.map +1 -0
  64. package/dist/security/ledger/testing.d.ts +27 -0
  65. package/dist/security/ledger/testing.js +70 -0
  66. package/dist/security/ledger/testing.js.map +1 -0
  67. package/dist/security/ledger/webauthn.d.ts +12 -0
  68. package/dist/security/ledger/webauthn.js +147 -0
  69. package/dist/security/ledger/webauthn.js.map +1 -0
  70. package/dist/security/protocol.d.ts +5 -10
  71. package/dist/security-cli.d.ts +5 -0
  72. package/dist/security-cli.js +28 -16
  73. package/dist/security-cli.js.map +1 -1
  74. package/dist/token-provider.d.ts +39 -0
  75. package/dist/token-provider.js +101 -0
  76. package/dist/token-provider.js.map +1 -0
  77. package/dist/types.d.ts +1 -1
  78. package/package.json +2 -2
  79. package/skills/ftown/references/sessions.md +3 -2
  80. package/dist/bridge-auth.d.ts +0 -31
  81. package/dist/bridge-auth.js +0 -70
  82. package/dist/bridge-auth.js.map +0 -1
  83. package/dist/pairing-client.d.ts +0 -62
  84. package/dist/pairing-client.js +0 -469
  85. package/dist/pairing-client.js.map +0 -1
  86. package/dist/rotating-token-refresher.d.ts +0 -42
  87. package/dist/rotating-token-refresher.js +0 -91
  88. package/dist/rotating-token-refresher.js.map +0 -1
  89. package/dist/security/account-crypto.d.ts +0 -33
  90. package/dist/security/account-crypto.js +0 -649
  91. package/dist/security/account-crypto.js.map +0 -1
  92. package/dist/security/account-protocol.d.ts +0 -228
  93. package/dist/security/account-protocol.js +0 -2
  94. package/dist/security/account-protocol.js.map +0 -1
  95. package/dist/security/bridge/account-client.d.ts +0 -7
  96. package/dist/security/bridge/account-client.js +0 -101
  97. package/dist/security/bridge/account-client.js.map +0 -1
  98. package/dist/security/bridge/account-state.d.ts +0 -105
  99. package/dist/security/bridge/account-state.js +0 -79
  100. package/dist/security/bridge/account-state.js.map +0 -1
  101. package/dist/security/bridge/pending-approval.d.ts +0 -21
  102. package/dist/security/bridge/pending-approval.js +0 -80
  103. package/dist/security/bridge/pending-approval.js.map +0 -1
  104. package/dist/security/bridge/pending-enrollment.d.ts +0 -33
  105. package/dist/security/bridge/pending-enrollment.js +0 -177
  106. package/dist/security/bridge/pending-enrollment.js.map +0 -1
  107. package/dist/security/bridge/revocation.d.ts +0 -14
  108. package/dist/security/bridge/revocation.js +0 -40
  109. package/dist/security/bridge/revocation.js.map +0 -1
  110. package/dist/security/pending-approval-crypto.d.ts +0 -29
  111. package/dist/security/pending-approval-crypto.js +0 -716
  112. package/dist/security/pending-approval-crypto.js.map +0 -1
  113. package/dist/security/pending-approval-protocol.d.ts +0 -329
  114. package/dist/security/pending-approval-protocol.js +0 -2
  115. package/dist/security/pending-approval-protocol.js.map +0 -1
  116. package/dist/security/security-nudge.d.ts +0 -31
  117. package/dist/security/security-nudge.js +0 -98
  118. package/dist/security/security-nudge.js.map +0 -1
@@ -0,0 +1,81 @@
1
+ import type { EndpointIdentity } from '../protocol.js';
2
+ import type { Ledger, LedgerBridge, LedgerCheckpoint } from './protocol.js';
3
+ export interface BridgePairRequest {
4
+ version: 2;
5
+ /** 32 random bytes, base64url. */
6
+ requestId: string;
7
+ bridgeId: string;
8
+ /** Raw uncompressed ECDH P-256 point, 65 bytes, base64url. */
9
+ endpointPublicKey: string;
10
+ /** Raw uncompressed ECDSA P-256 point, 65 bytes, base64url. */
11
+ authPublicKey: string;
12
+ label: string;
13
+ expiresAt: number;
14
+ }
15
+ export interface BridgePairLink {
16
+ request: BridgePairRequest;
17
+ /** 32 random bytes, base64url. Fragment only: it never reaches the server. */
18
+ secret: string;
19
+ }
20
+ export interface BridgePairRequestInput {
21
+ bridgeId: string;
22
+ endpointPublicKey: string;
23
+ authPublicKey: string;
24
+ label: string;
25
+ now?: number;
26
+ lifetimeMs?: number;
27
+ }
28
+ /** What the secret holder approved: the account and the ledger head at approval time. */
29
+ export interface PairApproval {
30
+ accountId: string;
31
+ head: string;
32
+ }
33
+ /** Revocations a replica has seen in any verified chain of the account (see ledgerRevocations / applyRevocations). */
34
+ export interface PairStickyRevocations {
35
+ deviceIds: string[];
36
+ bridgeIds: string[];
37
+ }
38
+ /** Default and maximum lifetime of a pairing request. */
39
+ export declare const PAIR_LIFETIME_MS = 600000;
40
+ /** Fragment prefix of the pairing URL; parsePairLink accepts the value with or without it. */
41
+ export declare const PAIR_FRAGMENT_PREFIX = "#req=";
42
+ /** A fresh request for this bridge, with a random requestId and secret. Throws Error('invalid_pair_link') on invalid input. */
43
+ export declare function createBridgePairRequest(input: BridgePairRequestInput): BridgePairLink;
44
+ /** The approving browser's add_bridge payload. Throws Error('secure_context_required') without WebCrypto, Error('invalid_pair_link') on invalid input. */
45
+ export declare function bridgeFromPairRequest(request: BridgePairRequest, accountId: string, approvedAt: number): Promise<LedgerBridge>;
46
+ /** Compact base64url JSON of the link: the fragment value after PAIR_FRAGMENT_PREFIX. Throws Error('invalid_pair_link'). */
47
+ export declare function encodePairLink(link: BridgePairLink): string;
48
+ /** Strict parse of the fragment, with or without the leading '#req='. Does not check expiry. Throws Error('invalid_pair_link'). */
49
+ export declare function parsePairLink(fragment: string): BridgePairLink;
50
+ /**
51
+ * Six decimal digits, shown by the bridge and by the approving page: SHA-256(UTF-8('ftown-pair-code-v2\n' + canonical(request))),
52
+ * first 4 bytes as a big-endian uint32, mod 10^6, zero-padded. Bias: 2^32 = 4294 * 10^6 + 967296, so codes below 967296 occur with
53
+ * probability 4295/2^32 and the rest 4294/2^32, a relative skew of 1/4294 (about 0.02%), negligible for a human comparison.
54
+ * Throws Error('secure_context_required') without WebCrypto, Error('invalid_pair_link') on a malformed request.
55
+ */
56
+ export declare function pairComparisonCode(request: BridgePairRequest): Promise<string>;
57
+ /**
58
+ * Browser side. Verifies the ledger and runs the same checks as confirmPairedLedger at its last head, then seals
59
+ * {version:2, requestId, accountId, head, proof} (no ledger) to the bridge's endpoint key, authenticated by `sender`.
60
+ * Returns the opaque string stored in the pair mailbox. Throws Error('secure_context_required') without WebCrypto,
61
+ * Error('invalid_pair_link') for a malformed or expired link, SecurityError from crypto.ts as is, else Error('invalid_pair_approval').
62
+ */
63
+ export declare function sealPairApproval(link: BridgePairLink, ledger: Ledger, sender: EndpointIdentity, now?: number): Promise<string>;
64
+ /**
65
+ * Bridge side, step 1. `identity` is the bridge's own endpoint identity (any pre-pairing ownerId; it is rebound to the account here).
66
+ * Never trusts the sender endpoint for authorization: it only authenticates the HPKE envelope. The authority is the HMAC proof of the
67
+ * link secret, which the server never sees, binding {accountId, head} to this request; step 2 (confirmPairedLedger) then requires a
68
+ * passkey-signed ledger of that account and head. A server can therefore not bind this bridge to another account.
69
+ * Throws Error('secure_context_required') without WebCrypto; every other failure throws Error('invalid_pair_approval').
70
+ */
71
+ export declare function openPairApproval(sealed: string, link: BridgePairLink, identity: EndpointIdentity, now?: number): Promise<PairApproval>;
72
+ /**
73
+ * Bridge side, step 2, on the ledger fetched from the server after openPairApproval. Verifies it from genesis and requires: its
74
+ * accountId equals approval.accountId; the chain contains approval.head (it may have grown since); this request's bridge
75
+ * (bridgeId, endpoint id, authPublicKey) is a member of applyRevocations(checkpoint, sticky).bridges, with its add_bridge at or before
76
+ * approval.head. `sticky` is every revocation this replica has seen for the account (default: the chain's own, ledgerRevocations).
77
+ * Returns the RAW checkpoint of the chain (never the sticky-applied one, which must not be used as a chooseLedger cache).
78
+ * The link's expiry is not rechecked: openPairApproval already enforced it.
79
+ * Throws Error('secure_context_required') without WebCrypto; every other failure throws Error('invalid_pair_approval').
80
+ */
81
+ export declare function confirmPairedLedger(link: BridgePairLink, approval: PairApproval, ledger: Ledger, now?: number, sticky?: PairStickyRevocations): Promise<LedgerCheckpoint>;
@@ -0,0 +1,414 @@
1
+ /*
2
+ * Bridge pairing by link (DESIGN 3.3; contract "Decision 2026-11-09"). The bridge prints `https://<origin>/pair#req=<encodePairLink(link)>`;
3
+ * the secret lives only in the fragment. A passkey holder opens it, compares the 6-digit code, signs an add_bridge built by
4
+ * bridgeFromPairRequest, and seals {requestId, accountId, head, proof} to the bridge's endpoint key, where proof is an HMAC of the
5
+ * secret over accountId, head and requestId. The bridge opens it (openPairApproval), fetches the ledger from the server, and accepts
6
+ * it only through confirmPairedLedger: verified from genesis, of exactly that account, containing the approved head, and adding this
7
+ * request's bridge at or before that head, never revoked since.
8
+ * ES2017 and WebCrypto only: this file is also compiled by the UI.
9
+ */
10
+ import { open, parseSecureEnvelope, seal, SecurityError } from '../crypto.js';
11
+ import { accountIdOf, applyRevocations, ledgerHead, ledgerRevocations, parseLedger, verifyLedger } from './ledger.js';
12
+ import { LEDGER_LIMITS } from './protocol.js';
13
+ /** Default and maximum lifetime of a pairing request. */
14
+ export const PAIR_LIFETIME_MS = 600000;
15
+ /** Fragment prefix of the pairing URL; parsePairLink accepts the value with or without it. */
16
+ export const PAIR_FRAGMENT_PREFIX = '#req=';
17
+ const LINK_ERROR = 'invalid_pair_link';
18
+ const APPROVAL_ERROR = 'invalid_pair_approval';
19
+ const SECURE_CONTEXT_ERROR = 'secure_context_required';
20
+ const CODE_DOMAIN = 'ftown-pair-code-v2\n';
21
+ const PROOF_DOMAIN = 'ftown-pair-proof-v2\n';
22
+ const CHANNEL_PREFIX = 'ftown-pair:';
23
+ const MAX_TIME = 253402300799999;
24
+ const MAX_LINK_BYTES = 2048;
25
+ const MAX_LINK_CHARS = Math.ceil(MAX_LINK_BYTES * 4 / 3);
26
+ /** The sealed bundle is a few hundred bytes; the HPKE envelope and sender endpoint stay far below this bound. */
27
+ const MAX_SEALED_CHARS = 8192;
28
+ const REQUEST_KEYS = ['version', 'requestId', 'bridgeId', 'endpointPublicKey', 'authPublicKey', 'label', 'expiresAt'];
29
+ const BUNDLE_KEYS = ['version', 'requestId', 'accountId', 'head', 'proof'];
30
+ const ENDPOINT_KINDS = ['bridge', 'browser', 'local-cli'];
31
+ const encoder = new TextEncoder();
32
+ /** Internal only: every public function catches it and throws its own stable Error message instead. */
33
+ function malformed() {
34
+ throw new Error('malformed');
35
+ }
36
+ function linkError() {
37
+ return new Error(LINK_ERROR);
38
+ }
39
+ function approvalError() {
40
+ return new Error(APPROVAL_ERROR);
41
+ }
42
+ /** WebCrypto's subtle API exists only in secure contexts (HTTPS or localhost); http LAN pages must say so, not "invalid link". */
43
+ function requireSecureContext() {
44
+ if (typeof crypto === 'undefined' || !crypto || !crypto.subtle)
45
+ throw new Error(SECURE_CONTEXT_ERROR);
46
+ }
47
+ function isPlain(value) {
48
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
49
+ return false;
50
+ const prototype = Object.getPrototypeOf(value);
51
+ return prototype === null || Object.getPrototypeOf(prototype) === null;
52
+ }
53
+ function exact(value, keys) {
54
+ if (!isPlain(value))
55
+ return malformed();
56
+ const own = Object.keys(value);
57
+ if (own.length !== keys.length || own.some(key => keys.indexOf(key) === -1))
58
+ return malformed();
59
+ return value;
60
+ }
61
+ function b64url(data) {
62
+ let binary = '';
63
+ for (let index = 0; index < data.length; index += 1)
64
+ binary += String.fromCharCode(data[index]);
65
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
66
+ }
67
+ /** Canonical unpadded base64url only; the length bound is checked before decoding. */
68
+ function decode(value, min, max) {
69
+ if (typeof value !== 'string' || value.length > Math.ceil(max * 4 / 3) || !/^[A-Za-z0-9_-]+$/.test(value))
70
+ return malformed();
71
+ let binary;
72
+ try {
73
+ binary = atob(value.replace(/-/g, '+').replace(/_/g, '/'));
74
+ }
75
+ catch {
76
+ return malformed();
77
+ }
78
+ if (binary.length < min || binary.length > max)
79
+ return malformed();
80
+ const result = new Uint8Array(binary.length);
81
+ for (let index = 0; index < binary.length; index += 1)
82
+ result[index] = binary.charCodeAt(index);
83
+ if (b64url(result) !== value)
84
+ return malformed();
85
+ return result;
86
+ }
87
+ const fingerprint = (value) => b64url(decode(value, 32, 32));
88
+ function point(value) {
89
+ const raw = decode(value, 65, 65);
90
+ return raw[0] === 4 ? b64url(raw) : malformed();
91
+ }
92
+ function token(value) {
93
+ return typeof value === 'string' && /^[A-Za-z0-9_-]{1,200}$/.test(value) ? value : malformed();
94
+ }
95
+ /** Same rule as the ledger's labels: at most 200 UTF-16 units; no C0/C1 controls, zero-width or bidi controls, BOM, unpaired surrogates. */
96
+ function label(value) {
97
+ if (typeof value !== 'string' || value.length > LEDGER_LIMITS.maxLabelLength)
98
+ return malformed();
99
+ return /[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u202a-\u202e\u2066-\u2069\ufeff\ud800-\udfff]/u.test(value) ? malformed() : value;
100
+ }
101
+ function time(value) {
102
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 && value <= MAX_TIME ? value : malformed();
103
+ }
104
+ function random() {
105
+ return b64url(crypto.getRandomValues(new Uint8Array(32)));
106
+ }
107
+ function canonical(value) {
108
+ if (value === null || typeof value === 'boolean' || typeof value === 'string')
109
+ return JSON.stringify(value);
110
+ if (typeof value === 'number')
111
+ return Number.isFinite(value) ? JSON.stringify(value) : malformed();
112
+ if (Array.isArray(value)) {
113
+ const items = value;
114
+ return `[${items.map(canonical).join(',')}]`;
115
+ }
116
+ if (!isPlain(value))
117
+ return malformed();
118
+ const record = value;
119
+ return `{${Object.keys(record).sort().map(key => `${JSON.stringify(key)}:${canonical(record[key])}`).join(',')}}`;
120
+ }
121
+ async function sha256(data) {
122
+ return new Uint8Array(await crypto.subtle.digest('SHA-256', data));
123
+ }
124
+ function sameBytes(left, right) {
125
+ if (left.length !== right.length)
126
+ return false;
127
+ let difference = 0;
128
+ for (let index = 0; index < left.length; index += 1)
129
+ difference |= left[index] ^ right[index];
130
+ return difference === 0;
131
+ }
132
+ /** Strict request shape; returns a rebuilt copy that shares nothing with the input. */
133
+ function requestShape(value) {
134
+ const record = exact(value, REQUEST_KEYS);
135
+ if (record.version !== 2)
136
+ return malformed();
137
+ const request = {
138
+ version: 2, requestId: fingerprint(record.requestId), bridgeId: token(record.bridgeId),
139
+ endpointPublicKey: point(record.endpointPublicKey), authPublicKey: point(record.authPublicKey),
140
+ label: label(record.label), expiresAt: time(record.expiresAt),
141
+ };
142
+ // The ledger refuses a member whose two keys are equal; such a request could never be approved.
143
+ return request.endpointPublicKey === request.authPublicKey ? malformed() : request;
144
+ }
145
+ function linkShape(value) {
146
+ const record = exact(value, ['request', 'secret']);
147
+ return { request: requestShape(record.request), secret: fingerprint(record.secret) };
148
+ }
149
+ function approvalShape(value) {
150
+ const record = exact(value, ['accountId', 'head']);
151
+ return { accountId: fingerprint(record.accountId), head: fingerprint(record.head) };
152
+ }
153
+ /** The bridge's endpoint once it belongs to `accountId`: the exact value the add_bridge must carry. */
154
+ async function bridgeEndpoint(request, accountId) {
155
+ const id = b64url(await sha256(decode(request.endpointPublicKey, 65, 65)));
156
+ return { version: 1, id, ownerId: fingerprint(accountId), kind: 'bridge', publicKey: request.endpointPublicKey };
157
+ }
158
+ function channelOf(request) {
159
+ return CHANNEL_PREFIX + request.requestId;
160
+ }
161
+ /** HMAC-SHA256(secret, PROOF_DOMAIN + accountId + '\n' + head + '\n' + requestId). */
162
+ async function secretProof(secret, accountId, head, requestId) {
163
+ const key = await crypto.subtle.importKey('raw', decode(secret, 32, 32), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
164
+ const message = encoder.encode(PROOF_DOMAIN + accountId + '\n' + head + '\n' + requestId);
165
+ return new Uint8Array(await crypto.subtle.sign('HMAC', key, message));
166
+ }
167
+ /**
168
+ * The ledger checks shared by both sides, on a ledger that already verified into `checkpoint`. Returns the endpoint to seal to.
169
+ * - The ledger is the approved account's (genesis hash equals approval.accountId).
170
+ * - The chain contains approval.head (genesis or any transition); it may have grown since.
171
+ * - This request's bridge (bridgeId, endpoint id = SHA-256(endpointPublicKey), authPublicKey) is a POSITIVE member of the trusted
172
+ * roster: the final checkpoint minus every sticky revocation, so a bridge revoked in any chain this replica saw never pairs.
173
+ * (verifyLedger already bound endpoint id to its key, owner to the account and kind to 'bridge'.)
174
+ * - Its add_bridge does not come after approval.head.
175
+ */
176
+ async function confirmVerified(request, approval, ledger, checkpoint, sticky) {
177
+ const accountId = await accountIdOf(ledger.genesis.payload);
178
+ if (accountId !== approval.accountId)
179
+ return malformed();
180
+ // heads[0] is the genesis head; heads[i + 1] is the head of transitions[i]. Heads are unique within one chain.
181
+ const heads = [accountId];
182
+ for (const record of ledger.transitions)
183
+ heads.push(await ledgerHead(record.payload));
184
+ if (heads.indexOf(approval.head) === -1)
185
+ return malformed();
186
+ const expected = await bridgeEndpoint(request, accountId);
187
+ const trusted = applyRevocations(checkpoint, sticky).bridges;
188
+ if (!trusted.some(item => item.bridgeId === request.bridgeId && item.endpoint.id === expected.id
189
+ && item.authPublicKey === request.authPublicKey))
190
+ return malformed();
191
+ // Index of the add_bridge; a roster member always has one (an absent one would count as after every head).
192
+ let addedAt = ledger.transitions.length;
193
+ for (let index = ledger.transitions.length - 1; index >= 0; index -= 1) {
194
+ const operation = ledger.transitions[index].payload.operation;
195
+ if (operation.type === 'add_bridge' && operation.bridge.bridgeId === request.bridgeId)
196
+ addedAt = index;
197
+ }
198
+ // The approval must not predate the add_bridge: approval.head is not among the heads up to the record before it.
199
+ if (heads.slice(0, addedAt + 1).indexOf(approval.head) !== -1)
200
+ return malformed();
201
+ return expected;
202
+ }
203
+ function senderShape(value) {
204
+ const record = exact(value, ['version', 'id', 'ownerId', 'kind', 'publicKey']);
205
+ const kind = ENDPOINT_KINDS.filter(item => item === record.kind)[0];
206
+ if (record.version !== 1 || kind === undefined || typeof record.ownerId !== 'string')
207
+ return malformed();
208
+ // seal/open re-check the owner syntax and id = SHA-256(publicKey).
209
+ return { version: 1, id: fingerprint(record.id), ownerId: record.ownerId, kind, publicKey: point(record.publicKey) };
210
+ }
211
+ function sealedShape(value) {
212
+ if (typeof value !== 'string' || value.length > MAX_SEALED_CHARS)
213
+ return malformed();
214
+ let parsed;
215
+ try {
216
+ parsed = JSON.parse(value);
217
+ }
218
+ catch {
219
+ return malformed();
220
+ }
221
+ const record = exact(parsed, ['version', 'sender', 'envelope']);
222
+ if (record.version !== 2)
223
+ return malformed();
224
+ return { sender: senderShape(record.sender), envelope: parseSecureEnvelope(record.envelope) };
225
+ }
226
+ /** A fresh request for this bridge, with a random requestId and secret. Throws Error('invalid_pair_link') on invalid input. */
227
+ export function createBridgePairRequest(input) {
228
+ try {
229
+ const now = input.now === undefined ? Date.now() : time(input.now);
230
+ const lifetime = input.lifetimeMs === undefined ? PAIR_LIFETIME_MS : input.lifetimeMs;
231
+ if (!Number.isSafeInteger(lifetime) || lifetime <= 0 || lifetime > PAIR_LIFETIME_MS)
232
+ return malformed();
233
+ return linkShape({
234
+ request: {
235
+ version: 2, requestId: random(), bridgeId: input.bridgeId, endpointPublicKey: input.endpointPublicKey,
236
+ authPublicKey: input.authPublicKey, label: input.label, expiresAt: now + lifetime,
237
+ },
238
+ secret: random(),
239
+ });
240
+ }
241
+ catch {
242
+ throw linkError();
243
+ }
244
+ }
245
+ /** The approving browser's add_bridge payload. Throws Error('secure_context_required') without WebCrypto, Error('invalid_pair_link') on invalid input. */
246
+ export async function bridgeFromPairRequest(request, accountId, approvedAt) {
247
+ requireSecureContext();
248
+ try {
249
+ const parsed = requestShape(request);
250
+ return {
251
+ bridgeId: parsed.bridgeId, endpoint: await bridgeEndpoint(parsed, accountId), authPublicKey: parsed.authPublicKey,
252
+ label: parsed.label, approvedAt: time(approvedAt),
253
+ };
254
+ }
255
+ catch {
256
+ throw linkError();
257
+ }
258
+ }
259
+ /** Compact base64url JSON of the link: the fragment value after PAIR_FRAGMENT_PREFIX. Throws Error('invalid_pair_link'). */
260
+ export function encodePairLink(link) {
261
+ try {
262
+ const data = encoder.encode(JSON.stringify(linkShape(link)));
263
+ return data.byteLength > MAX_LINK_BYTES ? malformed() : b64url(data);
264
+ }
265
+ catch {
266
+ throw linkError();
267
+ }
268
+ }
269
+ /** Strict parse of the fragment, with or without the leading '#req='. Does not check expiry. Throws Error('invalid_pair_link'). */
270
+ export function parsePairLink(fragment) {
271
+ try {
272
+ if (typeof fragment !== 'string')
273
+ return malformed();
274
+ const text = fragment.indexOf(PAIR_FRAGMENT_PREFIX) === 0 ? fragment.slice(PAIR_FRAGMENT_PREFIX.length) : fragment;
275
+ if (text.length > MAX_LINK_CHARS)
276
+ return malformed();
277
+ const data = decode(text, 1, MAX_LINK_BYTES);
278
+ return linkShape(JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(data)));
279
+ }
280
+ catch {
281
+ throw linkError();
282
+ }
283
+ }
284
+ /**
285
+ * Six decimal digits, shown by the bridge and by the approving page: SHA-256(UTF-8('ftown-pair-code-v2\n' + canonical(request))),
286
+ * first 4 bytes as a big-endian uint32, mod 10^6, zero-padded. Bias: 2^32 = 4294 * 10^6 + 967296, so codes below 967296 occur with
287
+ * probability 4295/2^32 and the rest 4294/2^32, a relative skew of 1/4294 (about 0.02%), negligible for a human comparison.
288
+ * Throws Error('secure_context_required') without WebCrypto, Error('invalid_pair_link') on a malformed request.
289
+ */
290
+ export async function pairComparisonCode(request) {
291
+ requireSecureContext();
292
+ let message;
293
+ try {
294
+ message = encoder.encode(CODE_DOMAIN + canonical(requestShape(request)));
295
+ }
296
+ catch {
297
+ throw linkError();
298
+ }
299
+ const digest = await sha256(message);
300
+ const value = digest[0] * 16777216 + digest[1] * 65536 + digest[2] * 256 + digest[3];
301
+ const code = String(value % 1000000);
302
+ return '000000'.slice(code.length) + code;
303
+ }
304
+ /**
305
+ * Browser side. Verifies the ledger and runs the same checks as confirmPairedLedger at its last head, then seals
306
+ * {version:2, requestId, accountId, head, proof} (no ledger) to the bridge's endpoint key, authenticated by `sender`.
307
+ * Returns the opaque string stored in the pair mailbox. Throws Error('secure_context_required') without WebCrypto,
308
+ * Error('invalid_pair_link') for a malformed or expired link, SecurityError from crypto.ts as is, else Error('invalid_pair_approval').
309
+ */
310
+ export async function sealPairApproval(link, ledger, sender, now = Date.now()) {
311
+ requireSecureContext();
312
+ let parsed;
313
+ let at;
314
+ try {
315
+ parsed = linkShape(link);
316
+ at = time(now);
317
+ // The envelope expires with the request; a request that is already due cannot be sealed.
318
+ if (at >= parsed.request.expiresAt)
319
+ return malformed();
320
+ }
321
+ catch {
322
+ throw linkError();
323
+ }
324
+ try {
325
+ const request = parsed.request;
326
+ const verifiedLedger = parseLedger(ledger);
327
+ const checkpoint = await verifyLedger(verifiedLedger, at);
328
+ const approval = { accountId: checkpoint.accountId, head: checkpoint.head };
329
+ const recipient = await confirmVerified(request, approval, verifiedLedger, checkpoint, ledgerRevocations(verifiedLedger));
330
+ const proof = b64url(await secretProof(parsed.secret, approval.accountId, approval.head, request.requestId));
331
+ // The sender only authenticates the HPKE envelope; it is rebound to the account like the recipient.
332
+ const from = { endpoint: { ...sender.endpoint, ownerId: approval.accountId }, keyPair: sender.keyPair };
333
+ const header = {
334
+ type: 'ftown_encrypted', version: 1, senderId: from.endpoint.id, recipientId: recipient.id, ownerId: approval.accountId,
335
+ bridgeId: request.bridgeId, channel: channelOf(request), purpose: 'enrolled', messageId: request.requestId,
336
+ createdAt: at, expiresAt: request.expiresAt, receiverEpoch: null,
337
+ };
338
+ const bundle = { version: 2, requestId: request.requestId, accountId: approval.accountId, head: approval.head, proof };
339
+ const envelope = await seal(from, recipient, header, encoder.encode(JSON.stringify(bundle)));
340
+ return JSON.stringify({ version: 2, sender: from.endpoint, envelope });
341
+ }
342
+ catch (error) {
343
+ if (error instanceof SecurityError)
344
+ throw error;
345
+ throw approvalError();
346
+ }
347
+ }
348
+ /**
349
+ * Bridge side, step 1. `identity` is the bridge's own endpoint identity (any pre-pairing ownerId; it is rebound to the account here).
350
+ * Never trusts the sender endpoint for authorization: it only authenticates the HPKE envelope. The authority is the HMAC proof of the
351
+ * link secret, which the server never sees, binding {accountId, head} to this request; step 2 (confirmPairedLedger) then requires a
352
+ * passkey-signed ledger of that account and head. A server can therefore not bind this bridge to another account.
353
+ * Throws Error('secure_context_required') without WebCrypto; every other failure throws Error('invalid_pair_approval').
354
+ */
355
+ export async function openPairApproval(sealed, link, identity, now = Date.now()) {
356
+ requireSecureContext();
357
+ try {
358
+ const { request, secret } = linkShape(link);
359
+ const at = time(now);
360
+ if (at > request.expiresAt)
361
+ return malformed();
362
+ if (identity.endpoint.publicKey !== request.endpointPublicKey)
363
+ return malformed();
364
+ const wire = sealedShape(sealed);
365
+ const envelope = wire.envelope;
366
+ if (envelope.messageId !== request.requestId || envelope.receiverEpoch !== null)
367
+ return malformed();
368
+ const recipient = await bridgeEndpoint(request, envelope.ownerId);
369
+ const data = await open({ endpoint: recipient, keyPair: identity.keyPair }, wire.sender, envelope, {
370
+ ownerId: envelope.ownerId, bridgeId: request.bridgeId, channel: channelOf(request), recipientId: recipient.id, purpose: 'enrolled',
371
+ });
372
+ const bundle = exact(JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(data)), BUNDLE_KEYS);
373
+ if (bundle.version !== 2)
374
+ return malformed();
375
+ if (bundle.requestId !== request.requestId)
376
+ return malformed();
377
+ const accountId = fingerprint(bundle.accountId);
378
+ const head = fingerprint(bundle.head);
379
+ if (accountId !== envelope.ownerId)
380
+ return malformed();
381
+ const proof = decode(bundle.proof, 32, 32);
382
+ const expected = await secretProof(secret, accountId, head, request.requestId);
383
+ if (!sameBytes(expected, proof))
384
+ return malformed();
385
+ return { accountId, head };
386
+ }
387
+ catch {
388
+ throw approvalError();
389
+ }
390
+ }
391
+ /**
392
+ * Bridge side, step 2, on the ledger fetched from the server after openPairApproval. Verifies it from genesis and requires: its
393
+ * accountId equals approval.accountId; the chain contains approval.head (it may have grown since); this request's bridge
394
+ * (bridgeId, endpoint id, authPublicKey) is a member of applyRevocations(checkpoint, sticky).bridges, with its add_bridge at or before
395
+ * approval.head. `sticky` is every revocation this replica has seen for the account (default: the chain's own, ledgerRevocations).
396
+ * Returns the RAW checkpoint of the chain (never the sticky-applied one, which must not be used as a chooseLedger cache).
397
+ * The link's expiry is not rechecked: openPairApproval already enforced it.
398
+ * Throws Error('secure_context_required') without WebCrypto; every other failure throws Error('invalid_pair_approval').
399
+ */
400
+ export async function confirmPairedLedger(link, approval, ledger, now = Date.now(), sticky) {
401
+ requireSecureContext();
402
+ try {
403
+ const { request } = linkShape(link);
404
+ const approved = approvalShape(approval);
405
+ const verifiedLedger = parseLedger(ledger);
406
+ const checkpoint = await verifyLedger(verifiedLedger, time(now));
407
+ await confirmVerified(request, approved, verifiedLedger, checkpoint, sticky === undefined ? ledgerRevocations(verifiedLedger) : sticky);
408
+ return checkpoint;
409
+ }
410
+ catch {
411
+ throw approvalError();
412
+ }
413
+ }
414
+ //# sourceMappingURL=pairing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairing.js","sourceRoot":"","sources":["../../../src/security/ledger/pairing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { LedgerCheckpoint } from './protocol.js';
2
+ export interface AuthProof {
3
+ accountId: string;
4
+ kind: 'device' | 'bridge';
5
+ /** endpoint.id for a device, bridgeId for a bridge. */
6
+ keyId: string;
7
+ nonce: string;
8
+ purpose: 'session' | 'relay';
9
+ /** Exact server origin. */
10
+ audience: string;
11
+ /** Raw r||s, base64url. */
12
+ signature: string;
13
+ }
14
+ export type AuthProofFields = Omit<AuthProof, 'signature'>;
15
+ export declare function generateAuthKey(extractable: boolean): Promise<{
16
+ publicKey: string;
17
+ privateKey: CryptoKey;
18
+ }>;
19
+ export declare function signAuthProof(privateKey: CryptoKey, fields: AuthProofFields): Promise<AuthProof>;
20
+ export declare function parseAuthProof(value: unknown): AuthProof | null;
21
+ export declare function verifyAuthProof(checkpoint: LedgerCheckpoint, proof: AuthProof, expect: {
22
+ audience: string;
23
+ purpose: 'session' | 'relay';
24
+ }): Promise<boolean>;