@freesignal/protocol 0.2.6 → 0.2.8

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/api.d.ts CHANGED
@@ -17,21 +17,21 @@
17
17
  * along with this program. If not, see <https://www.gnu.org/licenses/>
18
18
  */
19
19
  import { Crypto, KeyExchangeData, KeyExchangeDataBundle, KeyExchangeSynMessage, LocalStorage } from "@freesignal/interfaces";
20
- import { KeySession } from "./double-ratchet";
20
+ import { ExportedKeySession } from "./double-ratchet";
21
21
  import { KeyExchange } from "./x3dh";
22
22
  import { Datagram, IdentityKeys, EncryptedData, UserId } from "./types";
23
23
  type DatagramId = string;
24
24
  export declare class FreeSignalAPI {
25
25
  protected readonly signKey: Crypto.KeyPair;
26
26
  protected readonly boxKey: Crypto.KeyPair;
27
- protected readonly sessions: LocalStorage<UserId, KeySession>;
27
+ protected readonly sessions: LocalStorage<UserId, ExportedKeySession>;
28
28
  protected readonly keyExchange: KeyExchange;
29
29
  protected readonly users: LocalStorage<UserId, IdentityKeys>;
30
30
  readonly userId: UserId;
31
31
  constructor(opts: {
32
32
  secretSignKey: Uint8Array;
33
33
  secretBoxKey: Uint8Array;
34
- sessions: LocalStorage<UserId, KeySession>;
34
+ sessions: LocalStorage<UserId, ExportedKeySession>;
35
35
  keyExchange: LocalStorage<string, Crypto.KeyPair>;
36
36
  users: LocalStorage<UserId, IdentityKeys>;
37
37
  });
package/api.js CHANGED
@@ -32,6 +32,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
33
  exports.FreeSignalAPI = void 0;
34
34
  const crypto_1 = __importDefault(require("@freesignal/crypto"));
35
+ const double_ratchet_1 = require("./double-ratchet");
35
36
  const x3dh_1 = require("./x3dh");
36
37
  const utils_1 = require("@freesignal/utils");
37
38
  const types_1 = require("./types");
@@ -53,23 +54,25 @@ class FreeSignalAPI {
53
54
  }
54
55
  encryptData(data, userId) {
55
56
  return __awaiter(this, void 0, void 0, function* () {
56
- const session = yield this.sessions.get(userId);
57
- if (!session)
57
+ const sessionJson = yield this.sessions.get(userId);
58
+ if (!sessionJson)
58
59
  throw new Error('Session not found for user: ' + userId);
60
+ const session = double_ratchet_1.KeySession.from(sessionJson);
59
61
  const encrypted = session.encrypt(data);
60
- this.sessions.set(userId, session); // Ensure session is updated
62
+ this.sessions.set(userId, session.toJSON()); // Ensure session is updated
61
63
  return encrypted;
62
64
  });
63
65
  }
64
66
  decryptData(data, userId) {
65
67
  return __awaiter(this, void 0, void 0, function* () {
66
- const session = yield this.sessions.get(userId);
67
- if (!session)
68
+ const sessionJson = yield this.sessions.get(userId);
69
+ if (!sessionJson)
68
70
  throw new Error('Session not found for user: ' + userId);
71
+ const session = double_ratchet_1.KeySession.from(sessionJson);
69
72
  const decrypted = session.decrypt(data);
70
73
  if (!decrypted)
71
74
  throw new Error('Decryption failed for user: ' + userId);
72
- this.sessions.set(userId, session); // Ensure session is updated
75
+ this.sessions.set(userId, session.toJSON()); // Ensure session is updated
73
76
  return decrypted;
74
77
  });
75
78
  }
@@ -78,7 +81,10 @@ class FreeSignalAPI {
78
81
  const res = yield fetch(`${url}/${userId !== null && userId !== void 0 ? userId : ''}`, {
79
82
  method: 'GET'
80
83
  });
81
- return (0, utils_1.decodeJSON)(new Uint8Array(yield res.arrayBuffer()));
84
+ const body = types_1.XFreeSignal.decodeBody(new Uint8Array(yield res.arrayBuffer()));
85
+ if (body.type === 'error')
86
+ throw new Error(body.data);
87
+ return body.data;
82
88
  });
