@freesignal/protocol 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@
17
17
  * along with this program. If not, see <https://www.gnu.org/licenses/>
18
18
  */
19
19
  import { PrivateIdentityKey } from "./types.js";
20
- import { FreeSignalNode } from "./node.js";
20
+ import { FreeSignalNode, FreeSignalNodeState } from "./node.js";
21
21
  /**
22
22
  * Generates identity key
23
23
  *
@@ -26,5 +26,5 @@ import { FreeSignalNode } from "./node.js";
26
26
  */
27
27
  export declare function createIdentity(seed?: Uint8Array): PrivateIdentityKey;
28
28
  /** */
29
- export declare function createNode(privateIdentityKey?: PrivateIdentityKey): FreeSignalNode;
29
+ export declare function createNode(args?: Partial<FreeSignalNodeState>): FreeSignalNode;
30
30
  export * from "./types.js";
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ export function createIdentity(seed) {
35
35
  return PrivateIdentityKey.from(signatureKeyPair.secretKey, exchangeKeyPair.secretKey);
36
36
  }
37
37
  /** */
38
- export function createNode(privateIdentityKey) {
39
- return new FreeSignalNode(privateIdentityKey);
38
+ export function createNode(args) {
39
+ return new FreeSignalNode(args);
40
40
  }
41
41
  export * from "./types.js";
package/dist/node.d.ts CHANGED
@@ -16,9 +16,9 @@
16
16
  * You should have received a copy of the GNU General Public License
17
17
  * along with this program. If not, see <https://www.gnu.org/licenses/>
18
18
  */
19
- import { KeyExchangeDataBundle, KeyExchangeData } from "@freesignal/interfaces";
19
+ import { KeyExchangeDataBundle, KeyExchangeData, Crypto } from "@freesignal/interfaces";
20
20
  import { Datagram, EncryptedDatagram, IdentityKey, PrivateIdentityKey, Protocols, UserId } from "./types.js";
21
- import { KeyExchange, KeyExchangeState } from "./x3dh.js";
21
+ import { KeyExchange } from "./x3dh.js";
22
22
  import { ExportedKeySession as KeySessionState, KeySession } from "./double-ratchet.js";
23
23
  import { EventEmitter, EventCallback } from "easyemitter.ts";
24
24
  export declare class BootstrapRequest extends EventEmitter<'change', BootstrapRequest> {
@@ -55,7 +55,7 @@ export type FreeSignalNodeState = {
55
55
  sessions: Array<[string, KeySessionState]>;
56
56
  users: Array<[string, string]>;
57
57
  bundles: Array<[string, KeyExchangeDataBundle]>;
58
- keyExchange: KeyExchangeState;
58
+ keyExchange: Array<[string, Crypto.KeyPair]>;
59
59
  };
60
60
  export declare class FreeSignalNode {
61
61
  protected readonly privateIdentityKey: PrivateIdentityKey;
@@ -65,7 +65,7 @@ export declare class FreeSignalNode {
65
65
  protected readonly keyExchange: KeyExchange;
66
66
  protected readonly bootstraps: Map<string, BootstrapRequest>;
67
67
  protected readonly emitter: EventEmitter<"error" | "debug" | "send" | "handshake" | "message" | "bootstrap", NodeEventData>;
68
- constructor(privateIdentityKey?: PrivateIdentityKey);
68
+ constructor({ privateIdentityKey, sessions, users, bundles, keyExchange }?: Partial<FreeSignalNodeState>);
69
69
  protected messageHandler: EventCallback<NodeEventData, typeof this.emitter>;
70
70
  protected sendHandler: EventCallback<NodeEventData, typeof this.emitter>;
71
71
  protected handshakeHandler: EventCallback<NodeEventData, typeof this.emitter>;
@@ -82,16 +82,16 @@ export declare class FreeSignalNode {
82
82
  waitHandshaked(userId: UserId | string, timeout?: number): Promise<void>;
83
83
  get identityKey(): IdentityKey;
84
84
  get userId(): UserId;
85
- protected encrypt(receiverId: string | UserId, protocol: Protocols, data: Uint8Array): SendEventData;
86
- sendHandshake(data: KeyExchangeData): void;
87
- sendHandshake(session: KeySession): void;
88
- sendHandshake(userId: UserId | string): void;
89
- sendData<T>(receiverId: string | UserId, data: T): void;
90
- sendRelay(relayId: string | UserId, receiverId: string | UserId, data: Datagram): void;
85
+ protected encrypt(receiverId: string | UserId, protocol: Protocols, data: Uint8Array): Promise<SendEventData>;
86
+ sendHandshake(data: KeyExchangeData): Promise<void>;
87
+ sendHandshake(session: KeySession): Promise<void>;
88
+ sendHandshake(userId: UserId | string): Promise<void>;
89
+ sendData<T>(receiverId: string | UserId, data: T): Promise<void>;
90
+ sendRelay(relayId: string | UserId, receiverId: string | UserId, data: Datagram): Promise<void>;
91
91
  packBootstrap(): Datagram;
92
- sendBootstrap(receiverId: string | UserId): void;
93
- protected decrypt(datagram: EncryptedDatagram | Datagram | Uint8Array): MessageEventData;
94
- protected openHandshake(datagram: Datagram | EncryptedDatagram | Uint8Array): 'syn' | 'ack';
95
- protected open(datagram: Datagram | EncryptedDatagram | Uint8Array): void;
92
+ sendBootstrap(receiverId: string | UserId): Promise<void>;
93
+ protected decrypt(datagram: EncryptedDatagram | Datagram | Uint8Array): Promise<MessageEventData>;
94
+ protected openHandshake(datagram: Datagram | EncryptedDatagram | Uint8Array): Promise<"syn" | "ack">;
95
+ protected open(datagram: Datagram | EncryptedDatagram | Uint8Array): Promise<void>;
96
96
  toJSON(): FreeSignalNodeState;
97
97
  }
package/dist/node.js CHANGED
@@ -37,7 +37,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
37
37
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
38
38
  };
39
39
  var _BootstrapRequest_status;
40
- import { Datagram, decryptData, encryptData, EncryptedDatagram, IdentityKey, Protocols, UserId } from "./types.js";
40
+ import { Datagram, decryptData, encryptData, EncryptedDatagram, IdentityKey, PrivateIdentityKey, Protocols, UserId } from "./types.js";
41
41
  import { KeyExchange } from "./x3dh.js";
42
42
  import { KeySession } from "./double-ratchet.js";
43
43
  import { createIdentity } from "./index.js";
@@ -71,10 +71,8 @@ export class BootstrapRequest extends EventEmitter {
71
71
  }
72
72
  _BootstrapRequest_status = new WeakMap();
73
73
  export class FreeSignalNode {
74
- constructor(privateIdentityKey) {
75
- this.sessions = new Map();
76
- this.users = new Map();
77
- this.bundles = new Map();
74
+ constructor({ privateIdentityKey, sessions, users, bundles, keyExchange } = {}) {
75
+ var _a;
78
76
  this.bootstraps = new Map();
79
77
  this.emitter = new EventEmitter();
80
78
  this.messageHandler = (data) => this.onMessage({ session: data.session, payload: data.payload });
@@ -87,8 +85,11 @@ export class FreeSignalNode {
87
85
  this.onRequest = () => { };
88
86
  this.onError = () => { };
89
87
  this.onDebug = () => { };
90
- this.privateIdentityKey = privateIdentityKey !== null && privateIdentityKey !== void 0 ? privateIdentityKey : createIdentity();
91
- this.keyExchange = new KeyExchange({ privateIdentityKey: this.privateIdentityKey });
88
+ this.privateIdentityKey = privateIdentityKey ? PrivateIdentityKey.from(privateIdentityKey) : createIdentity();
89
+ this.sessions = new Map((_a = sessions === null || sessions === void 0 ? void 0 : sessions.map(([key, value]) => [key, KeySession.from(value)])) !== null && _a !== void 0 ? _a : []);
90
+ this.users = new Map(users);
91
+ this.bundles = new Map(bundles);
92
+ this.keyExchange = new KeyExchange({ privateIdentityKey: this.privateIdentityKey, storage: keyExchange });
92
93
  this.emitter.on('message', this.messageHandler);
93
94
  this.emitter.on('send', this.sendHandler);
94
95
  this.emitter.on('handshake', this.handshakeHandler);
@@ -122,57 +123,65 @@ export class FreeSignalNode {
122
123
  return this.identityKey.userId;
123
124
  }
124
125
  encrypt(receiverId, protocol, data) {
125
- try {
126
- const sessionTag = this.users.get(receiverId.toString());
127
- if (!sessionTag)
128
- throw new Error("User not found: " + receiverId);
129
- const session = this.sessions.get(sessionTag);
130
- if (!session)
131
- throw new Error("Session not found for sessionTag: " + sessionTag);
132
- const encrypted = encryptData(session, data);
133
- this.sessions.set(receiverId.toString(), session);
134
- return { session, userId: UserId.from(receiverId), datagram: new EncryptedDatagram(protocol, session.sessionTag, encrypted).sign(this.privateIdentityKey.signatureKey) };
135
- }
136
- catch (error) {
137
- this.error(error);
138
- throw error;
139
- }
126
+ return __awaiter(this, void 0, void 0, function* () {
127
+ try {
128
+ const sessionTag = this.users.get(receiverId.toString());
129
+ if (!sessionTag)
130
+ throw new Error("User not found: " + receiverId);
131
+ const session = this.sessions.get(sessionTag);
132
+ if (!session)
133
+ throw new Error("Session not found for sessionTag: " + sessionTag);
134
+ const encrypted = encryptData(session, data);
135
+ this.sessions.set(receiverId.toString(), session);
136
+ return { session, userId: UserId.from(receiverId), datagram: new EncryptedDatagram(protocol, session.sessionTag, encrypted).sign(this.privateIdentityKey.signatureKey) };
137
+ }
138
+ catch (error) {
139
+ this.error(error);
140
+ throw error;
141
+ }
142
+ });
140
143
  }
141
144
  sendHandshake(data) {
142
- try {
143
- if (data instanceof UserId || typeof data === 'string') {
144
- const session = this.sessions.get(data.toString());
145
- if (!session)
146
- throw new Error("Session not found for userId: " + data.toString());
147
- data = session;
145
+ return __awaiter(this, void 0, void 0, function* () {
146
+ try {
147
+ if (data instanceof UserId || typeof data === 'string') {
148
+ const session = this.sessions.get(data.toString());
149
+ if (!session)
150
+ throw new Error("Session not found for userId: " + data.toString());
151
+ data = session;
152
+ }
153
+ if (data instanceof KeySession) {
154
+ //console.debug("Sending Handshake Ack");
155
+ const session = this.sessions.get(data.sessionTag);
156
+ if (!session)
157
+ throw new Error("Session not found for sessionTag: " + data.sessionTag);
158
+ this.emitter.emit('send', yield this.encrypt(session.userId, Protocols.HANDSHAKE, crypto.ECDH.scalarMult(this.privateIdentityKey.exchangeKey, session.identityKey.exchangeKey)));
159
+ return;
160
+ }
148
161
  }
149
- if (data instanceof KeySession) {
150
- //console.debug("Sending Handshake Ack");
151
- const session = this.sessions.get(data.sessionTag);
152
- if (!session)
153
- throw new Error("Session not found for sessionTag: " + data.sessionTag);
154
- this.emitter.emit('send', this.encrypt(session.userId, Protocols.HANDSHAKE, crypto.ECDH.scalarMult(this.privateIdentityKey.exchangeKey, session.identityKey.exchangeKey)));
155
- return;
162
+ catch (error) {
163
+ this.error(error);
164
+ throw error;
156
165
  }
157
- }
158
- catch (error) {
159
- this.error(error);
160
- throw error;
161
- }
162
- //console.debug("Sending Handshake Syn");
163
- const { session, message } = this.keyExchange.digestData(data, encodeData(this.keyExchange.generateBundle()));
164
- this.sessions.set(session.sessionTag, session);
165
- this.users.set(session.userId.toString(), session.sessionTag);
166
- const datagram = new Datagram(Protocols.HANDSHAKE, encodeData(message), session.sessionTag).sign(this.privateIdentityKey.signatureKey);
167
- this.emitter.emit('send', { session, datagram, userId: session.userId });
166
+ //console.debug("Sending Handshake Syn");
167
+ const { session, message } = this.keyExchange.digestData(data, encodeData(this.keyExchange.generateBundle()));
168
+ this.sessions.set(session.sessionTag, session);
169
+ this.users.set(session.userId.toString(), session.sessionTag);
170
+ const datagram = new Datagram(Protocols.HANDSHAKE, encodeData(message), session.sessionTag).sign(this.privateIdentityKey.signatureKey);
171
+ this.emitter.emit('send', { session, datagram, userId: session.userId });
172
+ });
168
173
  }
169
174
  sendData(receiverId, data) {
170
- //console.debug("Sending Data");
171
- this.emitter.emit('send', this.encrypt(receiverId, Protocols.MESSAGE, encodeData(data)));
175
+ return __awaiter(this, void 0, void 0, function* () {
176
+ //console.debug("Sending Data");
177
+ this.emitter.emit('send', yield this.encrypt(receiverId, Protocols.MESSAGE, encodeData(data)));
178
+ });
172
179
  }
173
180
  sendRelay(relayId, receiverId, data) {
174
- //console.debug("Sending Relay");
175
- this.emitter.emit('send', this.encrypt(relayId, Protocols.RELAY, concatBytes(UserId.from(receiverId).toBytes(), data.toBytes())));
181
+ return __awaiter(this, void 0, void 0, function* () {
182
+ //console.debug("Sending Relay");
183
+ this.emitter.emit('send', yield this.encrypt(relayId, Protocols.RELAY, concatBytes(UserId.from(receiverId).toBytes(), data.toBytes())));
184
+ });
176
185
  }
177
186
  /*public async sendPing(receiverId: string | UserId): Promise<void> {
178
187
  //console.debug("Sending Ping");
@@ -203,173 +212,181 @@ export class FreeSignalNode {
203
212
  return new Datagram(Protocols.BOOTSTRAP, encodeData(this.keyExchange.generateData()));
204
213
  }
205
214
  sendBootstrap(receiverId) {
206
- try {
207
- //console.debug("Sending Bootstrap");
208
- if (this.sessions.has(receiverId.toString()))
209
- throw new Error("Session exists");
210
- const datagram = this.packBootstrap();
211
- this.emitter.emit('send', { datagram, userId: UserId.from(receiverId) });
212
- }
213
- catch (error) {
214
- this.error(error);
215
- throw error;
216
- }
215
+ return __awaiter(this, void 0, void 0, function* () {
216
+ try {
217
+ //console.debug("Sending Bootstrap");
218
+ if (this.sessions.has(receiverId.toString()))
219
+ throw new Error("Session exists");
220
+ const datagram = this.packBootstrap();
221
+ this.emitter.emit('send', { datagram, userId: UserId.from(receiverId) });
222
+ }
223
+ catch (error) {
224
+ this.error(error);
225
+ throw error;
226
+ }
227
+ });
217
228
  }
218
229
  decrypt(datagram) {
219
- try {
220
- datagram = EncryptedDatagram.from(datagram);
221
- if (!datagram.sessionTag)
222
- throw new Error("Datagram not encrypted");
223
- const session = this.sessions.get(datagram.sessionTag);
224
- if (!session)
225
- throw new Error("Session not found for sessionTag: " + datagram.sessionTag);
226
- if (!datagram.verify(session.identityKey.signatureKey))
227
- throw new Error("Signature not verified");
228
- if (!datagram.payload)
229
- throw new Error("Missing payload");
230
- const decrypted = decryptData(session, datagram.payload);
231
- this.sessions.set(datagram.sessionTag, session);
232
- return { session, payload: decrypted };
233
- }
234
- catch (error) {
235
- this.error(error);
236
- throw error;
237
- }
238
- }
239
- openHandshake(datagram) {
240
- try {
241
- const encrypted = EncryptedDatagram.from(datagram);
242
- if (!encrypted.payload)
243
- throw new Error("Missing payload");
244
- if (this.sessions.has(encrypted.sessionTag)) {
245
- //console.debug("Opening Handshake Ack");
246
- const session = this.sessions.get(encrypted.sessionTag);
247
- const { payload } = this.decrypt(encrypted);
230
+ return __awaiter(this, void 0, void 0, function* () {
231
+ try {
232
+ datagram = EncryptedDatagram.from(datagram);
233
+ if (!datagram.sessionTag)
234
+ throw new Error("Datagram not encrypted");
235
+ const session = this.sessions.get(datagram.sessionTag);
248
236
  if (!session)
249
- throw new Error("Session not found for sessionTag: " + encrypted.sessionTag);
250
- if (!compareBytes(payload, crypto.ECDH.scalarMult(this.privateIdentityKey.exchangeKey, session.identityKey.exchangeKey)))
251
- throw new Error("Error validating handshake data");
252
- return 'ack';
237
+ throw new Error("Session not found for sessionTag: " + datagram.sessionTag);
238
+ if (!datagram.verify(session.identityKey.signatureKey))
239
+ throw new Error("Signature not verified");
240
+ if (!datagram.payload)
241
+ throw new Error("Missing payload");
242
+ const decrypted = decryptData(session, datagram.payload);
243
+ this.sessions.set(datagram.sessionTag, session);
244
+ return { session, payload: decrypted };
253
245
  }
254
- //console.debug("Opening Handshake Syn");
255
- const data = decodeData(encrypted.payload);
256
- if (!encrypted.verify(IdentityKey.from(data.identityKey).signatureKey))
257
- throw new Error("Signature not verified");
258
- const { session, associatedData } = this.keyExchange.digestMessage(data);
259
- this.sessions.set(session.sessionTag, session);
260
- this.users.set(session.userId.toString(), session.sessionTag);
261
- this.bundles.set(session.userId.toString(), decodeData(associatedData));
262
- return 'syn';
263
- }
264
- catch (error) {
265
- this.error(error);
266
- throw error;
267
- }
246
+ catch (error) {
247
+ this.error(error);
248
+ throw error;
249
+ }
250
+ });
268
251
  }
269
- open(datagram) {
270
- try {
271
- if (datagram instanceof Uint8Array)
272
- datagram = Datagram.from(datagram);
273
- switch (datagram.protocol) {
274
- case Protocols.HANDSHAKE: {
275
- const encrypted = EncryptedDatagram.from(datagram);
276
- if (!encrypted.payload)
277
- throw new Error("Missing payload");
278
- const handshakeState = this.openHandshake(datagram);
252
+ openHandshake(datagram) {
253
+ return __awaiter(this, void 0, void 0, function* () {
254
+ try {
255
+ const encrypted = EncryptedDatagram.from(datagram);
256
+ if (!encrypted.payload)
257
+ throw new Error("Missing payload");
258
+ if (this.sessions.has(encrypted.sessionTag)) {
259
+ //console.debug("Opening Handshake Ack");
279
260
  const session = this.sessions.get(encrypted.sessionTag);
261
+ const { payload } = yield this.decrypt(encrypted);
280
262
  if (!session)
281
263
  throw new Error("Session not found for sessionTag: " + encrypted.sessionTag);
282
- if (handshakeState === 'syn')
283
- this.sendHandshake(session);
284
- this.emitter.emit('handshake', { session });
285
- return;
286
- }
287
- case Protocols.MESSAGE:
288
- //console.debug("Opening Message");
289
- this.emitter.emit('message', this.decrypt(datagram));
290
- return;
291
- case Protocols.RELAY: {
292
- //console.debug("Opening Relay");
293
- const opened = this.decrypt(datagram);
294
- const userId = decodeBase64(opened.payload.subarray(0, UserId.keyLength));
295
- const sessionTag = this.users.get(userId);
296
- if (!sessionTag)
297
- throw new Error("Session not found for user: " + userId);
298
- const session = this.sessions.get(sessionTag);
299
- if (!session)
300
- throw new Error("Session not found for sessionTag: " + datagram.sessionTag);
301
- this.emitter.emit('send', { session, datagram: Datagram.from(opened.payload.slice(UserId.keyLength)), userId: session.userId });
302
- return;
303
- }
304
- case Protocols.BOOTSTRAP: {
305
- //console.debug("Opening Bootstrap");
306
- if (!datagram.payload)
307
- throw new Error("Invalid Bootstrap");
308
- const keyExchangeData = decodeData(datagram.payload);
309
- const userId = UserId.fromKey(keyExchangeData.identityKey);
310
- const request = new BootstrapRequest(userId, keyExchangeData);
311
- let sended = false;
312
- request.onChange = (request) => {
313
- if (request.status === 'accepted' && !sended) {
314
- sended = true;
315
- this.sendHandshake(request.data);
316
- }
317
- };
318
- this.bootstraps.set(userId.toString(), request);
319
- this.emitter.emit('bootstrap', { request });
320
- return;
264
+ if (!compareBytes(payload, crypto.ECDH.scalarMult(this.privateIdentityKey.exchangeKey, session.identityKey.exchangeKey)))
265
+ throw new Error("Error validating handshake data");
266
+ return 'ack';
321
267
  }
322
- /*case Protocols.DISCOVER: {
323
- //console.debug("Opening Discover");
324
- const { session, payload } = await this.decrypt(datagram);
325
- const message = decodeData<DiscoverMessage>(payload);
326
- if (message.type === DiscoverType.REQUEST && message.discoverId && !(await this.sessions.has(message.discoverId))) {
327
- let data: KeyExchangeData;
328
- if (message.discoverId === this.userId.toString()) {
329
- data = await this.keyExchange.generateData();
330
- } else {
331
- const bundle = await this.bundles.get(message.discoverId);
332
- if (!bundle)
333
- return;
334
- const { version, identityKey, signedPreKey, signature } = bundle;
335
- const onetimePreKey = bundle.onetimePreKeys.shift();
336
- if (!onetimePreKey) {
337
- await this.bundles.delete(message.discoverId);
338
- return;
268
+ //console.debug("Opening Handshake Syn");
269
+ const data = decodeData(encrypted.payload);
270
+ if (!encrypted.verify(IdentityKey.from(data.identityKey).signatureKey))
271
+ throw new Error("Signature not verified");
272
+ const { session, associatedData } = this.keyExchange.digestMessage(data);
273
+ this.sessions.set(session.sessionTag, session);
274
+ this.users.set(session.userId.toString(), session.sessionTag);
275
+ this.bundles.set(session.userId.toString(), decodeData(associatedData));
276
+ return 'syn';
277
+ }
278
+ catch (error) {
279
+ this.error(error);
280
+ throw error;
281
+ }
282
+ });
283
+ }
284
+ open(datagram) {
285
+ return __awaiter(this, void 0, void 0, function* () {
286
+ try {
287
+ if (datagram instanceof Uint8Array)
288
+ datagram = Datagram.from(datagram);
289
+ switch (datagram.protocol) {
290
+ case Protocols.HANDSHAKE: {
291
+ const encrypted = EncryptedDatagram.from(datagram);
292
+ if (!encrypted.payload)
293
+ throw new Error("Missing payload");
294
+ const handshakeState = yield this.openHandshake(datagram);
295
+ const session = this.sessions.get(encrypted.sessionTag);
296
+ if (!session)
297
+ throw new Error("Session not found for sessionTag: " + encrypted.sessionTag);
298
+ if (handshakeState === 'syn')
299
+ this.sendHandshake(session);
300
+ this.emitter.emit('handshake', { session });
301
+ return;
302
+ }
303
+ case Protocols.MESSAGE:
304
+ //console.debug("Opening Message");
305
+ this.emitter.emit('message', yield this.decrypt(datagram));
306
+ return;
307
+ case Protocols.RELAY: {
308
+ //console.debug("Opening Relay");
309
+ const opened = yield this.decrypt(datagram);
310
+ const userId = decodeBase64(opened.payload.subarray(0, UserId.keyLength));
311
+ const sessionTag = this.users.get(userId);
312
+ if (!sessionTag)
313
+ throw new Error("Session not found for user: " + userId);
314
+ const session = this.sessions.get(sessionTag);
315
+ if (!session)
316
+ throw new Error("Session not found for sessionTag: " + datagram.sessionTag);
317
+ this.emitter.emit('send', { session, datagram: Datagram.from(opened.payload.slice(UserId.keyLength)), userId: session.userId });
318
+ return;
319
+ }
320
+ case Protocols.BOOTSTRAP: {
321
+ //console.debug("Opening Bootstrap");
322
+ if (!datagram.payload)
323
+ throw new Error("Invalid Bootstrap");
324
+ const keyExchangeData = decodeData(datagram.payload);
325
+ const userId = UserId.fromKey(keyExchangeData.identityKey);
326
+ const request = new BootstrapRequest(userId, keyExchangeData);
327
+ let sended = false;
328
+ request.onChange = (request) => {
329
+ if (request.status === 'accepted' && !sended) {
330
+ sended = true;
331
+ this.sendHandshake(request.data);
339
332
  }
340
- data = {
341
- version,
342
- identityKey,
343
- signedPreKey,
344
- signature,
345
- onetimePreKey
346
- };
333
+ };
334
+ this.bootstraps.set(userId.toString(), request);
335
+ this.emitter.emit('bootstrap', { request });
336
+ return;
337
+ }
338
+ /*case Protocols.DISCOVER: {
339
+ //console.debug("Opening Discover");
340
+ const { session, payload } = await this.decrypt(datagram);
341
+ const message = decodeData<DiscoverMessage>(payload);
342
+ if (message.type === DiscoverType.REQUEST && message.discoverId && !(await this.sessions.has(message.discoverId))) {
343
+ let data: KeyExchangeData;
344
+ if (message.discoverId === this.userId.toString()) {
345
+ data = await this.keyExchange.generateData();
346
+ } else {
347
+ const bundle = await this.bundles.get(message.discoverId);
348
+ if (!bundle)
349
+ return;
350
+ const { version, identityKey, signedPreKey, signature } = bundle;
351
+ const onetimePreKey = bundle.onetimePreKeys.shift();
352
+ if (!onetimePreKey) {
353
+ await this.bundles.delete(message.discoverId);
354
+ return;
355
+ }
356
+ data = {
357
+ version,
358
+ identityKey,
359
+ signedPreKey,
360
+ signature,
361
+ onetimePreKey
362
+ };
363
+ }
364
+ const response: DiscoverMessage = { type: DiscoverType.RESPONSE, discoverId: message.discoverId, data };
365
+ this.emitter.emit('send', await this.encrypt(session.userId, Protocols.DISCOVER, encodeData(response)));
366
+ } else if (message.type === DiscoverType.RESPONSE && this.discovers.has(message.discoverId)) {
367
+ this.discovers.delete(message.discoverId);
368
+ if (message.data)
369
+ await this.sendHandshake(message.data);
347
370
  }
348
- const response: DiscoverMessage = { type: DiscoverType.RESPONSE, discoverId: message.discoverId, data };
349
- this.emitter.emit('send', await this.encrypt(session.userId, Protocols.DISCOVER, encodeData(response)));
350
- } else if (message.type === DiscoverType.RESPONSE && this.discovers.has(message.discoverId)) {
351
- this.discovers.delete(message.discoverId);
352
- if (message.data)
353
- await this.sendHandshake(message.data);
371
+ return;
354
372
  }
355
- return;
373
+
374
+ case Protocols.PING:
375
+ datagram = EncryptedDatagram.from(datagram);
376
+ const session = await this.sessions.get(datagram.sessionTag!);
377
+ if (!session)
378
+ throw new Error("Session not found for sessionTag: " + datagram.sessionTag);
379
+ this.emitter.emit('ping', { session });
380
+ return;*/
381
+ default:
382
+ throw new Error("Invalid protocol");
356
383
  }
357
-
358
- case Protocols.PING:
359
- datagram = EncryptedDatagram.from(datagram);
360
- const session = await this.sessions.get(datagram.sessionTag!);
361
- if (!session)
362
- throw new Error("Session not found for sessionTag: " + datagram.sessionTag);
363
- this.emitter.emit('ping', { session });
364
- return;*/
365
- default:
366
- throw new Error("Invalid protocol");
367
384
  }
368
- }
369
- catch (error) {
370
- this.error(error);
371
- throw error;
372
- }
385
+ catch (error) {
386
+ this.error(error);
387
+ throw error;
388
+ }
389
+ });
373
390
  }
374
391
  toJSON() {
375
392
  return {
@@ -377,7 +394,7 @@ export class FreeSignalNode {
377
394
  sessions: Array.from(this.sessions.entries()).map(([key, session]) => [key, session.toJSON()]),
378
395
  users: Array.from(this.users.entries()),
379
396
  bundles: Array.from(this.bundles),
380
- keyExchange: this.keyExchange.toJSON(),
397
+ keyExchange: this.keyExchange.toJSON().storage,
381
398
  };
382
399
  }
383
400
  }
package/dist/x3dh.d.ts CHANGED
@@ -29,10 +29,7 @@ export declare class KeyExchange {
29
29
  private static readonly maxOPK;
30
30
  private readonly privateIdentityKey;
31
31
  private readonly storage;
32
- constructor({ storage, privateIdentityKey }: {
33
- storage?: Array<[string, Crypto.KeyPair]>;
34
- privateIdentityKey?: PrivateIdentityKey;
35
- });
32
+ constructor({ storage, privateIdentityKey }?: Partial<KeyExchangeState>);
36
33
  get identityKey(): IdentityKey;
37
34
  private generateSPK;
38
35
  private generateOPK;
package/dist/x3dh.js CHANGED
@@ -22,7 +22,7 @@ import { concatBytes, decodeBase64, encodeBase64, compareBytes } from "@freesign
22
22
  import { decryptData, encryptData, IdentityKey } from "./types.js";
23
23
  import { createIdentity } from "./index.js";
24
24
  export class KeyExchange {
25
- constructor({ storage, privateIdentityKey }) {
25
+ constructor({ storage, privateIdentityKey } = {}) {
26
26
  this.storage = new Map(storage);
27
27
  this.privateIdentityKey = privateIdentityKey !== null && privateIdentityKey !== void 0 ? privateIdentityKey : createIdentity();
28
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freesignal/protocol",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Signal Protocol implementation in TypeScript",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "Christian Braghette",