@vex-chat/libvex 5.1.0 → 5.3.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.
Files changed (142) hide show
  1. package/CLA.md +38 -0
  2. package/LICENSE-COMMERCIAL +10 -0
  3. package/LICENSING.md +15 -0
  4. package/README.md +8 -2
  5. package/dist/Client.d.ts +47 -3
  6. package/dist/Client.d.ts.map +1 -1
  7. package/dist/Client.js +998 -496
  8. package/dist/Client.js.map +1 -1
  9. package/dist/Storage.d.ts +5 -0
  10. package/dist/Storage.d.ts.map +1 -1
  11. package/dist/Storage.js +5 -0
  12. package/dist/Storage.js.map +1 -1
  13. package/dist/__tests__/harness/memory-storage.d.ts +7 -2
  14. package/dist/__tests__/harness/memory-storage.d.ts.map +1 -1
  15. package/dist/__tests__/harness/memory-storage.js +44 -29
  16. package/dist/__tests__/harness/memory-storage.js.map +1 -1
  17. package/dist/codec.d.ts +9 -9
  18. package/dist/codec.d.ts.map +1 -1
  19. package/dist/codec.js +17 -19
  20. package/dist/codec.js.map +1 -1
  21. package/dist/codecs.d.ts +5 -0
  22. package/dist/codecs.d.ts.map +1 -1
  23. package/dist/codecs.js +5 -0
  24. package/dist/codecs.js.map +1 -1
  25. package/dist/index.d.ts +5 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +5 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/keystore/memory.d.ts +5 -0
  30. package/dist/keystore/memory.d.ts.map +1 -1
  31. package/dist/keystore/memory.js +5 -0
  32. package/dist/keystore/memory.js.map +1 -1
  33. package/dist/keystore/node.d.ts +5 -0
  34. package/dist/keystore/node.d.ts.map +1 -1
  35. package/dist/keystore/node.js +16 -8
  36. package/dist/keystore/node.js.map +1 -1
  37. package/dist/preset/common.d.ts +5 -0
  38. package/dist/preset/common.d.ts.map +1 -1
  39. package/dist/preset/common.js +5 -0
  40. package/dist/preset/common.js.map +1 -1
  41. package/dist/preset/node.d.ts +5 -0
  42. package/dist/preset/node.d.ts.map +1 -1
  43. package/dist/preset/node.js +9 -1
  44. package/dist/preset/node.js.map +1 -1
  45. package/dist/preset/test.d.ts +5 -0
  46. package/dist/preset/test.d.ts.map +1 -1
  47. package/dist/preset/test.js +9 -1
  48. package/dist/preset/test.js.map +1 -1
  49. package/dist/storage/node/http-agents.d.ts +5 -0
  50. package/dist/storage/node/http-agents.d.ts.map +1 -1
  51. package/dist/storage/node/http-agents.js +5 -0
  52. package/dist/storage/node/http-agents.js.map +1 -1
  53. package/dist/storage/node.d.ts +6 -1
  54. package/dist/storage/node.d.ts.map +1 -1
  55. package/dist/storage/node.js +7 -4
  56. package/dist/storage/node.js.map +1 -1
  57. package/dist/storage/schema.d.ts +5 -0
  58. package/dist/storage/schema.d.ts.map +1 -1
  59. package/dist/storage/schema.js +5 -0
  60. package/dist/storage/schema.js.map +1 -1
  61. package/dist/storage/sqlite.d.ts +22 -4
  62. package/dist/storage/sqlite.d.ts.map +1 -1
  63. package/dist/storage/sqlite.js +172 -98
  64. package/dist/storage/sqlite.js.map +1 -1
  65. package/dist/transport/types.d.ts +5 -0
  66. package/dist/transport/types.d.ts.map +1 -1
  67. package/dist/transport/types.js +5 -0
  68. package/dist/transport/types.js.map +1 -1
  69. package/dist/transport/websocket.d.ts +5 -0
  70. package/dist/transport/websocket.d.ts.map +1 -1
  71. package/dist/transport/websocket.js +5 -0
  72. package/dist/transport/websocket.js.map +1 -1
  73. package/dist/types/crypto.d.ts +5 -0
  74. package/dist/types/crypto.d.ts.map +1 -1
  75. package/dist/types/crypto.js +3 -5
  76. package/dist/types/crypto.js.map +1 -1
  77. package/dist/types/identity.d.ts +5 -0
  78. package/dist/types/identity.d.ts.map +1 -1
  79. package/dist/types/identity.js +3 -2
  80. package/dist/types/identity.js.map +1 -1
  81. package/dist/types/index.d.ts +5 -0
  82. package/dist/types/index.d.ts.map +1 -1
  83. package/dist/types/index.js +5 -0
  84. package/dist/types/index.js.map +1 -1
  85. package/dist/utils/capitalize.d.ts +5 -0
  86. package/dist/utils/capitalize.d.ts.map +1 -1
  87. package/dist/utils/capitalize.js +5 -0
  88. package/dist/utils/capitalize.js.map +1 -1
  89. package/dist/utils/fipsMailExtra.d.ts +30 -0
  90. package/dist/utils/fipsMailExtra.d.ts.map +1 -0
  91. package/dist/utils/fipsMailExtra.js +114 -0
  92. package/dist/utils/fipsMailExtra.js.map +1 -0
  93. package/dist/utils/formatBytes.d.ts +5 -0
  94. package/dist/utils/formatBytes.d.ts.map +1 -1
  95. package/dist/utils/formatBytes.js +5 -0
  96. package/dist/utils/formatBytes.js.map +1 -1
  97. package/dist/utils/resolveAtRestAesKey.d.ts +13 -0
  98. package/dist/utils/resolveAtRestAesKey.d.ts.map +1 -0
  99. package/dist/utils/resolveAtRestAesKey.js +26 -0
  100. package/dist/utils/resolveAtRestAesKey.js.map +1 -0
  101. package/dist/utils/sqlSessionToCrypto.d.ts +5 -0
  102. package/dist/utils/sqlSessionToCrypto.d.ts.map +1 -1
  103. package/dist/utils/sqlSessionToCrypto.js +5 -0
  104. package/dist/utils/sqlSessionToCrypto.js.map +1 -1
  105. package/dist/utils/uint8uuid.d.ts +5 -0
  106. package/dist/utils/uint8uuid.d.ts.map +1 -1
  107. package/dist/utils/uint8uuid.js +5 -0
  108. package/dist/utils/uint8uuid.js.map +1 -1
  109. package/package.json +10 -3
  110. package/src/Client.ts +1281 -642
  111. package/src/Storage.ts +6 -0
  112. package/src/__tests__/codec.test.ts +6 -0
  113. package/src/__tests__/harness/fixtures.ts +6 -0
  114. package/src/__tests__/harness/memory-storage.ts +72 -52
  115. package/src/__tests__/harness/platform-transports.ts +6 -0
  116. package/src/__tests__/harness/poison-node-imports.ts +6 -0
  117. package/src/__tests__/harness/shared-suite.ts +288 -124
  118. package/src/__tests__/platform-browser.test.ts +15 -1
  119. package/src/__tests__/platform-node.test.ts +17 -3
  120. package/src/codec.ts +21 -8
  121. package/src/codecs.ts +6 -0
  122. package/src/index.ts +6 -0
  123. package/src/keystore/memory.ts +6 -0
  124. package/src/keystore/node.ts +27 -13
  125. package/src/preset/common.ts +6 -0
  126. package/src/preset/node.ts +14 -1
  127. package/src/preset/test.ts +14 -1
  128. package/src/storage/node/http-agents.ts +6 -0
  129. package/src/storage/node.ts +11 -4
  130. package/src/storage/schema.ts +6 -0
  131. package/src/storage/sqlite.ts +208 -135
  132. package/src/transport/types.ts +6 -0
  133. package/src/transport/websocket.ts +6 -0
  134. package/src/types/crypto.ts +6 -0
  135. package/src/types/identity.ts +6 -0
  136. package/src/types/index.ts +6 -0
  137. package/src/utils/capitalize.ts +6 -0
  138. package/src/utils/fipsMailExtra.ts +164 -0
  139. package/src/utils/formatBytes.ts +6 -0
  140. package/src/utils/resolveAtRestAesKey.ts +39 -0
  141. package/src/utils/sqlSessionToCrypto.ts +6 -0
  142. package/src/utils/uint8uuid.ts +6 -0