83
89
  }
84
90
  postHandshake(url, message) {
@@ -125,7 +131,10 @@ class FreeSignalAPI {
125
131
  authorization: this.createToken(publicKey instanceof Uint8Array ? publicKey : (0, utils_1.encodeBase64)(publicKey))
126
132
  }
127
133
  });
128
- return types_1.DataEncoder.from(yield this.decryptData(new Uint8Array(yield res.arrayBuffer()), types_1.UserId.getUserId(publicKey).toString())).data.map(array => types_1.Datagram.from(array));
134
+ const body = types_1.XFreeSignal.decodeBody(new Uint8Array(yield res.arrayBuffer()));
135
+ if (body.type === 'error')
136
+ throw new Error(body.data);
137
+ return types_1.DataEncoder.from(yield this.decryptData(body.data, types_1.UserId.getUserId(publicKey).toString())).data.map(array => types_1.Datagram.from(array));
129
138
  });
130
139
  }
131
140
  postDatagrams(datagrams, publicKey, url) {
@@ -139,7 +148,10 @@ class FreeSignalAPI {
139
148
  },
140
149
  body: types_1.XFreeSignal.encodeBody('data', data.encode())
141
150
  });
142
- return (0, utils_1.numberFromArray)(yield this.decryptData(new Uint8Array(yield res.arrayBuffer()), types_1.UserId.getUserId(publicKey).toString()));
151
+ const body = types_1.XFreeSignal.decodeBody(new Uint8Array(yield res.arrayBuffer()));
152
+ if (body.type === 'error')
153
+ throw new Error(body.data);
154
+ return types_1.DataEncoder.from(yield this.decryptData(body.data, types_1.UserId.getUserId(publicKey).toString())).data;
143
155
  });
144
156
  }
145
157
  deleteDatagrams(datagramIds, publicKey, url) {
@@ -153,7 +165,10 @@ class FreeSignalAPI {
153
165
  },
154
166
  body: types_1.XFreeSignal.encodeBody('data', data.encode())
155
167
  });
156
- return (0, utils_1.numberFromArray)(yield this.decryptData(new Uint8Array(yield res.arrayBuffer()), types_1.UserId.getUserId(publicKey).toString()));
168
+ const body = types_1.XFreeSignal.decodeBody(new Uint8Array(yield res.arrayBuffer()));
169
+ if (body.type === 'error')
170
+ throw new Error(body.data);
171
+ return types_1.DataEncoder.from(yield this.decryptData(body.data, types_1.UserId.getUserId(publicKey).toString())).data;
157
172
  });
158
173
  }
