@agora-sdk/secure-chat-crypto 0.4.0 → 0.6.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.
@@ -1,3 +1,4 @@
1
+ import { SecureChatDecryptError } from "./interface.js";
1
2
  const enc = new TextEncoder();
2
3
  const dec = new TextDecoder();
3
4
  const BACKUP_MAGIC = "AGORA_MOCK_BACKUP_V1";
@@ -75,13 +76,15 @@ export class MockSecureChatCrypto {
75
76
  bytesFrom(`grp:${did}:${opts.initialMembers.map((m) => m.deviceId).join(",")}`, 16);
76
77
  const idHex = toHex(mlsGroupId);
77
78
  const secret = bytesFrom(`secret:${idHex}:${did}`, 32);
78
- this.groups.set(idHex, { secret, epoch: 0n });
79
+ const members = [did, ...opts.initialMembers.map((m) => m.deviceId)];
80
+ this.groups.set(idHex, { secret, epoch: 0n, members });
79
81
  const welcomes = opts.initialMembers.map((m) => ({
80
82
  targetDeviceId: m.deviceId,
81
83
  payload: jsonBytes({
82
84
  groupId: idHex,
83
85
  secret: toHex(secret),
84
86
  epoch: "0",
87
+ members,
85
88
  }),
86
89
  }));
87
90
  return { group: { mlsGroupId, epoch: 0n }, welcomes };
@@ -93,6 +96,8 @@ export class MockSecureChatCrypto {
93
96
  throw new Error("mock: unknown group");
94
97
  st.epoch += 1n;
95
98
  const epoch = st.epoch;
99
+ if (!st.members.includes(newDevice.deviceId))
100
+ st.members.push(newDevice.deviceId);
96
101
  return {
97
102
  commit: jsonBytes({ type: "commit", groupId: idHex, epoch: epoch.toString() }),
98
103
  welcomes: [
@@ -102,18 +107,20 @@ export class MockSecureChatCrypto {
102
107
  groupId: idHex,
103
108
  secret: toHex(st.secret),
104
109
  epoch: epoch.toString(),
110
+ members: st.members,
105
111
  }),
106
112
  },
107
113
  ],
108
114
  epoch,
109
115
  };
110
116
  }
