canary-kit 0.9.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/CANARY.md +1065 -0
- package/INTEGRATION.md +351 -0
- package/LICENSE +21 -0
- package/NIP-CANARY.md +624 -0
- package/README.md +187 -0
- package/SECURITY.md +92 -0
- package/dist/beacon.d.ts +104 -0
- package/dist/beacon.d.ts.map +1 -0
- package/dist/beacon.js +197 -0
- package/dist/beacon.js.map +1 -0
- package/dist/counter.d.ts +37 -0
- package/dist/counter.d.ts.map +1 -0
- package/dist/counter.js +62 -0
- package/dist/counter.js.map +1 -0
- package/dist/crypto.d.ts +111 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +309 -0
- package/dist/crypto.js.map +1 -0
- package/dist/derive.d.ts +68 -0
- package/dist/derive.d.ts.map +1 -0
- package/dist/derive.js +85 -0
- package/dist/derive.js.map +1 -0
- package/dist/encoding.d.ts +56 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +98 -0
- package/dist/encoding.js.map +1 -0
- package/dist/group.d.ts +185 -0
- package/dist/group.d.ts.map +1 -0
- package/dist/group.js +263 -0
- package/dist/group.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/nostr.d.ts +134 -0
- package/dist/nostr.d.ts.map +1 -0
- package/dist/nostr.js +175 -0
- package/dist/nostr.js.map +1 -0
- package/dist/presets.d.ts +26 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +39 -0
- package/dist/presets.js.map +1 -0
- package/dist/session.d.ts +114 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +173 -0
- package/dist/session.js.map +1 -0
- package/dist/sync-crypto.d.ts +66 -0
- package/dist/sync-crypto.d.ts.map +1 -0
- package/dist/sync-crypto.js +125 -0
- package/dist/sync-crypto.js.map +1 -0
- package/dist/sync.d.ts +191 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +568 -0
- package/dist/sync.js.map +1 -0
- package/dist/token.d.ts +186 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +344 -0
- package/dist/token.js.map +1 -0
- package/dist/verify.d.ts +45 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +59 -0
- package/dist/verify.js.map +1 -0
- package/dist/wordlist.d.ts +28 -0
- package/dist/wordlist.d.ts.map +1 -0
- package/dist/wordlist.js +297 -0
- package/dist/wordlist.js.map +1 -0
- package/llms-full.txt +1461 -0
- package/llms.txt +180 -0
- package/package.json +144 -0
package/dist/sync.js
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
// Transport-agnostic sync message protocol
|
|
2
|
+
export { deriveGroupKey, deriveGroupSigningKey, hashGroupTag, encryptEnvelope, decryptEnvelope } from './sync-crypto.js';
|
|
3
|
+
import { bytesToHex, hexToBytes } from './crypto.js';
|
|
4
|
+
import { addMember, removeMember } from './group.js';
|
|
5
|
+
const VALID_TYPES = new Set([
|
|
6
|
+
'member-join', 'member-leave', 'counter-advance',
|
|
7
|
+
'reseed', 'beacon', 'duress-alert', 'duress-clear', 'liveness-checkin', 'state-snapshot',
|
|
8
|
+
]);
|
|
9
|
+
/**
|
|
10
|
+
* Message types that mutate group state or are safety-critical.
|
|
11
|
+
* These MUST be delivered to offline devices — use a stored event kind.
|
|
12
|
+
* Fire-and-forget messages (beacons, liveness) use ephemeral kinds.
|
|
13
|
+
*/
|
|
14
|
+
export const STORED_MESSAGE_TYPES = new Set([
|
|
15
|
+
'member-join', 'member-leave', 'counter-advance', 'reseed',
|
|
16
|
+
'state-snapshot', 'duress-alert', 'duress-clear',
|
|
17
|
+
]);
|
|
18
|
+
/** 64-character lowercase hex string (32 bytes — Nostr pubkey or CANARY seed). */
|
|
19
|
+
const HEX_64_RE = /^[0-9a-f]{64}$/;
|
|
20
|
+
const MAX_COUNTER_ADVANCE_OFFSET = 100;
|
|
21
|
+
const MAX_MEMBERS = 100;
|
|
22
|
+
const MAX_BEACON_ACCURACY_METERS = 20_000_000;
|
|
23
|
+
const MAX_TAG_LENGTH = 256;
|
|
24
|
+
/** Maximum age (in seconds) for fire-and-forget messages before they are dropped. */
|
|
25
|
+
export const FIRE_AND_FORGET_FRESHNESS_SEC = 300;
|
|
26
|
+
/** Maximum allowed future skew (in seconds) for fire-and-forget timestamps. */
|
|
27
|
+
export const MAX_FUTURE_SKEW_SEC = 60;
|
|
28
|
+
/** Maximum consumedOps entries per epoch before oldest are evicted. */
|
|
29
|
+
const MAX_CONSUMED_OPS = 1000;
|
|
30
|
+
function appendConsumedOp(ops, opId, timestamp, currentFloor) {
|
|
31
|
+
const next = [...ops, opId];
|
|
32
|
+
if (next.length > MAX_CONSUMED_OPS) {
|
|
33
|
+
return {
|
|
34
|
+
consumedOps: next.slice(-MAX_CONSUMED_OPS),
|
|
35
|
+
consumedOpsFloor: Math.max(currentFloor ?? 0, timestamp),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return { consumedOps: next, consumedOpsFloor: currentFloor };
|
|
39
|
+
}
|
|
40
|
+
/** Current protocol version. Bump on any breaking wire format change. */
|
|
41
|
+
export const PROTOCOL_VERSION = 2;
|
|
42
|
+
function isFiniteNumber(value) {
|
|
43
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
44
|
+
}
|
|
45
|
+
function isNonNegativeInt(value) {
|
|
46
|
+
return isFiniteNumber(value) && Number.isInteger(value) && value >= 0;
|
|
47
|
+
}
|
|
48
|
+
// ── Serialisation ─────────────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* Encode a sync message as a JSON string for transport.
|
|
51
|
+
* Binary fields (seed) are hex-encoded for safe JSON round-tripping.
|
|
52
|
+
*
|
|
53
|
+
* @param msg - The sync message to serialise.
|
|
54
|
+
* @returns JSON string with protocolVersion injected and binary fields hex-encoded.
|
|
55
|
+
*/
|
|
56
|
+
export function encodeSyncMessage(msg) {
|
|
57
|
+
const versioned = { ...msg, protocolVersion: PROTOCOL_VERSION };
|
|
58
|
+
if (msg.type === 'reseed') {
|
|
59
|
+
const { seed: _seed, ...rest } = versioned;
|
|
60
|
+
return JSON.stringify({ ...rest, seed: bytesToHex(msg.seed) });
|
|
61
|
+
}
|
|
62
|
+
return JSON.stringify(versioned);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Recursively produce a JSON string with sorted keys and no whitespace.
|
|
66
|
+
* Handles nested objects, arrays (elements stringified recursively), and
|
|
67
|
+
* all JSON-safe primitives. Used for deterministic signing (H2).
|
|
68
|
+
*
|
|
69
|
+
* @param value - Any JSON-serialisable value (null, boolean, number, string, array, or plain object).
|
|
70
|
+
* @returns Deterministic JSON string with sorted keys and no whitespace.
|
|
71
|
+
* @throws {Error} If value contains a Uint8Array (must be hex-encoded first) or unsupported type.
|
|
72
|
+
*/
|
|
73
|
+
export function stableStringify(value) {
|
|
74
|
+
if (value === null || value === undefined)
|
|
75
|
+
return 'null';
|
|
76
|
+
if (typeof value === 'boolean' || typeof value === 'number')
|
|
77
|
+
return JSON.stringify(value);
|
|
78
|
+
if (typeof value === 'string')
|
|
79
|
+
return JSON.stringify(value);
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
return '[' + value.map(stableStringify).join(',') + ']';
|
|
82
|
+
}
|
|
83
|
+
if (value instanceof Uint8Array) {
|
|
84
|
+
throw new Error('stableStringify: Uint8Array must be hex-encoded before serialisation');
|
|
85
|
+
}
|
|
86
|
+
if (typeof value === 'object') {
|
|
87
|
+
const obj = value;
|
|
88
|
+
const keys = Object.keys(obj).sort();
|
|
89
|
+
const pairs = keys
|
|
90
|
+
.filter(k => obj[k] !== undefined)
|
|
91
|
+
.map(k => JSON.stringify(k) + ':' + stableStringify(obj[k]));
|
|
92
|
+
return '{' + pairs.join(',') + '}';
|
|
93
|
+
}
|
|
94
|
+
throw new Error(`stableStringify: unsupported type ${typeof value}`);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Return the canonical string representation of a sync message for signing.
|
|
98
|
+
* Keys are sorted recursively, no whitespace. Binary fields are hex-encoded.
|
|
99
|
+
* The message's protocolVersion field is preserved as-is — the send side
|
|
100
|
+
* (encodeSyncMessage) is responsible for injecting PROTOCOL_VERSION before
|
|
101
|
+
* both encode and sign, so the canonical bytes always reflect the actual
|
|
102
|
+
* wire value. This is the format that inner signatures are computed over (H2).
|
|
103
|
+
*
|
|
104
|
+
* @param msg - The sync message to canonicalise.
|
|
105
|
+
* @returns Deterministic JSON string with sorted keys and no whitespace.
|
|
106
|
+
*/
|
|
107
|
+
export function canonicaliseSyncMessage(msg) {
|
|
108
|
+
if (msg.type === 'reseed') {
|
|
109
|
+
const { seed, ...rest } = msg;
|
|
110
|
+
return stableStringify({ ...rest, seed: bytesToHex(seed) });
|
|
111
|
+
}
|
|
112
|
+
return stableStringify(msg);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Decode a sync message from a JSON string.
|
|
116
|
+
* Throws on invalid or unrecognised messages.
|
|
117
|
+
*
|
|
118
|
+
* @param payload - JSON string to decode.
|
|
119
|
+
* @returns Validated {@link SyncMessage} with correct types (e.g. reseed.seed as Uint8Array).
|
|
120
|
+
* @throws {Error} If JSON is invalid, message type is unrecognised, required fields are missing, or protocolVersion does not match.
|
|
121
|
+
*/
|
|
122
|
+
export function decodeSyncMessage(payload) {
|
|
123
|
+
let parsed;
|
|
124
|
+
try {
|
|
125
|
+
parsed = JSON.parse(payload);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
throw new Error('Invalid sync message: not valid JSON');
|
|
129
|
+
}
|
|
130
|
+
const type = parsed.type;
|
|
131
|
+
if (typeof type !== 'string' || !VALID_TYPES.has(type)) {
|
|
132
|
+
throw new Error(`Invalid sync message type: ${String(type)}`);
|
|
133
|
+
}
|
|
134
|
+
// Per-type field validation
|
|
135
|
+
const ts = parsed.timestamp;
|
|
136
|
+
if (!isNonNegativeInt(ts)) {
|
|
137
|
+
throw new Error(`Invalid sync message: missing or invalid timestamp`);
|
|
138
|
+
}
|
|
139
|
+
// Protocol version check (H1: hard cutover, exact match only)
|
|
140
|
+
const version = parsed.protocolVersion;
|
|
141
|
+
if (version === undefined || version === null) {
|
|
142
|
+
throw new Error('Invalid sync message: protocolVersion is required');
|
|
143
|
+
}
|
|
144
|
+
if (version !== PROTOCOL_VERSION) {
|
|
145
|
+
throw new Error(`Unsupported protocol version: ${JSON.stringify(version)} (expected: ${PROTOCOL_VERSION})`);
|
|
146
|
+
}
|
|
147
|
+
switch (type) {
|
|
148
|
+
case 'member-join':
|
|
149
|
+
if (typeof parsed.pubkey !== 'string' || !HEX_64_RE.test(parsed.pubkey)) {
|
|
150
|
+
throw new Error('Invalid sync message: member-join requires a 64-char hex pubkey');
|
|
151
|
+
}
|
|
152
|
+
// member-join always requires epoch and opId (privileged action)
|
|
153
|
+
if (!isNonNegativeInt(parsed.epoch)) {
|
|
154
|
+
throw new Error('Invalid sync message: member-join requires a non-negative epoch');
|
|
155
|
+
}
|
|
156
|
+
if (typeof parsed.opId !== 'string' || parsed.opId.length === 0 || parsed.opId.length > 128) {
|
|
157
|
+
throw new Error('Invalid sync message: member-join requires a non-empty opId (max 128 chars)');
|
|
158
|
+
}
|
|
159
|
+
if (parsed.displayName !== undefined) {
|
|
160
|
+
if (typeof parsed.displayName !== 'string' || parsed.displayName.length > 256) {
|
|
161
|
+
throw new Error('Invalid sync message: member-join displayName must be a string of at most 256 characters');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
case 'member-leave':
|
|
166
|
+
if (typeof parsed.pubkey !== 'string' || !HEX_64_RE.test(parsed.pubkey)) {
|
|
167
|
+
throw new Error('Invalid sync message: member-leave requires a 64-char hex pubkey');
|
|
168
|
+
}
|
|
169
|
+
if (!isNonNegativeInt(parsed.epoch)) {
|
|
170
|
+
throw new Error('Invalid sync message: member-leave requires a non-negative epoch');
|
|
171
|
+
}
|
|
172
|
+
if (typeof parsed.opId !== 'string' || parsed.opId.length === 0 || parsed.opId.length > 128) {
|
|
173
|
+
throw new Error('Invalid sync message: member-leave requires a non-empty opId (max 128 chars)');
|
|
174
|
+
}
|
|
175
|
+
break;
|
|
176
|
+
case 'liveness-checkin':
|
|
177
|
+
if (typeof parsed.pubkey !== 'string' || !HEX_64_RE.test(parsed.pubkey)) {
|
|
178
|
+
throw new Error('Invalid sync message: liveness-checkin requires a 64-char hex pubkey');
|
|
179
|
+
}
|
|
180
|
+
if (typeof parsed.opId !== 'string' || parsed.opId.length === 0 || parsed.opId.length > 128) {
|
|
181
|
+
throw new Error('Invalid sync message: liveness-checkin requires a non-empty opId (max 128 chars)');
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
case 'counter-advance':
|
|
185
|
+
if (!isNonNegativeInt(parsed.counter)) {
|
|
186
|
+
throw new Error('Invalid sync message: counter-advance requires a non-negative counter');
|
|
187
|
+
}
|
|
188
|
+
if (!isNonNegativeInt(parsed.usageOffset)) {
|
|
189
|
+
throw new Error('Invalid sync message: counter-advance requires a non-negative usageOffset');
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
case 'reseed':
|
|
193
|
+
if (typeof parsed.seed !== 'string' || !HEX_64_RE.test(parsed.seed)) {
|
|
194
|
+
throw new Error('Invalid sync message: reseed.seed must be a 64-char hex string');
|
|
195
|
+
}
|
|
196
|
+
if (!isNonNegativeInt(parsed.counter)) {
|
|
197
|
+
throw new Error('Invalid sync message: reseed requires a non-negative counter');
|
|
198
|
+
}
|
|
199
|
+
if (!isNonNegativeInt(parsed.epoch)) {
|
|
200
|
+
throw new Error('Invalid sync message: reseed requires a non-negative epoch');
|
|
201
|
+
}
|
|
202
|
+
if (typeof parsed.opId !== 'string' || parsed.opId.length === 0 || parsed.opId.length > 128) {
|
|
203
|
+
throw new Error('Invalid sync message: reseed requires a non-empty opId (max 128 chars)');
|
|
204
|
+
}
|
|
205
|
+
if (!Array.isArray(parsed.admins) || !parsed.admins.every((a) => typeof a === 'string' && HEX_64_RE.test(a))) {
|
|
206
|
+
throw new Error('Invalid sync message: reseed.admins must be 64-char hex pubkeys');
|
|
207
|
+
}
|
|
208
|
+
if (!Array.isArray(parsed.members) || !parsed.members.every((m) => typeof m === 'string' && HEX_64_RE.test(m))) {
|
|
209
|
+
throw new Error('Invalid sync message: reseed.members must be 64-char hex pubkeys');
|
|
210
|
+
}
|
|
211
|
+
if (parsed.members.length > MAX_MEMBERS) {
|
|
212
|
+
throw new Error(`Invalid sync message: reseed.members exceeds maximum of ${MAX_MEMBERS}`);
|
|
213
|
+
}
|
|
214
|
+
if (parsed.admins.length > MAX_MEMBERS) {
|
|
215
|
+
throw new Error(`Invalid sync message: reseed.admins exceeds maximum of ${MAX_MEMBERS}`);
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
type, seed: hexToBytes(parsed.seed), counter: parsed.counter, timestamp: ts,
|
|
219
|
+
epoch: parsed.epoch, opId: parsed.opId,
|
|
220
|
+
admins: [...parsed.admins], members: [...parsed.members],
|
|
221
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
222
|
+
};
|
|
223
|
+
case 'beacon':
|
|
224
|
+
if (!isFiniteNumber(parsed.lat) || !isFiniteNumber(parsed.lon)) {
|
|
225
|
+
throw new Error('Invalid sync message: beacon requires numeric lat and lon');
|
|
226
|
+
}
|
|
227
|
+
if (parsed.lat < -90 || parsed.lat > 90 || parsed.lon < -180 || parsed.lon > 180) {
|
|
228
|
+
throw new Error('Invalid sync message: beacon lat/lon out of range');
|
|
229
|
+
}
|
|
230
|
+
if (!isFiniteNumber(parsed.accuracy) || parsed.accuracy < 0 || parsed.accuracy > MAX_BEACON_ACCURACY_METERS) {
|
|
231
|
+
throw new Error('Invalid sync message: beacon requires a non-negative accuracy');
|
|
232
|
+
}
|
|
233
|
+
if (typeof parsed.opId !== 'string' || parsed.opId.length === 0 || parsed.opId.length > 128) {
|
|
234
|
+
throw new Error('Invalid sync message: beacon requires a non-empty opId (max 128 chars)');
|
|
235
|
+
}
|
|
236
|
+
break;
|
|
237
|
+
case 'duress-alert':
|
|
238
|
+
if (!isFiniteNumber(parsed.lat) || !isFiniteNumber(parsed.lon)) {
|
|
239
|
+
throw new Error('Invalid sync message: duress-alert requires numeric lat and lon');
|
|
240
|
+
}
|
|
241
|
+
if (parsed.lat < -90 || parsed.lat > 90 || parsed.lon < -180 || parsed.lon > 180) {
|
|
242
|
+
throw new Error('Invalid sync message: duress-alert lat/lon out of range');
|
|
243
|
+
}
|
|
244
|
+
if (typeof parsed.opId !== 'string' || parsed.opId.length === 0 || parsed.opId.length > 128) {
|
|
245
|
+
throw new Error('Invalid sync message: duress-alert requires a non-empty opId (max 128 chars)');
|
|
246
|
+
}
|
|
247
|
+
if (parsed.subject !== undefined && (typeof parsed.subject !== 'string' || parsed.subject.length > MAX_TAG_LENGTH)) {
|
|
248
|
+
throw new Error(`Invalid sync message: duress-alert subject must be a string of at most ${MAX_TAG_LENGTH} characters`);
|
|
249
|
+
}
|
|
250
|
+
break;
|
|
251
|
+
case 'duress-clear':
|
|
252
|
+
if (typeof parsed.subject !== 'string' || parsed.subject.length === 0) {
|
|
253
|
+
throw new Error('Invalid sync message: duress-clear requires a non-empty subject');
|
|
254
|
+
}
|
|
255
|
+
if (parsed.subject.length > MAX_TAG_LENGTH) {
|
|
256
|
+
throw new Error(`Invalid sync message: duress-clear subject exceeds maximum length of ${MAX_TAG_LENGTH} characters`);
|
|
257
|
+
}
|
|
258
|
+
if (typeof parsed.opId !== 'string' || parsed.opId.length === 0 || parsed.opId.length > 128) {
|
|
259
|
+
throw new Error('Invalid sync message: duress-clear requires a non-empty opId (max 128 chars)');
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
case 'state-snapshot':
|
|
263
|
+
if (typeof parsed.seed !== 'string' || !HEX_64_RE.test(parsed.seed)) {
|
|
264
|
+
throw new Error('Invalid sync message: state-snapshot requires a 64-char hex seed');
|
|
265
|
+
}
|
|
266
|
+
if (!isNonNegativeInt(parsed.counter)) {
|
|
267
|
+
throw new Error('Invalid sync message: state-snapshot requires a non-negative counter');
|
|
268
|
+
}
|
|
269
|
+
if (!isNonNegativeInt(parsed.usageOffset)) {
|
|
270
|
+
throw new Error('Invalid sync message: state-snapshot requires a non-negative usageOffset');
|
|
271
|
+
}
|
|
272
|
+
if (!Array.isArray(parsed.members) || !parsed.members.every((m) => typeof m === 'string' && HEX_64_RE.test(m))) {
|
|
273
|
+
throw new Error('Invalid sync message: state-snapshot members must be 64-char hex pubkeys');
|
|
274
|
+
}
|
|
275
|
+
if (!Array.isArray(parsed.admins) || !parsed.admins.every((a) => typeof a === 'string' && HEX_64_RE.test(a))) {
|
|
276
|
+
throw new Error('Invalid sync message: state-snapshot admins must be 64-char hex pubkeys');
|
|
277
|
+
}
|
|
278
|
+
if (parsed.members.length > MAX_MEMBERS) {
|
|
279
|
+
throw new Error(`Invalid sync message: state-snapshot members exceeds maximum of ${MAX_MEMBERS}`);
|
|
280
|
+
}
|
|
281
|
+
if (parsed.admins.length > MAX_MEMBERS) {
|
|
282
|
+
throw new Error(`Invalid sync message: state-snapshot admins exceeds maximum of ${MAX_MEMBERS}`);
|
|
283
|
+
}
|
|
284
|
+
if (!isNonNegativeInt(parsed.epoch)) {
|
|
285
|
+
throw new Error('Invalid sync message: state-snapshot requires a non-negative epoch');
|
|
286
|
+
}
|
|
287
|
+
if (typeof parsed.opId !== 'string' || parsed.opId.length === 0 || parsed.opId.length > 128) {
|
|
288
|
+
throw new Error('Invalid sync message: state-snapshot requires a non-empty opId (max 128 chars)');
|
|
289
|
+
}
|
|
290
|
+
// Optional prevEpochSeed for epoch continuity verification
|
|
291
|
+
if (parsed.prevEpochSeed !== undefined) {
|
|
292
|
+
if (typeof parsed.prevEpochSeed !== 'string' || !HEX_64_RE.test(parsed.prevEpochSeed)) {
|
|
293
|
+
throw new Error('Invalid sync message: state-snapshot.prevEpochSeed must be a 64-char hex string');
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
return parsed;
|
|
299
|
+
}
|
|
300
|
+
// ── State application ─────────────────────────────────────────
|
|
301
|
+
/**
|
|
302
|
+
* Determine whether a sync message type is privileged (requires admin sender).
|
|
303
|
+
* member-join is privileged UNLESS the sender is adding themselves (self-join).
|
|
304
|
+
* Self-join is allowed because decrypting the group envelope proves the sender
|
|
305
|
+
* received a valid admin-signed invite containing the group key.
|
|
306
|
+
* member-leave is privileged when target !== sender.
|
|
307
|
+
* Self-leave is NOT privileged — a member can always remove themselves.
|
|
308
|
+
*/
|
|
309
|
+
function isPrivilegedAction(msg, sender) {
|
|
310
|
+
if (msg.type === 'reseed')
|
|
311
|
+
return true;
|
|
312
|
+
if (msg.type === 'state-snapshot')
|
|
313
|
+
return true;
|
|
314
|
+
if (msg.type === 'member-join' && msg.pubkey !== sender)
|
|
315
|
+
return true;
|
|
316
|
+
if (msg.type === 'member-leave' && msg.pubkey !== sender)
|
|
317
|
+
return true;
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Apply a sync message to group state.
|
|
322
|
+
* Returns a new GroupState with the change applied.
|
|
323
|
+
* Beacons and duress alerts don't modify group state (fire-and-forget).
|
|
324
|
+
*
|
|
325
|
+
* Authority invariants (I1-I6) are enforced for privileged actions.
|
|
326
|
+
* Privileged actions without a sender are rejected (fail-closed).
|
|
327
|
+
*
|
|
328
|
+
* @param group - Current group state.
|
|
329
|
+
* @param msg - The sync message to apply.
|
|
330
|
+
* @param nowSec - Current unix timestamp in seconds (default: `Date.now() / 1000`).
|
|
331
|
+
* @param sender - Hex pubkey of the message sender (required for privileged actions).
|
|
332
|
+
* @returns New group state with the change applied, or unchanged state if rejected.
|
|
333
|
+
*/
|
|
334
|
+
export function applySyncMessage(group, msg, nowSec = Math.floor(Date.now() / 1000), sender) {
|
|
335
|
+
// ── Authority checks (I1, I2, I3, I4, I6) ──────────────────
|
|
336
|
+
if (isPrivilegedAction(msg, sender)) {
|
|
337
|
+
// Fail-closed: no sender → reject privileged action
|
|
338
|
+
if (!sender)
|
|
339
|
+
return group;
|
|
340
|
+
// I1: sender must be in admins
|
|
341
|
+
if (!group.admins.includes(sender))
|
|
342
|
+
return group;
|
|
343
|
+
const msgEpoch = msg.epoch;
|
|
344
|
+
const msgOpId = msg.opId;
|
|
345
|
+
// Strict: privileged ops require epoch and opId
|
|
346
|
+
if (msgEpoch === undefined || msgOpId === undefined)
|
|
347
|
+
return group;
|
|
348
|
+
// I6: stale epoch — drop
|
|
349
|
+
if (msgEpoch < group.epoch)
|
|
350
|
+
return group;
|
|
351
|
+
if (msg.type === 'reseed') {
|
|
352
|
+
// I4: reseed must have msg.epoch == local.epoch + 1
|
|
353
|
+
if (msgEpoch !== group.epoch + 1)
|
|
354
|
+
return group;
|
|
355
|
+
// I4: reseed must carry admins and members
|
|
356
|
+
const reseedMsg = msg;
|
|
357
|
+
if (!reseedMsg.admins || !reseedMsg.members)
|
|
358
|
+
return group;
|
|
359
|
+
// Enforce admins ⊆ members
|
|
360
|
+
const memberSet = new Set(reseedMsg.members);
|
|
361
|
+
if (!reseedMsg.admins.every(a => memberSet.has(a)))
|
|
362
|
+
return group;
|
|
363
|
+
}
|
|
364
|
+
else if (msg.type === 'state-snapshot') {
|
|
365
|
+
// I5: snapshot epoch must be >= local epoch (allows catch-up across multiple reseeds)
|
|
366
|
+
if (msgEpoch < group.epoch)
|
|
367
|
+
return group;
|
|
368
|
+
// Snapshot must carry admins and members
|
|
369
|
+
const snapMsg = msg;
|
|
370
|
+
if (!snapMsg.admins || !snapMsg.members)
|
|
371
|
+
return group;
|
|
372
|
+
// Enforce admins ⊆ members
|
|
373
|
+
const memberSet = new Set(snapMsg.members);
|
|
374
|
+
if (!snapMsg.admins.every(a => memberSet.has(a)))
|
|
375
|
+
return group;
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
// I3: non-reseed privileged ops must have msg.epoch == local.epoch
|
|
379
|
+
if (msgEpoch !== group.epoch)
|
|
380
|
+
return group;
|
|
381
|
+
}
|
|
382
|
+
// I2: opId must not be consumed in current epoch
|
|
383
|
+
// reseed starts a new epoch so its opId is not subject to the current-epoch replay guard
|
|
384
|
+
// Higher-epoch snapshots also start fresh; same-epoch snapshot opId is checked in the switch case
|
|
385
|
+
if (msg.type !== 'reseed' && !(msg.type === 'state-snapshot' && msgEpoch > group.epoch)) {
|
|
386
|
+
const consumedSet = new Set(group.consumedOps);
|
|
387
|
+
if (consumedSet.has(msgOpId))
|
|
388
|
+
return group;
|
|
389
|
+
// Floor check: reject messages with timestamps at or below the eviction floor
|
|
390
|
+
// (prevents replay of ops that were evicted from consumedOps)
|
|
391
|
+
if (group.consumedOpsFloor !== undefined && msg.timestamp <= group.consumedOpsFloor)
|
|
392
|
+
return group;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
// ── Freshness gate for fire-and-forget messages ────────────
|
|
396
|
+
// Drop stale duress-alert/beacon/liveness-checkin messages to prevent replay.
|
|
397
|
+
if (msg.type === 'duress-alert' || msg.type === 'duress-clear' || msg.type === 'beacon' || msg.type === 'liveness-checkin') {
|
|
398
|
+
const elapsed = nowSec - msg.timestamp;
|
|
399
|
+
if (elapsed > FIRE_AND_FORGET_FRESHNESS_SEC)
|
|
400
|
+
return group; // stale
|
|
401
|
+
if (elapsed < -MAX_FUTURE_SKEW_SEC)
|
|
402
|
+
return group; // too far in the future
|
|
403
|
+
}
|
|
404
|
+
// Cross-check: liveness-checkin sender must match the pubkey in the message
|
|
405
|
+
if (msg.type === 'liveness-checkin' && sender && msg.pubkey !== sender)
|
|
406
|
+
return group;
|
|
407
|
+
// Non-privileged member-leave/member-join/duress-clear still need opId replay guard
|
|
408
|
+
if ((msg.type === 'member-leave' || msg.type === 'member-join' || msg.type === 'duress-clear') && !isPrivilegedAction(msg, sender)) {
|
|
409
|
+
const consumedSet = new Set(group.consumedOps);
|
|
410
|
+
if (consumedSet.has(msg.opId))
|
|
411
|
+
return group;
|
|
412
|
+
if (group.consumedOpsFloor !== undefined && msg.timestamp <= group.consumedOpsFloor)
|
|
413
|
+
return group;
|
|
414
|
+
}
|
|
415
|
+
switch (msg.type) {
|
|
416
|
+
case 'member-join': {
|
|
417
|
+
let updated;
|
|
418
|
+
try {
|
|
419
|
+
updated = addMember(group, msg.pubkey);
|
|
420
|
+
}
|
|
421
|
+
catch {
|
|
422
|
+
return group; // invalid pubkey or MAX_MEMBERS exceeded — reject silently
|
|
423
|
+
}
|
|
424
|
+
const ops = appendConsumedOp(updated.consumedOps, msg.opId, msg.timestamp, group.consumedOpsFloor);
|
|
425
|
+
const names = msg.displayName
|
|
426
|
+
? { memberNames: { ...updated.memberNames, [msg.pubkey]: msg.displayName } }
|
|
427
|
+
: {};
|
|
428
|
+
return { ...updated, ...ops, ...names };
|
|
429
|
+
}
|
|
430
|
+
case 'member-leave':
|
|
431
|
+
// Replay guard: if the pubkey is not a current member, ignore the message
|
|
432
|
+
if (!group.members.includes(msg.pubkey))
|
|
433
|
+
return group;
|
|
434
|
+
{
|
|
435
|
+
const updated = removeMember(group, msg.pubkey);
|
|
436
|
+
const ops = appendConsumedOp(updated.consumedOps, msg.opId, msg.timestamp, group.consumedOpsFloor);
|
|
437
|
+
return { ...updated, ...ops };
|
|
438
|
+
}
|
|
439
|
+
case 'counter-advance': {
|
|
440
|
+
// NOTE: counter-advance intentionally has no epoch field (unlike other
|
|
441
|
+
// mutation messages). This was evaluated during security audit 2026-03-15.
|
|
442
|
+
//
|
|
443
|
+
// Why this is safe without epoch:
|
|
444
|
+
// 1. Envelope encryption: messages travel inside AES-GCM envelopes keyed
|
|
445
|
+
// by deriveGroupKey(seed). After a reseed the key changes, so captured
|
|
446
|
+
// ciphertext from epoch N cannot be injected into epoch N+1.
|
|
447
|
+
// 2. Active replay requires a current member who survived the reseed —
|
|
448
|
+
// but such a member could just send a *new* counter-advance with any
|
|
449
|
+
// values they want. Epoch wouldn't stop a malicious current member.
|
|
450
|
+
// 3. Monotonic check rejects old effective counters (reseeds preserve the
|
|
451
|
+
// effective counter, so old values are always <=).
|
|
452
|
+
// 4. Time-based bound caps damage to +MAX_COUNTER_ADVANCE_OFFSET.
|
|
453
|
+
//
|
|
454
|
+
// Adding epoch is planned for protocol v3 for conceptual consistency.
|
|
455
|
+
// Require sender to be a current group member
|
|
456
|
+
if (!sender || !group.members.includes(sender))
|
|
457
|
+
return group;
|
|
458
|
+
// Bound individual fields to prevent overflow when summed
|
|
459
|
+
if (msg.usageOffset > MAX_COUNTER_ADVANCE_OFFSET)
|
|
460
|
+
return group;
|
|
461
|
+
// Monotonic: only advance, never retreat
|
|
462
|
+
const currentEffective = group.counter + group.usageOffset;
|
|
463
|
+
const incomingEffective = msg.counter + msg.usageOffset;
|
|
464
|
+
if (incomingEffective <= currentEffective)
|
|
465
|
+
return group;
|
|
466
|
+
// Bound forward jumps to limit desync damage from malicious/compromised senders.
|
|
467
|
+
const timeBasedCounter = Math.floor(nowSec / group.rotationInterval);
|
|
468
|
+
const maxAllowedEffective = timeBasedCounter + MAX_COUNTER_ADVANCE_OFFSET;
|
|
469
|
+
if (incomingEffective > maxAllowedEffective)
|
|
470
|
+
return group;
|
|
471
|
+
return { ...group, counter: msg.counter, usageOffset: msg.usageOffset };
|
|
472
|
+
}
|
|
473
|
+
case 'reseed':
|
|
474
|
+
// I4: atomic replacement of {seed, members, admins, epoch} + clear consumedOps
|
|
475
|
+
return {
|
|
476
|
+
...group,
|
|
477
|
+
seed: bytesToHex(msg.seed),
|
|
478
|
+
counter: msg.counter,
|
|
479
|
+
usageOffset: 0,
|
|
480
|
+
members: [...msg.members],
|
|
481
|
+
admins: [...msg.admins],
|
|
482
|
+
epoch: msg.epoch,
|
|
483
|
+
consumedOps: [msg.opId],
|
|
484
|
+
};
|
|
485
|
+
case 'state-snapshot': {
|
|
486
|
+
// I5: admin-gated state recovery for clients that missed transitions.
|
|
487
|
+
//
|
|
488
|
+
// KNOWN LIMITATION — stale-admin higher-epoch hijack:
|
|
489
|
+
// A removed admin still in the receiver's stale local cache can fabricate
|
|
490
|
+
// a higher-epoch snapshot. Single-field continuity proofs (prevEpochSeed)
|
|
491
|
+
// are either bypassable (optional) or create multi-epoch recovery dead-ends
|
|
492
|
+
// (mandatory). Full mitigation requires either:
|
|
493
|
+
// (a) quorum-based recovery (multiple admins must agree), or
|
|
494
|
+
// (b) a verifiable reseed-chain (signed epoch transitions stored on relays).
|
|
495
|
+
// Both are deferred to a future protocol version. The self-consistency check
|
|
496
|
+
// in the adapter (sender must be in snapshot's own admins list) narrows the
|
|
497
|
+
// attack surface to fabrication, not impersonation.
|
|
498
|
+
if (msg.epoch === group.epoch) {
|
|
499
|
+
// ── Same-epoch recovery: anti-rollback constraints ──
|
|
500
|
+
// No silent reseed within the same epoch
|
|
501
|
+
if (msg.seed !== group.seed)
|
|
502
|
+
return group;
|
|
503
|
+
// Effective counter must not regress
|
|
504
|
+
const localEffective = group.counter + group.usageOffset;
|
|
505
|
+
const incomingEffective = msg.counter + msg.usageOffset;
|
|
506
|
+
if (incomingEffective < localEffective)
|
|
507
|
+
return group;
|
|
508
|
+
// Members and admins must be supersets of current (removals require reseed/epoch bump)
|
|
509
|
+
if (!group.members.every(m => msg.members.includes(m)))
|
|
510
|
+
return group;
|
|
511
|
+
if (!group.admins.every(a => msg.admins.includes(a)))
|
|
512
|
+
return group;
|
|
513
|
+
// Append to consumedOps (preserve replay history within epoch)
|
|
514
|
+
const snapOps = appendConsumedOp(group.consumedOps, msg.opId, msg.timestamp, group.consumedOpsFloor);
|
|
515
|
+
return {
|
|
516
|
+
...group,
|
|
517
|
+
counter: msg.counter,
|
|
518
|
+
usageOffset: msg.usageOffset,
|
|
519
|
+
members: [...msg.members],
|
|
520
|
+
admins: [...msg.admins],
|
|
521
|
+
...snapOps,
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
// ── Higher-epoch recovery: DISABLED ──
|
|
525
|
+
// Higher-epoch snapshots are rejected. Members who miss reseeds
|
|
526
|
+
// must be re-invited. This eliminates the stale-admin hijack
|
|
527
|
+
// attack surface entirely.
|
|
528
|
+
return group;
|
|
529
|
+
}
|
|
530
|
+
case 'beacon':
|
|
531
|
+
case 'duress-alert':
|
|
532
|
+
case 'liveness-checkin':
|
|
533
|
+
return group;
|
|
534
|
+
default:
|
|
535
|
+
return group;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Apply a sync message and return a result indicating whether it was accepted.
|
|
540
|
+
*
|
|
541
|
+
* Unlike `applySyncMessage` which silently returns unchanged state on rejection,
|
|
542
|
+
* this function tells the caller whether the message was actually applied —
|
|
543
|
+
* enabling logging, alerting, and debugging of rejected messages.
|
|
544
|
+
*
|
|
545
|
+
* Fire-and-forget messages (beacon, duress-alert, liveness-checkin) always
|
|
546
|
+
* return `applied: true` when they pass freshness checks, even though they
|
|
547
|
+
* don't modify group state.
|
|
548
|
+
*
|
|
549
|
+
* @param group - Current group state.
|
|
550
|
+
* @param msg - The sync message to apply.
|
|
551
|
+
* @param nowSec - Current unix timestamp in seconds (default: `Date.now() / 1000`).
|
|
552
|
+
* @param sender - Hex pubkey of the message sender (required for privileged actions).
|
|
553
|
+
* @returns `{ state, applied }` where `applied` indicates whether the message was accepted.
|
|
554
|
+
*/
|
|
555
|
+
export function applySyncMessageWithResult(group, msg, nowSec = Math.floor(Date.now() / 1000), sender) {
|
|
556
|
+
const result = applySyncMessage(group, msg, nowSec, sender);
|
|
557
|
+
// Fire-and-forget messages don't modify state, so reference equality
|
|
558
|
+
// doesn't distinguish accepted from rejected. Check freshness directly.
|
|
559
|
+
if (msg.type === 'beacon' || msg.type === 'duress-alert' || msg.type === 'liveness-checkin') {
|
|
560
|
+
const elapsed = nowSec - msg.timestamp;
|
|
561
|
+
const fresh = elapsed <= FIRE_AND_FORGET_FRESHNESS_SEC && elapsed >= -MAX_FUTURE_SKEW_SEC;
|
|
562
|
+
// For liveness-checkin, also check sender-pubkey cross-check
|
|
563
|
+
const senderValid = msg.type !== 'liveness-checkin' || !sender || msg.pubkey === sender;
|
|
564
|
+
return { state: result, applied: fresh && senderValid };
|
|
565
|
+
}
|
|
566
|
+
return { state: result, applied: result !== group };
|
|
567
|
+
}
|
|
568
|
+
//# sourceMappingURL=sync.js.map
|
package/dist/sync.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}
|