@freesignal/protocol 0.11.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.
@@ -0,0 +1,296 @@
1
+ /**
2
+ * FreeSignal Protocol
3
+ *
4
+ * Copyright (C) 2025 Christian Braghette
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
18
+ */
19
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
20
+ if (kind === "m") throw new TypeError("Private method is not writable");
21
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
22
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
23
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
24
+ };
25
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
26
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
27
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
28
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
29
+ };
30
+ var _SessionConstructor_keyPair, _SessionConstructor_rootKey, _SessionConstructor_headerKey, _SessionConstructor_nextHeaderKey, _SessionConstructor_sendingChain, _SessionConstructor_receivingChain, _SessionConstructor_headerKeys, _SessionConstructor_previousKeys, _KeyChain_chainKey;
31
+ import { useConstructors } from "./constructors.js";
32
+ export class SessionManagerConstructor {
33
+ constructor(keyStore, crypto) {
34
+ this.keyStore = keyStore;
35
+ this.crypto = crypto;
36
+ }
37
+ async createSession(initialState) {
38
+ const session = new SessionConstructor(initialState, this.keyStore, this.crypto);
39
+ await session.save();
40
+ return session;
41
+ }
42
+ async getUserSession(userId) {
43
+ const state = await this.keyStore.loadUserSession(userId.toString());
44
+ if (!state)
45
+ throw new Error("Session not found for sessionTag: " + userId.toString());
46
+ return new SessionConstructor(state, this.keyStore, this.crypto);
47
+ }
48
+ async getSession(sessionTag) {
49
+ const state = await this.keyStore.loadSession(sessionTag);
50
+ if (!state)
51
+ throw new Error("Session not found for sessionTag: " + sessionTag);
52
+ return new SessionConstructor(state, this.keyStore, this.crypto);
53
+ }
54
+ async encrypt(userId, plaintext) {
55
+ const session = await this.getUserSession(userId);
56
+ const ciphertext = session.encrypt(plaintext);
57
+ await this.keyStore.setSessionTag(ciphertext.hashkey, session.sessionTag);
58
+ await session.save();
59
+ return ciphertext;
60
+ }
61
+ async decrypt(ciphertext) {
62
+ const { CiphertextConstructor, UserIdConstructor } = useConstructors(this.crypto);
63
+ ciphertext = CiphertextConstructor.from(ciphertext);
64
+ const sessionTag = await this.keyStore.getSessionTag(ciphertext.hashkey);
65
+ if (!sessionTag)
66
+ throw new Error("Headerkey not found: " + this.crypto.Utils.decodeBase64(ciphertext.hashkey));
67
+ const session = await this.getSession(sessionTag);
68
+ const cleartext = session.decrypt(ciphertext);
69
+ await session.save();
70
+ return {
71
+ userId: UserIdConstructor.from(session.userId),
72
+ data: this.crypto.Utils.decodeData(cleartext)
73
+ };
74
+ }
75
+ }
76
+ export class SessionConstructor {
77
+ constructor(init, keyStore, crypto) {
78
+ this.keyStore = keyStore;
79
+ this.crypto = crypto;
80
+ _SessionConstructor_keyPair.set(this, void 0);
81
+ _SessionConstructor_rootKey.set(this, void 0);
82
+ _SessionConstructor_headerKey.set(this, void 0);
83
+ _SessionConstructor_nextHeaderKey.set(this, void 0);
84
+ _SessionConstructor_sendingChain.set(this, void 0);
85
+ _SessionConstructor_receivingChain.set(this, void 0);
86
+ _SessionConstructor_headerKeys.set(this, void 0);
87
+ _SessionConstructor_previousKeys.set(this, new KeyMap());
88
+ if (!(init instanceof SessionConstructor)) {
89
+ const { remoteKey, userId, sessionTag, secretKey, rootKey, sendingChain, receivingChain, headerKey, nextHeaderKey, headerKeys, previousKeys } = init;
90
+ this.userId = userId;
91
+ this.sessionTag = sessionTag !== null && sessionTag !== void 0 ? sessionTag : this.crypto.Utils.decodeBase64(this.crypto.hkdf(this.crypto.Utils.encodeBase64(rootKey), new Uint8Array(32).fill(0), "/freesignal/session-authtag", 32));
92
+ __classPrivateFieldSet(this, _SessionConstructor_keyPair, this.crypto.ECDH.keyPair(secretKey ? this.crypto.Utils.encodeBase64(secretKey) : undefined), "f");
93
+ __classPrivateFieldSet(this, _SessionConstructor_rootKey, this.crypto.Utils.encodeBase64(rootKey), "f");
94
+ __classPrivateFieldSet(this, _SessionConstructor_sendingChain, sendingChain ? new KeyChain(sendingChain, this.crypto) : undefined, "f");
95
+ __classPrivateFieldSet(this, _SessionConstructor_receivingChain, receivingChain ? new KeyChain(receivingChain, this.crypto) : undefined, "f");
96
+ __classPrivateFieldSet(this, _SessionConstructor_headerKeys, new Map(headerKeys === null || headerKeys === void 0 ? void 0 : headerKeys.map(([key, value]) => [key, this.crypto.Utils.encodeBase64(value)])), "f");
97
+ __classPrivateFieldSet(this, _SessionConstructor_previousKeys, new Map(previousKeys === null || previousKeys === void 0 ? void 0 : previousKeys.map(([key, value]) => [key, this.crypto.Utils.encodeBase64(value)])), "f");
98
+ if (headerKey)
99
+ __classPrivateFieldSet(this, _SessionConstructor_headerKey, this.crypto.Utils.encodeBase64(headerKey), "f");
100
+ if (nextHeaderKey) {
101
+ __classPrivateFieldSet(this, _SessionConstructor_nextHeaderKey, this.crypto.Utils.encodeBase64(nextHeaderKey), "f");
102
+ __classPrivateFieldGet(this, _SessionConstructor_headerKeys, "f").set(this.crypto.Utils.decodeBase64(this.crypto.hash(this.crypto.Utils.encodeBase64(nextHeaderKey))), this.crypto.Utils.encodeBase64(nextHeaderKey));
103
+ }
104
+ if (remoteKey) {
105
+ __classPrivateFieldSet(this, _SessionConstructor_sendingChain, this.getChain(remoteKey, __classPrivateFieldGet(this, _SessionConstructor_headerKey, "f")), "f");
106
+ __classPrivateFieldSet(this, _SessionConstructor_headerKey, undefined, "f");
107
+ }
108
+ }
109
+ else {
110
+ this.userId = init.userId;
111
+ __classPrivateFieldSet(this, _SessionConstructor_keyPair, __classPrivateFieldGet(init, _SessionConstructor_keyPair, "f"), "f");
112
+ __classPrivateFieldSet(this, _SessionConstructor_rootKey, __classPrivateFieldGet(init, _SessionConstructor_rootKey, "f"), "f");
113
+ __classPrivateFieldSet(this, _SessionConstructor_headerKey, __classPrivateFieldGet(init, _SessionConstructor_headerKey, "f"), "f");
114
+ __classPrivateFieldSet(this, _SessionConstructor_nextHeaderKey, __classPrivateFieldGet(init, _SessionConstructor_nextHeaderKey, "f"), "f");
115
+ __classPrivateFieldSet(this, _SessionConstructor_previousKeys, __classPrivateFieldGet(init, _SessionConstructor_previousKeys, "f"), "f");
116
+ __classPrivateFieldSet(this, _SessionConstructor_sendingChain, __classPrivateFieldGet(init, _SessionConstructor_sendingChain, "f"), "f");
117
+ __classPrivateFieldSet(this, _SessionConstructor_receivingChain, __classPrivateFieldGet(init, _SessionConstructor_receivingChain, "f"), "f");
118
+ this.sessionTag = init.sessionTag;
119
+ __classPrivateFieldSet(this, _SessionConstructor_headerKeys, __classPrivateFieldGet(init, _SessionConstructor_headerKeys, "f"), "f");
120
+ }
121
+ }
122
+ //public get publicKey(): Uint8Array { return this.#keyPair.publicKey; }
123
+ getChain(remoteKey, headerKey, previousCount) {
124
+ const sharedKey = this.crypto.ECDH.scalarMult(__classPrivateFieldGet(this, _SessionConstructor_keyPair, "f").secretKey, remoteKey);
125
+ if (!__classPrivateFieldGet(this, _SessionConstructor_rootKey, "f"))
126
+ __classPrivateFieldSet(this, _SessionConstructor_rootKey, this.crypto.hash(sharedKey), "f");
127
+ const hashkey = this.crypto.hkdf(sharedKey, __classPrivateFieldGet(this, _SessionConstructor_rootKey, "f"), SessionConstructor.info, SessionConstructor.keyLength * 3);
128
+ __classPrivateFieldSet(this, _SessionConstructor_rootKey, hashkey.subarray(0, SessionConstructor.keyLength), "f");
129
+ return new KeyChain({
130
+ publicKey: this.crypto.Utils.decodeBase64(__classPrivateFieldGet(this, _SessionConstructor_keyPair, "f").publicKey),
131
+ remoteKey: this.crypto.Utils.decodeBase64(remoteKey),
132
+ chainKey: this.crypto.Utils.decodeBase64(hashkey.subarray(SessionConstructor.keyLength, SessionConstructor.keyLength * 2)),
133
+ nextHeaderKey: this.crypto.Utils.decodeBase64(hashkey.subarray(SessionConstructor.keyLength * 2)),
134
+ headerKey: headerKey ? this.crypto.Utils.decodeBase64(headerKey) : headerKey,
135
+ count: 0,
136
+ previousCount: previousCount !== null && previousCount !== void 0 ? previousCount : 0
137
+ }, this.crypto);
138
+ }
139
+ getHeaderKey(hash) {
140
+ var _a, _b;
141
+ if (!hash)
142
+ return (_a = __classPrivateFieldGet(this, _SessionConstructor_headerKey, "f")) !== null && _a !== void 0 ? _a : (_b = __classPrivateFieldGet(this, _SessionConstructor_sendingChain, "f")) === null || _b === void 0 ? void 0 : _b.headerKey;
143
+ return __classPrivateFieldGet(this, _SessionConstructor_headerKeys, "f").get(hash);
144
+ }
145
+ getSendingKey() {
146
+ if (!__classPrivateFieldGet(this, _SessionConstructor_sendingChain, "f"))
147
+ return;
148
+ const secretKey = __classPrivateFieldGet(this, _SessionConstructor_sendingChain, "f").getKey();
149
+ return {
150
+ count: __classPrivateFieldGet(this, _SessionConstructor_sendingChain, "f").count,
151
+ previous: __classPrivateFieldGet(this, _SessionConstructor_sendingChain, "f").previousCount,
152
+ publicKey: __classPrivateFieldGet(this, _SessionConstructor_sendingChain, "f").publicKey,
153
+ secretKey
154
+ };
155
+ }
156
+ getReceivingKey(encryptionKeys) {
157
+ var _a, _b, _c, _d, _e, _f, _g, _h;
158
+ if (!__classPrivateFieldGet(this, _SessionConstructor_previousKeys, "f").has(this.crypto.Utils.decodeBase64(encryptionKeys.publicKey) + encryptionKeys.count.toString())) {
159
+ if (!this.crypto.Utils.compareBytes(encryptionKeys.publicKey, (_b = (_a = __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f")) === null || _a === void 0 ? void 0 : _a.remoteKey) !== null && _b !== void 0 ? _b : new Uint8Array())) {
160
+ while (__classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f") && __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").count < encryptionKeys.previous) {
161
+ const key = __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").getKey();
162
+ __classPrivateFieldGet(this, _SessionConstructor_previousKeys, "f").set(this.crypto.Utils.decodeBase64(__classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").remoteKey) + __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").count.toString(), key);
163
+ }
164
+ __classPrivateFieldSet(this, _SessionConstructor_receivingChain, this.getChain(encryptionKeys.publicKey, (_c = __classPrivateFieldGet(this, _SessionConstructor_nextHeaderKey, "f")) !== null && _c !== void 0 ? _c : (_d = __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f")) === null || _d === void 0 ? void 0 : _d.nextHeaderKey, (_e = __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f")) === null || _e === void 0 ? void 0 : _e.count), "f");
165
+ __classPrivateFieldGet(this, _SessionConstructor_headerKeys, "f").set(this.crypto.Utils.decodeBase64(this.crypto.hash(__classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").nextHeaderKey)), __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").nextHeaderKey);
166
+ if (__classPrivateFieldGet(this, _SessionConstructor_nextHeaderKey, "f"))
167
+ __classPrivateFieldSet(this, _SessionConstructor_nextHeaderKey, undefined, "f");
168
+ __classPrivateFieldSet(this, _SessionConstructor_keyPair, this.crypto.ECDH.keyPair(), "f");
169
+ __classPrivateFieldSet(this, _SessionConstructor_sendingChain, this.getChain(encryptionKeys.publicKey, (_f = __classPrivateFieldGet(this, _SessionConstructor_headerKey, "f")) !== null && _f !== void 0 ? _f : (_g = __classPrivateFieldGet(this, _SessionConstructor_sendingChain, "f")) === null || _g === void 0 ? void 0 : _g.nextHeaderKey, (_h = __classPrivateFieldGet(this, _SessionConstructor_sendingChain, "f")) === null || _h === void 0 ? void 0 : _h.count), "f");
170
+ if (__classPrivateFieldGet(this, _SessionConstructor_headerKey, "f"))
171
+ __classPrivateFieldSet(this, _SessionConstructor_headerKey, undefined, "f");
172
+ }
173
+ if (!__classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f"))
174
+ throw new Error("Error initializing receivingChain");
175
+ while (__classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").count < encryptionKeys.count) {
176
+ const key = __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").getKey();
177
+ __classPrivateFieldGet(this, _SessionConstructor_previousKeys, "f").set(this.crypto.Utils.decodeBase64(__classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").remoteKey) + __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").count.toString(), key);
178
+ }
179
+ }
180
+ return __classPrivateFieldGet(this, _SessionConstructor_previousKeys, "f").get(this.crypto.Utils.decodeBase64(encryptionKeys.publicKey) + encryptionKeys.count.toString());
181
+ }
182
+ encrypt(data) {
183
+ const { CiphertextHeaderConstructor, CiphertextConstructor } = useConstructors(this.crypto);
184
+ const key = this.getSendingKey();
185
+ if (!key)
186
+ throw new Error("Error generating key");
187
+ const nonce = this.crypto.randomBytes(CiphertextHeaderConstructor.nonceLength);
188
+ const payload = this.crypto.Box.encrypt(data, nonce, key.secretKey);
189
+ let header = new CiphertextHeaderConstructor(key.count, key.previous, key.publicKey, nonce).bytes;
190
+ const headerKey = this.getHeaderKey();
191
+ if (!headerKey)
192
+ return new CiphertextConstructor({ header, payload });
193
+ const headerNonce = this.crypto.randomBytes(CiphertextHeaderConstructor.nonceLength);
194
+ if (headerKey)
195
+ header = this.crypto.Box.encrypt(header, headerNonce, headerKey);
196
+ return new CiphertextConstructor({ hashkey: this.crypto.hash(headerKey !== null && headerKey !== void 0 ? headerKey : new Uint8Array(32).fill(0)), header, nonce: headerNonce, payload });
197
+ }
198
+ decrypt(ciphertext) {
199
+ const { CiphertextHeaderConstructor, CiphertextConstructor } = useConstructors(this.crypto);
200
+ const encrypted = CiphertextConstructor.from(ciphertext);
201
+ let headerData = encrypted.header;
202
+ if (encrypted.hashkey && encrypted.nonce) {
203
+ const headerKey = this.getHeaderKey(this.crypto.Utils.decodeBase64(encrypted.hashkey));
204
+ if (!headerKey)
205
+ throw new Error("Error calculating headerKey");
206
+ const data = this.crypto.Box.decrypt(headerData, encrypted.nonce, headerKey);
207
+ if (!data)
208
+ throw new Error("Error decrypting header");
209
+ headerData = data;
210
+ }
211
+ const header = CiphertextHeaderConstructor.from(headerData);
212
+ const key = this.getReceivingKey(header);
213
+ if (!key)
214
+ throw new Error("Error calculating key");
215
+ const decrypted = this.crypto.Box.decrypt(encrypted.payload, header.nonce, key);
216
+ if (!decrypted)
217
+ throw new Error("Error decrypting data");
218
+ return decrypted;
219
+ }
220
+ hasSkippedKeys() {
221
+ return __classPrivateFieldGet(this, _SessionConstructor_previousKeys, "f").size > 0;
222
+ }
223
+ async save() {
224
+ var _a, _b, _c, _d;
225
+ if (__classPrivateFieldGet(this, _SessionConstructor_nextHeaderKey, "f"))
226
+ await this.keyStore.setSessionTag(this.crypto.hash(__classPrivateFieldGet(this, _SessionConstructor_nextHeaderKey, "f")), this.sessionTag);
227
+ if ((_a = __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f")) === null || _a === void 0 ? void 0 : _a.headerKey)
228
+ await this.keyStore.setSessionTag(this.crypto.hash(__classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").headerKey), this.sessionTag);
229
+ if ((_b = __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f")) === null || _b === void 0 ? void 0 : _b.nextHeaderKey)
230
+ await this.keyStore.setSessionTag(this.crypto.hash(__classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f").nextHeaderKey), this.sessionTag);
231
+ return this.keyStore.storeSession({
232
+ userId: this.userId,
233
+ sessionTag: this.sessionTag,
234
+ secretKey: this.crypto.Utils.decodeBase64(__classPrivateFieldGet(this, _SessionConstructor_keyPair, "f").secretKey),
235
+ rootKey: this.crypto.Utils.decodeBase64(__classPrivateFieldGet(this, _SessionConstructor_rootKey, "f")),
236
+ sendingChain: (_c = __classPrivateFieldGet(this, _SessionConstructor_sendingChain, "f")) === null || _c === void 0 ? void 0 : _c.toJSON(),
237
+ receivingChain: (_d = __classPrivateFieldGet(this, _SessionConstructor_receivingChain, "f")) === null || _d === void 0 ? void 0 : _d.toJSON(),
238
+ headerKey: __classPrivateFieldGet(this, _SessionConstructor_headerKey, "f") ? this.crypto.Utils.decodeBase64(__classPrivateFieldGet(this, _SessionConstructor_headerKey, "f")) : undefined,
239
+ nextHeaderKey: __classPrivateFieldGet(this, _SessionConstructor_nextHeaderKey, "f") ? this.crypto.Utils.decodeBase64(__classPrivateFieldGet(this, _SessionConstructor_nextHeaderKey, "f")) : undefined,
240
+ headerKeys: Array.from(__classPrivateFieldGet(this, _SessionConstructor_headerKeys, "f").entries()).map(([key, value]) => [key, this.crypto.Utils.decodeBase64(value)]),
241
+ previousKeys: Array.from(__classPrivateFieldGet(this, _SessionConstructor_previousKeys, "f").entries()).map(([key, value]) => [key, this.crypto.Utils.decodeBase64(value)]),
242
+ });
243
+ }
244
+ }
245
+ _SessionConstructor_keyPair = new WeakMap(), _SessionConstructor_rootKey = new WeakMap(), _SessionConstructor_headerKey = new WeakMap(), _SessionConstructor_nextHeaderKey = new WeakMap(), _SessionConstructor_sendingChain = new WeakMap(), _SessionConstructor_receivingChain = new WeakMap(), _SessionConstructor_headerKeys = new WeakMap(), _SessionConstructor_previousKeys = new WeakMap();
246
+ SessionConstructor.keyLength = 32;
247
+ SessionConstructor.version = 1;
248
+ SessionConstructor.info = "/freesignal/double-ratchet/v0." + SessionConstructor.version;
249
+ SessionConstructor.maxCount = 65536;
250
+ class KeyChain {
251
+ constructor({ publicKey, remoteKey, nextHeaderKey, chainKey, headerKey, count, previousCount }, crypto) {
252
+ this.crypto = crypto;
253
+ _KeyChain_chainKey.set(this, void 0);
254
+ this._count = 0;
255
+ __classPrivateFieldSet(this, _KeyChain_chainKey, this.crypto.Utils.encodeBase64(chainKey), "f");
256
+ this.publicKey = this.crypto.Utils.encodeBase64(publicKey);
257
+ this.remoteKey = this.crypto.Utils.encodeBase64(remoteKey);
258
+ this.nextHeaderKey = this.crypto.Utils.encodeBase64(nextHeaderKey);
259
+ this.headerKey = headerKey ? this.crypto.Utils.encodeBase64(headerKey) : undefined;
260
+ this._count = count;
261
+ this.previousCount = previousCount !== null && previousCount !== void 0 ? previousCount : 0;
262
+ }
263
+ get count() {
264
+ return this._count;
265
+ }
266
+ getKey() {
267
+ if (++this._count >= SessionConstructor.maxCount)
268
+ throw new Error("SendingChain count too big");
269
+ const hash = this.crypto.hkdf(__classPrivateFieldGet(this, _KeyChain_chainKey, "f"), new Uint8Array(SessionConstructor.keyLength).fill(0), SessionConstructor.info, SessionConstructor.keyLength * 2);
270
+ __classPrivateFieldSet(this, _KeyChain_chainKey, hash.subarray(0, SessionConstructor.keyLength), "f");
271
+ return hash.subarray(SessionConstructor.keyLength);
272
+ }
273
+ toString() {
274
+ return "[object KeyChain]";
275
+ }
276
+ toJSON() {
277
+ return {
278
+ publicKey: this.crypto.Utils.decodeBase64(this.publicKey),
279
+ remoteKey: this.crypto.Utils.decodeBase64(this.remoteKey),
280
+ headerKey: this.headerKey ? this.crypto.Utils.decodeBase64(this.headerKey) : undefined,
281
+ nextHeaderKey: this.crypto.Utils.decodeBase64(this.nextHeaderKey),
282
+ chainKey: this.crypto.Utils.decodeBase64(__classPrivateFieldGet(this, _KeyChain_chainKey, "f")),
283
+ count: this.count,
284
+ previousCount: this.previousCount
285
+ };
286
+ }
287
+ }
288
+ _KeyChain_chainKey = new WeakMap();
289
+ class KeyMap extends Map {
290
+ get(key) {
291
+ const out = super.get(key);
292
+ if (out && !super.delete(key))
293
+ throw new Error();
294
+ return out;
295
+ }
296
+ }
package/dist/user.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * FreeSignal Protocol
3
+ *
4
+ * Copyright (C) 2025 Christian Braghette
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
18
+ */
19
+ import type { KeyStore, PreKeyBundle, PublicIdentity, User, UserFactory, Crypto, Bytes, Ciphertext, UserId, KeyStoreFactory, PreKeyMessage, DecryptResult } from "./interfaces.ts";
20
+ export declare class UserFactoryConstructor implements UserFactory {
21
+ #private;
22
+ private readonly keyStoreFactory;
23
+ private readonly crypto;
24
+ constructor(keyStoreFactory: KeyStoreFactory, crypto: Crypto);
25
+ create(seed?: Bytes): Promise<User>;
26
+ destroy(user: User): boolean;
27
+ }
28
+ export declare class UserConstructor implements User {
29
+ #private;
30
+ readonly publicIdentity: PublicIdentity;
31
+ private readonly crypto;
32
+ constructor(publicIdentity: PublicIdentity, keyStore: KeyStore, crypto: Crypto);
33
+ get id(): UserId;
34
+ encrypt<T>(to: UserId | string, plaintext: T): Promise<Ciphertext>;
35
+ decrypt<T>(ciphertext: Ciphertext | Bytes): Promise<DecryptResult<T>>;
36
+ generatePreKeyBundle(): Promise<PreKeyBundle>;
37
+ handleIncomingPreKeyBundle(bundle: PreKeyBundle, associatedData?: Bytes): Promise<PreKeyMessage>;
38
+ handleIncomingPreKeyMessage(message: PreKeyMessage): Promise<Bytes | undefined>;
39
+ }
package/dist/user.js ADDED
@@ -0,0 +1,85 @@
1
+ /**
2
+ * FreeSignal Protocol
3
+ *
4
+ * Copyright (C) 2025 Christian Braghette
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
18
+ */
19
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
20
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
21
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
22
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
23
+ };
24
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
25
+ if (kind === "m") throw new TypeError("Private method is not writable");
26
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
27
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
28
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
29
+ };
30
+ var _UserFactoryConstructor_objestStore, _UserConstructor_sessionManager, _UserConstructor_keyExchangeManager;
31
+ import { KeyExchangeManagerConstructor } from "./keyexchange.js";
32
+ import { SessionManagerConstructor } from "./session.js";
33
+ import { useConstructors } from "./constructors.js";
34
+ export class UserFactoryConstructor {
35
+ constructor(keyStoreFactory, crypto) {
36
+ this.keyStoreFactory = keyStoreFactory;
37
+ this.crypto = crypto;
38
+ _UserFactoryConstructor_objestStore.set(this, new WeakSet());
39
+ }
40
+ async create(seed) {
41
+ const { IdentityConstructor } = useConstructors(this.crypto);
42
+ const identity = IdentityConstructor.from((seed ? this.crypto.EdDSA.keyPairFromSeed(seed) : this.crypto.EdDSA.keyPair()).secretKey);
43
+ const user = new UserConstructor(identity, await this.keyStoreFactory.createStore(identity), this.crypto);
44
+ __classPrivateFieldGet(this, _UserFactoryConstructor_objestStore, "f").add(user);
45
+ return user;
46
+ }
47
+ ;
48
+ destroy(user) {
49
+ return __classPrivateFieldGet(this, _UserFactoryConstructor_objestStore, "f").delete(user);
50
+ }
51
+ }
52
+ _UserFactoryConstructor_objestStore = new WeakMap();
53
+ export class UserConstructor {
54
+ constructor(publicIdentity, keyStore, crypto) {
55
+ this.publicIdentity = publicIdentity;
56
+ this.crypto = crypto;
57
+ _UserConstructor_sessionManager.set(this, void 0);
58
+ _UserConstructor_keyExchangeManager.set(this, void 0);
59
+ __classPrivateFieldSet(this, _UserConstructor_sessionManager, new SessionManagerConstructor(keyStore, crypto), "f");
60
+ __classPrivateFieldSet(this, _UserConstructor_keyExchangeManager, new KeyExchangeManagerConstructor(publicIdentity, keyStore, crypto), "f");
61
+ }
62
+ get id() {
63
+ return this.publicIdentity.userId;
64
+ }
65
+ encrypt(to, plaintext) {
66
+ return __classPrivateFieldGet(this, _UserConstructor_sessionManager, "f").encrypt(to, this.crypto.Utils.encodeData(plaintext));
67
+ }
68
+ async decrypt(ciphertext) {
69
+ return await __classPrivateFieldGet(this, _UserConstructor_sessionManager, "f").decrypt(ciphertext);
70
+ }
71
+ generatePreKeyBundle() {
72
+ return __classPrivateFieldGet(this, _UserConstructor_keyExchangeManager, "f").createPreKeyBundle();
73
+ }
74
+ async handleIncomingPreKeyBundle(bundle, associatedData) {
75
+ const { session, message } = await __classPrivateFieldGet(this, _UserConstructor_keyExchangeManager, "f").processPreKeyBundle(bundle, associatedData);
76
+ await __classPrivateFieldGet(this, _UserConstructor_sessionManager, "f").createSession(session);
77
+ return message;
78
+ }
79
+ async handleIncomingPreKeyMessage(message) {
80
+ const { session, associatedData } = await __classPrivateFieldGet(this, _UserConstructor_keyExchangeManager, "f").processPreKeyMessage(message);
81
+ await __classPrivateFieldGet(this, _UserConstructor_sessionManager, "f").createSession(session);
82
+ return associatedData;
83
+ }
84
+ }
85
+ _UserConstructor_sessionManager = new WeakMap(), _UserConstructor_keyExchangeManager = new WeakMap();
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@freesignal/protocol",
3
+ "version": "0.11.0",
4
+ "description": "Signal Protocol implementation in TypeScript",
5
+ "homepage": "https://github.com/christianbraghette/freesignal#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/christianbraghette/freesignal/issues"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/christianbraghette/freesignal.git"
12
+ },
13
+ "license": "GPL-3.0-or-later",
14
+ "author": "Christian Braghette",
15
+ "type": "module",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/index.js",
19
+ "types": "./dist/index.d.ts"
20
+ },
21
+ "./interfaces": {
22
+ "types": "./dist/interfaces.d.ts"
23
+ }
24
+ },
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "scripts": {
28
+ "build": "cpx \"./src/*.d.ts\" \"./dist\" && tsc",
29
+ "pretest": "npm run build",
30
+ "test": "node ./dist/test.js",
31
+ "prepare": "npm run build"
32
+ },
33
+ "peerDependencies": {
34
+ "@freesignal/crypto": "^0.11.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^24.2.1",
38
+ "cpx2": "^8.0.0"
39
+ }
40
+ }