@xbibzlibrary/whatsbibz 1.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 (260) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/LICENSE +22 -0
  3. package/LICENSE.upstream +21 -0
  4. package/README.md +280 -0
  5. package/VERIFIKASI-IDENTITAS-2026-09-03.md +138 -0
  6. package/WAProto/GenerateStatics.sh +3 -0
  7. package/WAProto/WAProto.proto +6035 -0
  8. package/WAProto/fix-imports.js +81 -0
  9. package/WAProto/index.d.ts +15314 -0
  10. package/WAProto/index.js +132326 -0
  11. package/assets/logo/README.md +21 -0
  12. package/assets/logo/png/banner-1200x360.png +0 -0
  13. package/assets/logo/png/icon-1024.png +0 -0
  14. package/assets/logo/png/icon-128.png +0 -0
  15. package/assets/logo/png/icon-16.png +0 -0
  16. package/assets/logo/png/icon-24.png +0 -0
  17. package/assets/logo/png/icon-256.png +0 -0
  18. package/assets/logo/png/icon-32.png +0 -0
  19. package/assets/logo/png/icon-48.png +0 -0
  20. package/assets/logo/png/icon-512.png +0 -0
  21. package/assets/logo/png/icon-64.png +0 -0
  22. package/assets/logo/png/mark-512.png +0 -0
  23. package/assets/logo/preview.png +0 -0
  24. package/assets/logo/whatsbibz.ico +0 -0
  25. package/lib/BibzWhats/client.d.ts +95 -0
  26. package/lib/BibzWhats/client.js +501 -0
  27. package/lib/BibzWhats/device-identity.d.ts +60 -0
  28. package/lib/BibzWhats/device-identity.js +234 -0
  29. package/lib/BibzWhats/extract.d.ts +29 -0
  30. package/lib/BibzWhats/extract.js +115 -0
  31. package/lib/BibzWhats/index.d.ts +7 -0
  32. package/lib/BibzWhats/index.js +8 -0
  33. package/lib/BibzWhats/jid.d.ts +22 -0
  34. package/lib/BibzWhats/jid.js +98 -0
  35. package/lib/BibzWhats/pairing.d.ts +35 -0
  36. package/lib/BibzWhats/pairing.js +186 -0
  37. package/lib/BibzWhats/send.d.ts +9 -0
  38. package/lib/BibzWhats/send.js +107 -0
  39. package/lib/BibzWhats/version.d.ts +6 -0
  40. package/lib/BibzWhats/version.js +7 -0
  41. package/lib/Defaults/index.d.ts +73 -0
  42. package/lib/Defaults/index.js +141 -0
  43. package/lib/Modded/message_builder.d.ts +15 -0
  44. package/lib/Modded/message_builder.js +2330 -0
  45. package/lib/Signal/Group/ciphertext-message.d.ts +9 -0
  46. package/lib/Signal/Group/ciphertext-message.js +11 -0
  47. package/lib/Signal/Group/group-session-builder.d.ts +14 -0
  48. package/lib/Signal/Group/group-session-builder.js +29 -0
  49. package/lib/Signal/Group/group_cipher.d.ts +16 -0
  50. package/lib/Signal/Group/group_cipher.js +81 -0
  51. package/lib/Signal/Group/index.d.ts +11 -0
  52. package/lib/Signal/Group/index.js +11 -0
  53. package/lib/Signal/Group/keyhelper.d.ts +10 -0
  54. package/lib/Signal/Group/keyhelper.js +17 -0
  55. package/lib/Signal/Group/sender-chain-key.d.ts +13 -0
  56. package/lib/Signal/Group/sender-chain-key.js +25 -0
  57. package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -0
  58. package/lib/Signal/Group/sender-key-distribution-message.js +62 -0
  59. package/lib/Signal/Group/sender-key-message.d.ts +18 -0
  60. package/lib/Signal/Group/sender-key-message.js +65 -0
  61. package/lib/Signal/Group/sender-key-name.d.ts +17 -0
  62. package/lib/Signal/Group/sender-key-name.js +47 -0
  63. package/lib/Signal/Group/sender-key-record.d.ts +30 -0
  64. package/lib/Signal/Group/sender-key-record.js +40 -0
  65. package/lib/Signal/Group/sender-key-state.d.ts +38 -0
  66. package/lib/Signal/Group/sender-key-state.js +83 -0
  67. package/lib/Signal/Group/sender-message-key.d.ts +11 -0
  68. package/lib/Signal/Group/sender-message-key.js +25 -0
  69. package/lib/Signal/libsignal.d.ts +4 -0
  70. package/lib/Signal/libsignal.js +406 -0
  71. package/lib/Signal/lid-mapping.d.ts +18 -0
  72. package/lib/Signal/lid-mapping.js +276 -0
  73. package/lib/Socket/Client/index.d.ts +2 -0
  74. package/lib/Socket/Client/index.js +2 -0
  75. package/lib/Socket/Client/types.d.ts +15 -0
  76. package/lib/Socket/Client/types.js +10 -0
  77. package/lib/Socket/Client/websocket.d.ts +12 -0
  78. package/lib/Socket/Client/websocket.js +53 -0
  79. package/lib/Socket/business.d.ts +537 -0
  80. package/lib/Socket/business.js +421 -0
  81. package/lib/Socket/chats.d.ts +110 -0
  82. package/lib/Socket/chats.js +1006 -0
  83. package/lib/Socket/communities.d.ts +646 -0
  84. package/lib/Socket/communities.js +430 -0
  85. package/lib/Socket/engine.d.ts +129 -0
  86. package/lib/Socket/engine.js +767 -0
  87. package/lib/Socket/groups.d.ts +149 -0
  88. package/lib/Socket/groups.js +326 -0
  89. package/lib/Socket/index.d.ts +637 -0
  90. package/lib/Socket/index.js +14 -0
  91. package/lib/Socket/messages-recv.d.ts +239 -0
  92. package/lib/Socket/messages-recv.js +1307 -0
  93. package/lib/Socket/messages-send.d.ts +580 -0
  94. package/lib/Socket/messages-send.js +1639 -0
  95. package/lib/Socket/mex.d.ts +2 -0
  96. package/lib/Socket/mex.js +47 -0
  97. package/lib/Socket/newsletter.d.ts +176 -0
  98. package/lib/Socket/newsletter.js +456 -0
  99. package/lib/Socket/socket.d.ts +56 -0
  100. package/lib/Socket/socket.js +998 -0
  101. package/lib/Types/Auth.d.ts +115 -0
  102. package/lib/Types/Auth.js +1 -0
  103. package/lib/Types/Bussines.d.ts +36 -0
  104. package/lib/Types/Bussines.js +1 -0
  105. package/lib/Types/Call.d.ts +14 -0
  106. package/lib/Types/Call.js +1 -0
  107. package/lib/Types/Chat.d.ts +124 -0
  108. package/lib/Types/Chat.js +7 -0
  109. package/lib/Types/Contact.d.ts +23 -0
  110. package/lib/Types/Contact.js +1 -0
  111. package/lib/Types/Events.d.ts +241 -0
  112. package/lib/Types/Events.js +1 -0
  113. package/lib/Types/GroupMetadata.d.ts +67 -0
  114. package/lib/Types/GroupMetadata.js +1 -0
  115. package/lib/Types/Label.d.ts +46 -0
  116. package/lib/Types/Label.js +24 -0
  117. package/lib/Types/LabelAssociation.d.ts +29 -0
  118. package/lib/Types/LabelAssociation.js +6 -0
  119. package/lib/Types/Message.d.ts +427 -0
  120. package/lib/Types/Message.js +10 -0
  121. package/lib/Types/Newsletter.d.ts +134 -0
  122. package/lib/Types/Newsletter.js +30 -0
  123. package/lib/Types/Product.d.ts +78 -0
  124. package/lib/Types/Product.js +1 -0
  125. package/lib/Types/Signal.d.ts +77 -0
  126. package/lib/Types/Signal.js +1 -0
  127. package/lib/Types/Socket.d.ts +173 -0
  128. package/lib/Types/Socket.js +2 -0
  129. package/lib/Types/State.d.ts +38 -0
  130. package/lib/Types/State.js +12 -0
  131. package/lib/Types/USync.d.ts +25 -0
  132. package/lib/Types/USync.js +1 -0
  133. package/lib/Types/index.d.ts +75 -0
  134. package/lib/Types/index.js +32 -0
  135. package/lib/Utils/auth-utils.d.ts +18 -0
  136. package/lib/Utils/auth-utils.js +289 -0
  137. package/lib/Utils/browser-utils.d.ts +3 -0
  138. package/lib/Utils/browser-utils.js +47 -0
  139. package/lib/Utils/business.d.ts +22 -0
  140. package/lib/Utils/business.js +230 -0
  141. package/lib/Utils/chat-utils.d.ts +69 -0
  142. package/lib/Utils/chat-utils.js +811 -0
  143. package/lib/Utils/companion-reg-client-utils.d.ts +20 -0
  144. package/lib/Utils/companion-reg-client-utils.js +66 -0
  145. package/lib/Utils/crypto.d.ts +41 -0
  146. package/lib/Utils/crypto.js +117 -0
  147. package/lib/Utils/decode-wa-message.d.ts +47 -0
  148. package/lib/Utils/decode-wa-message.js +282 -0
  149. package/lib/Utils/event-buffer.d.ts +35 -0
  150. package/lib/Utils/event-buffer.js +590 -0
  151. package/lib/Utils/generics.d.ts +90 -0
  152. package/lib/Utils/generics.js +384 -0
  153. package/lib/Utils/history.d.ts +21 -0
  154. package/lib/Utils/history.js +130 -0
  155. package/lib/Utils/identity-change-handler.d.ts +36 -0
  156. package/lib/Utils/identity-change-handler.js +48 -0
  157. package/lib/Utils/index.d.ts +25 -0
  158. package/lib/Utils/index.js +24 -0
  159. package/lib/Utils/link-preview.d.ts +20 -0
  160. package/lib/Utils/link-preview.js +84 -0
  161. package/lib/Utils/logger.d.ts +12 -0
  162. package/lib/Utils/logger.js +2 -0
  163. package/lib/Utils/lt-hash.d.ts +10 -0
  164. package/lib/Utils/lt-hash.js +7 -0
  165. package/lib/Utils/make-mutex.d.ts +8 -0
  166. package/lib/Utils/make-mutex.js +32 -0
  167. package/lib/Utils/message-retry-manager.d.ts +109 -0
  168. package/lib/Utils/message-retry-manager.js +224 -0
  169. package/lib/Utils/messages-media.d.ts +129 -0
  170. package/lib/Utils/messages-media.js +784 -0
  171. package/lib/Utils/messages.d.ts +90 -0
  172. package/lib/Utils/messages.js +1240 -0
  173. package/lib/Utils/noise-handler.d.ts +19 -0
  174. package/lib/Utils/noise-handler.js +200 -0
  175. package/lib/Utils/offline-node-processor.d.ts +16 -0
  176. package/lib/Utils/offline-node-processor.js +39 -0
  177. package/lib/Utils/platform-identity.d.ts +14 -0
  178. package/lib/Utils/platform-identity.js +148 -0
  179. package/lib/Utils/pre-key-manager.d.ts +27 -0
  180. package/lib/Utils/pre-key-manager.js +105 -0
  181. package/lib/Utils/process-message.d.ts +59 -0
  182. package/lib/Utils/process-message.js +544 -0
  183. package/lib/Utils/reporting-utils.d.ts +10 -0
  184. package/lib/Utils/reporting-utils.js +257 -0
  185. package/lib/Utils/rich-messages.d.ts +276 -0
  186. package/lib/Utils/rich-messages.js +1143 -0
  187. package/lib/Utils/signal.d.ts +33 -0
  188. package/lib/Utils/signal.js +158 -0
  189. package/lib/Utils/stanza-ack.d.ts +10 -0
  190. package/lib/Utils/stanza-ack.js +37 -0
  191. package/lib/Utils/sticker-pack.d.ts +10 -0
  192. package/lib/Utils/sticker-pack.js +111 -0
  193. package/lib/Utils/sync-action-utils.d.ts +18 -0
  194. package/lib/Utils/sync-action-utils.js +47 -0
  195. package/lib/Utils/tc-token-utils.d.ts +8 -0
  196. package/lib/Utils/tc-token-utils.js +45 -0
  197. package/lib/Utils/use-multi-file-auth-state.d.ts +12 -0
  198. package/lib/Utils/use-multi-file-auth-state.js +120 -0
  199. package/lib/Utils/validate-connection.d.ts +10 -0
  200. package/lib/Utils/validate-connection.js +222 -0
  201. package/lib/VoIP/audio-feeder.d.ts +15 -0
  202. package/lib/VoIP/audio-feeder.js +136 -0
  203. package/lib/VoIP/index.d.ts +12 -0
  204. package/lib/VoIP/index.js +282 -0
  205. package/lib/VoIP/relay-transport.d.ts +43 -0
  206. package/lib/VoIP/relay-transport.js +559 -0
  207. package/lib/VoIP/signaling.js +603 -0
  208. package/lib/VoIP/types.d.ts +69 -0
  209. package/lib/VoIP/types.js +17 -0
  210. package/lib/VoIP/wasm-engine.d.ts +103 -0
  211. package/lib/VoIP/wasm-engine.js +1214 -0
  212. package/lib/VoIP/worker-bootstrap.js +1042 -0
  213. package/lib/WABinary/constants.d.ts +27 -0
  214. package/lib/WABinary/constants.js +1300 -0
  215. package/lib/WABinary/decode.d.ts +6 -0
  216. package/lib/WABinary/decode.js +261 -0
  217. package/lib/WABinary/encode.d.ts +2 -0
  218. package/lib/WABinary/encode.js +219 -0
  219. package/lib/WABinary/generic-utils.d.ts +16 -0
  220. package/lib/WABinary/generic-utils.js +190 -0
  221. package/lib/WABinary/index.d.ts +5 -0
  222. package/lib/WABinary/index.js +5 -0
  223. package/lib/WABinary/jid-utils.d.ts +47 -0
  224. package/lib/WABinary/jid-utils.js +95 -0
  225. package/lib/WABinary/types.d.ts +18 -0
  226. package/lib/WABinary/types.js +1 -0
  227. package/lib/WAM/BinaryInfo.d.ts +8 -0
  228. package/lib/WAM/BinaryInfo.js +9 -0
  229. package/lib/WAM/constants.d.ts +39 -0
  230. package/lib/WAM/constants.js +22852 -0
  231. package/lib/WAM/encode.d.ts +2 -0
  232. package/lib/WAM/encode.js +149 -0
  233. package/lib/WAM/index.d.ts +3 -0
  234. package/lib/WAM/index.js +3 -0
  235. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -0
  236. package/lib/WAUSync/Protocols/USyncContactProtocol.js +28 -0
  237. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
  238. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +53 -0
  239. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
  240. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +26 -0
  241. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
  242. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +37 -0
  243. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +25 -0
  244. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -0
  245. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +9 -0
  246. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +28 -0
  247. package/lib/WAUSync/Protocols/index.d.ts +4 -0
  248. package/lib/WAUSync/Protocols/index.js +4 -0
  249. package/lib/WAUSync/USyncQuery.d.ts +28 -0
  250. package/lib/WAUSync/USyncQuery.js +93 -0
  251. package/lib/WAUSync/USyncUser.d.ts +12 -0
  252. package/lib/WAUSync/USyncUser.js +22 -0
  253. package/lib/WAUSync/index.d.ts +3 -0
  254. package/lib/WAUSync/index.js +3 -0
  255. package/lib/assets/wasm/loader.js +5 -0
  256. package/lib/assets/wasm/whatsapp.wasm +0 -0
  257. package/lib/assets/wasm/worker-modules.js +273 -0
  258. package/lib/index.d.ts +21 -0
  259. package/lib/index.js +22 -0
  260. package/package.json +111 -0