159
174
  createToken(publicKey) {
@@ -17,7 +17,7 @@
17
17
  * along with this program. If not, see <https://www.gnu.org/licenses/>
18
18
  */
19
19
  import { EncryptedData } from "./types";
20
- type ExportedKeySession = {
20
+ export interface ExportedKeySession {
21
21
  secretKey: string;
22
22
  remoteKey: string;
23
23
  rootKey: string;
@@ -27,7 +27,7 @@ type ExportedKeySession = {
27
27
  receivingCount: number;
28
28
  previousCount: number;
29
29
  previousKeys: [number, Uint8Array][];
30
- };
30
+ }
31
31
  /**
32
32
  * Represents a secure Double Ratchet session.
33
33
  * Used for forward-secure encryption and decryption of messages.
@@ -90,7 +90,7 @@ export declare class KeySession {
90
90
  * @param json string returned by `export()` method.
91
91
  * @returns session with the state parsed.
92
92
  */
93
- static parse(json: string): KeySession;
93
+ static from(data: ExportedKeySession): KeySession;
94
94
  /**
95
95
  * The fixed key length (in bytes) used throughout the Double Ratchet session.
96
96
  * Typically 32 bytes (256 bits) for symmetric keys.
@@ -98,4 +98,3 @@ export declare class KeySession {
98
98
  static readonly keyLength = 32;
99
99
  private static symmetricRatchet;
100
100
  }
101
- export {};
package/double-ratchet.js CHANGED
@@ -162,8 +162,7 @@ class KeySession {
162
162
  * @param json string returned by `export()` method.
163
163
  * @returns session with the state parsed.
164
164
  */
165
- static parse(json) {
166
- const data = JSON.parse(json);
165
+ static from(data) {
167
166
  const session = new KeySession({ secretKey: (0, utils_1.encodeBase64)(data.secretKey), rootKey: (0, utils_1.encodeBase64)(data.rootKey) });
168
167
  session._remoteKey = (0, utils_1.encodeBase64)(data.remoteKey);
169
168
  session.sendingChain = (0, utils_1.encodeBase64)(data.sendingChain);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freesignal/protocol",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Signal Protocol implementation in javascript",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "Christian Braghette",
package/types.d.ts CHANGED
@@ -144,7 +144,14 @@ export interface EncryptedData extends Encodable {
144
144
  /**
145
145
  * Returns the decoded object as a JSON string.
146
146
  */
147
- toJSON(): string;
147
+ toJSON(): {
148
+ version: number;
149
+ count: number;
150
+ previous: number;
151
+ publicKey: string;
152
+ nonce: string;
153
+ ciphertext: string;
154
+ };
148
155
  }
149
156
  export declare class EncryptedData {
150
157
  /**
@@ -174,7 +181,14 @@ export declare class EncryptedDataConstructor implements EncryptedData {
174
181
  get ciphertext(): Uint8Array;
175
182
  encode(): Uint8Array;
176
183
  toString(): string;
177
- toJSON(): string;
184
+ toJSON(): {
185
+ version: number;
186
+ count: number;
187
+ previous: number;
188
+ publicKey: string;
189
+ nonce: string;
190
+ ciphertext: string;
191
+ };
178
192
  }
179
193
  declare enum DataType {
180
194
  UKNOWN = -1,
@@ -196,7 +210,7 @@ export declare class DataEncoder<T> implements Encodable {
196
210
  protected get _type(): DataType;
197
211
  encode(): Uint8Array;
198
212
  toString(): string;
199
- toJSON(): string;
213
+ toJSON(): T;
200
214
  static from<T = any>(array: Uint8Array): DataEncoder<T>;
201
215
  }
202
216
  export declare namespace XFreeSignal {
@@ -210,7 +224,10 @@ export declare namespace XFreeSignal {
210
224
  constructor(type: 'data' | 'error', data: T);
211
225
  encode(compressed?: boolean): Uint8Array;
212
226
  toString(): string;
213
- toJSON(): string;
227
+ toJSON(): {
228
+ type: "data" | "error";
229
+ data: T;
230
+ };
214
231
  static from<T = any>(array: Uint8Array): Body<T>;
215
232
  }
216
233
  export {};
package/types.js CHANGED
@@ -37,7 +37,7 @@ var UserId;
37
37
  return (0, utils_1.decodeBase64)(this.array);
38
38
  }
39
39
  toJSON() {
40
- return JSON.stringify(this.toString());
40
+ return this.toString();
41
41
  }
42
42
  toUint8Array() {
43
43
  return this.array;
@@ -75,7 +75,7 @@ var IdentityKeys;
75
75
  throw (0, utils_1.decodeBase64)(this.encode());
76
76
  }
77
77
  toJSON() {
78
- throw JSON.stringify(this.toString());
78
+ throw this.toString();
79
79
  }
80
80
  }
81
81
  function isIdentityKeys(obj) {
@@ -197,7 +197,7 @@ var Datagram;
197
197
  return (0, utils_1.decodeBase64)(this.encode());
198
198
  }
199
199
  toJSON() {
200
- return JSON.stringify(this.toString());
200
+ return this.toString();
201
201
  }
202
202
  }
203
203
  DatagramConstructor.headerOffset = 26 + crypto_1.default.EdDSA.publicKeyLength * 2;
@@ -265,14 +265,14 @@ class EncryptedDataConstructor {
265
265
  return (0, utils_1.decodeBase64)(this.raw);
266
266
  }
267
267
  toJSON() {
268
- return JSON.stringify({
268
+ return {
269
269
  version: this.version,
270
270
  count: this.count,
271
271
  previous: this.previous,
272
272
  publicKey: (0, utils_1.decodeBase64)(this.publicKey),
273
273
  nonce: (0, utils_1.decodeBase64)(this.nonce),
274
274
  ciphertext: (0, utils_1.decodeBase64)(this.ciphertext)
275
- });
275
+ };
276
276
  }
277
277
  }
278
278
  exports.EncryptedDataConstructor = EncryptedDataConstructor;
@@ -368,7 +368,7 @@ class DataEncoder {
368
368
  return "[Object XFreeSignalData]";
369
369
  }
370
370
  toJSON() {
371
- return JSON.stringify(this.data);
371
+ return this.data;
372
372
  }
373
373
  static from(array) {
374
374
  const type = array[0];
@@ -448,10 +448,10 @@ var XFreeSignal;
448
448
  return "[Object XFreeSignalBody]";
449
449
  }
450
450
  toJSON() {
451
- return JSON.stringify({
451
+ return {
452
452
  type: this.type,
453
453
  data: this.data
454
- });
454
+ };
455
455
  }
456
456
  static from(array) {
457
457
  return new Body(BodyType.getName((array[0] & 64) >> 6), DataEncoder.from((array[0] & 32) >> 5 === 1 ? fflate_1.default.inflateSync(array.subarray(1)) : array.subarray(1)).data);
package/x3dh.d.ts CHANGED
@@ -19,6 +19,11 @@
19
19
  import { KeyExchangeData, KeyExchangeDataBundle, KeyExchangeSynMessage, LocalStorage, Crypto } from "@freesignal/interfaces";
20
20
  import { KeySession } from "./double-ratchet";
21
21
  import { IdentityKeys } from "./types";
22
+ export interface ExportedKeyExchange {
23
+ signatureKey: Crypto.KeyPair;
24
+ identityKey: Crypto.KeyPair;
25
+ bundleStore: Array<[string, Crypto.KeyPair]>;
26
+ }
22
27
  export declare class KeyExchange {
23
28
  static readonly version = 1;
24
29
  private static readonly hkdfInfo;
@@ -42,4 +47,6 @@ export declare class KeyExchange {
42
47
  session: KeySession;
43
48
  identityKeys: IdentityKeys;
44
49
  }>;
50
+ toJSON(): ExportedKeyExchange;
51
+ static from(data: ExportedKeyExchange): KeyExchange;
45
52
  }
package/x3dh.js CHANGED
@@ -146,19 +146,29 @@ class KeyExchange {
146
146
  };
147
147
  });
148
148
  }
149
+ toJSON() {
150
+ return {
151
+ identityKey: this._identityKey,
152
+ signatureKey: this._signatureKey,
153
+ bundleStore: Array.from(this.bundleStore.entries())
154
+ };
155
+ }
156
+ static from(data) {
157
+ return new KeyExchange(data.signatureKey.secretKey, data.identityKey.secretKey, new AsyncMap(data.bundleStore));
158
+ }
149
159
  }
150
160
  exports.KeyExchange = KeyExchange;
151
161
  KeyExchange.version = 1;
152
162
  KeyExchange.hkdfInfo = (0, utils_1.encodeUTF8)("freesignal/x3dh/" + KeyExchange.version);
153
163
  KeyExchange.maxOPK = 10;
154
164
  class AsyncMap {
155
- constructor() {
156
- this.map = new Map();
165
+ constructor(iterable) {
166
+ this.map = new Map(iterable);
157
167
  }
158
168
  set(key, value) {
159
169
  return __awaiter(this, void 0, void 0, function* () {
160
170
  this.map.set(key, value);
161
- return this;
171
+ return;
162
172
  });
163
173
  }
164
174
  get(key) {
@@ -177,8 +187,6 @@ class AsyncMap {
177
187
  });
178
188
  }
179
189
  entries() {
180
- return __awaiter(this, void 0, void 0, function* () {
181
- return this.map.entries();
182
- });
190
+ return this.map.entries();
183
191
  }
184
192
  }