@freesignal/protocol 0.4.3 → 0.4.4

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.
@@ -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
  }
@@ -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 * 2);
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, (_c = this.sendingChain) === null || _c === void 0 ? void 0 : _c.count);
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: KeyExchangeData;
27
- private readonly acceptFn;
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
- accept(): Promise<Datagram | undefined>;
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: Set<BootstrapRequest>;
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
- get requests(): BootstrapRequest[];
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
- open<T extends OpenFnReturns>(datagram: Datagram | Uint8Array): Promise<T>;
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, acceptFn) {
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
- if (__classPrivateFieldGet(this, _BootstrapRequest_status, "f") === 'accepted')
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.bootstraps = new Set();
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
- get requests() {
90
- return Array.from(this.bootstraps.values());
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
- return (0, utils_1.decodeData)(yield this.decrypt(datagram));
190
+ out.payload = (0, utils_1.decodeData)(yield this.decrypt(datagram));
191
+ return out;
174
192
  case types_1.Protocols.RELAY:
175
- return (0, utils_1.decodeData)(yield this.decrypt(datagram));
193
+ out.payload = (0, utils_1.decodeData)(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
- return yield this.encrypt(datagram.sender, types_1.Protocols.DISCOVER, (0, utils_1.encodeData)(response));
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
- return message.data;
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
- return;
214
- this.bootstraps.add(new BootstrapRequest(datagram.sender, data, (data) => this.packHandshake(data)));
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
- return;
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 bootstraps = yield Promise.all(alice.requests.map(request => request.accept()));
25
- const aliceHandshake = bootstraps.filter(value => (value === null || value === void 0 ? void 0 : value.receiver) === bob.userId.toString())[0];
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 = yield Promise.all(Array(400).fill(0).map(() => alice.packData(bob.userId, (0, utils_1.decodeBase64)(crypto_1.default.randomBytes(64)))));
40
- console.log((yield bob.open(testone[350])));
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 interface DatagramHeader {
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freesignal/protocol",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "Signal Protocol implementation in javascript",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "Christian Braghette",