@zapo-js/fake-server 0.3.0 → 1.0.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 (298) hide show
  1. package/README.md +3 -3
  2. package/dist/api/AppStateSyncManager.d.ts +0 -1
  3. package/dist/api/AppStateSyncManager.js +0 -1
  4. package/dist/api/FakePairingDriver.d.ts +0 -1
  5. package/dist/api/FakePairingDriver.js +0 -1
  6. package/dist/api/FakePeer.d.ts +77 -4
  7. package/dist/api/FakePeer.js +201 -1
  8. package/dist/api/FakeWaServer.d.ts +11 -1
  9. package/dist/api/FakeWaServer.js +34 -2
  10. package/dist/api/PreKeyDispenser.d.ts +0 -1
  11. package/dist/api/PreKeyDispenser.js +0 -1
  12. package/dist/api/Scenario.d.ts +0 -1
  13. package/dist/api/Scenario.js +0 -1
  14. package/dist/api/ServerRegistries.d.ts +0 -1
  15. package/dist/api/ServerRegistries.js +0 -1
  16. package/dist/api/iq-handlers.d.ts +0 -1
  17. package/dist/api/iq-handlers.js +0 -1
  18. package/dist/{cli.d.ts → bin.d.ts} +0 -1
  19. package/dist/{cli.js → bin.js} +1 -2
  20. package/dist/esm/api/AppStateSyncManager.js +146 -0
  21. package/dist/esm/api/FakePairingDriver.js +31 -0
  22. package/dist/esm/api/FakePeer.js +604 -0
  23. package/dist/esm/api/FakeWaServer.js +680 -0
  24. package/dist/esm/api/PreKeyDispenser.js +93 -0
  25. package/dist/esm/api/Scenario.js +32 -0
  26. package/dist/esm/api/ServerRegistries.js +261 -0
  27. package/dist/esm/api/iq-handlers.js +492 -0
  28. package/dist/esm/bin.js +246 -0
  29. package/dist/esm/index.js +26 -0
  30. package/dist/esm/infra/WaFakeConnection.js +49 -0
  31. package/dist/esm/infra/WaFakeConnectionPipeline.js +223 -0
  32. package/dist/esm/infra/WaFakeFrameSocket.js +117 -0
  33. package/dist/esm/infra/WaFakeMediaHttpsServer.js +126 -0
  34. package/dist/esm/infra/WaFakeNoiseHandshake.js +67 -0
  35. package/dist/esm/infra/WaFakeTransport.js +31 -0
  36. package/dist/esm/infra/WaFakeWsServer.js +96 -0
  37. package/dist/esm/package.json +3 -0
  38. package/dist/esm/protocol/auth/cert-chain.js +39 -0
  39. package/dist/esm/protocol/auth/client-payload-validate.js +55 -0
  40. package/dist/esm/protocol/auth/fake-primary-device.js +47 -0
  41. package/dist/esm/protocol/auth/pair-device.js +87 -0
  42. package/dist/esm/protocol/auth/success-node.js +26 -0
  43. package/dist/esm/protocol/iq/abprops.js +30 -0
  44. package/dist/esm/protocol/iq/appstate-sync.js +146 -0
  45. package/dist/esm/protocol/iq/business.js +59 -0
  46. package/dist/esm/protocol/iq/dirty-bits.js +19 -0
  47. package/dist/esm/protocol/iq/group-ops.js +154 -0
  48. package/dist/esm/protocol/iq/newsletter.js +14 -0
  49. package/dist/esm/protocol/iq/prekey-fetch.js +88 -0
  50. package/dist/esm/protocol/iq/privacy-token.js +26 -0
  51. package/dist/esm/protocol/iq/privacy.js +123 -0
  52. package/dist/esm/protocol/iq/profile.js +72 -0
  53. package/dist/esm/protocol/iq/router.js +111 -0
  54. package/dist/esm/protocol/iq/usync.js +64 -0
  55. package/dist/esm/protocol/push/app-state-key-share.js +26 -0
  56. package/dist/esm/protocol/push/call-failure.js +27 -0
  57. package/dist/esm/protocol/push/chatstate.js +23 -0
  58. package/dist/esm/protocol/push/error-stanza.js +13 -0
  59. package/dist/esm/protocol/push/history-sync.js +111 -0
  60. package/dist/esm/protocol/push/message.js +38 -0
  61. package/dist/esm/protocol/push/notification.js +29 -0
  62. package/dist/esm/protocol/push/presence.js +14 -0
  63. package/dist/esm/protocol/push/receipt.js +21 -0
  64. package/dist/esm/protocol/signal/fake-app-state-crypto.js +196 -0
  65. package/dist/esm/protocol/signal/fake-peer-double-ratchet.js +398 -0
  66. package/dist/esm/protocol/signal/fake-peer-group-recv-session.js +120 -0
  67. package/dist/esm/protocol/signal/fake-peer-identity.js +8 -0
  68. package/dist/esm/protocol/signal/fake-peer-key-bundle.js +25 -0
  69. package/dist/esm/protocol/signal/fake-sender-key.js +83 -0
  70. package/dist/esm/protocol/signal/prekey-upload.js +107 -0
  71. package/dist/esm/protocol/stream/stream-error.js +56 -0
  72. package/dist/esm/state/fake-app-state-collection.js +134 -0
  73. package/dist/esm/state/fake-media-store.js +53 -0
  74. package/dist/esm/transport/codec.js +8 -0
  75. package/dist/esm/transport/crypto.js +8 -0
  76. package/dist/esm/transport/protos.js +7 -0
  77. package/dist/esm/transport/util.js +8 -0
  78. package/dist/index.d.ts +0 -1
  79. package/dist/index.js +0 -1
  80. package/dist/infra/WaFakeConnection.d.ts +0 -1
  81. package/dist/infra/WaFakeConnection.js +0 -1
  82. package/dist/infra/WaFakeConnectionPipeline.d.ts +0 -1
  83. package/dist/infra/WaFakeConnectionPipeline.js +27 -24
  84. package/dist/infra/WaFakeFrameSocket.d.ts +0 -1
  85. package/dist/infra/WaFakeFrameSocket.js +0 -1
  86. package/dist/infra/WaFakeMediaHttpsServer.d.ts +0 -1
  87. package/dist/infra/WaFakeMediaHttpsServer.js +0 -1
  88. package/dist/infra/WaFakeNoiseHandshake.d.ts +8 -10
  89. package/dist/infra/WaFakeNoiseHandshake.js +19 -24
  90. package/dist/infra/WaFakeTransport.d.ts +2 -4
  91. package/dist/infra/WaFakeTransport.js +2 -1
  92. package/dist/infra/WaFakeWsServer.d.ts +0 -1
  93. package/dist/infra/WaFakeWsServer.js +0 -1
  94. package/dist/protocol/auth/cert-chain.d.ts +0 -1
  95. package/dist/protocol/auth/cert-chain.js +0 -1
  96. package/dist/protocol/auth/client-payload-validate.d.ts +0 -1
  97. package/dist/protocol/auth/client-payload-validate.js +0 -1
  98. package/dist/protocol/auth/fake-primary-device.d.ts +0 -1
  99. package/dist/protocol/auth/fake-primary-device.js +1 -3
  100. package/dist/protocol/auth/pair-device.d.ts +0 -1
  101. package/dist/protocol/auth/pair-device.js +4 -16
  102. package/dist/protocol/auth/success-node.d.ts +0 -1
  103. package/dist/protocol/auth/success-node.js +0 -1
  104. package/dist/protocol/iq/abprops.d.ts +0 -1
  105. package/dist/protocol/iq/abprops.js +0 -1
  106. package/dist/protocol/iq/appstate-sync.d.ts +0 -1
  107. package/dist/protocol/iq/appstate-sync.js +0 -1
  108. package/dist/protocol/iq/business.d.ts +0 -1
  109. package/dist/protocol/iq/business.js +0 -1
  110. package/dist/protocol/iq/dirty-bits.d.ts +0 -1
  111. package/dist/protocol/iq/dirty-bits.js +0 -1
  112. package/dist/protocol/iq/group-ops.d.ts +0 -1
  113. package/dist/protocol/iq/group-ops.js +0 -1
  114. package/dist/protocol/iq/newsletter.d.ts +0 -1
  115. package/dist/protocol/iq/newsletter.js +0 -1
  116. package/dist/protocol/iq/prekey-fetch.d.ts +0 -1
  117. package/dist/protocol/iq/prekey-fetch.js +0 -1
  118. package/dist/protocol/iq/privacy-token.d.ts +0 -1
  119. package/dist/protocol/iq/privacy-token.js +0 -1
  120. package/dist/protocol/iq/privacy.d.ts +0 -1
  121. package/dist/protocol/iq/privacy.js +15 -16
  122. package/dist/protocol/iq/profile.d.ts +0 -1
  123. package/dist/protocol/iq/profile.js +0 -1
  124. package/dist/protocol/iq/router.d.ts +0 -1
  125. package/dist/protocol/iq/router.js +0 -1
  126. package/dist/protocol/iq/usync.d.ts +0 -1
  127. package/dist/protocol/iq/usync.js +0 -1
  128. package/dist/protocol/push/app-state-key-share.d.ts +0 -1
  129. package/dist/protocol/push/app-state-key-share.js +0 -1
  130. package/dist/protocol/push/call-failure.d.ts +0 -1
  131. package/dist/protocol/push/call-failure.js +0 -1
  132. package/dist/protocol/push/chatstate.d.ts +0 -1
  133. package/dist/protocol/push/chatstate.js +0 -1
  134. package/dist/protocol/push/error-stanza.d.ts +0 -1
  135. package/dist/protocol/push/error-stanza.js +0 -1
  136. package/dist/protocol/push/history-sync.d.ts +0 -1
  137. package/dist/protocol/push/history-sync.js +0 -1
  138. package/dist/protocol/push/message.d.ts +0 -1
  139. package/dist/protocol/push/message.js +0 -1
  140. package/dist/protocol/push/notification.d.ts +0 -1
  141. package/dist/protocol/push/notification.js +0 -1
  142. package/dist/protocol/push/presence.d.ts +0 -1
  143. package/dist/protocol/push/presence.js +0 -1
  144. package/dist/protocol/push/receipt.d.ts +0 -1
  145. package/dist/protocol/push/receipt.js +0 -1
  146. package/dist/protocol/signal/fake-app-state-crypto.d.ts +7 -9
  147. package/dist/protocol/signal/fake-app-state-crypto.js +31 -33
  148. package/dist/protocol/signal/fake-peer-double-ratchet.d.ts +0 -1
  149. package/dist/protocol/signal/fake-peer-double-ratchet.js +23 -28
  150. package/dist/protocol/signal/fake-peer-group-recv-session.d.ts +0 -1
  151. package/dist/protocol/signal/fake-peer-group-recv-session.js +6 -10
  152. package/dist/protocol/signal/fake-peer-identity.d.ts +0 -1
  153. package/dist/protocol/signal/fake-peer-identity.js +0 -1
  154. package/dist/protocol/signal/fake-peer-key-bundle.d.ts +0 -1
  155. package/dist/protocol/signal/fake-peer-key-bundle.js +0 -1
  156. package/dist/protocol/signal/fake-sender-key.d.ts +0 -1
  157. package/dist/protocol/signal/fake-sender-key.js +5 -9
  158. package/dist/protocol/signal/prekey-upload.d.ts +0 -1
  159. package/dist/protocol/signal/prekey-upload.js +0 -1
  160. package/dist/protocol/stream/stream-error.d.ts +0 -1
  161. package/dist/protocol/stream/stream-error.js +0 -1
  162. package/dist/state/fake-app-state-collection.d.ts +0 -1
  163. package/dist/state/fake-app-state-collection.js +0 -1
  164. package/dist/state/fake-media-store.d.ts +0 -1
  165. package/dist/state/fake-media-store.js +2 -2
  166. package/dist/transport/codec.d.ts +2 -3
  167. package/dist/transport/codec.js +2 -3
  168. package/dist/transport/crypto.d.ts +5 -7
  169. package/dist/transport/crypto.js +6 -11
  170. package/dist/transport/protos.d.ts +2 -4
  171. package/dist/transport/protos.js +2 -4
  172. package/dist/transport/util.d.ts +8 -0
  173. package/dist/transport/util.js +15 -0
  174. package/package.json +21 -6
  175. package/dist/api/AppStateSyncManager.d.ts.map +0 -1
  176. package/dist/api/AppStateSyncManager.js.map +0 -1
  177. package/dist/api/FakePairingDriver.d.ts.map +0 -1
  178. package/dist/api/FakePairingDriver.js.map +0 -1
  179. package/dist/api/FakePeer.d.ts.map +0 -1
  180. package/dist/api/FakePeer.js.map +0 -1
  181. package/dist/api/FakeWaServer.d.ts.map +0 -1
  182. package/dist/api/FakeWaServer.js.map +0 -1
  183. package/dist/api/PreKeyDispenser.d.ts.map +0 -1
  184. package/dist/api/PreKeyDispenser.js.map +0 -1
  185. package/dist/api/Scenario.d.ts.map +0 -1
  186. package/dist/api/Scenario.js.map +0 -1
  187. package/dist/api/ServerRegistries.d.ts.map +0 -1
  188. package/dist/api/ServerRegistries.js.map +0 -1
  189. package/dist/api/iq-handlers.d.ts.map +0 -1
  190. package/dist/api/iq-handlers.js.map +0 -1
  191. package/dist/cli.d.ts.map +0 -1
  192. package/dist/cli.js.map +0 -1
  193. package/dist/index.d.ts.map +0 -1
  194. package/dist/index.js.map +0 -1
  195. package/dist/infra/WaFakeConnection.d.ts.map +0 -1
  196. package/dist/infra/WaFakeConnection.js.map +0 -1
  197. package/dist/infra/WaFakeConnectionPipeline.d.ts.map +0 -1
  198. package/dist/infra/WaFakeConnectionPipeline.js.map +0 -1
  199. package/dist/infra/WaFakeFrameSocket.d.ts.map +0 -1
  200. package/dist/infra/WaFakeFrameSocket.js.map +0 -1
  201. package/dist/infra/WaFakeMediaHttpsServer.d.ts.map +0 -1
  202. package/dist/infra/WaFakeMediaHttpsServer.js.map +0 -1
  203. package/dist/infra/WaFakeNoiseHandshake.d.ts.map +0 -1
  204. package/dist/infra/WaFakeNoiseHandshake.js.map +0 -1
  205. package/dist/infra/WaFakeTransport.d.ts.map +0 -1
  206. package/dist/infra/WaFakeTransport.js.map +0 -1
  207. package/dist/infra/WaFakeWsServer.d.ts.map +0 -1
  208. package/dist/infra/WaFakeWsServer.js.map +0 -1
  209. package/dist/protocol/auth/cert-chain.d.ts.map +0 -1
  210. package/dist/protocol/auth/cert-chain.js.map +0 -1
  211. package/dist/protocol/auth/client-payload-validate.d.ts.map +0 -1
  212. package/dist/protocol/auth/client-payload-validate.js.map +0 -1
  213. package/dist/protocol/auth/fake-primary-device.d.ts.map +0 -1
  214. package/dist/protocol/auth/fake-primary-device.js.map +0 -1
  215. package/dist/protocol/auth/pair-device.d.ts.map +0 -1
  216. package/dist/protocol/auth/pair-device.js.map +0 -1
  217. package/dist/protocol/auth/success-node.d.ts.map +0 -1
  218. package/dist/protocol/auth/success-node.js.map +0 -1
  219. package/dist/protocol/iq/abprops.d.ts.map +0 -1
  220. package/dist/protocol/iq/abprops.js.map +0 -1
  221. package/dist/protocol/iq/appstate-sync.d.ts.map +0 -1
  222. package/dist/protocol/iq/appstate-sync.js.map +0 -1
  223. package/dist/protocol/iq/business.d.ts.map +0 -1
  224. package/dist/protocol/iq/business.js.map +0 -1
  225. package/dist/protocol/iq/dirty-bits.d.ts.map +0 -1
  226. package/dist/protocol/iq/dirty-bits.js.map +0 -1
  227. package/dist/protocol/iq/group-ops.d.ts.map +0 -1
  228. package/dist/protocol/iq/group-ops.js.map +0 -1
  229. package/dist/protocol/iq/newsletter.d.ts.map +0 -1
  230. package/dist/protocol/iq/newsletter.js.map +0 -1
  231. package/dist/protocol/iq/prekey-fetch.d.ts.map +0 -1
  232. package/dist/protocol/iq/prekey-fetch.js.map +0 -1
  233. package/dist/protocol/iq/privacy-token.d.ts.map +0 -1
  234. package/dist/protocol/iq/privacy-token.js.map +0 -1
  235. package/dist/protocol/iq/privacy.d.ts.map +0 -1
  236. package/dist/protocol/iq/privacy.js.map +0 -1
  237. package/dist/protocol/iq/profile.d.ts.map +0 -1
  238. package/dist/protocol/iq/profile.js.map +0 -1
  239. package/dist/protocol/iq/router.d.ts.map +0 -1
  240. package/dist/protocol/iq/router.js.map +0 -1
  241. package/dist/protocol/iq/usync.d.ts.map +0 -1
  242. package/dist/protocol/iq/usync.js.map +0 -1
  243. package/dist/protocol/push/app-state-key-share.d.ts.map +0 -1
  244. package/dist/protocol/push/app-state-key-share.js.map +0 -1
  245. package/dist/protocol/push/call-failure.d.ts.map +0 -1
  246. package/dist/protocol/push/call-failure.js.map +0 -1
  247. package/dist/protocol/push/chatstate.d.ts.map +0 -1
  248. package/dist/protocol/push/chatstate.js.map +0 -1
  249. package/dist/protocol/push/error-stanza.d.ts.map +0 -1
  250. package/dist/protocol/push/error-stanza.js.map +0 -1
  251. package/dist/protocol/push/history-sync.d.ts.map +0 -1
  252. package/dist/protocol/push/history-sync.js.map +0 -1
  253. package/dist/protocol/push/message.d.ts.map +0 -1
  254. package/dist/protocol/push/message.js.map +0 -1
  255. package/dist/protocol/push/notification.d.ts.map +0 -1
  256. package/dist/protocol/push/notification.js.map +0 -1
  257. package/dist/protocol/push/presence.d.ts.map +0 -1
  258. package/dist/protocol/push/presence.js.map +0 -1
  259. package/dist/protocol/push/receipt.d.ts.map +0 -1
  260. package/dist/protocol/push/receipt.js.map +0 -1
  261. package/dist/protocol/signal/fake-app-state-crypto.d.ts.map +0 -1
  262. package/dist/protocol/signal/fake-app-state-crypto.js.map +0 -1
  263. package/dist/protocol/signal/fake-peer-double-ratchet.d.ts.map +0 -1
  264. package/dist/protocol/signal/fake-peer-double-ratchet.js.map +0 -1
  265. package/dist/protocol/signal/fake-peer-group-recv-session.d.ts.map +0 -1
  266. package/dist/protocol/signal/fake-peer-group-recv-session.js.map +0 -1
  267. package/dist/protocol/signal/fake-peer-identity.d.ts.map +0 -1
  268. package/dist/protocol/signal/fake-peer-identity.js.map +0 -1
  269. package/dist/protocol/signal/fake-peer-key-bundle.d.ts.map +0 -1
  270. package/dist/protocol/signal/fake-peer-key-bundle.js.map +0 -1
  271. package/dist/protocol/signal/fake-peer-recv-session.d.ts +0 -60
  272. package/dist/protocol/signal/fake-peer-recv-session.d.ts.map +0 -1
  273. package/dist/protocol/signal/fake-peer-recv-session.js +0 -284
  274. package/dist/protocol/signal/fake-peer-recv-session.js.map +0 -1
  275. package/dist/protocol/signal/fake-peer-session.d.ts +0 -87
  276. package/dist/protocol/signal/fake-peer-session.d.ts.map +0 -1
  277. package/dist/protocol/signal/fake-peer-session.js +0 -207
  278. package/dist/protocol/signal/fake-peer-session.js.map +0 -1
  279. package/dist/protocol/signal/fake-sender-key.d.ts.map +0 -1
  280. package/dist/protocol/signal/fake-sender-key.js.map +0 -1
  281. package/dist/protocol/signal/prekey-upload.d.ts.map +0 -1
  282. package/dist/protocol/signal/prekey-upload.js.map +0 -1
  283. package/dist/protocol/stream/stream-error.d.ts.map +0 -1
  284. package/dist/protocol/stream/stream-error.js.map +0 -1
  285. package/dist/state/fake-app-state-collection.d.ts.map +0 -1
  286. package/dist/state/fake-app-state-collection.js.map +0 -1
  287. package/dist/state/fake-media-store.d.ts.map +0 -1
  288. package/dist/state/fake-media-store.js.map +0 -1
  289. package/dist/transport/codec.d.ts.map +0 -1
  290. package/dist/transport/codec.js.map +0 -1
  291. package/dist/transport/crypto.d.ts.map +0 -1
  292. package/dist/transport/crypto.js.map +0 -1
  293. package/dist/transport/index.d.ts +0 -4
  294. package/dist/transport/index.d.ts.map +0 -1
  295. package/dist/transport/index.js +0 -20
  296. package/dist/transport/index.js.map +0 -1
  297. package/dist/transport/protos.d.ts.map +0 -1
  298. package/dist/transport/protos.js.map +0 -1