package/src/Storage.ts CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Message, Session } from "./index.js";
2
8
  import type {
3
9
  PreKeysCrypto,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import fc from "fast-check";
2
8
  /**
3
9
  * Property-based round-trip tests for msgpack codec.
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  /**
2
8
  * Inline test fixtures — no fs needed, works on all platforms.
3
9
  */
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Message } from "../../index.js";
2
8
  import type { Storage } from "../../Storage.js";
3
9
  import type {
@@ -8,12 +14,13 @@ import type {
8
14
  import type { Device, PreKeysSQL, SessionSQL } from "@vex-chat/types";
9
15
 
10
16
  import {
11
- type KeyPair,
17
+ getCryptoProfile,
12
18
  xBoxKeyPairFromSecret,
13
- XKeyConvert,
19
+ xBoxKeyPairFromSecretAsync,
14
20
  xSecretbox,
21
+ xSecretboxAsync,
15
22
  xSecretboxOpen,
16
- xSignKeyPairFromSecret,
23
+ xSecretboxOpenAsync,
17
24
  XUtils,
18
25
  } from "@vex-chat/crypto";
19
26
 
@@ -28,7 +35,7 @@ import { EventEmitter } from "eventemitter3";
28
35
  export class MemoryStorage extends EventEmitter implements Storage {
29
36
  public ready = false;
30
37
  private readonly devices: Device[] = [];
31
- private readonly idKeys: KeyPair;
38
+ private readonly atRestAesKey: Uint8Array;
32
39
  private messages: Message[] = [];
33
40
  private nextOtkIndex = 1;
34
41
  private nextPreKeyIndex = 1;
@@ -36,13 +43,12 @@ export class MemoryStorage extends EventEmitter implements Storage {
36
43
  private preKeys: any[] = [];
37
44
  private sessions: SessionSQL[] = [];
38
45
 
39
- constructor(SK: string) {
46
+ constructor(atRestAesKey: Uint8Array) {
40
47
  super();
41
- const idKeys = XKeyConvert.convertKeyPair(
42
- xSignKeyPairFromSecret(XUtils.decodeHex(SK)),
43
- );
44
- if (!idKeys) throw new Error("Can't convert SK!");
45
- this.idKeys = idKeys;
48
+ if (atRestAesKey.length !== 32) {
49
+ throw new Error("MemoryStorage requires a 32-byte atRestAes key.");
50
+ }
51
+ this.atRestAesKey = atRestAesKey;
46
52
  }
47
53
 
48
54
  close(): Promise<void> {
@@ -84,49 +90,51 @@ export class MemoryStorage extends EventEmitter implements Storage {
84
90
  );
85
91
  }
86
92
 
87
- getGroupHistory(channelID: string): Promise<Message[]> {
88
- return Promise.resolve(
89
- this.messages
90
- .filter((m) => m.group === channelID)
91
- .map((m) => this.decryptMessage(m)),
92
- );
93
+ async getGroupHistory(channelID: string): Promise<Message[]> {
94
+ const rows = this.messages.filter((m) => m.group === channelID);
95
+ return Promise.all(rows.map((m) => this.decryptMessage(m)));
93
96
  }
94
97
 
95
- getMessageHistory(userID: string): Promise<Message[]> {
96
- return Promise.resolve(
97
- this.messages
98
- .filter(
99
- (m) =>
100
- (m.direction === "incoming" &&
101
- m.authorID === userID &&
102
- !m.group) ||
103
- (m.direction === "outgoing" &&
104
- m.readerID === userID &&
105
- !m.group),
106
- )
107
- .map((m) => this.decryptMessage(m)),
98
+ async getMessageHistory(userID: string): Promise<Message[]> {
99
+ const rows = this.messages.filter(
100
+ (m) =>
101
+ (m.direction === "incoming" &&
102
+ m.authorID === userID &&
103
+ !m.group) ||
104
+ (m.direction === "outgoing" &&
105
+ m.readerID === userID &&
106
+ !m.group),
108
107
  );
108
+ return Promise.all(rows.map((m) => this.decryptMessage(m)));
109
109
  }
110
110
 
111
- getOneTimeKey(index: number): Promise<null | PreKeysCrypto> {
111
+ async getOneTimeKey(index: number): Promise<null | PreKeysCrypto> {
112
112
  const otk = this.oneTimeKeys.find((k) => k.index === index);
113
113
  if (!otk || !otk.privateKey) return Promise.resolve(null);
114
- return Promise.resolve({
114
+ const sk = XUtils.decodeHex(otk.privateKey);
115
+ return {
115
116
  index: otk.index,
116
- keyPair: xBoxKeyPairFromSecret(XUtils.decodeHex(otk.privateKey)),
117
+ keyPair:
118
+ getCryptoProfile() === "fips"
119
+ ? await xBoxKeyPairFromSecretAsync(sk)
120
+ : xBoxKeyPairFromSecret(sk),
117
121
  signature: XUtils.decodeHex(otk.signature),
118
- });
122
+ };
119
123
  }
120
124
 
121
- getPreKeys(): Promise<null | PreKeysCrypto> {
125
+ async getPreKeys(): Promise<null | PreKeysCrypto> {
122
126
  if (this.preKeys.length === 0) return Promise.resolve(null);
123
127
  const pk = this.preKeys[0];
124
128
  if (!pk.privateKey) return Promise.resolve(null);
125
- return Promise.resolve({
129
+ const sk = XUtils.decodeHex(pk.privateKey);
130
+ return {
126
131
  index: pk.index,
127
- keyPair: xBoxKeyPairFromSecret(XUtils.decodeHex(pk.privateKey)),
132
+ keyPair:
133
+ getCryptoProfile() === "fips"
134
+ ? await xBoxKeyPairFromSecretAsync(sk)
135
+ : xBoxKeyPairFromSecret(sk),
128
136
  signature: XUtils.decodeHex(pk.signature),
129
- });
137
+ };
130
138
  }
131
139
 
132
140
  getSessionByDeviceID(deviceID: string): Promise<null | SessionCrypto> {
@@ -182,17 +190,22 @@ export class MemoryStorage extends EventEmitter implements Storage {
182
190
  return Promise.resolve();
183
191
  }
184
192
 
185
- saveMessage(message: Message): Promise<void> {
193
+ async saveMessage(message: Message): Promise<void> {
186
194
  const copy = { ...message };
187
- copy.message = XUtils.encodeHex(
188
- xSecretbox(
189
- XUtils.decodeUTF8(message.message),
190
- XUtils.decodeHex(message.nonce),
191
- this.idKeys.secretKey,
192
- ),
193
- );
195
+ const fips = getCryptoProfile() === "fips";
196
+ const ct = fips
197
+ ? await xSecretboxAsync(
198
+ XUtils.decodeUTF8(message.message),
199
+ XUtils.decodeHex(message.nonce),
200
+ this.atRestAesKey,
201
+ )
202
+ : xSecretbox(
203
+ XUtils.decodeUTF8(message.message),
204
+ XUtils.decodeHex(message.nonce),
205
+ this.atRestAesKey,
206
+ );
207
+ copy.message = XUtils.encodeHex(ct);
194
208
  this.messages.push(copy);
195
- return Promise.resolve();
196
209
  }
197
210
 
198
211
  savePreKeys(
@@ -227,14 +240,21 @@ export class MemoryStorage extends EventEmitter implements Storage {
227
240
  return Promise.resolve();
228
241
  }
229
242
 
230
- private decryptMessage(msg: Message): Message {
243
+ private async decryptMessage(msg: Message): Promise<Message> {
231
244
  const copy = { ...msg };
232
245
  if (copy.decrypted) {
233
- const dec = xSecretboxOpen(
234
- XUtils.decodeHex(copy.message),
235
- XUtils.decodeHex(copy.nonce),
236
- this.idKeys.secretKey,
237
- );
246
+ const fips = getCryptoProfile() === "fips";
247
+ const dec = fips
248
+ ? await xSecretboxOpenAsync(
249
+ XUtils.decodeHex(copy.message),
250
+ XUtils.decodeHex(copy.nonce),
251
+ this.atRestAesKey,
252
+ )
253
+ : xSecretboxOpen(
254
+ XUtils.decodeHex(copy.message),
255
+ XUtils.decodeHex(copy.nonce),
256
+ this.atRestAesKey,
257
+ );
238
258
  if (dec) copy.message = XUtils.encodeUTF8(dec);
239
259
  }
240
260
  return copy;
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  /**
2
8
  * Shared test transport utilities — kept as a module boundary for
3
9
  * platform-specific test setup.
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import type { Plugin } from "vite";
2
8
 
3
9
  /**