@@ -0,0 +1,603 @@
1
+ import { decodeBinaryNode } from '../WABinary/decode.js';
2
+ import { encodeBinaryNode } from '../WABinary/encode.js';
3
+ import { getBinaryNodeChild, getAllBinaryNodeChildren } from '../WABinary/generic-utils.js';
4
+ import { jidDecode, jidEncode, jidNormalizedUser } from '../WABinary/jid-utils.js';
5
+ import { encodeWAMessage, unpadRandomMax16 } from '../Utils/generics.js';
6
+ import { parseAndInjectE2ESessions } from '../Utils/signal.js';
7
+ import { encodeSignedDeviceIdentity } from '../Utils/validate-connection.js';
8
+ import { proto } from '../../WAProto/index.js';
9
+
10
+ const S_WHATSAPP_NET = "@s.whatsapp.net";
11
+ const TC_TOKEN_REQUEST_TIMEOUT_MS = 3500;
12
+ const SESSION_CACHE_TTL_MS = 5 * 60_000;
13
+ const ACK_TIMEOUT_MS = 15_000;
14
+
15
+ const getNodeChildren = (node) =>
16
+ Array.isArray(node.content) ? node.content : [];
17
+
18
+ const setNodeChildren = (node, children) => {
19
+ node.content = children.length ? children : undefined;
20
+ };
21
+
22
+ const replaceNodeChild = (node, tag, nextChild) => {
23
+ const children = getNodeChildren(node);
24
+ const index = children.findIndex((c) => c.tag === tag);
25
+ if (index >= 0) children[index] = nextChild;
26
+ else children.push(nextChild);
27
+ setNodeChildren(node, children);
28
+ };
29
+
30
+ const removeNodeChildrenByTag = (node, tag) => {
31
+ setNodeChildren(node, getNodeChildren(node).filter((c) => c.tag !== tag));
32
+ };
33
+
34
+ const parseCountAttr = (value, fallback = 0) => {
35
+ const parsed = Number(value);
36
+ return Number.isFinite(parsed) ? parsed : fallback;
37
+ };
38
+
39
+ export class SignalingBridge {
40
+ #sock;
41
+ #voip = null;
42
+ #observedTcTokens = new Map();
43
+ #pendingTcTokenWaiters = new Map();
44
+ #ensuredSignalSessions = new Map();
45
+ #remoteDevicePeerByCallId = new Map();
46
+ #remoteObfuscatedPeerByCallId = new Map();
47
+ #remoteXmppRoutePeerByCallId = new Map();
48
+ #incomingCallPeerById = new Map();
49
+ #outgoingSignalingQueue = Promise.resolve(undefined);
50
+ #incomingSignalingQueue = Promise.resolve(undefined);
51
+
52
+ constructor(config) {
53
+ this.#sock = config.sock;
54
+ }
55
+
56
+ attachEngine = (voip) => {
57
+ this.#voip = voip;
58
+ };
59
+
60
+ init = async () => {
61
+ const originalKeysSet = this.#sock.authState.keys.set.bind(this.#sock.authState.keys);
62
+ this.#sock.authState.keys.set = async (data) => {
63
+ const result = await originalKeysSet(data);
64
+ for (const [jid, entry] of Object.entries(data?.tctoken ?? {})) {
65
+ if (entry?.token instanceof Uint8Array && entry.token.length > 0) {
66
+ this.#rememberTcToken(jid, entry.token, entry.timestamp);
67
+ }
68
+ }
69
+ return result;
70
+ };
71
+ };
72
+
73
+ sendSignaling = (peerJid, callId, xmlPayload) => {
74
+ this.#outgoingSignalingQueue = this.#outgoingSignalingQueue
75
+ .then(() => this.#doSendSignaling(peerJid, callId, xmlPayload))
76
+ .catch(() => {});
77
+ };
78
+
79
+ processIncomingCall = (node, voip, activeCallId) => {
80
+ this.#incomingSignalingQueue = this.#incomingSignalingQueue
81
+ .then(() => this.#doProcessIncomingCall(node, voip, activeCallId))
82
+ .catch(() => {});
83
+ };
84
+
85
+ processIncomingReceipt = (node, voip, activeCallId) => {
86
+ this.#incomingSignalingQueue = this.#incomingSignalingQueue
87
+ .then(() => this.#doProcessIncomingReceipt(node, voip, activeCallId))
88
+ .catch(() => {});
89
+ };
90
+
91
+ requestTcToken = async (jid) => {
92
+ const userJid = this.#toBareJid(jid);
93
+ const cached = await this.#getTcToken(userJid);
94
+ if (cached?.length) return cached;
95
+
96
+ try {
97
+ const response = await this.#sock.getPrivacyTokens([userJid]);
98
+ const tokensNode =
99
+ getBinaryNodeChild(response, "tokens") ??
100
+ getBinaryNodeChild(getBinaryNodeChild(response, "iq"), "tokens");
101
+ const tokenNodes = tokensNode
102
+ ? getAllBinaryNodeChildren(tokensNode).filter((c) => c.tag === "token")
103
+ : [];
104
+
105
+ for (const tokenNode of tokenNodes) {
106
+ const tokenJid = String(tokenNode.attrs.jid ?? "");
107
+ if (jidNormalizedUser(tokenJid) !== jidNormalizedUser(userJid)) continue;
108
+ const content = tokenNode.content;
109
+ if (content instanceof Uint8Array && content.length > 0) {
110
+ const token = Buffer.from(content);
111
+ await this.#sock.authState.keys.set({
112
+ tctoken: { [userJid]: { token, timestamp: String(tokenNode.attrs.t ?? "") } },
113
+ });
114
+ return token;
115
+ }
116
+ }
117
+ } catch {}
118
+
119
+ return this.#getTcToken(userJid);
120
+ };
121
+
122
+ ensureTcToken = async (...jids) => {
123
+ const uniqueJids = [
124
+ ...new Set(jids.map((j) => this.#toBareJid(String(j ?? "").trim())).filter(Boolean)),
125
+ ];
126
+ for (const jid of uniqueJids) {
127
+ const cached = await this.#getTcToken(jid);
128
+ if (cached?.length) return cached;
129
+ }
130
+ for (const jid of uniqueJids) {
131
+ const fetched = await Promise.race([
132
+ this.requestTcToken(jid),
133
+ new Promise((r) => setTimeout(() => r(undefined), TC_TOKEN_REQUEST_TIMEOUT_MS)),
134
+ ]);
135
+ if (fetched?.length) return fetched;
136
+ }
137
+ return undefined;
138
+ };
139
+
140
+ discoverPeerDevices = async (peerLidJid) => {
141
+ const devices = await this.#sock.getUSyncDevices([peerLidJid], true, false);
142
+ return this.#normalizeStartCallPeerList(devices.map((d) => d.jid).filter(Boolean));
143
+ };
144
+
145
+ ensureSessionsForPeers = async (jids) => {
146
+ const targets = this.#expandSignalSessionTargets(jids);
147
+ if (targets.length) await this.#ensureSignalSessions(targets, true);
148
+ };
149
+
150
+ resolveLid = async (pnJid) =>
151
+ this.#sock.signalRepository.lidMapping?.getLIDForPN(pnJid);
152
+
153
+ issueTcToken = async (jid) => {
154
+ const userJid = this.#toBareJid(jid);
155
+ const issuedAt = Math.floor(Date.now() / 1000);
156
+ try {
157
+ await this.#sock.query({
158
+ tag: "iq",
159
+ attrs: {
160
+ to: S_WHATSAPP_NET, type: "set", xmlns: "privacy",
161
+ id: this.#sock.generateMessageTag(),
162
+ },
163
+ content: [{
164
+ tag: "tokens", attrs: {},
165
+ content: [{
166
+ tag: "token",
167
+ attrs: { jid: userJid, t: String(issuedAt), type: "trusted_contact" },
168
+ }],
169
+ }],
170
+ });
171
+ return true;
172
+ } catch {
173
+ return false;
174
+ }
175
+ };
176
+
177
+ getRemoteDeviceJid = (callId) =>
178
+ this.#remoteDevicePeerByCallId.get(callId);
179
+
180
+ #doSendSignaling = async (peerJid, callId, xmlPayload) => {
181
+ const rawPayload = Buffer.from(xmlPayload);
182
+ let voipNode;
183
+ try {
184
+ voipNode = await decodeBinaryNode(Buffer.concat([Buffer.from([0]), rawPayload]));
185
+ } catch {
186
+ voipNode = await decodeBinaryNode(rawPayload);
187
+ }
188
+
189
+ const signalingTag = String(voipNode.tag);
190
+ const effectivePeerJid = this.#resolveOutboundPeerJid(callId, peerJid);
191
+
192
+ if (signalingTag === "offer" && !voipNode.attrs["call-creator"]) {
193
+ const selfLid = this.#sock.authState.creds.me?.lid;
194
+ if (selfLid) voipNode.attrs["call-creator"] = selfLid;
195
+ }
196
+
197
+ const destination = getBinaryNodeChild(voipNode, "destination");
198
+ if (destination) {
199
+ const destinations = getNodeChildren(destination);
200
+ const destinationJids = destinations
201
+ .map((n) => String(n.attrs.jid ?? "").trim())
202
+ .filter(Boolean);
203
+ const sessionTargets = this.#expandSignalSessionTargets(destinationJids);
204
+ if (sessionTargets.length) await this.#ensureSignalSessions(sessionTargets, signalingTag === "offer");
205
+
206
+ const rootEnc = getBinaryNodeChild(voipNode, "enc");
207
+ const encCount = parseCountAttr(rootEnc?.attrs.count);
208
+ let includeDeviceIdentity = false;
209
+
210
+ for (const destNode of destinations) {
211
+ const targetJid = String(destNode.attrs.jid ?? "").trim();
212
+ const destEnc = getBinaryNodeChild(destNode, "enc");
213
+ if (!targetJid || !destEnc || !(destEnc.content instanceof Uint8Array)) continue;
214
+ try {
215
+ const encrypted = await this.#encryptCallKey(targetJid, destEnc.content, encCount);
216
+ includeDeviceIdentity = includeDeviceIdentity || encrypted.shouldIncludeDeviceIdentity;
217
+ setNodeChildren(destNode, [encrypted.encNode]);
218
+ } catch {
219
+ for (const d of destinations) removeNodeChildrenByTag(d, "enc");
220
+ break;
221
+ }
222
+ }
223
+ if (includeDeviceIdentity) this.#appendDeviceIdentity(voipNode);
224
+
225
+ await this.#sendCallStanza(this.#toBareJid(peerJid), voipNode, signalingTag, effectivePeerJid, peerJid);
226
+ return;
227
+ }
228
+
229
+ if (signalingTag === "offer" || signalingTag === "enc_rekey") {
230
+ const enc = getBinaryNodeChild(voipNode, "enc");
231
+ if (enc && enc.content instanceof Uint8Array) {
232
+ const targetJid = this.#toCallDeviceJid(effectivePeerJid);
233
+ const encrypted = await this.#encryptCallKey(targetJid, enc.content, parseCountAttr(enc.attrs.count));
234
+ replaceNodeChild(voipNode, "enc", encrypted.encNode);
235
+ if (encrypted.shouldIncludeDeviceIdentity) this.#appendDeviceIdentity(voipNode);
236
+
237
+ await this.#sendCallStanza(targetJid, voipNode, signalingTag, effectivePeerJid, peerJid);
238
+ return;
239
+ }
240
+ }
241
+
242
+ const routeTo = signalingTag !== "offer" && signalingTag !== "enc_rekey"
243
+ ? this.#toBareJid(effectivePeerJid)
244
+ : this.#toCallDeviceJid(effectivePeerJid);
245
+ await this.#sendCallStanza(routeTo, voipNode, signalingTag, effectivePeerJid, peerJid);
246
+ };
247
+
248
+ #sendCallStanza = async (routeTo, voipNode, signalingTag, effectivePeerJid, callbackPeerJid) => {
249
+ const stanzaId = this.#sock.generateMessageTag();
250
+ await this.#sock.sendNode({
251
+ tag: "call",
252
+ attrs: { to: routeTo, id: stanzaId },
253
+ content: [voipNode],
254
+ });
255
+
256
+ void (async () => {
257
+ try {
258
+ const ackNode = await this.#sock.waitForMessage(stanzaId, ACK_TIMEOUT_MS);
259
+ if (!ackNode || !this.#voip) return;
260
+ const ackPayload = Buffer.from(encodeBinaryNode(ackNode)).toString("base64");
261
+ const tcToken = await this.ensureTcToken(effectivePeerJid, callbackPeerJid);
262
+ try {
263
+ this.#voip.handleSignalingAck({
264
+ payload: ackPayload,
265
+ ackError: ackNode.attrs?.error ?? "0",
266
+ msgType: ackNode.attrs?.type ?? signalingTag,
267
+ peerJid: effectivePeerJid,
268
+ extraData: tcToken,
269
+ });
270
+ } catch {}
271
+ } catch {}
272
+ })();
273
+ };
274
+
275
+ #doProcessIncomingCall = async (node, voip, activeCallId) => {
276
+ const voipChild = getAllBinaryNodeChildren(node)[0];
277
+ if (!voipChild) return;
278
+
279
+ const incomingCallId = String(voipChild.attrs["call-id"] ?? voipChild.attrs.call_id ?? "");
280
+ const normalizedIncomingId = incomingCallId.toUpperCase();
281
+ const normalizedActiveId = String(activeCallId ?? "").toUpperCase();
282
+ const callIdForRouting = normalizedIncomingId || normalizedActiveId;
283
+ if (normalizedActiveId && normalizedIncomingId && normalizedIncomingId !== normalizedActiveId) return;
284
+
285
+ const senderDeviceJid =
286
+ String(voipChild.attrs.participant ?? "") ||
287
+ String(node.attrs.participant ?? "") ||
288
+ String(node.attrs.from ?? "") ||
289
+ String(voipChild.attrs["call-creator"] ?? "");
290
+ const callbackPeerJid = String(node.attrs.from ?? "") || senderDeviceJid;
291
+ const platform = voipChild.attrs.platform ?? node.attrs.platform ?? "";
292
+ const appVersion = voipChild.attrs.version ?? node.attrs.version ?? "";
293
+ const epochId = voipChild.attrs.e ?? node.attrs.e ?? "0";
294
+ const timestamp = voipChild.attrs.t ?? node.attrs.t ?? "0";
295
+ const offline = !!(voipChild.attrs.offline ?? node.attrs.offline);
296
+
297
+ let usableNode = voipChild;
298
+ if (getBinaryNodeChild(voipChild, "enc")) {
299
+ usableNode = await this.#maybeDecryptEnc(voipChild, senderDeviceJid);
300
+ }
301
+
302
+ const b64 = Buffer.from(encodeBinaryNode(usableNode)).toString("base64");
303
+
304
+ const storedPeerJid = callIdForRouting ? this.#incomingCallPeerById.get(callIdForRouting) : undefined;
305
+ let mappedRemoteDeviceJid = callIdForRouting ? this.#remoteDevicePeerByCallId.get(callIdForRouting) : undefined;
306
+
307
+ if (callIdForRouting && (callbackPeerJid || senderDeviceJid)) {
308
+ this.#remoteXmppRoutePeerByCallId.set(callIdForRouting, callbackPeerJid || senderDeviceJid);
309
+ const hinted = this.#pickConcreteRouteHint(senderDeviceJid, callbackPeerJid);
310
+ if (hinted && hinted !== mappedRemoteDeviceJid) {
311
+ mappedRemoteDeviceJid = hinted;
312
+ this.#remoteDevicePeerByCallId.set(callIdForRouting, hinted);
313
+ }
314
+ }
315
+
316
+ const routedPeerJid = usableNode.tag === "offer"
317
+ ? this.#preferDeviceRouteJid(senderDeviceJid, callbackPeerJid, storedPeerJid)
318
+ : this.#preferOrderedRouteJid(mappedRemoteDeviceJid, storedPeerJid, senderDeviceJid, callbackPeerJid);
319
+
320
+ if (callIdForRouting && routedPeerJid) {
321
+ this.#incomingCallPeerById.set(callIdForRouting, routedPeerJid);
322
+ }
323
+
324
+ const tcToken = await this.ensureTcToken(routedPeerJid, callbackPeerJid);
325
+
326
+ switch (usableNode.tag) {
327
+ case "offer":
328
+ voip.handleSignalingOffer({
329
+ payload: b64,
330
+ peerPlatform: Number(platform || 0),
331
+ peerAppVersion: appVersion,
332
+ epochId, timestamp,
333
+ isOffline: offline,
334
+ isOfferNotContact: false,
335
+ peerJid: routedPeerJid,
336
+ tcToken,
337
+ });
338
+ break;
339
+ case "ack":
340
+ voip.handleSignalingAck({
341
+ payload: b64,
342
+ ackError: usableNode.attrs.error ?? "0",
343
+ msgType: usableNode.attrs.type ?? "",
344
+ peerJid: routedPeerJid,
345
+ extraData: tcToken,
346
+ });
347
+ break;
348
+ default:
349
+ voip.handleSignalingMessage({
350
+ payload: b64,
351
+ peerPlatform: platform,
352
+ peerAppVersion: appVersion,
353
+ epochId, timestamp,
354
+ isOffline: offline,
355
+ peerJid: routedPeerJid,
356
+ tcToken,
357
+ });
358
+ if (callIdForRouting && (usableNode.tag === "terminate" || usableNode.tag === "reject")) {
359
+ this.#incomingCallPeerById.delete(callIdForRouting);
360
+ this.#remoteDevicePeerByCallId.delete(callIdForRouting);
361
+ this.#remoteObfuscatedPeerByCallId.delete(callIdForRouting);
362
+ this.#remoteXmppRoutePeerByCallId.delete(callIdForRouting);
363
+ }
364
+ break;
365
+ }
366
+ };
367
+
368
+ #doProcessIncomingReceipt = async (node, voip, activeCallId) => {
369
+ const receiptChild = getAllBinaryNodeChildren(node)[0];
370
+ if (!receiptChild) return;
371
+
372
+ const incomingCallId = String(receiptChild.attrs["call-id"] ?? receiptChild.attrs.call_id ?? "");
373
+ const normalizedIncomingId = incomingCallId.toUpperCase();
374
+ const normalizedActiveId = String(activeCallId ?? "").toUpperCase();
375
+ const callIdForRouting = normalizedIncomingId || normalizedActiveId;
376
+ if (normalizedActiveId && normalizedIncomingId && normalizedIncomingId !== normalizedActiveId) return;
377
+
378
+ const callbackPeerJid = String(node.attrs.from ?? receiptChild.attrs["call-creator"] ?? "");
379
+ const storedPeerJid = callIdForRouting ? this.#incomingCallPeerById.get(callIdForRouting) : undefined;
380
+ const routedPeerJid = this.#preferOrderedRouteJid(storedPeerJid, callbackPeerJid);
381
+ if (callIdForRouting && routedPeerJid) this.#incomingCallPeerById.set(callIdForRouting, routedPeerJid);
382
+
383
+ const tcToken = await this.ensureTcToken(routedPeerJid, callbackPeerJid);
384
+ voip.handleSignalingReceipt({
385
+ payload: Buffer.from(encodeBinaryNode(node)).toString("base64"),
386
+ peerJid: routedPeerJid,
387
+ tcToken,
388
+ });
389
+ };
390
+
391
+ #maybeDecryptEnc = async (voipNode, peerJid) => {
392
+ const enc = getBinaryNodeChild(voipNode, "enc");
393
+ if (!enc || !(enc.content instanceof Uint8Array)) return voipNode;
394
+ const type = enc.attrs.type;
395
+ if (type !== "pkmsg" && type !== "msg") return voipNode;
396
+
397
+ const candidates = [...new Set([
398
+ peerJid,
399
+ this.#toCallDeviceJid(peerJid),
400
+ ].filter(Boolean))];
401
+
402
+ let lastErr;
403
+ for (const jid of candidates) {
404
+ try {
405
+ const decrypted = await this.#sock.signalRepository.decryptMessage({
406
+ jid, type, ciphertext: enc.content,
407
+ });
408
+ const parsed = proto.Message.decode(unpadRandomMax16(decrypted));
409
+ const callKey = parsed.call?.callKey;
410
+ if (!callKey || callKey.length === 0) {
411
+ throw new Error("decrypted signaling has no call.callKey");
412
+ }
413
+ enc.content = callKey;
414
+ return voipNode;
415
+ } catch (err) {
416
+ lastErr = err;
417
+ }
418
+ }
419
+ throw lastErr;
420
+ };
421
+
422
+ #encryptCallKey = async (targetJid, rawCallKey, count) => {
423
+ const primaryDeviceJid = this.#toPrimaryDeviceJid(targetJid);
424
+ const sessionTargets = primaryDeviceJid && primaryDeviceJid !== targetJid
425
+ ? [primaryDeviceJid, targetJid]
426
+ : [targetJid];
427
+ await this.#ensureSignalSessions(sessionTargets, false);
428
+
429
+ const { type, ciphertext } = await this.#sock.signalRepository.encryptMessage({
430
+ jid: targetJid,
431
+ data: encodeWAMessage({ call: { callKey: Buffer.from(rawCallKey) } }),
432
+ });
433
+
434
+ return {
435
+ encNode: {
436
+ tag: "enc",
437
+ attrs: { v: "2", type, count: String(count) },
438
+ content: Buffer.from(ciphertext),
439
+ },
440
+ shouldIncludeDeviceIdentity: type === "pkmsg",
441
+ };
442
+ };
443
+
444
+ #ensureSignalSessions = async (jids, refresh) => {
445
+ const missing = [];
446
+ for (const jid of [...new Set(jids.filter(Boolean))]) {
447
+ const signalId = this.#sock.signalRepository.jidToSignalProtocolAddress(jid);
448
+ const cachedAt = this.#ensuredSignalSessions.get(signalId);
449
+ if (!refresh && cachedAt && Date.now() - cachedAt < SESSION_CACHE_TTL_MS) continue;
450
+ if (!refresh) {
451
+ const validation = await this.#sock.signalRepository.validateSession(jid);
452
+ if (validation.exists) {
453
+ this.#ensuredSignalSessions.set(signalId, Date.now());
454
+ continue;
455
+ }
456
+ }
457
+ missing.push(jid);
458
+ }
459
+ if (!missing.length) return;
460
+
461
+ const sessionNode = await this.#sock.query({
462
+ tag: "iq",
463
+ attrs: { xmlns: "encrypt", type: "get", to: S_WHATSAPP_NET },
464
+ content: [{
465
+ tag: "key", attrs: {},
466
+ content: missing.map((jid) => ({ tag: "user", attrs: { jid } })),
467
+ }],
468
+ });
469
+ await parseAndInjectE2ESessions(sessionNode, this.#sock.signalRepository);
470
+ for (const jid of missing) {
471
+ this.#ensuredSignalSessions.set(
472
+ this.#sock.signalRepository.jidToSignalProtocolAddress(jid),
473
+ Date.now(),
474
+ );
475
+ }
476
+ };
477
+
478
+ #appendDeviceIdentity = (voipNode) => {
479
+ if (getBinaryNodeChild(voipNode, "device-identity")) return;
480
+ const account = this.#sock.authState.creds.account;
481
+ if (!account) return;
482
+ const children = getNodeChildren(voipNode);
483
+ children.push({
484
+ tag: "device-identity",
485
+ attrs: {},
486
+ content: encodeSignedDeviceIdentity(account, true),
487
+ });
488
+ setNodeChildren(voipNode, children);
489
+ };
490
+
491
+ #toBareJid = (jid) => {
492
+ const decoded = jidDecode(jid);
493
+ if (!decoded?.user) return jid;
494
+ const server = jid.endsWith("@lid") ? "lid" : "s.whatsapp.net";
495
+ return jidEncode(decoded.user, server);
496
+ };
497
+
498
+ #toCallDeviceJid = (jid) => {
499
+ const decoded = jidDecode(jid);
500
+ if (!decoded?.user) return jid;
501
+ const server = jid.endsWith("@lid") ? "lid" : "s.whatsapp.net";
502
+ if (decoded.device == null) return jidEncode(decoded.user, server);
503
+ return `${decoded.user}:${decoded.device}@${server}`;
504
+ };
505
+
506
+ #toPrimaryDeviceJid = (jid) => {
507
+ const decoded = jidDecode(jid);
508
+ if (!decoded?.user) return undefined;
509
+ const device = decoded.device;
510
+ if (device == null || device === 0) return undefined;
511
+ const server = jid.endsWith("@lid") ? "lid" : "s.whatsapp.net";
512
+ return jidEncode(decoded.user, server);
513
+ };
514
+
515
+ #hasConcreteDevice = (jid) => {
516
+ const decoded = jidDecode(jid);
517
+ return !!decoded?.user && decoded.device != null;
518
+ };
519
+
520
+ #preferDeviceRouteJid = (...candidates) => {
521
+ for (const c of candidates) {
522
+ const jid = String(c ?? "").trim();
523
+ if (jid && this.#hasConcreteDevice(jid)) return jid;
524
+ }
525
+ for (const c of candidates) {
526
+ const jid = String(c ?? "").trim();
527
+ if (jid) return this.#toCallDeviceJid(jid);
528
+ }
529
+ return "";
530
+ };
531
+
532
+ #preferOrderedRouteJid = (...candidates) => {
533
+ for (const c of candidates) {
534
+ const jid = String(c ?? "").trim();
535
+ if (jid) return this.#toCallDeviceJid(jid);
536
+ }
537
+ return "";
538
+ };
539
+
540
+ #pickConcreteRouteHint = (...candidates) => {
541
+ for (const c of candidates) {
542
+ const jid = String(c ?? "").trim();
543
+ if (jid && this.#hasConcreteDevice(jid)) return jid;
544
+ }
545
+ return "";
546
+ };
547
+
548
+ #resolveOutboundPeerJid = (callId, wasmPeerJid) => {
549
+ const peerJid = String(wasmPeerJid ?? "").trim();
550
+ if (!peerJid || !callId) return peerJid;
551
+ const normalizedCallId = String(callId).toUpperCase();
552
+ return this.#remoteDevicePeerByCallId.get(normalizedCallId) ?? this.#remoteDevicePeerByCallId.get(callId) ?? peerJid;
553
+ };
554
+
555
+ #expandSignalSessionTargets = (jids) =>
556
+ [...new Set(jids.flatMap((jid) => {
557
+ const primary = this.#toPrimaryDeviceJid(jid);
558
+ return primary && primary !== jid ? [primary, jid] : [jid];
559
+ }))];
560
+
561
+ #normalizeStartCallPeerList = (jids) => {
562
+ const result = new Set();
563
+ for (const jid of jids) {
564
+ const decoded = jidDecode(jid);
565
+ if (!decoded?.user) {
566
+ result.add(jid);
567
+ continue;
568
+ }
569
+ const server = jid.endsWith("@lid") ? "lid" : "s.whatsapp.net";
570
+ result.add(jidEncode(decoded.user, server));
571
+ if (decoded.device != null) {
572
+ result.add(`${decoded.user}:${decoded.device}@${server}`);
573
+ }
574
+ }
575
+ return [...result].slice(0, 5);
576
+ };
577
+
578
+ #rememberTcToken = (jid, token, timestamp = "") => {
579
+ const bareJid = this.#toBareJid(jid);
580
+ if (!token.length) return;
581
+ this.#observedTcTokens.set(bareJid, { token: Buffer.from(token), timestamp });
582
+ const waiters = this.#pendingTcTokenWaiters.get(bareJid);
583
+ if (waiters?.length) {
584
+ this.#pendingTcTokenWaiters.delete(bareJid);
585
+ for (const w of waiters) w(Buffer.from(token));
586
+ }
587
+ };
588
+
589
+ #getTcToken = async (jid) => {
590
+ const userJid = this.#toBareJid(jid);
591
+ const observed = this.#observedTcTokens.get(userJid)?.token;
592
+ if (observed?.length) return Buffer.from(observed);
593
+ try {
594
+ const data = await this.#sock.authState.keys.get("tctoken", [userJid]);
595
+ const token = data[userJid]?.token;
596
+ if (token && token.length > 0) {
597
+ this.#rememberTcToken(userJid, token, data[userJid]?.timestamp);
598
+ return token;
599
+ }
600
+ } catch {}
601
+ return undefined;
602
+ };
603
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Shared type definitions for BibzWhats VoIP.
3
+ *
4
+ * @author ShellTear
5
+ */
6
+ /** Audio stream configuration reported by the WASM. */
7
+ export type AudioConfig = {
8
+ sampleRate: number;
9
+ channels: number;
10
+ bitsPerSample: number;
11
+ framesPerChunk: number;
12
+ };
13
+ /** Options for placing a call. */
14
+ export type CallOptions = {
15
+ /** Phone number, digits only (e.g. `"12345678901"`). */
16
+ to: string;
17
+ /** Audio source: file path to MP3/WAV, or `"silence"` for an empty uplink. */
18
+ audioSource?: string;
19
+ /** Auto-hangup after N ms (default: 120000). */
20
+ durationMs?: number;
21
+ };
22
+ /** Events emitted by an `ActiveCall`. */
23
+ export type CallEvents = {
24
+ ringing: () => void;
25
+ connected: () => void;
26
+ /** 16 kHz mono Float32 PCM frame from the remote peer. */
27
+ audio: (pcm: Float32Array) => void;
28
+ /** Reason: `"hangup"` | `"timeout"` | `"rejected"` | `"remote_end"` | `"disconnect"` | etc. */
29
+ ended: (reason: string) => void;
30
+ error: (err: Error) => void;
31
+ };
32
+ /** Top-level SDK configuration. */
33
+ export type VoipSdkConfig = {
34
+ /** Path to a Baileys multi-file auth state directory. */
35
+ authDir: string;
36
+ };
37
+ /** Mirrors the WhatsApp WASM `CallState` enum. */
38
+ export declare const CallState: {
39
+ readonly Idle: 0;
40
+ readonly Calling: 1;
41
+ readonly PreacceptReceived: 2;
42
+ readonly ReceivedCall: 3;
43
+ readonly AcceptSent: 4;
44
+ readonly AcceptReceived: 5;
45
+ readonly Active: 6;
46
+ readonly ActiveElsewhere: 7;
47
+ readonly Ending: 13;
48
+ };
49
+ export type CallState = (typeof CallState)[keyof typeof CallState];
50
+ /** Relay list update payload from WASM call event 156. */
51
+ export type RelayListUpdate = {
52
+ relay_key: string;
53
+ relay_tokens: string[];
54
+ auth_tokens?: string[];
55
+ enable_edgeray_dtls_active_mode?: boolean;
56
+ relays: ReadonlyArray<{
57
+ relay_id: number;
58
+ relay_name: string;
59
+ token_id: number;
60
+ auth_token_id?: number;
61
+ addresses: ReadonlyArray<{
62
+ protocol: number;
63
+ ipv4?: string;
64
+ ipv6?: string;
65
+ port?: number;
66
+ port_v6?: number;
67
+ }>;
68
+ }>;
69
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Shared type definitions for BibzWhats VoIP.
3
+ *
4
+ * @author ShellTear
5
+ */
6
+ /** Mirrors the WhatsApp WASM `CallState` enum. */
7
+ export const CallState = {
8
+ Idle: 0,
9
+ Calling: 1,
10
+ PreacceptReceived: 2,
11
+ ReceivedCall: 3,
12
+ AcceptSent: 4,
13
+ AcceptReceived: 5,
14
+ Active: 6,
15
+ ActiveElsewhere: 7,
16
+ Ending: 13,
17
+ };