@freesignal/protocol 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/double-ratchet.d.ts +13 -49
- package/dist/double-ratchet.js +33 -211
- package/dist/node.d.ts +18 -0
- package/dist/node.js +25 -6
- package/dist/types.d.ts +5 -2
- package/dist/types.js +97 -4
- package/dist/x3dh.d.ts +2 -6
- package/dist/x3dh.js +10 -11
- package/package.json +5 -5
package/dist/double-ratchet.d.ts
CHANGED
|
@@ -16,8 +16,6 @@
|
|
|
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 { LocalStorage } from "@freesignal/interfaces";
|
|
20
|
-
import { EncryptedData } from "./types";
|
|
21
19
|
export interface ExportedKeySession {
|
|
22
20
|
secretKey: string;
|
|
23
21
|
rootKey?: string;
|
|
@@ -25,6 +23,14 @@ export interface ExportedKeySession {
|
|
|
25
23
|
receivingChain?: ExportedKeyChain;
|
|
26
24
|
previousKeys: [string, Uint8Array][];
|
|
27
25
|
}
|
|
26
|
+
export interface EncryptionKeys {
|
|
27
|
+
readonly count: number;
|
|
28
|
+
readonly previous: number;
|
|
29
|
+
readonly publicKey: Uint8Array;
|
|
30
|
+
}
|
|
31
|
+
export interface PrivateEncryptionKeys extends EncryptionKeys {
|
|
32
|
+
readonly secretKey: Uint8Array;
|
|
33
|
+
}
|
|
28
34
|
/**
|
|
29
35
|
* Represents a secure Double Ratchet session.
|
|
30
36
|
* Used for forward-secure encryption and decryption of messages.
|
|
@@ -33,36 +39,22 @@ export declare class KeySession {
|
|
|
33
39
|
static readonly keyLength = 32;
|
|
34
40
|
static readonly version = 1;
|
|
35
41
|
static readonly info: string;
|
|
42
|
+
static readonly maxCount = 65536;
|
|
36
43
|
readonly id: string;
|
|
37
|
-
private readonly mutex;
|
|
38
|
-
private readonly storage;
|
|
39
44
|
private keyPair;
|
|
40
45
|
private rootKey?;
|
|
41
46
|
private sendingChain?;
|
|
42
47
|
private receivingChain?;
|
|
43
48
|
private previousKeys;
|
|
44
|
-
constructor(
|
|
49
|
+
constructor(opts?: {
|
|
45
50
|
id?: string;
|
|
46
51
|
secretKey?: Uint8Array;
|
|
47
52
|
remoteKey?: Uint8Array;
|
|
48
53
|
rootKey?: Uint8Array;
|
|
49
54
|
});
|
|
50
55
|
private getChain;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
* Encrypts a message payload using the current sending chain.
|
|
54
|
-
*
|
|
55
|
-
* @param message - The message as a Uint8Array.
|
|
56
|
-
* @returns An EncryptedPayload or undefined if encryption fails.
|
|
57
|
-
*/
|
|
58
|
-
encrypt(message: Uint8Array): Promise<EncryptedData>;
|
|
59
|
-
/**
|
|
60
|
-
* Decrypts an encrypted message.
|
|
61
|
-
*
|
|
62
|
-
* @param payload - The received encrypted message.
|
|
63
|
-
* @returns The decrypted message as a Uint8Array, or undefined if decryption fails.
|
|
64
|
-
*/
|
|
65
|
-
decrypt(payload: Uint8Array | EncryptedData): Promise<Uint8Array>;
|
|
56
|
+
getSendingKey(): PrivateEncryptionKeys | undefined;
|
|
57
|
+
getReceivingKey(encryptionKeys: EncryptionKeys): Uint8Array | undefined;
|
|
66
58
|
/**
|
|
67
59
|
* Whether both the sending and receiving chains are initialized.
|
|
68
60
|
*/
|
|
@@ -81,7 +73,7 @@ export declare class KeySession {
|
|
|
81
73
|
* @param json string returned by `export()` method.
|
|
82
74
|
* @returns session with the state parsed.
|
|
83
75
|
*/
|
|
84
|
-
static from(data: ExportedKeySession
|
|
76
|
+
static from(data: ExportedKeySession): KeySession;
|
|
85
77
|
}
|
|
86
78
|
interface ExportedKeyChain {
|
|
87
79
|
publicKey: string;
|
|
@@ -90,32 +82,4 @@ interface ExportedKeyChain {
|
|
|
90
82
|
count: number;
|
|
91
83
|
previousCount: number;
|
|
92
84
|
}
|
|
93
|
-
export declare class EncryptedDataConstructor implements EncryptedData {
|
|
94
|
-
static readonly secretKeyLength: number;
|
|
95
|
-
static readonly publicKeyLength: number;
|
|
96
|
-
static readonly keyLength: number;
|
|
97
|
-
static readonly nonceLength: number;
|
|
98
|
-
static readonly maxCount = 65536;
|
|
99
|
-
static readonly countLength = 2;
|
|
100
|
-
private raw;
|
|
101
|
-
constructor(count: number | Uint8Array, previous: number | Uint8Array, publicKey: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, version?: number | Uint8Array);
|
|
102
|
-
constructor(encrypted: Uint8Array | EncryptedData);
|
|
103
|
-
get length(): number;
|
|
104
|
-
get version(): number;
|
|
105
|
-
get count(): number;
|
|
106
|
-
get previous(): number;
|
|
107
|
-
get publicKey(): Uint8Array;
|
|
108
|
-
get nonce(): Uint8Array;
|
|
109
|
-
get ciphertext(): Uint8Array;
|
|
110
|
-
toBytes(): Uint8Array;
|
|
111
|
-
toString(): string;
|
|
112
|
-
toJSON(): {
|
|
113
|
-
version: number;
|
|
114
|
-
count: number;
|
|
115
|
-
previous: number;
|
|
116
|
-
publicKey: string;
|
|
117
|
-
nonce: string;
|
|
118
|
-
ciphertext: string;
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
85
|
export {};
|
package/dist/double-ratchet.js
CHANGED
|
@@ -17,84 +17,20 @@
|
|
|
17
17
|
* You should have received a copy of the GNU General Public License
|
|
18
18
|
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
19
19
|
*/
|
|
20
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
21
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
22
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
23
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
24
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
25
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
26
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
27
|
-
});
|
|
28
|
-
};
|
|
29
|
-
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
30
|
-
if (value !== null && value !== void 0) {
|
|
31
|
-
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
32
|
-
var dispose, inner;
|
|
33
|
-
if (async) {
|
|
34
|
-
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
35
|
-
dispose = value[Symbol.asyncDispose];
|
|
36
|
-
}
|
|
37
|
-
if (dispose === void 0) {
|
|
38
|
-
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
39
|
-
dispose = value[Symbol.dispose];
|
|
40
|
-
if (async) inner = dispose;
|
|
41
|
-
}
|
|
42
|
-
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
43
|
-
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
44
|
-
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
45
|
-
}
|
|
46
|
-
else if (async) {
|
|
47
|
-
env.stack.push({ async: true });
|
|
48
|
-
}
|
|
49
|
-
return value;
|
|
50
|
-
};
|
|
51
|
-
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
52
|
-
return function (env) {
|
|
53
|
-
function fail(e) {
|
|
54
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
55
|
-
env.hasError = true;
|
|
56
|
-
}
|
|
57
|
-
var r, s = 0;
|
|
58
|
-
function next() {
|
|
59
|
-
while (r = env.stack.pop()) {
|
|
60
|
-
try {
|
|
61
|
-
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
62
|
-
if (r.dispose) {
|
|
63
|
-
var result = r.dispose.call(r.value);
|
|
64
|
-
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
65
|
-
}
|
|
66
|
-
else s |= 1;
|
|
67
|
-
}
|
|
68
|
-
catch (e) {
|
|
69
|
-
fail(e);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
73
|
-
if (env.hasError) throw env.error;
|
|
74
|
-
}
|
|
75
|
-
return next();
|
|
76
|
-
};
|
|
77
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
78
|
-
var e = new Error(message);
|
|
79
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
80
|
-
});
|
|
81
20
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
82
21
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
83
22
|
};
|
|
84
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
85
|
-
exports.
|
|
24
|
+
exports.KeySession = void 0;
|
|
86
25
|
const crypto_1 = __importDefault(require("@freesignal/crypto"));
|
|
87
26
|
const utils_1 = require("@freesignal/utils");
|
|
88
|
-
const types_1 = require("./types");
|
|
89
|
-
const semaphore_ts_1 = require("semaphore.ts");
|
|
90
27
|
/**
|
|
91
28
|
* Represents a secure Double Ratchet session.
|
|
92
29
|
* Used for forward-secure encryption and decryption of messages.
|
|
93
30
|
*/
|
|
94
31
|
class KeySession {
|
|
95
|
-
constructor(
|
|
32
|
+
constructor(opts = {}) {
|
|
96
33
|
var _a;
|
|
97
|
-
this.mutex = { sending: new semaphore_ts_1.AsyncMutex(), receiving: new semaphore_ts_1.AsyncMutex() };
|
|
98
34
|
this.previousKeys = new KeyMap();
|
|
99
35
|
this.id = (_a = opts.id) !== null && _a !== void 0 ? _a : crypto_1.default.UUID.generate().toString();
|
|
100
36
|
this.keyPair = crypto_1.default.ECDH.keyPair(opts.secretKey);
|
|
@@ -103,8 +39,6 @@ class KeySession {
|
|
|
103
39
|
if (opts.remoteKey) {
|
|
104
40
|
this.sendingChain = this.getChain(opts.remoteKey);
|
|
105
41
|
}
|
|
106
|
-
this.storage = storage;
|
|
107
|
-
this.save();
|
|
108
42
|
}
|
|
109
43
|
getChain(remoteKey, previousCount) {
|
|
110
44
|
const sharedKey = crypto_1.default.ECDH.scalarMult(this.keyPair.secretKey, remoteKey);
|
|
@@ -114,75 +48,38 @@ class KeySession {
|
|
|
114
48
|
this.rootKey = hashkey.subarray(0, KeySession.keyLength);
|
|
115
49
|
return new KeyChain(this.publicKey, remoteKey, hashkey.subarray(KeySession.keyLength), previousCount);
|
|
116
50
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
129
|
-
try {
|
|
130
|
-
const lock = __addDisposableResource(env_1, yield this.mutex.sending.acquire(), false);
|
|
131
|
-
if (!this.sendingChain)
|
|
132
|
-
throw new Error("SendingChain not initialized");
|
|
133
|
-
const key = this.sendingChain.getKey();
|
|
134
|
-
const nonce = crypto_1.default.randomBytes(EncryptedDataConstructor.nonceLength);
|
|
135
|
-
const ciphertext = crypto_1.default.box.encrypt(message, nonce, key);
|
|
136
|
-
this.save();
|
|
137
|
-
return new EncryptedDataConstructor(this.sendingChain.count, this.sendingChain.previousCount, this.keyPair.publicKey, nonce, ciphertext);
|
|
138
|
-
}
|
|
139
|
-
catch (e_1) {
|
|
140
|
-
env_1.error = e_1;
|
|
141
|
-
env_1.hasError = true;
|
|
142
|
-
}
|
|
143
|
-
finally {
|
|
144
|
-
__disposeResources(env_1);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
51
|
+
getSendingKey() {
|
|
52
|
+
if (!this.sendingChain)
|
|
53
|
+
return;
|
|
54
|
+
const secretKey = this.sendingChain.getKey();
|
|
55
|
+
return {
|
|
56
|
+
//version: KeySession.version,
|
|
57
|
+
count: this.sendingChain.count,
|
|
58
|
+
previous: this.sendingChain.previousCount,
|
|
59
|
+
publicKey: this.sendingChain.publicKey,
|
|
60
|
+
secretKey
|
|
61
|
+
};
|
|
147
62
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
*/
|
|
154
|
-
decrypt(payload) {
|
|
155
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
156
|
-
var _a, _b, _c;
|
|
157
|
-
const encrypted = types_1.EncryptedData.from(payload);
|
|
158
|
-
if (!this.previousKeys.has((0, utils_1.decodeBase64)(encrypted.publicKey) + encrypted.count.toString())) {
|
|
159
|
-
const lock = yield this.mutex.receiving.acquire();
|
|
160
|
-
if (!(0, utils_1.compareBytes)(encrypted.publicKey, (_b = (_a = this.receivingChain) === null || _a === void 0 ? void 0 : _a.remoteKey) !== null && _b !== void 0 ? _b : new Uint8Array())) {
|
|
161
|
-
while (this.receivingChain && this.receivingChain.count < encrypted.previous) {
|
|
162
|
-
const key = this.receivingChain.getKey();
|
|
163
|
-
this.previousKeys.set((0, utils_1.decodeBase64)(this.receivingChain.remoteKey) + this.receivingChain.count.toString(), key);
|
|
164
|
-
}
|
|
165
|
-
this.receivingChain = this.getChain(encrypted.publicKey);
|
|
166
|
-
this.keyPair = crypto_1.default.ECDH.keyPair();
|
|
167
|
-
this.sendingChain = this.getChain(encrypted.publicKey, (_c = this.sendingChain) === null || _c === void 0 ? void 0 : _c.count);
|
|
168
|
-
}
|
|
169
|
-
if (!this.receivingChain)
|
|
170
|
-
throw new Error("Error initializing receivingChain");
|
|
171
|
-
while (this.receivingChain.count < encrypted.count) {
|
|
63
|
+
getReceivingKey(encryptionKeys) {
|
|
64
|
+
var _a, _b, _c;
|
|
65
|
+
if (!this.previousKeys.has((0, utils_1.decodeBase64)(encryptionKeys.publicKey) + encryptionKeys.count.toString())) {
|
|
66
|
+
if (!(0, utils_1.compareBytes)(encryptionKeys.publicKey, (_b = (_a = this.receivingChain) === null || _a === void 0 ? void 0 : _a.remoteKey) !== null && _b !== void 0 ? _b : new Uint8Array())) {
|
|
67
|
+
while (this.receivingChain && this.receivingChain.count < encryptionKeys.previous) {
|
|
172
68
|
const key = this.receivingChain.getKey();
|
|
173
69
|
this.previousKeys.set((0, utils_1.decodeBase64)(this.receivingChain.remoteKey) + this.receivingChain.count.toString(), key);
|
|
174
70
|
}
|
|
175
|
-
|
|
71
|
+
this.receivingChain = this.getChain(encryptionKeys.publicKey);
|
|
72
|
+
this.keyPair = crypto_1.default.ECDH.keyPair();
|
|
73
|
+
this.sendingChain = this.getChain(encryptionKeys.publicKey, (_c = this.sendingChain) === null || _c === void 0 ? void 0 : _c.count);
|
|
74
|
+
}
|
|
75
|
+
if (!this.receivingChain)
|
|
76
|
+
throw new Error("Error initializing receivingChain");
|
|
77
|
+
while (this.receivingChain.count < encryptionKeys.count) {
|
|
78
|
+
const key = this.receivingChain.getKey();
|
|
79
|
+
this.previousKeys.set((0, utils_1.decodeBase64)(this.receivingChain.remoteKey) + this.receivingChain.count.toString(), key);
|
|
176
80
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
throw new Error("Error calculating key");
|
|
180
|
-
this.save();
|
|
181
|
-
const cleartext = crypto_1.default.box.decrypt(encrypted.ciphertext, encrypted.nonce, key);
|
|
182
|
-
if (!cleartext)
|
|
183
|
-
throw new Error("Error decrypting ciphertext");
|
|
184
|
-
return cleartext;
|
|
185
|
-
});
|
|
81
|
+
}
|
|
82
|
+
return this.previousKeys.get((0, utils_1.decodeBase64)(encryptionKeys.publicKey) + encryptionKeys.count.toString());
|
|
186
83
|
}
|
|
187
84
|
/**
|
|
188
85
|
* Whether both the sending and receiving chains are initialized.
|
|
@@ -211,13 +108,11 @@ class KeySession {
|
|
|
211
108
|
* @param json string returned by `export()` method.
|
|
212
109
|
* @returns session with the state parsed.
|
|
213
110
|
*/
|
|
214
|
-
static from(data
|
|
215
|
-
const session = new KeySession(
|
|
216
|
-
//session._remoteKey = data.remoteKey ? encodeBase64(data.remoteKey) : undefined;
|
|
111
|
+
static from(data) {
|
|
112
|
+
const session = new KeySession({ secretKey: (0, utils_1.encodeBase64)(data.secretKey), rootKey: data.rootKey ? (0, utils_1.encodeBase64)(data.rootKey) : undefined });
|
|
217
113
|
session.sendingChain = data.sendingChain ? KeyChain.from(data.sendingChain) : undefined;
|
|
218
114
|
session.receivingChain = data.receivingChain ? KeyChain.from(data.receivingChain) : undefined;
|
|
219
115
|
session.previousKeys = new KeyMap(data.previousKeys);
|
|
220
|
-
session.save();
|
|
221
116
|
return session;
|
|
222
117
|
}
|
|
223
118
|
}
|
|
@@ -225,6 +120,7 @@ exports.KeySession = KeySession;
|
|
|
225
120
|
KeySession.keyLength = 32;
|
|
226
121
|
KeySession.version = 1;
|
|
227
122
|
KeySession.info = "/freesignal/double-ratchet/v0." + KeySession.version;
|
|
123
|
+
KeySession.maxCount = 65536;
|
|
228
124
|
class KeyChain {
|
|
229
125
|
constructor(publicKey, remoteKey, chainKey, previousCount = 0) {
|
|
230
126
|
this.publicKey = publicKey;
|
|
@@ -234,7 +130,7 @@ class KeyChain {
|
|
|
234
130
|
this._count = 0;
|
|
235
131
|
}
|
|
236
132
|
getKey() {
|
|
237
|
-
if (++this._count >=
|
|
133
|
+
if (++this._count >= KeySession.maxCount)
|
|
238
134
|
throw new Error("SendingChain count too big");
|
|
239
135
|
const hash = crypto_1.default.hkdf(this.chainKey, new Uint8Array(KeySession.keyLength).fill(0), KeySession.info, KeySession.keyLength * 2);
|
|
240
136
|
this.chainKey = hash.subarray(0, KeySession.keyLength);
|
|
@@ -261,80 +157,6 @@ class KeyChain {
|
|
|
261
157
|
return chain;
|
|
262
158
|
}
|
|
263
159
|
}
|
|
264
|
-
class EncryptedDataConstructor {
|
|
265
|
-
constructor(...arrays) {
|
|
266
|
-
arrays = arrays.filter(value => value !== undefined);
|
|
267
|
-
if (arrays[0] instanceof EncryptedDataConstructor) {
|
|
268
|
-
this.raw = arrays[0].raw;
|
|
269
|
-
return this;
|
|
270
|
-
}
|
|
271
|
-
if (typeof arrays[0] === 'number')
|
|
272
|
-
arrays[0] = (0, utils_1.numberToBytes)(arrays[0], EncryptedDataConstructor.countLength);
|
|
273
|
-
if (typeof arrays[1] === 'number')
|
|
274
|
-
arrays[1] = (0, utils_1.numberToBytes)(arrays[1], EncryptedDataConstructor.countLength);
|
|
275
|
-
if (arrays.length === 6) {
|
|
276
|
-
arrays.unshift(typeof arrays[5] === 'number' ? (0, utils_1.numberToBytes)(arrays[5], 1) : arrays[5]);
|
|
277
|
-
arrays.pop();
|
|
278
|
-
}
|
|
279
|
-
else if (arrays.length > 1) {
|
|
280
|
-
arrays.unshift((0, utils_1.numberToBytes)(KeySession.version, 1));
|
|
281
|
-
}
|
|
282
|
-
this.raw = (0, utils_1.concatBytes)(...arrays);
|
|
283
|
-
}
|
|
284
|
-
get length() { return this.raw.length; }
|
|
285
|
-
get version() { return (0, utils_1.bytesToNumber)(new Uint8Array(this.raw.buffer, ...Offsets.version.get)); }
|
|
286
|
-
get count() { return (0, utils_1.bytesToNumber)(new Uint8Array(this.raw.buffer, ...Offsets.count.get)); }
|
|
287
|
-
get previous() { return (0, utils_1.bytesToNumber)(new Uint8Array(this.raw.buffer, ...Offsets.previous.get)); }
|
|
288
|
-
get publicKey() { return new Uint8Array(this.raw.buffer, ...Offsets.publicKey.get); }
|
|
289
|
-
get nonce() { return new Uint8Array(this.raw.buffer, ...Offsets.nonce.get); }
|
|
290
|
-
get ciphertext() { return new Uint8Array(this.raw.buffer, Offsets.ciphertext.start); }
|
|
291
|
-
toBytes() {
|
|
292
|
-
return this.raw;
|
|
293
|
-
}
|
|
294
|
-
toString() {
|
|
295
|
-
return (0, utils_1.decodeBase64)(this.raw);
|
|
296
|
-
}
|
|
297
|
-
toJSON() {
|
|
298
|
-
return {
|
|
299
|
-
version: this.version,
|
|
300
|
-
count: this.count,
|
|
301
|
-
previous: this.previous,
|
|
302
|
-
publicKey: (0, utils_1.decodeBase64)(this.publicKey),
|
|
303
|
-
nonce: (0, utils_1.decodeBase64)(this.nonce),
|
|
304
|
-
ciphertext: (0, utils_1.decodeBase64)(this.ciphertext)
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
exports.EncryptedDataConstructor = EncryptedDataConstructor;
|
|
309
|
-
EncryptedDataConstructor.secretKeyLength = crypto_1.default.ECDH.secretKeyLength;
|
|
310
|
-
EncryptedDataConstructor.publicKeyLength = crypto_1.default.ECDH.publicKeyLength;
|
|
311
|
-
EncryptedDataConstructor.keyLength = crypto_1.default.box.keyLength;
|
|
312
|
-
EncryptedDataConstructor.nonceLength = crypto_1.default.box.nonceLength;
|
|
313
|
-
EncryptedDataConstructor.maxCount = 65536; //32768;
|
|
314
|
-
EncryptedDataConstructor.countLength = 2;
|
|
315
|
-
class Offsets {
|
|
316
|
-
static set(start, length) {
|
|
317
|
-
class Offset {
|
|
318
|
-
constructor(start, length) {
|
|
319
|
-
this.start = start;
|
|
320
|
-
this.length = length;
|
|
321
|
-
if (typeof length === 'number')
|
|
322
|
-
this.end = start + length;
|
|
323
|
-
}
|
|
324
|
-
get get() {
|
|
325
|
-
return [this.start, this.length];
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return new Offset(start, length);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
Offsets.checksum = Offsets.set(0, 0);
|
|
332
|
-
Offsets.version = Offsets.set(Offsets.checksum.end, 1);
|
|
333
|
-
Offsets.count = Offsets.set(Offsets.version.end, EncryptedDataConstructor.countLength);
|
|
334
|
-
Offsets.previous = Offsets.set(Offsets.count.end, EncryptedDataConstructor.countLength);
|
|
335
|
-
Offsets.publicKey = Offsets.set(Offsets.previous.end, EncryptedDataConstructor.publicKeyLength);
|
|
336
|
-
Offsets.nonce = Offsets.set(Offsets.publicKey.end, EncryptedDataConstructor.nonceLength);
|
|
337
|
-
Offsets.ciphertext = Offsets.set(Offsets.nonce.end, undefined);
|
|
338
160
|
class KeyMap extends Map {
|
|
339
161
|
get(key) {
|
|
340
162
|
const out = super.get(key);
|
package/dist/node.d.ts
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
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
|
+
*/
|
|
1
19
|
import { Database, LocalStorage, Crypto, KeyExchangeDataBundle, KeyExchangeData } from "@freesignal/interfaces";
|
|
2
20
|
import { Datagram, IdentityKey, PrivateIdentityKey, Protocols, UserId } from "./types";
|
|
3
21
|
import { KeyExchange } from "./x3dh";
|
package/dist/node.js
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* FreeSignal Protocol
|
|
4
|
+
*
|
|
5
|
+
* Copyright (C) 2025 Christian Braghette
|
|
6
|
+
*
|
|
7
|
+
* This program is free software: you can redistribute it and/or modify
|
|
8
|
+
* it under the terms of the GNU General Public License as published by
|
|
9
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
* (at your option) any later version.
|
|
11
|
+
*
|
|
12
|
+
* This program is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
* GNU General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* You should have received a copy of the GNU General Public License
|
|
18
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
19
|
+
*/
|
|
2
20
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
21
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
22
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -58,7 +76,7 @@ class FreeSignalNode {
|
|
|
58
76
|
this.bootstraps = new Set();
|
|
59
77
|
this.privateIdentityKey = privateIdentityKey !== null && privateIdentityKey !== void 0 ? privateIdentityKey : (0, _1.createIdentity)();
|
|
60
78
|
this.sessions = new SessionMap(storage.sessions);
|
|
61
|
-
this.keyExchange = new x3dh_1.KeyExchange(
|
|
79
|
+
this.keyExchange = new x3dh_1.KeyExchange(storage.keyExchange, this.privateIdentityKey);
|
|
62
80
|
this.users = storage.users;
|
|
63
81
|
this.bundles = storage.bundles;
|
|
64
82
|
}
|
|
@@ -78,7 +96,9 @@ class FreeSignalNode {
|
|
|
78
96
|
const session = yield this.sessions.get(receiverId);
|
|
79
97
|
if (!session)
|
|
80
98
|
throw new Error("Session not found for user: " + receiverId);
|
|
81
|
-
|
|
99
|
+
const encrypted = (0, types_1.encryptData)(session, data);
|
|
100
|
+
this.sessions.set(receiverId, session);
|
|
101
|
+
return new types_1.Datagram(this.userId.toString(), receiverId, protocol, encrypted).sign(this.privateIdentityKey.signatureKey);
|
|
82
102
|
});
|
|
83
103
|
}
|
|
84
104
|
packHandshake(data) {
|
|
@@ -127,9 +147,8 @@ class FreeSignalNode {
|
|
|
127
147
|
throw new Error("Session not found for user: " + datagram.sender);
|
|
128
148
|
if (!datagram.payload)
|
|
129
149
|
throw new Error("Missing payload");
|
|
130
|
-
const decrypted =
|
|
131
|
-
|
|
132
|
-
throw new Error("Decryption failed");
|
|
150
|
+
const decrypted = (0, types_1.decryptData)(session, datagram.payload);
|
|
151
|
+
this.sessions.set(datagram.sender, session);
|
|
133
152
|
return decrypted;
|
|
134
153
|
});
|
|
135
154
|
}
|
|
@@ -220,7 +239,7 @@ class SessionMap {
|
|
|
220
239
|
const sessionData = yield this.storage.get(key);
|
|
221
240
|
if (!sessionData)
|
|
222
241
|
return undefined;
|
|
223
|
-
return double_ratchet_1.KeySession.from(sessionData
|
|
242
|
+
return double_ratchet_1.KeySession.from(sessionData);
|
|
224
243
|
}
|
|
225
244
|
return session;
|
|
226
245
|
});
|
package/dist/types.d.ts
CHANGED
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
18
18
|
*/
|
|
19
19
|
import { LocalStorage, Encodable, KeyExchangeData } from "@freesignal/interfaces";
|
|
20
|
+
import { KeySession } from "./double-ratchet";
|
|
21
|
+
export declare function encryptData(session: KeySession, data: Uint8Array): EncryptedData;
|
|
22
|
+
export declare function decryptData(session: KeySession, encryptedData: Uint8Array): Uint8Array;
|
|
20
23
|
export declare class UserId implements Encodable {
|
|
21
24
|
private readonly array;
|
|
22
25
|
private constructor();
|
|
@@ -167,14 +170,14 @@ export interface EncryptedData extends Encodable {
|
|
|
167
170
|
ciphertext: string;
|
|
168
171
|
};
|
|
169
172
|
}
|
|
170
|
-
export declare
|
|
173
|
+
export declare namespace EncryptedData {
|
|
171
174
|
/**
|
|
172
175
|
* Static factory method that constructs an `EncryptedPayload` from a raw Uint8Array.
|
|
173
176
|
*
|
|
174
177
|
* @param array - A previously serialized encrypted payload.
|
|
175
178
|
* @returns An instance of `EncryptedPayload`.
|
|
176
179
|
*/
|
|
177
|
-
|
|
180
|
+
function from(array: Uint8Array | EncryptedData): EncryptedData;
|
|
178
181
|
}
|
|
179
182
|
export declare class AsyncMap<K, V> implements LocalStorage<K, V> {
|
|
180
183
|
private readonly map;
|
package/dist/types.js
CHANGED
|
@@ -31,9 +31,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
31
31
|
};
|
|
32
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
33
|
exports.AsyncMap = exports.EncryptedData = exports.Datagram = exports.Protocols = exports.DiscoverType = exports.PrivateIdentityKey = exports.IdentityKey = exports.UserId = void 0;
|
|
34
|
+
exports.encryptData = encryptData;
|
|
35
|
+
exports.decryptData = decryptData;
|
|
34
36
|
const utils_1 = require("@freesignal/utils");
|
|
35
37
|
const crypto_1 = __importDefault(require("@freesignal/crypto"));
|
|
36
38
|
const double_ratchet_1 = require("./double-ratchet");
|
|
39
|
+
function encryptData(session, data) {
|
|
40
|
+
const key = session.getSendingKey();
|
|
41
|
+
if (!key)
|
|
42
|
+
throw new Error("Error generating key");
|
|
43
|
+
const nonce = crypto_1.default.randomBytes(EncryptedDataConstructor.nonceLength);
|
|
44
|
+
const ciphertext = crypto_1.default.box.encrypt(data, nonce, key.secretKey);
|
|
45
|
+
return new EncryptedDataConstructor(key.count, key.previous, key.publicKey, nonce, ciphertext);
|
|
46
|
+
}
|
|
47
|
+
function decryptData(session, encryptedData) {
|
|
48
|
+
const encrypted = EncryptedData.from(encryptedData);
|
|
49
|
+
const key = session.getReceivingKey(encrypted);
|
|
50
|
+
if (!key)
|
|
51
|
+
throw new Error("Error calculating key");
|
|
52
|
+
const decrypted = crypto_1.default.box.decrypt(encrypted.ciphertext, encrypted.nonce, key);
|
|
53
|
+
if (!decrypted)
|
|
54
|
+
throw new Error("Error decrypting data");
|
|
55
|
+
return decrypted;
|
|
56
|
+
}
|
|
37
57
|
class UserId {
|
|
38
58
|
constructor(array) {
|
|
39
59
|
this.array = array;
|
|
@@ -300,18 +320,91 @@ class Datagram {
|
|
|
300
320
|
exports.Datagram = Datagram;
|
|
301
321
|
Datagram.version = 1;
|
|
302
322
|
Datagram.headerOffset = 26 + crypto_1.default.EdDSA.publicKeyLength * 2;
|
|
303
|
-
|
|
323
|
+
var EncryptedData;
|
|
324
|
+
(function (EncryptedData) {
|
|
304
325
|
/**
|
|
305
326
|
* Static factory method that constructs an `EncryptedPayload` from a raw Uint8Array.
|
|
306
327
|
*
|
|
307
328
|
* @param array - A previously serialized encrypted payload.
|
|
308
329
|
* @returns An instance of `EncryptedPayload`.
|
|
309
330
|
*/
|
|
310
|
-
|
|
311
|
-
return new
|
|
331
|
+
function from(array) {
|
|
332
|
+
return new EncryptedDataConstructor(array);
|
|
333
|
+
}
|
|
334
|
+
EncryptedData.from = from;
|
|
335
|
+
})(EncryptedData || (exports.EncryptedData = EncryptedData = {}));
|
|
336
|
+
class EncryptedDataConstructor {
|
|
337
|
+
constructor(...arrays) {
|
|
338
|
+
arrays = arrays.filter(value => value !== undefined);
|
|
339
|
+
if (arrays[0] instanceof EncryptedDataConstructor) {
|
|
340
|
+
this.raw = arrays[0].raw;
|
|
341
|
+
return this;
|
|
342
|
+
}
|
|
343
|
+
if (typeof arrays[0] === 'number')
|
|
344
|
+
arrays[0] = (0, utils_1.numberToBytes)(arrays[0], EncryptedDataConstructor.countLength);
|
|
345
|
+
if (typeof arrays[1] === 'number')
|
|
346
|
+
arrays[1] = (0, utils_1.numberToBytes)(arrays[1], EncryptedDataConstructor.countLength);
|
|
347
|
+
if (arrays.length === 6) {
|
|
348
|
+
arrays.unshift(typeof arrays[5] === 'number' ? (0, utils_1.numberToBytes)(arrays[5], 1) : arrays[5]);
|
|
349
|
+
arrays.pop();
|
|
350
|
+
}
|
|
351
|
+
else if (arrays.length > 1) {
|
|
352
|
+
arrays.unshift((0, utils_1.numberToBytes)(double_ratchet_1.KeySession.version, 1));
|
|
353
|
+
}
|
|
354
|
+
this.raw = (0, utils_1.concatBytes)(...arrays);
|
|
355
|
+
}
|
|
356
|
+
get length() { return this.raw.length; }
|
|
357
|
+
get version() { return (0, utils_1.bytesToNumber)(new Uint8Array(this.raw.buffer, ...Offsets.version.get)); }
|
|
358
|
+
get count() { return (0, utils_1.bytesToNumber)(new Uint8Array(this.raw.buffer, ...Offsets.count.get)); }
|
|
359
|
+
get previous() { return (0, utils_1.bytesToNumber)(new Uint8Array(this.raw.buffer, ...Offsets.previous.get)); }
|
|
360
|
+
get publicKey() { return new Uint8Array(this.raw.buffer, ...Offsets.publicKey.get); }
|
|
361
|
+
get nonce() { return new Uint8Array(this.raw.buffer, ...Offsets.nonce.get); }
|
|
362
|
+
get ciphertext() { return new Uint8Array(this.raw.buffer, Offsets.ciphertext.start); }
|
|
363
|
+
toBytes() {
|
|
364
|
+
return this.raw;
|
|
365
|
+
}
|
|
366
|
+
toString() {
|
|
367
|
+
return (0, utils_1.decodeBase64)(this.raw);
|
|
368
|
+
}
|
|
369
|
+
toJSON() {
|
|
370
|
+
return {
|
|
371
|
+
version: this.version,
|
|
372
|
+
count: this.count,
|
|
373
|
+
previous: this.previous,
|
|
374
|
+
publicKey: (0, utils_1.decodeBase64)(this.publicKey),
|
|
375
|
+
nonce: (0, utils_1.decodeBase64)(this.nonce),
|
|
376
|
+
ciphertext: (0, utils_1.decodeBase64)(this.ciphertext)
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
EncryptedDataConstructor.secretKeyLength = crypto_1.default.ECDH.secretKeyLength;
|
|
381
|
+
EncryptedDataConstructor.publicKeyLength = crypto_1.default.ECDH.publicKeyLength;
|
|
382
|
+
EncryptedDataConstructor.keyLength = crypto_1.default.box.keyLength;
|
|
383
|
+
EncryptedDataConstructor.nonceLength = crypto_1.default.box.nonceLength;
|
|
384
|
+
EncryptedDataConstructor.countLength = 2;
|
|
385
|
+
class Offsets {
|
|
386
|
+
static set(start, length) {
|
|
387
|
+
class Offset {
|
|
388
|
+
constructor(start, length) {
|
|
389
|
+
this.start = start;
|
|
390
|
+
this.length = length;
|
|
391
|
+
if (typeof length === 'number')
|
|
392
|
+
this.end = start + length;
|
|
393
|
+
}
|
|
394
|
+
get get() {
|
|
395
|
+
return [this.start, this.length];
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return new Offset(start, length);
|
|
312
399
|
}
|
|
313
400
|
}
|
|
314
|
-
|
|
401
|
+
Offsets.checksum = Offsets.set(0, 0);
|
|
402
|
+
Offsets.version = Offsets.set(Offsets.checksum.end, 1);
|
|
403
|
+
Offsets.count = Offsets.set(Offsets.version.end, EncryptedDataConstructor.countLength);
|
|
404
|
+
Offsets.previous = Offsets.set(Offsets.count.end, EncryptedDataConstructor.countLength);
|
|
405
|
+
Offsets.publicKey = Offsets.set(Offsets.previous.end, EncryptedDataConstructor.publicKeyLength);
|
|
406
|
+
Offsets.nonce = Offsets.set(Offsets.publicKey.end, EncryptedDataConstructor.nonceLength);
|
|
407
|
+
Offsets.ciphertext = Offsets.set(Offsets.nonce.end, undefined);
|
|
315
408
|
class AsyncMap {
|
|
316
409
|
constructor(iterable) {
|
|
317
410
|
this.map = new Map(iterable);
|
package/dist/x3dh.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 { KeyExchangeData, KeyExchangeDataBundle, KeyExchangeSynMessage, LocalStorage, Crypto } from "@freesignal/interfaces";
|
|
20
|
-
import {
|
|
20
|
+
import { KeySession } from "./double-ratchet";
|
|
21
21
|
import { IdentityKey, PrivateIdentityKey } from "./types";
|
|
22
22
|
export interface ExportedKeyExchange {
|
|
23
23
|
privateIdentityKey: PrivateIdentityKey;
|
|
@@ -29,11 +29,7 @@ export declare class KeyExchange {
|
|
|
29
29
|
private static readonly maxOPK;
|
|
30
30
|
private readonly privateIdentityKey;
|
|
31
31
|
private readonly storage;
|
|
32
|
-
|
|
33
|
-
constructor(storage: {
|
|
34
|
-
keys: LocalStorage<string, Crypto.KeyPair>;
|
|
35
|
-
sessions: LocalStorage<string, ExportedKeySession>;
|
|
36
|
-
}, privateIdentityKey?: PrivateIdentityKey);
|
|
32
|
+
constructor(storage: LocalStorage<string, Crypto.KeyPair>, privateIdentityKey?: PrivateIdentityKey);
|
|
37
33
|
get identityKey(): IdentityKey;
|
|
38
34
|
private generateSPK;
|
|
39
35
|
private generateOPK;
|
package/dist/x3dh.js
CHANGED
|
@@ -38,8 +38,7 @@ const types_1 = require("./types");
|
|
|
38
38
|
const _1 = require(".");
|
|
39
39
|
class KeyExchange {
|
|
40
40
|
constructor(storage, privateIdentityKey) {
|
|
41
|
-
this.storage = storage
|
|
42
|
-
this.sessions = storage.sessions;
|
|
41
|
+
this.storage = storage;
|
|
43
42
|
this.privateIdentityKey = privateIdentityKey !== null && privateIdentityKey !== void 0 ? privateIdentityKey : (0, _1.createIdentity)();
|
|
44
43
|
}
|
|
45
44
|
get identityKey() {
|
|
@@ -99,9 +98,9 @@ class KeyExchange {
|
|
|
99
98
|
...crypto_1.default.ECDH.scalarMult(ephemeralKey.secretKey, signedPreKey),
|
|
100
99
|
...onetimePreKey ? crypto_1.default.ECDH.scalarMult(ephemeralKey.secretKey, onetimePreKey) : new Uint8Array()
|
|
101
100
|
]), new Uint8Array(double_ratchet_1.KeySession.keyLength).fill(0), KeyExchange.hkdfInfo, double_ratchet_1.KeySession.keyLength);
|
|
102
|
-
const session = new double_ratchet_1.KeySession(
|
|
103
|
-
const
|
|
104
|
-
if (!
|
|
101
|
+
const session = new double_ratchet_1.KeySession({ remoteKey: identityKey.exchangeKey, rootKey });
|
|
102
|
+
const encrypted = (0, types_1.encryptData)(session, (0, utils_1.concatBytes)(crypto_1.default.hash(this.identityKey.toBytes()), crypto_1.default.hash(identityKey.toBytes()), associatedData !== null && associatedData !== void 0 ? associatedData : new Uint8Array()));
|
|
103
|
+
if (!encrypted)
|
|
105
104
|
throw new Error("Decryption error");
|
|
106
105
|
return {
|
|
107
106
|
session,
|
|
@@ -111,7 +110,7 @@ class KeyExchange {
|
|
|
111
110
|
ephemeralKey: (0, utils_1.decodeBase64)(ephemeralKey.publicKey),
|
|
112
111
|
signedPreKeyHash: (0, utils_1.decodeBase64)(signedPreKeyHash),
|
|
113
112
|
onetimePreKeyHash: (0, utils_1.decodeBase64)(onetimePreKeyHash),
|
|
114
|
-
associatedData: (0, utils_1.decodeBase64)(
|
|
113
|
+
associatedData: (0, utils_1.decodeBase64)(encrypted.toBytes())
|
|
115
114
|
},
|
|
116
115
|
identityKey
|
|
117
116
|
};
|
|
@@ -134,16 +133,16 @@ class KeyExchange {
|
|
|
134
133
|
...crypto_1.default.ECDH.scalarMult(signedPreKey.secretKey, ephemeralKey),
|
|
135
134
|
...onetimePreKey ? crypto_1.default.ECDH.scalarMult(onetimePreKey.secretKey, ephemeralKey) : new Uint8Array()
|
|
136
135
|
]), new Uint8Array(double_ratchet_1.KeySession.keyLength).fill(0), KeyExchange.hkdfInfo, double_ratchet_1.KeySession.keyLength);
|
|
137
|
-
const session = new double_ratchet_1.KeySession(
|
|
138
|
-
const
|
|
139
|
-
if (!
|
|
136
|
+
const session = new double_ratchet_1.KeySession({ secretKey: this.privateIdentityKey.exchangeKey, rootKey });
|
|
137
|
+
const data = (0, types_1.decryptData)(session, (0, utils_1.encodeBase64)(message.associatedData));
|
|
138
|
+
if (!data)
|
|
140
139
|
throw new Error("Error decrypting ACK message");
|
|
141
|
-
if (!(0, utils_1.compareBytes)(
|
|
140
|
+
if (!(0, utils_1.compareBytes)(data.subarray(0, 64), (0, utils_1.concatBytes)(crypto_1.default.hash(identityKey.toBytes()), crypto_1.default.hash(this.identityKey.toBytes()))))
|
|
142
141
|
throw new Error("Error verifing Associated Data");
|
|
143
142
|
return {
|
|
144
143
|
session,
|
|
145
144
|
identityKey,
|
|
146
|
-
associatedData:
|
|
145
|
+
associatedData: data.subarray(64)
|
|
147
146
|
};
|
|
148
147
|
});
|
|
149
148
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freesignal/protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Signal Protocol implementation in javascript",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"author": "Christian Braghette",
|
|
@@ -8,22 +8,22 @@
|
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
10
|
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.js",
|
|
11
12
|
"types": "./dist/index.d.ts"
|
|
12
13
|
},
|
|
13
14
|
"./double-ratchet": {
|
|
14
15
|
"import": "./dist/double-ratchet.js",
|
|
16
|
+
"require": "./dist/double-ratchet.js",
|
|
15
17
|
"types": "./dist/double-ratchet.d.ts"
|
|
16
18
|
},
|
|
17
19
|
"./node": {
|
|
18
20
|
"import": "./dist/node.js",
|
|
21
|
+
"require": "./dist/node.js",
|
|
19
22
|
"types": "./dist/node.d.ts"
|
|
20
23
|
},
|
|
21
|
-
"./types": {
|
|
22
|
-
"import": "./dist/types.js",
|
|
23
|
-
"types": "./dist/types.d.ts"
|
|
24
|
-
},
|
|
25
24
|
"./x3dh": {
|
|
26
25
|
"import": "./dist/x3dh.js",
|
|
26
|
+
"require": "./dist/x3dh.js",
|
|
27
27
|
"types": "./dist/x3dh.d.ts"
|
|
28
28
|
}
|
|
29
29
|
},
|