@@ -0,0 +1,120 @@
1
+ /** Receiver-side SenderKey session for group `skmsg` decrypt. */
2
+ import { aesCbcDecrypt, hkdf, hmacSha256Sign, toRawPubKey, toSerializedPubKey, xeddsaVerify } from '../../transport/crypto.js';
3
+ import { proto } from '../../transport/protos.js';
4
+ import { TEXT_ENCODER } from '../../transport/util.js';
5
+ const SIGNAL_GROUP_VERSION = 3;
6
+ const SIGNAL_SIGNATURE_LENGTH = 64;
7
+ const MESSAGE_KEY_LABEL = new Uint8Array([1]);
8
+ const CHAIN_KEY_LABEL = new Uint8Array([2]);
9
+ const WHISPER_GROUP_INFO = TEXT_ENCODER.encode('WhisperGroup');
10
+ export class FakePeerGroupRecvSessionError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = 'FakePeerGroupRecvSessionError';
14
+ }
15
+ }
16
+ export class FakePeerGroupRecvSession {
17
+ constructor() {
18
+ this.records = new Map();
19
+ }
20
+ addDistribution(groupId, senderJid, axolotlBytes) {
21
+ if (axolotlBytes.byteLength < 1) {
22
+ throw new FakePeerGroupRecvSessionError('SKDM payload empty');
23
+ }
24
+ const version = axolotlBytes[0] >>> 4;
25
+ if (version !== SIGNAL_GROUP_VERSION) {
26
+ throw new FakePeerGroupRecvSessionError(`unsupported SKDM version ${version}`);
27
+ }
28
+ const body = axolotlBytes.subarray(1);
29
+ const decoded = proto.SenderKeyDistributionMessage.decode(body);
30
+ if (decoded.id === null ||
31
+ decoded.id === undefined ||
32
+ decoded.iteration === null ||
33
+ decoded.iteration === undefined ||
34
+ !decoded.chainKey ||
35
+ !decoded.signingKey) {
36
+ throw new FakePeerGroupRecvSessionError('invalid SKDM');
37
+ }
38
+ if (decoded.chainKey.byteLength !== 32) {
39
+ throw new FakePeerGroupRecvSessionError(`SKDM chainKey must be 32 bytes, got ${decoded.chainKey.byteLength}`);
40
+ }
41
+ this.records.set(recordKey(groupId, senderJid), {
42
+ keyId: decoded.id,
43
+ nextIteration: decoded.iteration,
44
+ chainKey: decoded.chainKey,
45
+ signingPublicKey: toSerializedPubKey(decoded.signingKey)
46
+ });
47
+ }
48
+ async decryptGroupMessage(groupId, senderJid, skmsgBytes) {
49
+ const record = this.records.get(recordKey(groupId, senderJid));
50
+ if (!record) {
51
+ throw new FakePeerGroupRecvSessionError(`no senderkey state for group=${groupId} sender=${senderJid}`);
52
+ }
53
+ if (skmsgBytes.byteLength < 1 + SIGNAL_SIGNATURE_LENGTH) {
54
+ throw new FakePeerGroupRecvSessionError('skmsg too short');
55
+ }
56
+ const versionByte = skmsgBytes[0];
57
+ if (versionByte >>> 4 !== SIGNAL_GROUP_VERSION) {
58
+ throw new FakePeerGroupRecvSessionError(`unsupported skmsg version ${versionByte >>> 4}`);
59
+ }
60
+ const sigStart = skmsgBytes.byteLength - SIGNAL_SIGNATURE_LENGTH;
61
+ // xeddsaVerify mutates the signature buffer; isolate with copies.
62
+ const versionedContent = skmsgBytes.subarray(0, sigStart).slice();
63
+ const signature = skmsgBytes.subarray(sigStart).slice();
64
+ const protoBody = versionedContent.subarray(1);
65
+ const decoded = proto.SenderKeyMessage.decode(protoBody);
66
+ if (decoded.id === null ||
67
+ decoded.id === undefined ||
68
+ decoded.iteration === null ||
69
+ decoded.iteration === undefined ||
70
+ !decoded.ciphertext) {
71
+ throw new FakePeerGroupRecvSessionError('invalid SenderKeyMessage');
72
+ }
73
+ if (decoded.id !== record.keyId) {
74
+ throw new FakePeerGroupRecvSessionError(`senderKey id mismatch: got ${decoded.id}, expected ${record.keyId}`);
75
+ }
76
+ const validSignature = await xeddsaVerify(toRawPubKey(record.signingPublicKey), versionedContent, signature);
77
+ if (!validSignature) {
78
+ throw new FakePeerGroupRecvSessionError('invalid sender key signature');
79
+ }
80
+ const targetIteration = decoded.iteration;
81
+ if (targetIteration < record.nextIteration) {
82
+ throw new FakePeerGroupRecvSessionError(`out-of-order skmsg iteration ${targetIteration} < ${record.nextIteration}`);
83
+ }
84
+ let chainKey = record.chainKey;
85
+ let seed = null;
86
+ let iteration = record.nextIteration;
87
+ while (iteration <= targetIteration) {
88
+ const nextChainRaw = hmacSha256Sign(chainKey, CHAIN_KEY_LABEL);
89
+ const messageInputKey = hmacSha256Sign(chainKey, MESSAGE_KEY_LABEL);
90
+ const messageSeed = hkdf(messageInputKey, null, WHISPER_GROUP_INFO, 50);
91
+ if (iteration === targetIteration) {
92
+ seed = messageSeed;
93
+ }
94
+ chainKey = nextChainRaw.subarray(0, 32);
95
+ iteration += 1;
96
+ }
97
+ if (!seed) {
98
+ throw new FakePeerGroupRecvSessionError('failed to derive message seed');
99
+ }
100
+ record.chainKey = chainKey;
101
+ record.nextIteration = iteration;
102
+ const iv = seed.subarray(0, 16);
103
+ const keyBytes = seed.subarray(16, 48);
104
+ const padded = aesCbcDecrypt(keyBytes, iv, decoded.ciphertext);
105
+ return unpadPkcs7(padded);
106
+ }
107
+ }
108
+ function recordKey(groupId, senderJid) {
109
+ return `${groupId}\u0000${senderJid}`;
110
+ }
111
+ function unpadPkcs7(padded) {
112
+ if (padded.byteLength === 0)
113
+ return padded;
114
+ const padLen = padded[padded.byteLength - 1];
115
+ if (padLen === 0 || padLen > 16)
116
+ return padded;
117
+ if (padLen > padded.byteLength)
118
+ return padded;
119
+ return padded.subarray(0, padded.byteLength - padLen);
120
+ }
@@ -0,0 +1,8 @@
1
+ import { X25519 } from '../../transport/crypto.js';
2
+ export async function generateFakePeerIdentity() {
3
+ const identityKeyPair = await X25519.generateKeyPair();
4
+ return {
5
+ identityKeyPair,
6
+ registrationId: Math.floor(Math.random() * 0x3fff) + 1
7
+ };
8
+ }
@@ -0,0 +1,25 @@
1
+ /** Generates Signal prekey bundles for fake peers. */
2
+ import { toSerializedPubKey, X25519, xeddsaSign } from '../../transport/crypto.js';
3
+ export async function generateFakePeerKeyBundle(options = {}) {
4
+ const identityKeyPair = options.identityKeyPair ?? (await X25519.generateKeyPair());
5
+ const signedPreKeyKeyPair = await X25519.generateKeyPair();
6
+ const signedPreKeyId = options.signedPreKeyId ?? 1;
7
+ const signedPreKeySerialized = toSerializedPubKey(signedPreKeyKeyPair.pubKey);
8
+ const signedPreKeySignature = await xeddsaSign(identityKeyPair.privKey, signedPreKeySerialized);
9
+ const oneTimeCount = options.oneTimePreKeyCount ?? 4;
10
+ const firstId = options.firstOneTimePreKeyId ?? 1;
11
+ const oneTimePreKeys = await Promise.all(Array.from({ length: oneTimeCount }, async (_, idx) => ({
12
+ id: firstId + idx,
13
+ keyPair: await X25519.generateKeyPair()
14
+ })));
15
+ return {
16
+ registrationId: options.registrationId ?? Math.floor(Math.random() * 0x3fff) + 1,
17
+ identityKeyPair,
18
+ signedPreKey: {
19
+ id: signedPreKeyId,
20
+ keyPair: signedPreKeyKeyPair,
21
+ signature: signedPreKeySignature
22
+ },
23
+ oneTimePreKeys
24
+ };
25
+ }
@@ -0,0 +1,83 @@
1
+ /** SenderKey state used by fake peers for group encryption. */
2
+ import { aesCbcEncrypt, hkdf, hmacSha256Sign, prependVersion, randomBytesAsync, toSerializedPubKey, X25519, xeddsaSign } from '../../transport/crypto.js';
3
+ import { proto } from '../../transport/protos.js';
4
+ const SIGNAL_GROUP_VERSION = 3;
5
+ const WHISPER_GROUP_INFO = new TextEncoder().encode('WhisperGroup');
6
+ const MESSAGE_KEY_LABEL = new Uint8Array([1]);
7
+ const CHAIN_KEY_LABEL = new Uint8Array([2]);
8
+ export class FakeSenderKey {
9
+ constructor(state) {
10
+ this.state = state;
11
+ }
12
+ static async generate() {
13
+ const [chainKey, signingKeyPair, idBytes] = await Promise.all([
14
+ randomBytesAsync(32),
15
+ X25519.generateKeyPair(),
16
+ randomBytesAsync(4)
17
+ ]);
18
+ const id = ((idBytes[0] << 24) | (idBytes[1] << 16) | (idBytes[2] << 8) | idBytes[3]) >>> 0;
19
+ return new FakeSenderKey({
20
+ id,
21
+ chainKey,
22
+ iteration: 0,
23
+ signingKeyPair
24
+ });
25
+ }
26
+ get id() {
27
+ return this.state.id;
28
+ }
29
+ async encrypt(plaintext) {
30
+ const distributionMessage = this.buildDistributionMessage();
31
+ const { messageKey, nextChainKey } = await deriveSenderKeyMessageKey(this.state.iteration, this.state.chainKey);
32
+ const { iv, cipherKey } = splitSenderKeyMessageSeed(messageKey.seed);
33
+ const ciphertext = aesCbcEncrypt(cipherKey, iv, plaintext);
34
+ const senderKeyMessage = proto.SenderKeyMessage.encode({
35
+ id: this.state.id,
36
+ iteration: messageKey.iteration,
37
+ ciphertext
38
+ }).finish();
39
+ const versioned = prependVersion(senderKeyMessage, SIGNAL_GROUP_VERSION);
40
+ const signature = await xeddsaSign(this.state.signingKeyPair.privKey, versioned);
41
+ const finalCiphertext = new Uint8Array(versioned.byteLength + signature.byteLength);
42
+ finalCiphertext.set(versioned, 0);
43
+ finalCiphertext.set(signature, versioned.byteLength);
44
+ this.state = {
45
+ ...this.state,
46
+ chainKey: nextChainKey,
47
+ iteration: messageKey.iteration + 1
48
+ };
49
+ return {
50
+ ciphertext: finalCiphertext,
51
+ distributionMessage,
52
+ keyId: this.state.id
53
+ };
54
+ }
55
+ buildDistributionMessage() {
56
+ const proto1 = proto.SenderKeyDistributionMessage.encode({
57
+ id: this.state.id,
58
+ iteration: this.state.iteration,
59
+ chainKey: this.state.chainKey,
60
+ signingKey: toSerializedPubKey(this.state.signingKeyPair.pubKey)
61
+ }).finish();
62
+ return prependVersion(proto1, SIGNAL_GROUP_VERSION);
63
+ }
64
+ }
65
+ // eslint-disable-next-line @typescript-eslint/require-await
66
+ async function deriveSenderKeyMessageKey(iteration, chainKey) {
67
+ const messageInputKey = hmacSha256Sign(chainKey, MESSAGE_KEY_LABEL);
68
+ const nextChainRaw = hmacSha256Sign(chainKey, CHAIN_KEY_LABEL);
69
+ const seed = hkdf(messageInputKey, null, WHISPER_GROUP_INFO, 50);
70
+ return {
71
+ messageKey: { iteration, seed },
72
+ nextChainKey: nextChainRaw.subarray(0, 32)
73
+ };
74
+ }
75
+ function splitSenderKeyMessageSeed(seed) {
76
+ if (seed.byteLength < 48) {
77
+ throw new Error(`sender key message seed too short: ${seed.byteLength}`);
78
+ }
79
+ return {
80
+ iv: seed.subarray(0, 16),
81
+ cipherKey: seed.subarray(16, 48)
82
+ };
83
+ }
@@ -0,0 +1,107 @@
1
+ /** Parser for client prekey upload IQs (`xmlns=encrypt`, `type=set`). */
2
+ export class PreKeyUploadParseError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = 'PreKeyUploadParseError';
6
+ }
7
+ }
8
+ export function parsePreKeyUploadIq(iq) {
9
+ if (iq.tag !== 'iq') {
10
+ throw new PreKeyUploadParseError(`expected iq stanza, got ${iq.tag}`);
11
+ }
12
+ if (iq.attrs.xmlns !== 'encrypt' || iq.attrs.type !== 'set') {
13
+ throw new PreKeyUploadParseError(`expected iq with xmlns=encrypt type=set, got xmlns=${iq.attrs.xmlns} type=${iq.attrs.type}`);
14
+ }
15
+ const children = iq.content;
16
+ if (!Array.isArray(children)) {
17
+ throw new PreKeyUploadParseError('iq has no children');
18
+ }
19
+ const registrationNode = findChild(children, 'registration');
20
+ const identityNode = findChild(children, 'identity');
21
+ const listNode = findChild(children, 'list');
22
+ const skeyNode = findChild(children, 'skey');
23
+ const registrationId = readBigEndianInt(requireBytes(registrationNode?.content, 'registration'));
24
+ const identityKey = requireBytes(identityNode?.content, 'identity');
25
+ if (identityKey.byteLength !== 32) {
26
+ throw new PreKeyUploadParseError(`identity key must be 32 bytes, got ${identityKey.byteLength}`);
27
+ }
28
+ const signedPreKey = parseSignedPreKey(skeyNode);
29
+ const preKeys = parsePreKeyList(listNode);
30
+ return {
31
+ registrationId,
32
+ identityKey,
33
+ signedPreKey,
34
+ preKeys
35
+ };
36
+ }
37
+ function findChild(children, tag) {
38
+ for (const child of children) {
39
+ if (child.tag === tag)
40
+ return child;
41
+ }
42
+ return null;
43
+ }
44
+ function parseSignedPreKey(node) {
45
+ if (!node) {
46
+ throw new PreKeyUploadParseError('skey child missing');
47
+ }
48
+ if (!Array.isArray(node.content)) {
49
+ throw new PreKeyUploadParseError('skey has no inner nodes');
50
+ }
51
+ const idNode = findChild(node.content, 'id');
52
+ const valueNode = findChild(node.content, 'value');
53
+ const signatureNode = findChild(node.content, 'signature');
54
+ const keyId = readBigEndianInt(requireBytes(idNode?.content, 'skey.id'));
55
+ const publicKey = requireBytes(valueNode?.content, 'skey.value');
56
+ const signature = requireBytes(signatureNode?.content, 'skey.signature');
57
+ if (publicKey.byteLength !== 32) {
58
+ throw new PreKeyUploadParseError(`skey value must be 32 bytes, got ${publicKey.byteLength}`);
59
+ }
60
+ if (signature.byteLength !== 64) {
61
+ throw new PreKeyUploadParseError(`skey signature must be 64 bytes, got ${signature.byteLength}`);
62
+ }
63
+ return { keyId, publicKey, signature };
64
+ }
65
+ function parsePreKeyList(node) {
66
+ if (!node) {
67
+ throw new PreKeyUploadParseError('list child missing');
68
+ }
69
+ if (!Array.isArray(node.content)) {
70
+ throw new PreKeyUploadParseError('list has no inner key entries');
71
+ }
72
+ const out = [];
73
+ for (const entry of node.content) {
74
+ if (entry.tag !== 'key')
75
+ continue;
76
+ if (!Array.isArray(entry.content))
77
+ continue;
78
+ const idNode = findChild(entry.content, 'id');
79
+ const valueNode = findChild(entry.content, 'value');
80
+ const keyId = readBigEndianInt(requireBytes(idNode?.content, 'key.id'));
81
+ const publicKey = requireBytes(valueNode?.content, 'key.value');
82
+ if (publicKey.byteLength !== 32) {
83
+ throw new PreKeyUploadParseError(`key value must be 32 bytes, got ${publicKey.byteLength}`);
84
+ }
85
+ out.push({ keyId, publicKey });
86
+ }
87
+ if (out.length === 0) {
88
+ throw new PreKeyUploadParseError('list is empty');
89
+ }
90
+ return out;
91
+ }
92
+ function requireBytes(content, label) {
93
+ if (content === undefined || content === null) {
94
+ throw new PreKeyUploadParseError(`${label} child has no content`);
95
+ }
96
+ if (!(content instanceof Uint8Array)) {
97
+ throw new PreKeyUploadParseError(`${label} content must be bytes`);
98
+ }
99
+ return content;
100
+ }
101
+ function readBigEndianInt(bytes) {
102
+ let value = 0;
103
+ for (let i = 0; i < bytes.byteLength; i += 1) {
104
+ value = value * 256 + bytes[i];
105
+ }
106
+ return value;
107
+ }
@@ -0,0 +1,56 @@
1
+ /** Builders for `<stream:error/>` stanzas pushed to the client. */
2
+ const STREAM_ERROR_TAG = 'stream:error';
3
+ export function buildStreamErrorCode(code) {
4
+ return {
5
+ tag: STREAM_ERROR_TAG,
6
+ attrs: { code: String(code) }
7
+ };
8
+ }
9
+ export function buildStreamErrorReplaced() {
10
+ return {
11
+ tag: STREAM_ERROR_TAG,
12
+ attrs: {},
13
+ content: [
14
+ {
15
+ tag: 'conflict',
16
+ attrs: { type: 'replaced' }
17
+ }
18
+ ]
19
+ };
20
+ }
21
+ export function buildStreamErrorDeviceRemoved() {
22
+ return {
23
+ tag: STREAM_ERROR_TAG,
24
+ attrs: {},
25
+ content: [
26
+ {
27
+ tag: 'conflict',
28
+ attrs: { type: 'device_removed' }
29
+ }
30
+ ]
31
+ };
32
+ }
33
+ export function buildStreamErrorAck(id) {
34
+ return {
35
+ tag: STREAM_ERROR_TAG,
36
+ attrs: {},
37
+ content: [
38
+ {
39
+ tag: 'ack',
40
+ attrs: { id }
41
+ }
42
+ ]
43
+ };
44
+ }
45
+ export function buildStreamErrorXmlNotWellFormed() {
46
+ return {
47
+ tag: STREAM_ERROR_TAG,
48
+ attrs: {},
49
+ content: [
50
+ {
51
+ tag: 'xml-not-well-formed',
52
+ attrs: {}
53
+ }
54
+ ]
55
+ };
56
+ }
@@ -0,0 +1,134 @@
1
+ /** In-memory app-state collection tracker (version/LTHash + patch queue). */
2
+ import { APP_STATE_EMPTY_LT_HASH, FakeAppStateCrypto } from '../protocol/signal/fake-app-state-crypto.js';
3
+ import { proto } from '../transport/protos.js';
4
+ export class FakeAppStateCollection {
5
+ constructor(options) {
6
+ this.currentVersion = 0;
7
+ this.currentLtHash = APP_STATE_EMPTY_LT_HASH;
8
+ this.recordsByIndexMacHex = new Map();
9
+ this.pendingPatchMutations = [];
10
+ this.hasUnflushedSnapshotChanges = false;
11
+ this.name = options.name;
12
+ this.keyId = options.keyId;
13
+ this.keyData = options.keyData;
14
+ this.crypto = options.crypto ?? new FakeAppStateCrypto();
15
+ }
16
+ get version() {
17
+ return this.currentVersion;
18
+ }
19
+ get ltHash() {
20
+ return this.currentLtHash;
21
+ }
22
+ async applyMutation(input) {
23
+ const baseInput = {
24
+ operation: input.operation,
25
+ keyId: this.keyId,
26
+ keyData: this.keyData,
27
+ index: input.index,
28
+ value: input.value,
29
+ version: input.version
30
+ };
31
+ const encrypted = await this.crypto.encryptMutation(baseInput);
32
+ const indexMacHex = bytesToHex(encrypted.indexMac);
33
+ const existing = this.recordsByIndexMacHex.get(indexMacHex);
34
+ const removeValues = [];
35
+ const addValues = [];
36
+ if (existing) {
37
+ removeValues.push(existing.valueMac);
38
+ this.recordsByIndexMacHex.delete(indexMacHex);
39
+ }
40
+ if (input.operation === 'set') {
41
+ const record = {
42
+ indexMacHex,
43
+ indexMac: encrypted.indexMac,
44
+ valueMac: encrypted.valueMac,
45
+ valueBlob: encrypted.valueBlob
46
+ };
47
+ this.recordsByIndexMacHex.set(indexMacHex, record);
48
+ addValues.push(encrypted.valueMac);
49
+ this.pendingPatchMutations.push({ operation: 'set', record });
50
+ }
51
+ else {
52
+ this.pendingPatchMutations.push({
53
+ operation: 'remove',
54
+ record: {
55
+ indexMacHex,
56
+ indexMac: encrypted.indexMac,
57
+ valueMac: encrypted.valueMac,
58
+ valueBlob: encrypted.valueBlob
59
+ }
60
+ });
61
+ }
62
+ const nextHash = await this.applyLtHash(this.currentLtHash, addValues, removeValues);
63
+ this.currentLtHash = nextHash;
64
+ this.hasUnflushedSnapshotChanges = true;
65
+ }
66
+ async encodeSnapshot() {
67
+ this.currentVersion += 1;
68
+ const records = [];
69
+ for (const record of this.recordsByIndexMacHex.values()) {
70
+ records.push({
71
+ index: { blob: record.indexMac },
72
+ value: { blob: record.valueBlob },
73
+ keyId: { id: this.keyId }
74
+ });
75
+ }
76
+ const mac = await this.crypto.generateSnapshotMac(this.keyData, this.currentLtHash, this.currentVersion, this.name);
77
+ this.pendingPatchMutations.length = 0;
78
+ this.hasUnflushedSnapshotChanges = false;
79
+ return proto.SyncdSnapshot.encode({
80
+ version: { version: this.currentVersion },
81
+ records,
82
+ mac,
83
+ keyId: { id: this.keyId }
84
+ }).finish();
85
+ }
86
+ async encodePendingPatch() {
87
+ if (this.pendingPatchMutations.length === 0) {
88
+ throw new Error(`fake app-state collection ${this.name}: no pending mutations to encode`);
89
+ }
90
+ this.currentVersion += 1;
91
+ const patchVersion = this.currentVersion;
92
+ const mutations = [];
93
+ const valueMacs = [];
94
+ for (const pending of this.pendingPatchMutations) {
95
+ mutations.push({
96
+ operation: pending.operation === 'set'
97
+ ? proto.SyncdMutation.SyncdOperation.SET
98
+ : proto.SyncdMutation.SyncdOperation.REMOVE,
99
+ record: {
100
+ keyId: { id: this.keyId },
101
+ index: { blob: pending.record.indexMac },
102
+ value: { blob: pending.record.valueBlob }
103
+ }
104
+ });
105
+ valueMacs.push(pending.record.valueMac);
106
+ }
107
+ const snapshotMac = await this.crypto.generateSnapshotMac(this.keyData, this.currentLtHash, patchVersion, this.name);
108
+ const patchMac = await this.crypto.generatePatchMac(this.keyData, snapshotMac, valueMacs, patchVersion, this.name);
109
+ this.pendingPatchMutations.length = 0;
110
+ this.hasUnflushedSnapshotChanges = false;
111
+ return proto.SyncdPatch.encode({
112
+ version: { version: patchVersion },
113
+ mutations,
114
+ snapshotMac,
115
+ patchMac,
116
+ keyId: { id: this.keyId }
117
+ }).finish();
118
+ }
119
+ hasPending() {
120
+ return this.pendingPatchMutations.length > 0 || this.hasUnflushedSnapshotChanges;
121
+ }
122
+ async applyLtHash(base, addValues, removeValues) {
123
+ const afterRemove = await this.crypto.ltHashSubtract(base, removeValues);
124
+ return this.crypto.ltHashAdd(afterRemove, addValues);
125
+ }
126
+ }
127
+ function bytesToHex(bytes) {
128
+ let out = '';
129
+ for (let index = 0; index < bytes.byteLength; index += 1) {
130
+ const value = bytes[index];
131
+ out += value < 16 ? `0${value.toString(16)}` : value.toString(16);
132
+ }
133
+ return out;
134
+ }
@@ -0,0 +1,53 @@
1
+ /** In-memory media blob store served by the fake media endpoint. */
2
+ import { randomBytes } from 'node:crypto';
3
+ import { WaMediaCrypto } from '../transport/crypto.js';
4
+ import { bytesToHex } from '../transport/util.js';
5
+ export class FakeMediaStore {
6
+ constructor() {
7
+ this.blobs = new Map();
8
+ }
9
+ async publish(input) {
10
+ const mediaKey = input.mediaKey ?? new Uint8Array(randomBytes(32));
11
+ const encrypted = await WaMediaCrypto.encryptBytes(input.mediaType, mediaKey, input.plaintext);
12
+ const path = input.path ?? this.randomPath(input.mediaType);
13
+ const stored = {
14
+ mediaType: input.mediaType,
15
+ encryptedBytes: encrypted.ciphertextHmac,
16
+ mediaKey,
17
+ fileSha256: encrypted.fileSha256,
18
+ fileEncSha256: encrypted.fileEncSha256
19
+ };
20
+ this.blobs.set(path, stored);
21
+ return {
22
+ path,
23
+ mediaKey,
24
+ fileSha256: encrypted.fileSha256,
25
+ fileEncSha256: encrypted.fileEncSha256,
26
+ fileLength: encrypted.ciphertextHmac.byteLength,
27
+ mediaType: input.mediaType
28
+ };
29
+ }
30
+ /** Stores pre-encrypted bytes uploaded by the lib so the download path can serve them back. */
31
+ setRaw(path, encryptedBytes, mediaType = 'image') {
32
+ this.blobs.set(path, {
33
+ mediaType,
34
+ encryptedBytes,
35
+ mediaKey: new Uint8Array(32),
36
+ fileSha256: new Uint8Array(32),
37
+ fileEncSha256: new Uint8Array(32)
38
+ });
39
+ }
40
+ get(path) {
41
+ return this.blobs.get(path);
42
+ }
43
+ delete(path) {
44
+ return this.blobs.delete(path);
45
+ }
46
+ clear() {
47
+ this.blobs.clear();
48
+ }
49
+ randomPath(mediaType) {
50
+ const slug = bytesToHex(randomBytes(16));
51
+ return `/fake-media/${mediaType}/${slug}`;
52
+ }
53
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Layer 1 – binary stanza codec wrapper.
3
+ *
4
+ * Re-exports the bit-exact WhatsApp WAP token encoder/decoder from zapo-js.
5
+ * This file is the only sanctioned import path for binary node serialization
6
+ * inside the fake server.
7
+ */
8
+ export { decodeBinaryNode, decodeBinaryNodeStanza, encodeBinaryNode, encodeBinaryNodeStanza, verifyNoiseCertificateChain } from 'zapo-js/transport';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Layer 1 – crypto primitives wrapper.
3
+ *
4
+ * Re-exports bit-exact cryptographic primitives from zapo-js. No protocol
5
+ * interpretation, so reusing them does not create a test-vs-impl tautology.
6
+ */
7
+ export { aesCbcDecrypt, aesCbcEncrypt, aesGcmDecrypt, aesGcmEncrypt, Ed25519, hkdf, hkdfSplit, hmacSha256Sign, hmacSha512Sign, prependVersion, randomBytesAsync, readVersionedContent, sha256, sha512, toRawPubKey, toSerializedPubKey, X25519, xeddsaSign, xeddsaVerify } from 'zapo-js/crypto';
8
+ export { WaMediaCrypto } from 'zapo-js/media';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Layer 1 – generated protobuf wrapper.
3
+ *
4
+ * Re-exports the proto namespace from zapo-js. The protos are generated from
5
+ * `.proto` definitions, not lib behavior, so direct reuse is safe.
6
+ */
7
+ export { proto } from 'zapo-js/proto';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Layer 1 – byte/encoding primitives wrapper.
3
+ *
4
+ * Re-exports bit-exact byte helpers from zapo-js so Layer 2/3 of the fake
5
+ * server can use them without importing zapo-js directly.
6
+ */
7
+ export { bytesToBase64, bytesToBase64UrlSafe, bytesToHex, decodeBase64Url } from 'zapo-js/util';
8
+ export const TEXT_ENCODER = new TextEncoder();
package/dist/index.d.ts CHANGED
@@ -48,4 +48,3 @@ export type { BuildPairDeviceIqInput, BuildPairSuccessIqInput, ParsedPairingQr }
48
48
  export { parsePreKeyUploadIq, PreKeyUploadParseError } from './protocol/signal/prekey-upload';
49
49
  export type { ClientPreKeyBundle, ClientPreKeyEntry, ClientSignedPreKey } from './protocol/signal/prekey-upload';
50
50
  export { buildStreamErrorAck, buildStreamErrorCode, buildStreamErrorDeviceRemoved, buildStreamErrorReplaced, buildStreamErrorXmlNotWellFormed } from './protocol/stream/stream-error';
51
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -71,4 +71,3 @@ Object.defineProperty(exports, "buildStreamErrorCode", { enumerable: true, get:
71
71
  Object.defineProperty(exports, "buildStreamErrorDeviceRemoved", { enumerable: true, get: function () { return stream_error_1.buildStreamErrorDeviceRemoved; } });
72
72
  Object.defineProperty(exports, "buildStreamErrorReplaced", { enumerable: true, get: function () { return stream_error_1.buildStreamErrorReplaced; } });
73
73
  Object.defineProperty(exports, "buildStreamErrorXmlNotWellFormed", { enumerable: true, get: function () { return stream_error_1.buildStreamErrorXmlNotWellFormed; } });
74
- //# sourceMappingURL=index.js.map
@@ -20,4 +20,3 @@ export declare class WaFakeConnection {
20
20
  close(code?: number, reason?: string): void;
21
21
  private bindSocketEvents;
22
22
  }
23
- //# sourceMappingURL=WaFakeConnection.d.ts.map
@@ -51,4 +51,3 @@ class WaFakeConnection {
51
51
  }
52
52
  }
53
53
  exports.WaFakeConnection = WaFakeConnection;
54
- //# sourceMappingURL=WaFakeConnection.js.map
@@ -48,4 +48,3 @@ export declare class WaFakeConnectionPipeline {
48
48
  private handleAuthenticatedFrame;
49
49
  private fail;
50
50
  }
51
- //# sourceMappingURL=WaFakeConnectionPipeline.d.ts.map