111
- async removeMember(group, _leafDeviceId) {
117
+ async removeMember(group, leafDeviceId) {
112
118
  const idHex = toHex(group.mlsGroupId);
113
119
  const st = this.groups.get(idHex);
114
120
  if (!st)
115
121
  throw new Error("mock: unknown group");
116
122
  st.epoch += 1n;
123
+ st.members = st.members.filter((m) => m !== leafDeviceId);
117
124
  return {
118
125
  commit: jsonBytes({ type: "commit", groupId: idHex, epoch: st.epoch.toString() }),
119
126
  welcomes: [],
@@ -138,7 +145,7 @@ export class MockSecureChatCrypto {
138
145
  const idHex = toHex(group.mlsGroupId);
139
146
  const st = this.groups.get(idHex);
140
147
  if (!st)
141
- throw new Error("mock: unknown group");
148
+ throw new SecureChatDecryptError("unknown", "mock: unknown group");
142
149
  // header = "<deviceId>|<epoch>|" — split on the SECOND pipe.
143
150
  let pipes = 0;
144
151
  let cut = -1;
@@ -152,7 +159,7 @@ export class MockSecureChatCrypto {
152
159
  }
153
160
  }
154
161
  if (cut < 0)
155
- throw new Error("mock: malformed ciphertext");
162
+ throw new SecureChatDecryptError("malformed", "mock: malformed ciphertext");
156
163
  const [senderDeviceId, epochStr] = dec.decode(ciphertext.slice(0, cut - 1)).split("|");
157
164
  const body = ciphertext.slice(cut);
158
165
  const ks = keystream(st.secret, body.length);
@@ -164,9 +171,25 @@ export class MockSecureChatCrypto {
164
171
  }
165
172
  async processWelcome(welcome) {
166
173
  const w = parseJson(welcome);
167
- this.groups.set(w.groupId, { secret: fromHex(w.secret), epoch: BigInt(w.epoch) });
174
+ this.groups.set(w.groupId, {
175
+ secret: fromHex(w.secret),
176
+ epoch: BigInt(w.epoch),
177
+ members: w.members ?? [],
178
+ });
168
179
  return { mlsGroupId: fromHex(w.groupId), epoch: BigInt(w.epoch) };
169
180
  }
181
+ async exportGroupIdentities(group) {
182
+ const idHex = toHex(group.mlsGroupId);
183
+ const st = this.groups.get(idHex);
184
+ if (!st)
185
+ throw new Error("mock: unknown group");
186
+ // The mock derives each device's signature key deterministically from its id (see
187
+ // generateDeviceIdentity), so the roster of device ids is enough to reconstruct every member's key.
188
+ return st.members.map((deviceId) => ({
189
+ deviceId,
190
+ signaturePublicKey: bytesFrom(`sig:${deviceId}`, 32),
191
+ }));
192
+ }
170
193
  async processCommit(group, commit) {
171
194
  const c = parseJson(commit);
172
195
  const idHex = toHex(group.mlsGroupId);
@@ -207,11 +230,20 @@ export class MockSecureChatCrypto {
207
230
  const st = this.groups.get(idHex);
208
231
  if (!st)
209
232
  throw new Error("mock: unknown group");
210
- return jsonBytes({ groupId: idHex, secret: toHex(st.secret), epoch: st.epoch.toString() });
233
+ return jsonBytes({
234
+ groupId: idHex,
235
+ secret: toHex(st.secret),
236
+ epoch: st.epoch.toString(),
237
+ members: st.members,
238
+ });
211
239
  }
212
240
  async importGroupState(state) {
213
241
  const s = parseJson(state);
214
- this.groups.set(s.groupId, { secret: fromHex(s.secret), epoch: BigInt(s.epoch) });
242
+ this.groups.set(s.groupId, {
243
+ secret: fromHex(s.secret),
244
+ epoch: BigInt(s.epoch),
245
+ members: s.members ?? [],
246
+ });
215
247
  return { mlsGroupId: fromHex(s.groupId), epoch: BigInt(s.epoch) };
216
248
  }
217
249
  async exportBackup(passphrase) {
@@ -219,11 +251,13 @@ export class MockSecureChatCrypto {
219
251
  id,
220
252
  secret: toHex(st.secret),
221
253
  epoch: st.epoch.toString(),
254
+ members: st.members,
222
255
  }));
223
256
  const plain = jsonBytes({
224
257
  magic: BACKUP_MAGIC,
225
258
  identityPriv: this.privateState ? toHex(this.privateState) : null,
226
259
  deviceId: this.identity?.deviceId ?? null,
260
+ ciphersuite: this.identity?.ciphersuite ?? 1,
227
261
  groups,
228
262
  });
229
263
  const salt = bytesFrom(`salt:${passphrase}`, 16);
@@ -248,14 +282,25 @@ export class MockSecureChatCrypto {
248
282
  catch {
249
283
  throw new Error("mock: backup decrypt failed (wrong passphrase?)");
250
284
  }
251
- if (parsed.magic !== BACKUP_MAGIC) {
285
+ if (parsed.magic !== BACKUP_MAGIC || !parsed.deviceId) {
252
286
  throw new Error("mock: backup decrypt failed (wrong passphrase?)");
253
287
  }
254
288
  if (parsed.identityPriv)
255
289
  this.privateState = fromHex(parsed.identityPriv);
256
290
  for (const g of parsed.groups) {
257
- this.groups.set(g.id, { secret: fromHex(g.secret), epoch: BigInt(g.epoch) });
291
+ this.groups.set(g.id, { secret: fromHex(g.secret), epoch: BigInt(g.epoch), members: g.members ?? [] });
258
292
  }
293
+ // Rebuild the (deterministic) identity so the restored mock is usable, and return it — symmetric
294
+ // with importDeviceState, so the restore flow can re-assert the device server-side.
295
+ const ciphersuite = parsed.ciphersuite ?? 1;
296
+ const identity = {
297
+ deviceId: parsed.deviceId,
298
+ signaturePublicKey: bytesFrom(`sig:${parsed.deviceId}`, 32),
299
+ credential: enc.encode(parsed.deviceId),
300
+ ciphersuite,
301
+ };
302
+ this.identity = identity;
303
+ return identity;
259
304
  }
260
305
  }
261
306
  //# sourceMappingURL=mock-crypto.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mock-crypto.js","sourceRoot":"","sources":["../../src/mock-crypto.ts"],"names":[],"mappings":"AA0BA,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;AAC9B,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;AAC9B,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAE5C,SAAS,KAAK,CAAC,CAAa;IAC1B,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,KAAK,MAAM,CAAC,IAAI,CAAC;QAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,CAAC;AACX,CAAC;AACD,SAAS,OAAO,CAAC,CAAS;IACxB,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACtF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,mGAAmG;AACnG,SAAS,SAAS,CAAC,IAAgB,EAAE,GAAW;IAC9C,IAAI,KAAK,GAAG,UAAU,KAAK,CAAC,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACvD,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;QAC/B,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AACD,SAAS,SAAS,CAAC,CAAS,EAAE,GAAW;IACvC,OAAO,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACvC,CAAC;AACD,SAAS,GAAG,CAAC,IAAgB,EAAE,GAAe;IAC5C,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAE,CAAC;IAC/E,OAAO,GAAG,CAAC;AACb,CAAC;AACD,SAAS,SAAS,CAAC,CAAU;IAC3B,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AACD,SAAS,SAAS,CAAI,CAAa;IACjC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAM,CAAC;AACxC,CAAC;AAYD,MAAM,OAAO,oBAAoB;IAAjC;QAGU,WAAM,GAAG,IAAI,GAAG,EAAsB,CAAC,CAAC,sBAAsB;QAC9D,cAAS,GAAG,CAAC,CAAC;IAmPxB,CAAC;IAjPC,KAAK,CAAC,sBAAsB,CAAC,IAAgD;QAC3E,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAmB;YAC/B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,kBAAkB,EAAE,SAAS,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;YACzD,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,kCAAkC;YACzE,WAAW;SACZ,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,KAAa;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,IAAI,SAAS,CAAC;QACjD,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,IAAI,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAuB,EAAE,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,GAAG,GAAG,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YAC5C,GAAG,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,CAAC,MAAM,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5F,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAGjB;QACC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,IAAI,SAAS,CAAC;QACjD,MAAM,UAAU,GACd,IAAI,CAAC,UAAU;YACf,SAAS,CAAC,OAAO,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtF,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU,KAAK,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/C,cAAc,EAAE,CAAC,CAAC,QAAQ;YAC1B,OAAO,EAAE,SAAS,CAAC;gBACjB,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;gBACrB,KAAK,EAAE,GAAG;aACc,CAAC;SAC5B,CAAC,CAAC,CAAC;QACJ,OAAO,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,SAAS,CACb,KAAkB,EAClB,SAAuD;QAEvD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAChD,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC;QACvB,OAAO;YACL,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC9E,QAAQ,EAAE;gBACR;oBACE,cAAc,EAAE,SAAS,CAAC,QAAQ;oBAClC,OAAO,EAAE,SAAS,CAAC;wBACjB,OAAO,EAAE,KAAK;wBACd,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;wBACxB,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE;qBACC,CAAC;iBAC5B;aACF;YACD,KAAK;SACN,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAkB,EAAE,aAAqB;QAC1D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAChD,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;QACf,OAAO;YACL,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC;YACjF,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,EAAE,CAAC,KAAK;SAChB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,KAAkB,EAClB,SAAqB;QAErB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,IAAI,SAAS,CAAC;QACpD,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,IAAI,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC;QACpD,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/D,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC1B,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,KAAkB,EAClB,UAAsB;QAEtB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAChD,6DAA6D;QAC7D,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;QACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;gBACnC,KAAK,EAAE,CAAC;gBACR,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;oBAChB,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;oBACZ,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,GAAG,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAC3D,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACvF,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;YACxB,cAAc,EAAE,cAAc,IAAI,EAAE;YACpC,KAAK,EAAE,MAAM,CAAC,QAAQ,IAAI,GAAG,CAAC;SAC/B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAAmB;QACtC,MAAM,CAAC,GAAG,SAAS,CAAiB,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClF,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAAkB,EAAE,MAAkB;QACxD,MAAM,CAAC,GAAG,SAAS,CAAoB,MAAM,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,EAAE;YAAE,EAAE,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,MAAmB,EAAE,SAAqB;QAC9D,2DAA2D;IAC7D,CAAC;IAED,KAAK,CAAC,iBAAiB;QACrB,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;QAC5F,CAAC;QACD,OAAO,SAAS,CAAC;YACf,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ;YAChC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW;YACtC,kBAAkB,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC;YAC3D,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC3C,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;SACvC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,KAAiB;QACvC,MAAM,CAAC,GAAG,SAAS,CAMhB,KAAK,CAAC,CAAC;QACV,MAAM,QAAQ,GAAmB;YAC/B,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,kBAAkB,EAAE,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC;YACjD,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;SAClC,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAC5C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,KAAkB;QACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAChD,OAAO,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,KAAiB;QACtC,MAAM,CAAC,GAAG,SAAS,CAAqD,KAAK,CAAC,CAAC;QAC/E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClF,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,UAAkB;QACnC,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3D,EAAE;YACF,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC;YACxB,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE;SAC3B,CAAC,CAAC,CAAC;QACJ,MAAM,KAAK,GAAG,SAAS,CAAC;YACtB,KAAK,EAAE,YAAY;YACnB,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI;YACjE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,IAAI,IAAI;YACzC,MAAM;SACP,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,UAAU,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAChF,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC;YACrB,GAAG,EAAE,UAAU;YACf,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;YACtD,MAAM,EAAE,mBAAmB;YAC3B,KAAK,EAAE,SAAS,CAAC,SAAS,UAAU,EAAE,EAAE,EAAE,CAAC;YAC3C,OAAO,EAAE,CAAC;SACX,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,UAAkB,EAAE,MAAwB;QAC7D,MAAM,IAAI,GACP,MAAM,CAAC,SAA+B,CAAC,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,QAAQ,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAC7F,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,UAAU,IAAI,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/E,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,MAKH,CAAC;QACF,IAAI,CAAC;YACH,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,MAAM,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,MAAM,CAAC,YAAY;YAAE,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC1E,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAC9B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"mock-crypto.js","sourceRoot":"","sources":["../../src/mock-crypto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { PassphraseBackup } from "../interface.js";
2
+ /**
3
+ * argon2id parameters — RFC 9106 "FIRST RECOMMENDED" high-memory profile (m=64 MiB, t=3, p=1),
4
+ * 32-byte derived key. Backup/restore is rare, so the ~0.5–1s cost is acceptable and buys strong
5
+ * resistance to offline brute-force of the passphrase if the server's blob store is exfiltrated.
6
+ */
7
+ export declare const ARGON2_PARAMS: {
8
+ readonly m: 65536;
9
+ readonly t: 3;
10
+ readonly p: 1;
11
+ readonly dkLen: 32;
12
+ };
13
+ /**
14
+ * Seal plaintext key material into a passphrase-encrypted {@link PassphraseBackup}.
15
+ *
16
+ * @param plaintext - The serialized key material to protect.
17
+ * @param passphrase - The user's backup passphrase.
18
+ * @returns The encrypted envelope (random salt in `kdfParams`, random `nonce`, argon2id + xchacha20poly1305).
19
+ */
20
+ export declare function sealBackup(plaintext: Uint8Array, passphrase: string): Promise<PassphraseBackup>;
21
+ /**
22
+ * Open a {@link PassphraseBackup} sealed by {@link sealBackup}.
23
+ *
24
+ * @param backup - The encrypted envelope.
25
+ * @param passphrase - The user's backup passphrase.
26
+ * @returns The decrypted plaintext key material.
27
+ * @throws {Error} On an unknown `kdf`/`cipher`/`version`, a missing salt, or AEAD authentication
28
+ * failure (wrong passphrase, or a tampered blob/nonce/metadata) — always fails closed.
29
+ */
30
+ export declare function openBackup(backup: PassphraseBackup, passphrase: string): Promise<Uint8Array>;
@@ -0,0 +1,105 @@
1
+ // Passphrase backup envelope codec — the REAL at-rest crypto for key-material backups.
2
+ //
3
+ // Where it sits in the blind-server model: the Agora server stores the resulting `blob` verbatim and
4
+ // can never decrypt it (it never sees the passphrase; the KDF params alone are useless). So this is
5
+ // the one place the backup's secrecy is decided. Per CLAUDE.md #1 we use a real memory-hard KDF
6
+ // (argon2id, RFC 9106 high-memory profile) so a weak passphrase is expensive to brute-force on a DB
7
+ // exfil, and an AEAD (xchacha20poly1305) so a tampered blob/nonce/metadata fails closed.
8
+ //
9
+ // Binary is `Uint8Array` in memory; the wire/transport layer base64-encodes `blob`/`nonce` and the
10
+ // KDF params (incl. the hex salt) are non-secret metadata stored alongside.
11
+ import { argon2idAsync } from "@noble/hashes/argon2.js";
12
+ import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
13
+ import { zeroOutUint8Array } from "ts-mls";
14
+ import { toHex, fromHex } from "./hex.js";
15
+ const utf8 = (s) => new TextEncoder().encode(s);
16
+ /** The only KDF this codec emits/accepts. */
17
+ const KDF = "argon2id";
18
+ /** The only AEAD this codec emits/accepts. */
19
+ const CIPHER = "xchacha20poly1305";
20
+ /** The only envelope version this codec emits/accepts. */
21
+ const VERSION = 1;
22
+ const SALT_BYTES = 16;
23
+ const NONCE_BYTES = 24; // xchacha20poly1305 extended nonce — safe with random nonces
24
+ /**
25
+ * argon2id parameters — RFC 9106 "FIRST RECOMMENDED" high-memory profile (m=64 MiB, t=3, p=1),
26
+ * 32-byte derived key. Backup/restore is rare, so the ~0.5–1s cost is acceptable and buys strong
27
+ * resistance to offline brute-force of the passphrase if the server's blob store is exfiltrated.
28
+ */
29
+ export const ARGON2_PARAMS = { m: 65536, t: 3, p: 1, dkLen: 32 };
30
+ /**
31
+ * The associated data bound into the AEAD: the STABLE scalar envelope descriptors. Binding them means
32
+ * an attacker can't swap the stored `kdf`/`cipher`/`version` (e.g. downgrade the KDF) without the open
33
+ * failing closed.
34
+ *
35
+ * `kdfParams` is deliberately NOT bound here: the server stores it as Postgres jsonb, which does not
36
+ * preserve object key order, so a `JSON.stringify(kdfParams)`-based AAD would differ between seal and
37
+ * open and break a perfectly valid backup. It needs no AAD anyway — the `salt` is bound implicitly
38
+ * (it's a KDF input: any change yields the wrong key and the AEAD fails), and the cost params are
39
+ * pinned to {@link ARGON2_PARAMS} on open, so tampering them is inert.
40
+ */
41
+ function aad(kdf, cipher, version) {
42
+ return utf8(JSON.stringify({ v: version, kdf, cipher }));
43
+ }
44
+ /**
45
+ * Derive a 32-byte key from the passphrase + salt with argon2id at {@link ARGON2_PARAMS}.
46
+ *
47
+ * @param passphrase - The user's backup passphrase.
48
+ * @param salt - The 16-byte random salt.
49
+ * @returns The 32-byte derived symmetric key (caller must zeroize after use).
50
+ */
51
+ async function deriveKey(passphrase, salt) {
52
+ return argon2idAsync(utf8(passphrase), salt, ARGON2_PARAMS);
53
+ }
54
+ /**
55
+ * Seal plaintext key material into a passphrase-encrypted {@link PassphraseBackup}.
56
+ *
57
+ * @param plaintext - The serialized key material to protect.
58
+ * @param passphrase - The user's backup passphrase.
59
+ * @returns The encrypted envelope (random salt in `kdfParams`, random `nonce`, argon2id + xchacha20poly1305).
60
+ */
61
+ export async function sealBackup(plaintext, passphrase) {
62
+ const salt = crypto.getRandomValues(new Uint8Array(SALT_BYTES));
63
+ const nonce = crypto.getRandomValues(new Uint8Array(NONCE_BYTES));
64
+ const kdfParams = { salt: toHex(salt), m: ARGON2_PARAMS.m, t: ARGON2_PARAMS.t, p: ARGON2_PARAMS.p };
65
+ const key = await deriveKey(passphrase, salt);
66
+ try {
67
+ const blob = xchacha20poly1305(key, nonce, aad(KDF, CIPHER, VERSION)).encrypt(plaintext);
68
+ return { blob, kdf: KDF, kdfParams, cipher: CIPHER, nonce, version: VERSION };
69
+ }
70
+ finally {
71
+ zeroOutUint8Array(key);
72
+ }
73
+ }
74
+ /**
75
+ * Open a {@link PassphraseBackup} sealed by {@link sealBackup}.
76
+ *
77
+ * @param backup - The encrypted envelope.
78
+ * @param passphrase - The user's backup passphrase.
79
+ * @returns The decrypted plaintext key material.
80
+ * @throws {Error} On an unknown `kdf`/`cipher`/`version`, a missing salt, or AEAD authentication
81
+ * failure (wrong passphrase, or a tampered blob/nonce/metadata) — always fails closed.
82
+ */
83
+ export async function openBackup(backup, passphrase) {
84
+ if (backup.kdf !== KDF)
85
+ throw new Error(`secure-chat: unsupported backup kdf "${backup.kdf}"`);
86
+ if (backup.cipher !== CIPHER)
87
+ throw new Error(`secure-chat: unsupported backup cipher "${backup.cipher}"`);
88
+ if (backup.version !== VERSION)
89
+ throw new Error(`secure-chat: unsupported backup version ${backup.version}`);
90
+ const saltHex = backup.kdfParams.salt;
91
+ if (!saltHex)
92
+ throw new Error("secure-chat: backup is missing its KDF salt");
93
+ const key = await deriveKey(passphrase, fromHex(saltHex));
94
+ try {
95
+ return xchacha20poly1305(key, backup.nonce, aad(backup.kdf, backup.cipher, backup.version)).decrypt(backup.blob);
96
+ }
97
+ catch {
98
+ // Don't leak which check failed; a wrong passphrase and a tampered blob are indistinguishable here.
99
+ throw new Error("secure-chat: backup decrypt failed (wrong passphrase or corrupt backup)");
100
+ }
101
+ finally {
102
+ zeroOutUint8Array(key);
103
+ }
104
+ }
105
+ //# sourceMappingURL=backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../../../src/ts-mls/backup.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { type CiphersuiteImpl, type KeyPackage, type PrivateKeyPackage, type ClientState } from "ts-mls";
2
- import type { SecureChatCrypto, DeviceIdentity, KeyPackageBundle, GroupHandle, CommitResult, TargetedWelcome, PassphraseBackup } from "../interface.js";
2
+ import type { SecureChatCrypto, DeviceIdentity, KeyPackageBundle, GroupHandle, GroupMemberIdentity, CommitResult, TargetedWelcome, PassphraseBackup } from "../interface.js";
3
3
  interface DeviceState {
4
4
  deviceId: string;
5
5
  ciphersuite: number;
@@ -11,10 +11,29 @@ interface PendingKeyPackage {
11
11
  publicPackage: KeyPackage;
12
12
  privatePackage: PrivateKeyPackage;
13
13
  }
14
+ /**
15
+ * Tuning for the MLS secret-tree ratchet that backs replay/gap enforcement (RFC 9420). These are the
16
+ * legitimate dials — they tighten or loosen the window, they never disable enforcement. Omitted fields
17
+ * fall back to ts-mls's conservative defaults.
18
+ */
19
+ export interface KeyRetentionOptions {
20
+ /** Max generations the ratchet will skip forward before rejecting (`gap-too-large`). ts-mls default 200. */
21
+ maximumForwardRatchetSteps?: number;
22
+ /** How many skipped per-sender message keys to retain (the out-of-order/reorder window). ts-mls default 10. */
23
+ retainKeysForGenerations?: number;
24
+ /** How many past epochs of receiver keys to retain (late delivery across a Commit). ts-mls default 4. */
25
+ retainKeysForEpochs?: number;
26
+ }
14
27
  /** Options for {@link TsMlsSecureChatCrypto}. */
15
28
  export interface TsMlsSecureChatCryptoOptions {
16
29
  /** Numeric MLS ciphersuite id (RFC 9420). Defaults to 1 (the MTI baseline). */
17
30
  ciphersuite?: number;
31
+ /**
32
+ * Override the ts-mls key-retention window (replay/gap tolerance). Defaults to ts-mls's conservative
33
+ * values. Tightening (e.g. a smaller `maximumForwardRatchetSteps`) narrows the accepted gap; it cannot
34
+ * turn enforcement off. Applied consistently to created, joined, imported, and restored groups.
35
+ */
36
+ keyRetention?: KeyRetentionOptions;
18
37
  }
19
38
  /**
20
39
  * Real RFC 9420 MLS implementation of {@link SecureChatCrypto}, built on ts-mls. Construct via
@@ -27,6 +46,7 @@ export declare class TsMlsSecureChatCrypto implements SecureChatCrypto {
27
46
  private credential?;
28
47
  protected readonly pending: Map<string, PendingKeyPackage>;
29
48
  protected readonly groups: Map<string, ClientState>;
49
+ private readonly clientConfig;
30
50
  constructor(options?: TsMlsSecureChatCryptoOptions);
31
51
  /** Lazily load + memoize the ciphersuite primitives. */
32
52
  protected cs(): Promise<CiphersuiteImpl>;
@@ -63,6 +83,7 @@ export declare class TsMlsSecureChatCrypto implements SecureChatCrypto {
63
83
  senderDeviceId: string;
64
84
  epoch: bigint;
65
85
  }>;
86
+ exportGroupIdentities(group: GroupHandle): Promise<GroupMemberIdentity[]>;
66
87
  processWelcome(welcomePayload: Uint8Array): Promise<GroupHandle>;
67
88
  processCommit(group: GroupHandle, commit: Uint8Array): Promise<GroupHandle>;
68
89
  processProposal(group: GroupHandle, proposal: Uint8Array): Promise<void>;
@@ -70,8 +91,8 @@ export declare class TsMlsSecureChatCrypto implements SecureChatCrypto {
70
91
  importGroupState(state: Uint8Array): Promise<GroupHandle>;
71
92
  exportDeviceState(): Promise<Uint8Array>;
72
93
  importDeviceState(state: Uint8Array): Promise<DeviceIdentity>;
73
- exportBackup(_passphrase: string): Promise<PassphraseBackup>;
74
- importBackup(_passphrase: string, _backup: PassphraseBackup): Promise<void>;
94
+ exportBackup(passphrase: string): Promise<PassphraseBackup>;
95
+ importBackup(passphrase: string, backup: PassphraseBackup): Promise<DeviceIdentity>;
75
96
  /** Serialize identity (incl. signature private key) + the pending KeyPackage store to an opaque blob. */
76
97
  protected serializeDeviceState(): Uint8Array;
77
98
  private peerDeviceId;
@@ -7,16 +7,39 @@
7
7
  //
8
8
  // Security (CLAUDE.md #1): randomness is the platform CSPRNG (crypto.getRandomValues) + ts-mls/@noble;
9
9
  // failed decode/decrypt/join fail closed (throw, drop); consumed key material is zeroized.
10
- import { generateKeyPackageWithKey, defaultCapabilities, defaultLifetime, createGroup, createCommit, joinGroup, createApplicationMessage, processMessage, encodeMlsMessage, decodeMlsMessage, encodeGroupState, decodeGroupState, zeroOutUint8Array, acceptAll, emptyPskIndex, } from "ts-mls";
10
+ import { generateKeyPackageWithKey, defaultCapabilities, defaultLifetime, createGroup, createCommit, joinGroup, createApplicationMessage, processMessage, encodeMlsMessage, decodeMlsMessage, encodeGroupState, decodeGroupState, zeroOutUint8Array, acceptAll, emptyPskIndex, defaultKeyRetentionConfig, } from "ts-mls";
11
11
  // makeKeyPackageRef + getGroupMembers + defaultClientConfig aren't re-exported from the package root;
12
12
  // ts-mls exposes every module via its "./*.js" export, so deep-import them.
13
13
  import { makeKeyPackageRef } from "ts-mls/keyPackage.js";
14
14
  import { getGroupMembers } from "ts-mls/clientState.js";
15
15
  import { defaultClientConfig } from "ts-mls/clientConfig.js";
16
+ import { SecureChatDecryptError } from "../interface.js";
16
17
  import { DEFAULT_CIPHERSUITE_ID, loadCiphersuite } from "./ciphersuite.js";
18
+ import { sealBackup, openBackup } from "./backup.js";
17
19
  import { toHex, fromHex } from "./hex.js";
18
20
  const utf8 = (s) => new TextEncoder().encode(s);
19
21
  const MLS_VERSION = "mls10";
22
+ /**
23
+ * Map a ts-mls decrypt/process failure to a {@link SecureChatDecryptError} with a classified reason.
24
+ * Matches on ts-mls's error messages/names (its secret-tree ratchet is the actual enforcement). The
25
+ * returned message is generic-by-reason — we never echo internal bytes or plaintext into the error.
26
+ */
27
+ function classifyDecryptError(err) {
28
+ const msg = err instanceof Error ? err.message : String(err);
29
+ const name = err instanceof Error ? err.name : "";
30
+ let reason = "unknown";
31
+ if (/desired gen(?:eration)? in the past/i.test(msg))
32
+ reason = "replay";
33
+ else if (/too far in the future/i.test(msg))
34
+ reason = "gap-too-large";
35
+ else if (/epoch too old|former epoch/i.test(msg))
36
+ reason = "epoch-too-old";
37
+ else if (name === "CryptoVerificationError" || /signature|verif|auth/i.test(msg))
38
+ reason = "unauthenticated";
39
+ else if (name === "CodecError" || /decode|malformed/i.test(msg))
40
+ reason = "malformed";
41
+ return new SecureChatDecryptError(reason, `secure-chat: message decrypt rejected (${reason})`);
42
+ }
20
43
  /**
21
44
  * Real RFC 9420 MLS implementation of {@link SecureChatCrypto}, built on ts-mls. Construct via
22
45
  * `createTsMlsSecureChatCrypto`; inject into `<SecureChatProvider crypto={…}>`.
@@ -27,6 +50,10 @@ export class TsMlsSecureChatCrypto {
27
50
  this.pending = new Map(); // hex(ref) → kp
28
51
  this.groups = new Map(); // hex(groupId) → state
29
52
  this.ciphersuiteId = options.ciphersuite ?? DEFAULT_CIPHERSUITE_ID;
53
+ this.clientConfig = {
54
+ ...defaultClientConfig,
55
+ keyRetentionConfig: { ...defaultKeyRetentionConfig, ...options.keyRetention },
56
+ };
30
57
  }
31
58
  /** Lazily load + memoize the ciphersuite primitives. */
32
59
  async cs() {
@@ -77,7 +104,7 @@ export class TsMlsSecureChatCrypto {
77
104
  const groupId = opts.mlsGroupId ?? crypto.getRandomValues(new Uint8Array(32));
78
105
  // Seed the group with a fresh self KeyPackage (local-only; never published).
79
106
  const self = await generateKeyPackageWithKey(this.credential, defaultCapabilities(), defaultLifetime, [], { signKey: dev.signKey, publicKey: dev.publicKey }, cs);
80
- let state = await createGroup(groupId, self.publicPackage, self.privatePackage, [], cs);
107
+ let state = await createGroup(groupId, self.publicPackage, self.privatePackage, [], cs, this.clientConfig);
81
108
  const adds = opts.initialMembers.map((m) => ({
82
109
  proposalType: "add", add: { keyPackage: this.decodeKeyPackage(m.keyPackage) },
83
110
  }));
@@ -124,16 +151,43 @@ export class TsMlsSecureChatCrypto {
124
151
  async decryptMessage(group, ciphertext) {
125
152
  const cs = await this.cs();
126
153
  const state = this.lookupGroup(group);
127
- const decoded = decodeMlsMessage(ciphertext, 0);
128
- if (!decoded)
129
- throw new Error("secure-chat: malformed MLS message");
130
- const res = await processMessage(decoded[0], state, emptyPskIndex, acceptAll, cs);
154
+ // ts-mls's secret-tree ratchet is the enforcement point: it throws on a replayed generation, an
155
+ // over-limit forward gap, a too-old epoch, or a failed authentication. We classify that throw (and
156
+ // decode failures) into a SecureChatDecryptError and re-raise it and crucially we do NOT advance
157
+ // stored group state on failure (processMessage threw before returning newState), so a rejected
158
+ // message never ratchets us forward. Fail closed.
159
+ let res;
160
+ try {
161
+ const decoded = decodeMlsMessage(ciphertext, 0);
162
+ if (!decoded)
163
+ throw new SecureChatDecryptError("malformed", "secure-chat: malformed MLS message");
164
+ res = await processMessage(decoded[0], state, emptyPskIndex, acceptAll, cs);
165
+ }
166
+ catch (err) {
167
+ throw err instanceof SecureChatDecryptError ? err : classifyDecryptError(err);
168
+ }
131
169
  this.zeroize(res.consumed);
132
170
  this.groups.set(toHex(group.mlsGroupId), res.newState);
133
- if (res.kind !== "applicationMessage")
134
- throw new Error("secure-chat: expected an application message");
171
+ if (res.kind !== "applicationMessage") {
172
+ throw new SecureChatDecryptError("malformed", "secure-chat: expected an application message");
173
+ }
135
174
  return { plaintext: res.message, senderDeviceId: this.peerDeviceId(res.newState), epoch: res.newState.groupContext.epoch };
136
175
  }
176
+ async exportGroupIdentities(group) {
177
+ const state = this.lookupGroup(group);
178
+ const out = [];
179
+ // Read the roster from the MLS ratchet tree (same source peerDeviceId uses). Only basic-credential
180
+ // leaves carry a device-id identity; skip anything else rather than guess.
181
+ for (const leaf of getGroupMembers(state)) {
182
+ if (leaf.credential.credentialType !== "basic")
183
+ continue;
184
+ out.push({
185
+ deviceId: new TextDecoder().decode(leaf.credential.identity),
186
+ signaturePublicKey: leaf.signaturePublicKey,
187
+ });
188
+ }
189
+ return out;
190
+ }
137
191
  async processWelcome(welcomePayload) {
138
192
  const cs = await this.cs();
139
193
  const decoded = decodeMlsMessage(welcomePayload, 0);
@@ -154,8 +208,10 @@ export class TsMlsSecureChatCrypto {
154
208
  }
155
209
  if (!matched || !matchedRef)
156
210
  throw new Error("secure-chat: no matching KeyPackage for this Welcome");
157
- // ratchetTree omitted — it rode in via the creator's ratchetTreeExtension.
158
- const state = await joinGroup(welcome, matched.publicPackage, matched.privatePackage, emptyPskIndex, cs);
211
+ // ratchetTree omitted — it rode in via the creator's ratchetTreeExtension. Pass our clientConfig
212
+ // (positional args 6/7 ratchetTree/resumingFromState are unused here) so the joined group gets
213
+ // the configured key-retention window, not ts-mls's default.
214
+ const state = await joinGroup(welcome, matched.publicPackage, matched.privatePackage, emptyPskIndex, cs, undefined, undefined, this.clientConfig);
159
215
  this.pending.delete(matchedRef); // one-time: consumed
160
216
  this.groups.set(toHex(state.groupContext.groupId), state);
161
217
  return { mlsGroupId: state.groupContext.groupId, epoch: state.groupContext.epoch };
@@ -193,7 +249,9 @@ export class TsMlsSecureChatCrypto {
193
249
  const decoded = decodeGroupState(state, 0);
194
250
  if (!decoded)
195
251
  throw new Error("secure-chat: corrupt group state");
196
- const clientState = { ...decoded[0], clientConfig: defaultClientConfig };
252
+ // Reattach OUR clientConfig (not ts-mls's default) so the configured key-retention window survives
253
+ // the persistence round-trip — encodeGroupState drops the (callback-bearing) config.
254
+ const clientState = { ...decoded[0], clientConfig: this.clientConfig };
197
255
  this.groups.set(toHex(clientState.groupContext.groupId), clientState);
198
256
  return { mlsGroupId: clientState.groupContext.groupId, epoch: clientState.groupContext.epoch };
199
257
  }
@@ -221,13 +279,34 @@ export class TsMlsSecureChatCrypto {
221
279
  }
222
280
  return { deviceId: p.deviceId, signaturePublicKey: this.device.publicKey, credential: utf8(p.deviceId), ciphersuite: p.ciphersuite };
223
281
  }
224
- // Backup/restore UX (real argon2id KDF + AEAD) is Phase 2 task 5. async so callers get a rejected
225
- // promise, not a synchronous throw.
226
- async exportBackup(_passphrase) {
227
- throw new Error("secure-chat: passphrase backup is not implemented in this core yet (Phase 2 task 5)");
282
+ // Passphrase backup of ALL local key material: the device identity (incl. the signature private
283
+ // key + pending KeyPackages, via serializeDeviceState) and every joined group's full MLS state.
284
+ // The argon2id KDF + AEAD live in ./backup.ts; here we just (de)serialize the payload. The blob is
285
+ // opaque to the blind server only ciphertext crosses the wire.
286
+ async exportBackup(passphrase) {
287
+ const payload = {
288
+ v: 1,
289
+ device: toHex(this.serializeDeviceState()),
290
+ groups: [...this.groups.values()].map((st) => toHex(encodeGroupState(st))),
291
+ };
292
+ return sealBackup(utf8(JSON.stringify(payload)), passphrase);
228
293
  }
229
- async importBackup(_passphrase, _backup) {
230
- throw new Error("secure-chat: passphrase restore is not implemented in this core yet (Phase 2 task 5)");
294
+ async importBackup(passphrase, backup) {
295
+ const plain = await openBackup(backup, passphrase);
296
+ const payload = JSON.parse(new TextDecoder().decode(plain));
297
+ if (payload.v !== 1)
298
+ throw new Error(`secure-chat: unsupported backup payload version ${payload.v}`);
299
+ // Restore the device identity first (also clears + repopulates the pending KeyPackages).
300
+ const identity = await this.importDeviceState(fromHex(payload.device));
301
+ // Then every group's full state, keyed by its MLS group id (mirrors importGroupState).
302
+ for (const g of payload.groups) {
303
+ const decoded = decodeGroupState(fromHex(g), 0);
304
+ if (!decoded)
305
+ throw new Error("secure-chat: corrupt group state in backup");
306
+ const clientState = { ...decoded[0], clientConfig: this.clientConfig };
307
+ this.groups.set(toHex(clientState.groupContext.groupId), clientState);
308
+ }
309
+ return identity;
231
310
  }
232
311
  /** Serialize identity (incl. signature private key) + the pending KeyPackage store to an opaque blob. */
233
312
  serializeDeviceState() {