@freesignal/protocol 0.4.3 → 0.4.5
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 +9 -0
- package/dist/double-ratchet.js +23 -9
- package/dist/index.d.ts +2 -1
- package/dist/node.d.ts +20 -10
- package/dist/node.js +47 -19
- package/dist/test.js +12 -16
- package/dist/types.d.ts +6 -2
- package/dist/types.js +21 -1
- package/dist/x3dh.js +1 -1
- package/package.json +1 -1
package/dist/double-ratchet.d.ts
CHANGED
|
@@ -45,14 +45,21 @@ export declare class KeySession {
|
|
|
45
45
|
private rootKey?;
|
|
46
46
|
private sendingChain?;
|
|
47
47
|
private receivingChain?;
|
|
48
|
+
private nextHeaderKey?;
|
|
48
49
|
private previousKeys;
|
|
49
50
|
constructor(opts?: {
|
|
50
51
|
id?: string;
|
|
51
52
|
secretKey?: Uint8Array;
|
|
52
53
|
remoteKey?: Uint8Array;
|
|
54
|
+
headerKey?: Uint8Array;
|
|
55
|
+
nextHeaderKey?: Uint8Array;
|
|
53
56
|
rootKey?: Uint8Array;
|
|
54
57
|
});
|
|
55
58
|
private getChain;
|
|
59
|
+
getHeaderKeys(): {
|
|
60
|
+
readonly sending?: Uint8Array;
|
|
61
|
+
readonly receiving?: Uint8Array;
|
|
62
|
+
};
|
|
56
63
|
getSendingKey(): PrivateEncryptionKeys | undefined;
|
|
57
64
|
getReceivingKey(encryptionKeys: EncryptionKeys): Uint8Array | undefined;
|
|
58
65
|
/**
|
|
@@ -79,6 +86,8 @@ interface ExportedKeyChain {
|
|
|
79
86
|
publicKey: string;
|
|
80
87
|
remoteKey: string;
|
|
81
88
|
chainKey: string;
|
|
89
|
+
nextHeaderKey: string;
|
|
90
|
+
headerKey?: string;
|
|
82
91
|
count: number;
|
|
83
92
|
previousCount: number;
|
|
84
93
|
}
|
package/dist/double-ratchet.js
CHANGED
|
@@ -36,17 +36,26 @@ class KeySession {
|
|
|
36
36
|
this.keyPair = crypto_1.default.ECDH.keyPair(opts.secretKey);
|
|
37
37
|
if (opts.rootKey)
|
|
38
38
|
this.rootKey = opts.rootKey;
|
|
39
|
+
if (opts.nextHeaderKey)
|
|
40
|
+
this.nextHeaderKey = opts.nextHeaderKey;
|
|
39
41
|
if (opts.remoteKey) {
|
|
40
|
-
this.sendingChain = this.getChain(opts.remoteKey);
|
|
42
|
+
this.sendingChain = this.getChain(opts.remoteKey, opts.headerKey);
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
|
-
getChain(remoteKey, previousCount) {
|
|
45
|
+
getChain(remoteKey, headerKey, previousCount) {
|
|
44
46
|
const sharedKey = crypto_1.default.ECDH.scalarMult(this.keyPair.secretKey, remoteKey);
|
|
45
47
|
if (!this.rootKey)
|
|
46
48
|
this.rootKey = crypto_1.default.hash(sharedKey);
|
|
47
|
-
const hashkey = crypto_1.default.hkdf(sharedKey, this.rootKey, KeySession.info, KeySession.keyLength *
|
|
49
|
+
const hashkey = crypto_1.default.hkdf(sharedKey, this.rootKey, KeySession.info, KeySession.keyLength * 3);
|
|
48
50
|
this.rootKey = hashkey.subarray(0, KeySession.keyLength);
|
|
49
|
-
return new KeyChain(this.publicKey, remoteKey, hashkey.subarray(KeySession.keyLength), previousCount);
|
|
51
|
+
return new KeyChain(this.publicKey, remoteKey, hashkey.subarray(KeySession.keyLength, KeySession.keyLength * 2), hashkey.subarray(KeySession.keyLength * 2), headerKey, previousCount);
|
|
52
|
+
}
|
|
53
|
+
getHeaderKeys() {
|
|
54
|
+
var _a, _b, _c;
|
|
55
|
+
return {
|
|
56
|
+
sending: (_a = this.sendingChain) === null || _a === void 0 ? void 0 : _a.headerKey,
|
|
57
|
+
receiving: (_b = this.nextHeaderKey) !== null && _b !== void 0 ? _b : (_c = this.receivingChain) === null || _c === void 0 ? void 0 : _c.headerKey
|
|
58
|
+
};
|
|
50
59
|
}
|
|
51
60
|
getSendingKey() {
|
|
52
61
|
if (!this.sendingChain)
|
|
@@ -61,16 +70,17 @@ class KeySession {
|
|
|
61
70
|
};
|
|
62
71
|
}
|
|
63
72
|
getReceivingKey(encryptionKeys) {
|
|
64
|
-
var _a, _b, _c;
|
|
73
|
+
var _a, _b, _c, _d, _e, _f;
|
|
65
74
|
if (!this.previousKeys.has((0, utils_1.decodeBase64)(encryptionKeys.publicKey) + encryptionKeys.count.toString())) {
|
|
66
75
|
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
76
|
while (this.receivingChain && this.receivingChain.count < encryptionKeys.previous) {
|
|
68
77
|
const key = this.receivingChain.getKey();
|
|
69
78
|
this.previousKeys.set((0, utils_1.decodeBase64)(this.receivingChain.remoteKey) + this.receivingChain.count.toString(), key);
|
|
70
79
|
}
|
|
71
|
-
this.receivingChain = this.getChain(encryptionKeys.publicKey);
|
|
80
|
+
this.receivingChain = this.getChain(encryptionKeys.publicKey, (_c = this.nextHeaderKey) !== null && _c !== void 0 ? _c : (_d = this.receivingChain) === null || _d === void 0 ? void 0 : _d.nextHeaderKey);
|
|
81
|
+
this.nextHeaderKey = undefined;
|
|
72
82
|
this.keyPair = crypto_1.default.ECDH.keyPair();
|
|
73
|
-
this.sendingChain = this.getChain(encryptionKeys.publicKey, (
|
|
83
|
+
this.sendingChain = this.getChain(encryptionKeys.publicKey, (_e = this.sendingChain) === null || _e === void 0 ? void 0 : _e.nextHeaderKey, (_f = this.sendingChain) === null || _f === void 0 ? void 0 : _f.count);
|
|
74
84
|
}
|
|
75
85
|
if (!this.receivingChain)
|
|
76
86
|
throw new Error("Error initializing receivingChain");
|
|
@@ -122,10 +132,12 @@ KeySession.version = 1;
|
|
|
122
132
|
KeySession.info = "/freesignal/double-ratchet/v0." + KeySession.version;
|
|
123
133
|
KeySession.maxCount = 65536;
|
|
124
134
|
class KeyChain {
|
|
125
|
-
constructor(publicKey, remoteKey, chainKey, previousCount = 0) {
|
|
135
|
+
constructor(publicKey, remoteKey, chainKey, nextHeaderKey, headerKey, previousCount = 0) {
|
|
126
136
|
this.publicKey = publicKey;
|
|
127
137
|
this.remoteKey = remoteKey;
|
|
128
138
|
this.chainKey = chainKey;
|
|
139
|
+
this.nextHeaderKey = nextHeaderKey;
|
|
140
|
+
this.headerKey = headerKey;
|
|
129
141
|
this.previousCount = previousCount;
|
|
130
142
|
this._count = 0;
|
|
131
143
|
}
|
|
@@ -147,12 +159,14 @@ class KeyChain {
|
|
|
147
159
|
publicKey: (0, utils_1.decodeBase64)(this.publicKey),
|
|
148
160
|
remoteKey: (0, utils_1.decodeBase64)(this.remoteKey),
|
|
149
161
|
chainKey: (0, utils_1.decodeBase64)(this.chainKey),
|
|
162
|
+
nextHeaderKey: (0, utils_1.decodeBase64)(this.nextHeaderKey),
|
|
163
|
+
headerKey: this.headerKey ? (0, utils_1.decodeBase64)(this.headerKey) : undefined,
|
|
150
164
|
count: this.count,
|
|
151
165
|
previousCount: this.previousCount
|
|
152
166
|
};
|
|
153
167
|
}
|
|
154
168
|
static from(obj) {
|
|
155
|
-
const chain = new KeyChain((0, utils_1.encodeBase64)(obj.publicKey), (0, utils_1.encodeBase64)(obj.remoteKey), (0, utils_1.encodeBase64)(obj.chainKey), obj.previousCount);
|
|
169
|
+
const chain = new KeyChain((0, utils_1.encodeBase64)(obj.publicKey), (0, utils_1.encodeBase64)(obj.remoteKey), (0, utils_1.encodeBase64)(obj.chainKey), (0, utils_1.encodeBase64)(obj.nextHeaderKey), obj.headerKey ? (0, utils_1.encodeBase64)(obj.headerKey) : undefined, obj.previousCount);
|
|
156
170
|
chain._count = obj.count;
|
|
157
171
|
return chain;
|
|
158
172
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { LocalStorage, Crypto, Database, KeyExchangeDataBundle } from "@freesignal/interfaces";
|
|
20
20
|
import { ExportedKeySession } from "./double-ratchet";
|
|
21
21
|
import { IdentityKey, PrivateIdentityKey } from "./types";
|
|
22
|
-
import { FreeSignalNode } from "./node";
|
|
22
|
+
import { BootstrapRequest, FreeSignalNode } from "./node";
|
|
23
23
|
/**
|
|
24
24
|
* Creates a new Double Ratchet session for secure message exchange.
|
|
25
25
|
*
|
|
@@ -48,5 +48,6 @@ export declare function createNode(storage: Database<{
|
|
|
48
48
|
keyExchange: LocalStorage<string, Crypto.KeyPair>;
|
|
49
49
|
users: LocalStorage<string, IdentityKey>;
|
|
50
50
|
bundles: LocalStorage<string, KeyExchangeDataBundle>;
|
|
51
|
+
bootstraps: LocalStorage<string, BootstrapRequest>;
|
|
51
52
|
}>, privateIdentityKey?: PrivateIdentityKey): FreeSignalNode;
|
|
52
53
|
export * from "./types";
|
package/dist/node.d.ts
CHANGED
|
@@ -17,20 +17,19 @@
|
|
|
17
17
|
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
18
18
|
*/
|
|
19
19
|
import { Database, LocalStorage, Crypto, KeyExchangeDataBundle, KeyExchangeData } from "@freesignal/interfaces";
|
|
20
|
-
import { Datagram, IdentityKey, PrivateIdentityKey, Protocols, UserId } from "./types";
|
|
20
|
+
import { Datagram, DatagramHeader, IdentityKey, PrivateIdentityKey, Protocols, UserId } from "./types";
|
|
21
21
|
import { KeyExchange } from "./x3dh";
|
|
22
22
|
import { ExportedKeySession, KeySession } from "./double-ratchet";
|
|
23
|
-
declare class BootstrapRequest {
|
|
23
|
+
export declare class BootstrapRequest {
|
|
24
24
|
#private;
|
|
25
25
|
readonly senderId: UserId | string;
|
|
26
|
-
readonly data
|
|
27
|
-
|
|
28
|
-
constructor(senderId: UserId | string, data: KeyExchangeData, acceptFn: (data: KeyExchangeData) => Promise<Datagram>);
|
|
26
|
+
private readonly data;
|
|
27
|
+
constructor(senderId: UserId | string, data: KeyExchangeData);
|
|
29
28
|
get status(): "pending" | "accepted" | "denied";
|
|
30
|
-
|
|
29
|
+
get(): Promise<KeyExchangeData | undefined>;
|
|
30
|
+
accept(): Promise<KeyExchangeData | undefined>;
|
|
31
31
|
deny(): void;
|
|
32
32
|
}
|
|
33
|
-
type OpenFnReturns = Uint8Array | UserId | Datagram | UserId | KeyExchangeData | undefined | void;
|
|
34
33
|
export declare class FreeSignalNode {
|
|
35
34
|
protected readonly privateIdentityKey: PrivateIdentityKey;
|
|
36
35
|
protected readonly sessions: SessionMap;
|
|
@@ -38,16 +37,18 @@ export declare class FreeSignalNode {
|
|
|
38
37
|
protected readonly bundles: LocalStorage<string, KeyExchangeDataBundle>;
|
|
39
38
|
protected readonly keyExchange: KeyExchange;
|
|
40
39
|
protected readonly discovers: Set<string>;
|
|
41
|
-
protected readonly bootstraps:
|
|
40
|
+
protected readonly bootstraps: LocalStorage<string, BootstrapRequest>;
|
|
42
41
|
constructor(storage: Database<{
|
|
43
42
|
sessions: LocalStorage<string, ExportedKeySession>;
|
|
44
43
|
keyExchange: LocalStorage<string, Crypto.KeyPair>;
|
|
45
44
|
users: LocalStorage<string, IdentityKey>;
|
|
46
45
|
bundles: LocalStorage<string, KeyExchangeDataBundle>;
|
|
46
|
+
bootstraps: LocalStorage<string, BootstrapRequest>;
|
|
47
47
|
}>, privateIdentityKey?: PrivateIdentityKey);
|
|
48
48
|
get identityKey(): IdentityKey;
|
|
49
49
|
get userId(): UserId;
|
|
50
|
-
|
|
50
|
+
onRequest: (request: BootstrapRequest) => void;
|
|
51
|
+
getRequest(userId: string): Promise<KeyExchangeData | undefined>;
|
|
51
52
|
protected encrypt(receiverId: string | UserId, protocol: Protocols, data: Uint8Array): Promise<Datagram>;
|
|
52
53
|
packHandshake(data: KeyExchangeData): Promise<Datagram>;
|
|
53
54
|
packData<T>(receiverId: string | UserId, data: T): Promise<Datagram>;
|
|
@@ -55,7 +56,16 @@ export declare class FreeSignalNode {
|
|
|
55
56
|
packDiscover(receiverId: string | UserId, discoverId: string | UserId): Promise<Datagram>;
|
|
56
57
|
packBootstrap(receiverId: string | UserId): Promise<Datagram>;
|
|
57
58
|
protected decrypt(datagram: Datagram): Promise<Uint8Array>;
|
|
58
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Open the datagram and execute operation of Discover and Handshake.
|
|
61
|
+
*
|
|
62
|
+
* @param datagram
|
|
63
|
+
* @returns Header and decrypted payload
|
|
64
|
+
*/
|
|
65
|
+
open(datagram: Datagram | Uint8Array): Promise<{
|
|
66
|
+
header: DatagramHeader;
|
|
67
|
+
payload?: Uint8Array;
|
|
68
|
+
}>;
|
|
59
69
|
}
|
|
60
70
|
declare class SessionMap implements LocalStorage<string, KeySession> {
|
|
61
71
|
readonly storage: LocalStorage<string, ExportedKeySession>;
|
package/dist/node.js
CHANGED
|
@@ -39,28 +39,31 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
39
39
|
};
|
|
40
40
|
var _BootstrapRequest_status;
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.FreeSignalNode = void 0;
|
|
42
|
+
exports.FreeSignalNode = exports.BootstrapRequest = void 0;
|
|
43
43
|
const types_1 = require("./types");
|
|
44
44
|
const x3dh_1 = require("./x3dh");
|
|
45
45
|
const double_ratchet_1 = require("./double-ratchet");
|
|
46
46
|
const _1 = require(".");
|
|
47
47
|
const utils_1 = require("@freesignal/utils");
|
|
48
48
|
class BootstrapRequest {
|
|
49
|
-
constructor(senderId, data
|
|
49
|
+
constructor(senderId, data) {
|
|
50
50
|
this.senderId = senderId;
|
|
51
51
|
this.data = data;
|
|
52
|
-
this.acceptFn = acceptFn;
|
|
53
52
|
_BootstrapRequest_status.set(this, 'pending');
|
|
54
53
|
}
|
|
55
54
|
get status() {
|
|
56
55
|
return __classPrivateFieldGet(this, _BootstrapRequest_status, "f");
|
|
57
56
|
}
|
|
57
|
+
get() {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
return __classPrivateFieldGet(this, _BootstrapRequest_status, "f") === 'accepted' ? this.data : undefined;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
58
62
|
accept() {
|
|
59
63
|
return __awaiter(this, void 0, void 0, function* () {
|
|
60
64
|
if (this.status === 'pending')
|
|
61
65
|
__classPrivateFieldSet(this, _BootstrapRequest_status, 'accepted', "f");
|
|
62
|
-
|
|
63
|
-
return yield this.acceptFn(this.data);
|
|
66
|
+
return yield this.get();
|
|
64
67
|
});
|
|
65
68
|
}
|
|
66
69
|
deny() {
|
|
@@ -69,16 +72,18 @@ class BootstrapRequest {
|
|
|
69
72
|
return;
|
|
70
73
|
}
|
|
71
74
|
}
|
|
75
|
+
exports.BootstrapRequest = BootstrapRequest;
|
|
72
76
|
_BootstrapRequest_status = new WeakMap();
|
|
73
77
|
class FreeSignalNode {
|
|
74
78
|
constructor(storage, privateIdentityKey) {
|
|
75
79
|
this.discovers = new Set();
|
|
76
|
-
this.
|
|
80
|
+
this.onRequest = () => { };
|
|
77
81
|
this.privateIdentityKey = privateIdentityKey !== null && privateIdentityKey !== void 0 ? privateIdentityKey : (0, _1.createIdentity)();
|
|
78
82
|
this.sessions = new SessionMap(storage.sessions);
|
|
79
83
|
this.keyExchange = new x3dh_1.KeyExchange(storage.keyExchange, this.privateIdentityKey);
|
|
80
84
|
this.users = storage.users;
|
|
81
85
|
this.bundles = storage.bundles;
|
|
86
|
+
this.bootstraps = storage.bootstraps;
|
|
82
87
|
}
|
|
83
88
|
get identityKey() {
|
|
84
89
|
return this.privateIdentityKey.identityKey;
|
|
@@ -86,8 +91,11 @@ class FreeSignalNode {
|
|
|
86
91
|
get userId() {
|
|
87
92
|
return types_1.UserId.fromKey(this.identityKey);
|
|
88
93
|
}
|
|
89
|
-
|
|
90
|
-
return
|
|
94
|
+
getRequest(userId) {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
var _a;
|
|
97
|
+
return (_a = (yield this.bootstraps.get(userId))) === null || _a === void 0 ? void 0 : _a.get();
|
|
98
|
+
});
|
|
91
99
|
}
|
|
92
100
|
encrypt(receiverId, protocol, data) {
|
|
93
101
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -152,10 +160,19 @@ class FreeSignalNode {
|
|
|
152
160
|
return decrypted;
|
|
153
161
|
});
|
|
154
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Open the datagram and execute operation of Discover and Handshake.
|
|
165
|
+
*
|
|
166
|
+
* @param datagram
|
|
167
|
+
* @returns Header and decrypted payload
|
|
168
|
+
*/
|
|
155
169
|
open(datagram) {
|
|
156
170
|
return __awaiter(this, void 0, void 0, function* () {
|
|
157
171
|
if (datagram instanceof Uint8Array)
|
|
158
172
|
datagram = types_1.Datagram.from(datagram);
|
|
173
|
+
let out = {
|
|
174
|
+
header: types_1.DatagramHeader.from(datagram.header)
|
|
175
|
+
};
|
|
159
176
|
switch (datagram.protocol) {
|
|
160
177
|
case types_1.Protocols.HANDSHAKE:
|
|
161
178
|
if (!datagram.payload)
|
|
@@ -168,11 +185,13 @@ class FreeSignalNode {
|
|
|
168
185
|
yield this.users.set(userId.toString(), identityKey);
|
|
169
186
|
yield this.sessions.set(userId.toString(), session);
|
|
170
187
|
yield this.bundles.set(userId.toString(), (0, utils_1.decodeData)(associatedData));
|
|
171
|
-
return;
|
|
188
|
+
return out;
|
|
172
189
|
case types_1.Protocols.MESSAGE:
|
|
173
|
-
|
|
190
|
+
out.payload = yield this.decrypt(datagram);
|
|
191
|
+
return out;
|
|
174
192
|
case types_1.Protocols.RELAY:
|
|
175
|
-
|
|
193
|
+
out.payload = yield this.decrypt(datagram);
|
|
194
|
+
return out;
|
|
176
195
|
case types_1.Protocols.DISCOVER:
|
|
177
196
|
const message = (0, utils_1.decodeData)(yield this.decrypt(datagram));
|
|
178
197
|
if (message.type === types_1.DiscoverType.REQUEST && message.discoverId && !(yield this.users.has(message.discoverId))) {
|
|
@@ -183,12 +202,12 @@ class FreeSignalNode {
|
|
|
183
202
|
else {
|
|
184
203
|
const bundle = yield this.bundles.get(message.discoverId);
|
|
185
204
|
if (!bundle)
|
|
186
|
-
return;
|
|
205
|
+
return out;
|
|
187
206
|
const { version, identityKey, signedPreKey, signature } = bundle;
|
|
188
207
|
const onetimePreKey = bundle.onetimePreKeys.shift();
|
|
189
208
|
if (!onetimePreKey) {
|
|
190
209
|
yield this.bundles.delete(message.discoverId);
|
|
191
|
-
return;
|
|
210
|
+
return out;
|
|
192
211
|
}
|
|
193
212
|
data = {
|
|
194
213
|
version,
|
|
@@ -199,22 +218,31 @@ class FreeSignalNode {
|
|
|
199
218
|
};
|
|
200
219
|
}
|
|
201
220
|
const response = { type: types_1.DiscoverType.RESPONSE, discoverId: message.discoverId, data };
|
|
202
|
-
|
|
221
|
+
out.payload = (yield this.encrypt(datagram.sender, types_1.Protocols.DISCOVER, (0, utils_1.encodeData)(response))).toBytes();
|
|
203
222
|
}
|
|
204
223
|
else if (message.type === types_1.DiscoverType.RESPONSE && this.discovers.has(message.discoverId)) {
|
|
205
224
|
this.discovers.delete(message.discoverId);
|
|
206
|
-
|
|
225
|
+
if (message.data)
|
|
226
|
+
out.payload = (0, utils_1.encodeData)(message.data);
|
|
207
227
|
}
|
|
208
|
-
return;
|
|
228
|
+
return out;
|
|
209
229
|
case types_1.Protocols.BOOTSTRAP:
|
|
210
230
|
if (datagram.payload) {
|
|
211
231
|
const data = (0, utils_1.decodeData)(datagram.payload);
|
|
212
232
|
if (!(0, utils_1.compareBytes)(types_1.UserId.fromKey(data.identityKey).toBytes(), (0, utils_1.encodeBase64)(datagram.sender)))
|
|
213
|
-
|
|
214
|
-
|
|
233
|
+
new Error("Malicious bootstrap request");
|
|
234
|
+
const request = new BootstrapRequest(datagram.sender, data);
|
|
235
|
+
yield this.bootstraps.set(datagram.sender, request);
|
|
236
|
+
this.onRequest(request);
|
|
215
237
|
}
|
|
216
238
|
;
|
|
217
|
-
|
|
239
|
+
const request = yield this.bootstraps.get(datagram.sender);
|
|
240
|
+
if (request) {
|
|
241
|
+
const data = yield request.get();
|
|
242
|
+
if (data)
|
|
243
|
+
out.payload = (0, utils_1.encodeData)(data);
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
218
246
|
default:
|
|
219
247
|
throw new Error("Invalid protocol");
|
|
220
248
|
}
|
package/dist/test.js
CHANGED
|
@@ -8,34 +8,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
const utils_1 = require("@freesignal/utils");
|
|
16
12
|
const _1 = require(".");
|
|
17
|
-
const crypto_1 = __importDefault(require("@freesignal/crypto"));
|
|
18
13
|
console.log("FreeSignal protocol test");
|
|
19
|
-
const bob = (0, _1.createNode)({ keyExchange: new _1.AsyncMap(), sessions: new _1.AsyncMap(), users: new _1.AsyncMap(), bundles: new _1.AsyncMap() });
|
|
20
|
-
const alice = (0, _1.createNode)({ keyExchange: new _1.AsyncMap(), sessions: new _1.AsyncMap(), users: new _1.AsyncMap(), bundles: new _1.AsyncMap() });
|
|
14
|
+
const bob = (0, _1.createNode)({ keyExchange: new _1.AsyncMap(), sessions: new _1.AsyncMap(), users: new _1.AsyncMap(), bundles: new _1.AsyncMap(), bootstraps: new _1.AsyncMap() });
|
|
15
|
+
const alice = (0, _1.createNode)({ keyExchange: new _1.AsyncMap(), sessions: new _1.AsyncMap(), users: new _1.AsyncMap(), bundles: new _1.AsyncMap(), bootstraps: new _1.AsyncMap() });
|
|
21
16
|
setImmediate(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
17
|
const bobBootstrap = yield bob.packBootstrap(alice.userId);
|
|
18
|
+
alice.onRequest = (request) => { request.accept(); };
|
|
23
19
|
yield alice.open(bobBootstrap);
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
if (!aliceHandshake)
|
|
20
|
+
const bobRequest = yield alice.getRequest(bob.userId.toString());
|
|
21
|
+
if (!bobRequest)
|
|
27
22
|
throw new Error("Bootstrap Failed");
|
|
23
|
+
const aliceHandshake = yield alice.packHandshake(bobRequest);
|
|
28
24
|
yield bob.open(aliceHandshake);
|
|
29
25
|
const first = (yield bob.packData(alice.userId, "Hi Alice!")).toBytes();
|
|
30
|
-
console.log("Bob: ", yield alice.open(first));
|
|
26
|
+
console.log("Bob: ", (yield alice.open(first)).payload);
|
|
31
27
|
const second = yield alice.packData(bob.userId, "Hi Bob!");
|
|
32
|
-
console.log("Alice: ", yield bob.open(second));
|
|
28
|
+
console.log("Alice: ", (yield bob.open(second)).payload);
|
|
33
29
|
const third = yield Promise.all(["How are you?", "How are this days?", "For me it's a good time"].map(msg => bob.packData(alice.userId, msg)));
|
|
34
30
|
third.forEach((data) => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
-
console.log("Bob: ", yield alice.open(data));
|
|
31
|
+
console.log("Bob: ", (yield alice.open(data)).payload);
|
|
36
32
|
}));
|
|
37
33
|
const fourth = yield alice.packData(bob.userId, "Not so bad my man");
|
|
38
|
-
console.log("Alice: ", yield bob.open(fourth));
|
|
39
|
-
const testone =
|
|
40
|
-
console.log((
|
|
34
|
+
console.log("Alice: ", (yield bob.open(fourth)).payload);
|
|
35
|
+
//const testone = await Promise.all(Array(400).fill(0).map(() => alice.packData(bob.userId, decodeBase64(crypto.randomBytes(64)))));
|
|
36
|
+
//console.log(((await bob.open(testone[350])).payload));
|
|
41
37
|
}));
|
package/dist/types.d.ts
CHANGED
|
@@ -91,15 +91,19 @@ interface DatagramJSON {
|
|
|
91
91
|
export interface SignedDatagram extends Datagram {
|
|
92
92
|
signature: string;
|
|
93
93
|
}
|
|
94
|
-
export
|
|
94
|
+
export declare class DatagramHeader implements Encodable {
|
|
95
|
+
private static offset;
|
|
95
96
|
readonly id: string;
|
|
96
97
|
readonly version: number;
|
|
97
98
|
readonly sender: string;
|
|
98
99
|
readonly receiver: string;
|
|
99
100
|
readonly protocol: Protocols;
|
|
100
101
|
readonly createdAt: number;
|
|
102
|
+
private constructor();
|
|
103
|
+
toBytes(): Uint8Array;
|
|
104
|
+
static from(data: Uint8Array | string): DatagramHeader;
|
|
101
105
|
}
|
|
102
|
-
export declare class Datagram implements Encodable {
|
|
106
|
+
export declare class Datagram implements Encodable, DatagramHeader {
|
|
103
107
|
static version: number;
|
|
104
108
|
private _id;
|
|
105
109
|
private _version;
|
package/dist/types.js
CHANGED
|
@@ -30,7 +30,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
30
30
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
31
31
|
};
|
|
32
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
-
exports.AsyncMap = exports.EncryptedData = exports.Datagram = exports.Protocols = exports.DiscoverType = exports.PrivateIdentityKey = exports.IdentityKey = exports.UserId = void 0;
|
|
33
|
+
exports.AsyncMap = exports.EncryptedData = exports.Datagram = exports.DatagramHeader = exports.Protocols = exports.DiscoverType = exports.PrivateIdentityKey = exports.IdentityKey = exports.UserId = void 0;
|
|
34
34
|
exports.encryptData = encryptData;
|
|
35
35
|
exports.decryptData = decryptData;
|
|
36
36
|
const utils_1 = require("@freesignal/utils");
|
|
@@ -225,6 +225,26 @@ var Protocols;
|
|
|
225
225
|
Protocols.decode = decode;
|
|
226
226
|
})(Protocols || (exports.Protocols = Protocols = {}));
|
|
227
227
|
;
|
|
228
|
+
class DatagramHeader {
|
|
229
|
+
constructor(data) {
|
|
230
|
+
this.version = data[0] & 127;
|
|
231
|
+
this.protocol = Protocols.decode(data.subarray(1, 2));
|
|
232
|
+
this.id = crypto_1.default.UUID.stringify(data.subarray(2, 18));
|
|
233
|
+
this.createdAt = (0, utils_1.bytesToNumber)(data.subarray(18, 26));
|
|
234
|
+
this.sender = (0, utils_1.decodeBase64)(data.subarray(26, 26 + crypto_1.default.EdDSA.publicKeyLength));
|
|
235
|
+
this.receiver = (0, utils_1.decodeBase64)(data.subarray(26 + crypto_1.default.EdDSA.publicKeyLength, DatagramHeader.offset));
|
|
236
|
+
}
|
|
237
|
+
toBytes() {
|
|
238
|
+
return (0, utils_1.concatBytes)((0, utils_1.numberToBytes)(this.version, 1), Protocols.encode(this.protocol, 1), crypto_1.default.UUID.parse(this.protocol), (0, utils_1.numberToBytes)(this.createdAt, 8), (0, utils_1.encodeBase64)(this.sender), (0, utils_1.encodeBase64)(this.receiver));
|
|
239
|
+
}
|
|
240
|
+
static from(data) {
|
|
241
|
+
if (typeof data === 'string')
|
|
242
|
+
data = (0, utils_1.encodeBase64)(data);
|
|
243
|
+
return new DatagramHeader(data);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
exports.DatagramHeader = DatagramHeader;
|
|
247
|
+
DatagramHeader.offset = 26 + crypto_1.default.EdDSA.publicKeyLength * 2;
|
|
228
248
|
class Datagram {
|
|
229
249
|
constructor(sender, receiver, protocol, payload) {
|
|
230
250
|
this._id = crypto_1.default.UUID.generate().toString();
|
package/dist/x3dh.js
CHANGED
|
@@ -149,5 +149,5 @@ class KeyExchange {
|
|
|
149
149
|
}
|
|
150
150
|
exports.KeyExchange = KeyExchange;
|
|
151
151
|
KeyExchange.version = 1;
|
|
152
|
-
KeyExchange.hkdfInfo = "freesignal/x3dh/" + KeyExchange.version;
|
|
152
|
+
KeyExchange.hkdfInfo = "freesignal/x3dh/v." + KeyExchange.version;
|
|
153
153
|
KeyExchange.maxOPK = 10;
|