@bellaxchuu/flowred 0.8.6

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/LICENSE +21 -0
  2. package/README.md +214 -0
  3. package/WAProto/GenerateStatics.sh +3 -0
  4. package/WAProto/WAProto.proto +6902 -0
  5. package/WAProto/fix-imports.js +85 -0
  6. package/WAProto/index.js +242946 -0
  7. package/engine-requirements.js +10 -0
  8. package/lib/Defaults/index.js +190 -0
  9. package/lib/Defaults/phonenumber-mcc.json +223 -0
  10. package/lib/Signal/Group/ciphertext-message.js +15 -0
  11. package/lib/Signal/Group/group-session-builder.js +92 -0
  12. package/lib/Signal/Group/group_cipher.js +89 -0
  13. package/lib/Signal/Group/index.js +136 -0
  14. package/lib/Signal/Group/keyhelper.js +73 -0
  15. package/lib/Signal/Group/sender-chain-key.js +32 -0
  16. package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
  17. package/lib/Signal/Group/sender-key-message.js +69 -0
  18. package/lib/Signal/Group/sender-key-name.js +50 -0
  19. package/lib/Signal/Group/sender-key-record.js +44 -0
  20. package/lib/Signal/Group/sender-key-state.js +97 -0
  21. package/lib/Signal/Group/sender-message-key.js +30 -0
  22. package/lib/Signal/libsignal.js +490 -0
  23. package/lib/Signal/lid-mapping.js +262 -0
  24. package/lib/Socket/Client/index.js +30 -0
  25. package/lib/Socket/Client/types.js +13 -0
  26. package/lib/Socket/Client/websocket.js +62 -0
  27. package/lib/Socket/aigroups.js +240 -0
  28. package/lib/Socket/business.js +422 -0
  29. package/lib/Socket/chats.js +1816 -0
  30. package/lib/Socket/communities.js +549 -0
  31. package/lib/Socket/graphql.js +656 -0
  32. package/lib/Socket/groups.js +764 -0
  33. package/lib/Socket/index.js +39 -0
  34. package/lib/Socket/interactive-handler.js +522 -0
  35. package/lib/Socket/interop.js +549 -0
  36. package/lib/Socket/luxu.js +387 -0
  37. package/lib/Socket/managed-account.js +183 -0
  38. package/lib/Socket/messages-recv.js +2440 -0
  39. package/lib/Socket/messages-send.js +1853 -0
  40. package/lib/Socket/mex.js +60 -0
  41. package/lib/Socket/newsletter.js +820 -0
  42. package/lib/Socket/privacy.js +449 -0
  43. package/lib/Socket/registration.js +427 -0
  44. package/lib/Socket/socket.js +1092 -0
  45. package/lib/Socket/text-router.js +83 -0
  46. package/lib/Socket/username.js +243 -0
  47. package/lib/Store/index.js +36 -0
  48. package/lib/Store/keyed-db.js +108 -0
  49. package/lib/Store/make-cache-manager-store.js +90 -0
  50. package/lib/Store/make-in-memory-store.js +604 -0
  51. package/lib/Store/make-ordered-dictionary.js +81 -0
  52. package/lib/Store/object-repository.js +29 -0
  53. package/lib/Types/Auth.js +38 -0
  54. package/lib/Types/Bussines.js +2 -0
  55. package/lib/Types/Call.js +2 -0
  56. package/lib/Types/Chat.js +4 -0
  57. package/lib/Types/Contact.js +2 -0
  58. package/lib/Types/Events.js +2 -0
  59. package/lib/Types/GroupMetadata.js +2 -0
  60. package/lib/Types/Label.js +27 -0
  61. package/lib/Types/LabelAssociation.js +9 -0
  62. package/lib/Types/Message.js +95 -0
  63. package/lib/Types/Mex.js +112 -0
  64. package/lib/Types/Newsletter.js +121 -0
  65. package/lib/Types/Product.js +2 -0
  66. package/lib/Types/Signal.js +2 -0
  67. package/lib/Types/Socket.js +2 -0
  68. package/lib/Types/State.js +70 -0
  69. package/lib/Types/USync.js +2 -0
  70. package/lib/Types/index.js +55 -0
  71. package/lib/Utils/auth-utils.js +306 -0
  72. package/lib/Utils/browser-utils.js +114 -0
  73. package/lib/Utils/business.js +247 -0
  74. package/lib/Utils/chat-utils.js +1208 -0
  75. package/lib/Utils/command-loader.js +100 -0
  76. package/lib/Utils/companion-reg-client-utils.js +42 -0
  77. package/lib/Utils/consumer-application.js +107 -0
  78. package/lib/Utils/crypto.js +155 -0
  79. package/lib/Utils/curve25519-js.js +275 -0
  80. package/lib/Utils/decode-wa-message.js +560 -0
  81. package/lib/Utils/event-buffer.js +607 -0
  82. package/lib/Utils/generics.js +563 -0
  83. package/lib/Utils/group-history.js +60 -0
  84. package/lib/Utils/history.js +244 -0
  85. package/lib/Utils/identity-change-handler.js +52 -0
  86. package/lib/Utils/index.js +57 -0
  87. package/lib/Utils/jid-display-normalization.js +218 -0
  88. package/lib/Utils/link-preview.js +143 -0
  89. package/lib/Utils/logger.js +9 -0
  90. package/lib/Utils/lt-hash.js +39 -0
  91. package/lib/Utils/make-mutex.js +36 -0
  92. package/lib/Utils/message-composer.js +479 -0
  93. package/lib/Utils/message-retry-manager.js +270 -0
  94. package/lib/Utils/messages-media.js +896 -0
  95. package/lib/Utils/messages.js +2904 -0
  96. package/lib/Utils/meta-ai-msmsg.js +262 -0
  97. package/lib/Utils/native-bridge.js +82 -0
  98. package/lib/Utils/noise-handler.js +196 -0
  99. package/lib/Utils/offline-node-processor.js +42 -0
  100. package/lib/Utils/pre-key-manager.js +107 -0
  101. package/lib/Utils/process-message.js +1048 -0
  102. package/lib/Utils/reporting-utils.js +262 -0
  103. package/lib/Utils/session-pool.js +94 -0
  104. package/lib/Utils/signal.js +224 -0
  105. package/lib/Utils/stanza-ack.js +40 -0
  106. package/lib/Utils/sticker.js +145 -0
  107. package/lib/Utils/sync-action-utils.js +54 -0
  108. package/lib/Utils/tc-token-utils.js +161 -0
  109. package/lib/Utils/use-multi-file-auth-state.js +121 -0
  110. package/lib/Utils/validate-connection.js +219 -0
  111. package/lib/Utils/view-once-cache.js +79 -0
  112. package/lib/Utils/voip-rekey.js +22 -0
  113. package/lib/WABinary/constants.js +1304 -0
  114. package/lib/WABinary/decode.js +343 -0
  115. package/lib/WABinary/encode.js +228 -0
  116. package/lib/WABinary/generic-utils.js +240 -0
  117. package/lib/WABinary/index.js +33 -0
  118. package/lib/WABinary/jid-utils.js +361 -0
  119. package/lib/WABinary/types.js +2 -0
  120. package/lib/WAM/BinaryInfo.js +13 -0
  121. package/lib/WAM/constants.js +39486 -0
  122. package/lib/WAM/encode.js +142 -0
  123. package/lib/WAM/index.js +31 -0
  124. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +55 -0
  125. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
  126. package/lib/WAUSync/Protocols/USyncContactProtocol.js +54 -0
  127. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
  128. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
  129. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +59 -0
  130. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +31 -0
  131. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  132. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +29 -0
  133. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +39 -0
  134. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  135. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +27 -0
  136. package/lib/WAUSync/Protocols/index.js +39 -0
  137. package/lib/WAUSync/USyncQuery.js +133 -0
  138. package/lib/WAUSync/USyncUser.js +50 -0
  139. package/lib/WAUSync/index.js +31 -0
  140. package/lib/antiban.js +4637 -0
  141. package/lib/index.js +45 -0
  142. package/package.json +107 -0
@@ -0,0 +1,262 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.getMessageReportingToken = exports.shouldIncludeReportingToken = void 0
4
+ const Crypto_1 = require('./crypto')
5
+ const crypto_2 = require('./crypto')
6
+ const reportingFields = [
7
+ { f: 1 },
8
+ {
9
+ f: 3,
10
+ s: [{ f: 2 }, { f: 3 }, { f: 8 }, { f: 11 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }, { f: 25 }]
11
+ },
12
+ { f: 4, s: [{ f: 1 }, { f: 16 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }] },
13
+ { f: 5, s: [{ f: 3 }, { f: 4 }, { f: 5 }, { f: 16 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }] },
14
+ { f: 6, s: [{ f: 1 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }, { f: 30 }] },
15
+ { f: 7, s: [{ f: 2 }, { f: 7 }, { f: 10 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }, { f: 20 }] },
16
+ { f: 8, s: [{ f: 2 }, { f: 7 }, { f: 9 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }, { f: 21 }] },
17
+ { f: 9, s: [{ f: 2 }, { f: 6 }, { f: 7 }, { f: 13 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }, { f: 20 }] },
18
+ { f: 12, s: [{ f: 1 }, { f: 2 }, { f: 14, m: true }, { f: 15 }] },
19
+ { f: 18, s: [{ f: 6 }, { f: 16 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }] },
20
+ { f: 26, s: [{ f: 4 }, { f: 5 }, { f: 8 }, { f: 13 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }] },
21
+ { f: 28, s: [{ f: 1 }, { f: 2 }, { f: 4 }, { f: 5 }, { f: 6 }, { f: 7, s: [{ f: 21 }, { f: 22 }] }] },
22
+ { f: 37, s: [{ f: 1, m: true }] },
23
+ {
24
+ f: 49,
25
+ s: [
26
+ { f: 2 },
27
+ { f: 3, s: [{ f: 1 }, { f: 2 }] },
28
+ { f: 5, s: [{ f: 21 }, { f: 22 }] },
29
+ { f: 8, s: [{ f: 1 }, { f: 2 }] }
30
+ ]
31
+ },
32
+ { f: 53, s: [{ f: 1, m: true }] },
33
+ { f: 55, s: [{ f: 1, m: true }] },
34
+ { f: 58, s: [{ f: 1, m: true }] },
35
+ { f: 59, s: [{ f: 1, m: true }] },
36
+ {
37
+ f: 60,
38
+ s: [
39
+ { f: 2 },
40
+ { f: 3, s: [{ f: 1 }, { f: 2 }] },
41
+ { f: 5, s: [{ f: 21 }, { f: 22 }] },
42
+ { f: 8, s: [{ f: 1 }, { f: 2 }] }
43
+ ]
44
+ },
45
+ {
46
+ f: 64,
47
+ s: [
48
+ { f: 2 },
49
+ { f: 3, s: [{ f: 1 }, { f: 2 }] },
50
+ { f: 5, s: [{ f: 21 }, { f: 22 }] },
51
+ { f: 8, s: [{ f: 1 }, { f: 2 }] }
52
+ ]
53
+ },
54
+ { f: 66, s: [{ f: 2 }, { f: 6 }, { f: 7 }, { f: 13 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }, { f: 20 }] },
55
+ { f: 74, s: [{ f: 1, m: true }] },
56
+ { f: 87, s: [{ f: 1, m: true }] },
57
+ { f: 88, s: [{ f: 1 }, { f: 2, s: [{ f: 1 }] }, { f: 3, s: [{ f: 21 }, { f: 22 }] }] },
58
+ { f: 92, s: [{ f: 1, m: true }] },
59
+ { f: 93, s: [{ f: 1, m: true }] },
60
+ { f: 94, s: [{ f: 1, m: true }] }
61
+ ]
62
+ const compileReportingFields = fields => {
63
+ const map = new Map()
64
+ for (const f of fields) {
65
+ map.set(f.f, {
66
+ m: f.m,
67
+ children: f.s ? compileReportingFields(f.s) : undefined
68
+ })
69
+ }
70
+ return map
71
+ }
72
+ const compiledReportingFields = compileReportingFields(reportingFields)
73
+ const EMPTY_MAP = new Map()
74
+ const ENC_SECRET_REPORT_TOKEN = 'Report Token'
75
+ const WIRE = {
76
+ VARINT: 0,
77
+ FIXED64: 1,
78
+ BYTES: 2,
79
+ FIXED32: 5
80
+ }
81
+ const shouldIncludeReportingToken = message =>
82
+ !message.reactionMessage &&
83
+ !message.encReactionMessage &&
84
+ !message.encEventResponseMessage &&
85
+ !message.pollUpdateMessage
86
+ exports.shouldIncludeReportingToken = shouldIncludeReportingToken
87
+ const generateMsgSecretKey = (modificationType, origMsgId, origMsgSender, modificationSender, origMsgSecret) => {
88
+ const useCaseSecret = Buffer.concat([
89
+ Buffer.from(origMsgId, 'utf8'),
90
+ Buffer.from(origMsgSender, 'utf8'),
91
+ Buffer.from(modificationSender, 'utf8'),
92
+ Buffer.from(modificationType, 'utf8')
93
+ ])
94
+ return (0, crypto_2.hkdf)(origMsgSecret, 32, { info: useCaseSecret.toString('latin1') })
95
+ }
96
+ const extractReportingTokenContent = (data, cfg) => {
97
+ const out = []
98
+ let i = 0
99
+ while (i < data.length) {
100
+ const tag = decodeVarint(data, i)
101
+ if (!tag.ok) {
102
+ return null
103
+ }
104
+ const fieldNum = tag.value >> 3
105
+ const wireType = tag.value & 0x7
106
+ const fieldStart = i
107
+ i += tag.bytes
108
+ const fieldCfg = cfg.get(fieldNum)
109
+ const pushSlice = end => {
110
+ if (end > data.length) {
111
+ return false
112
+ }
113
+ out.push({ num: fieldNum, bytes: data.subarray(fieldStart, end) })
114
+ i = end
115
+ return true
116
+ }
117
+ const skip = end => {
118
+ if (end > data.length) {
119
+ return false
120
+ }
121
+ i = end
122
+ return true
123
+ }
124
+ if (wireType === WIRE.VARINT) {
125
+ const v = decodeVarint(data, i)
126
+ if (!v.ok) {
127
+ return null
128
+ }
129
+ const end = i + v.bytes
130
+ if (!fieldCfg) {
131
+ if (!skip(end)) {
132
+ return null
133
+ }
134
+ continue
135
+ }
136
+ if (!pushSlice(end)) {
137
+ return null
138
+ }
139
+ continue
140
+ }
141
+ if (wireType === WIRE.FIXED64) {
142
+ const end = i + 8
143
+ if (!fieldCfg) {
144
+ if (!skip(end)) {
145
+ return null
146
+ }
147
+ continue
148
+ }
149
+ if (!pushSlice(end)) {
150
+ return null
151
+ }
152
+ continue
153
+ }
154
+ if (wireType === WIRE.FIXED32) {
155
+ const end = i + 4
156
+ if (!fieldCfg) {
157
+ if (!skip(end)) {
158
+ return null
159
+ }
160
+ continue
161
+ }
162
+ if (!pushSlice(end)) {
163
+ return null
164
+ }
165
+ continue
166
+ }
167
+ if (wireType === WIRE.BYTES) {
168
+ const len = decodeVarint(data, i)
169
+ if (!len.ok) {
170
+ return null
171
+ }
172
+ const valStart = i + len.bytes
173
+ const valEnd = valStart + len.value
174
+ if (valEnd > data.length) {
175
+ return null
176
+ }
177
+ if (!fieldCfg) {
178
+ i = valEnd
179
+ continue
180
+ }
181
+ if (fieldCfg.m || fieldCfg.children) {
182
+ const sub = extractReportingTokenContent(data.subarray(valStart, valEnd), fieldCfg.children ?? EMPTY_MAP)
183
+ if (sub === null) {
184
+ return null
185
+ }
186
+ if (sub.length > 0) {
187
+ const newTag = encodeVarint(tag.value)
188
+ const newLen = encodeVarint(sub.length)
189
+ out.push({
190
+ num: fieldNum,
191
+ bytes: Buffer.concat([newTag, newLen, sub])
192
+ })
193
+ }
194
+ i = valEnd
195
+ continue
196
+ }
197
+ out.push({ num: fieldNum, bytes: data.subarray(fieldStart, valEnd) })
198
+ i = valEnd
199
+ continue
200
+ }
201
+ return null
202
+ }
203
+ if (out.length === 0) {
204
+ return Buffer.alloc(0)
205
+ }
206
+ out.sort((a, b) => a.num - b.num)
207
+ return Buffer.concat(out.map(f => f.bytes))
208
+ }
209
+ const decodeVarint = (buffer, offset) => {
210
+ let value = 0
211
+ let bytes = 0
212
+ let shift = 0
213
+ while (offset + bytes < buffer.length) {
214
+ const current = buffer[offset + bytes]
215
+ value |= (current & 0x7f) << shift
216
+ bytes++
217
+ if ((current & 0x80) === 0) {
218
+ return { value, bytes, ok: true }
219
+ }
220
+ shift += 7
221
+ if (shift > 35) {
222
+ return { value: 0, bytes: 0, ok: false }
223
+ }
224
+ }
225
+ return { value: 0, bytes: 0, ok: false }
226
+ }
227
+ const encodeVarint = value => {
228
+ const parts = []
229
+ let remaining = value >>> 0
230
+ while (remaining > 0x7f) {
231
+ parts.push((remaining & 0x7f) | 0x80)
232
+ remaining >>>= 7
233
+ }
234
+ parts.push(remaining)
235
+ return Buffer.from(parts)
236
+ }
237
+ const getMessageReportingToken = async (msgProtobuf, message, key) => {
238
+ const msgSecret = message.messageContextInfo?.messageSecret
239
+ if (!msgSecret || !key.id) {
240
+ return null
241
+ }
242
+ const from = key.fromMe ? key.remoteJid : key.participant || key.remoteJid
243
+ const to = key.fromMe ? key.participant || key.remoteJid : key.remoteJid
244
+ const reportingSecret = generateMsgSecretKey(ENC_SECRET_REPORT_TOKEN, key.id, from, to, msgSecret)
245
+ const content = extractReportingTokenContent(msgProtobuf, compiledReportingFields)
246
+ if (!content || content.length === 0) {
247
+ return null
248
+ }
249
+ const reportingToken = Buffer.from(Crypto_1.hmacSign(content, reportingSecret)).subarray(0, 16)
250
+ return {
251
+ tag: 'reporting',
252
+ attrs: {},
253
+ content: [
254
+ {
255
+ tag: 'reporting_token',
256
+ attrs: { v: '2' },
257
+ content: reportingToken
258
+ }
259
+ ]
260
+ }
261
+ }
262
+ exports.getMessageReportingToken = getMessageReportingToken
@@ -0,0 +1,94 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.createSessionPool = void 0
4
+
5
+ const DISCONNECT_REASON_LOGGED_OUT = 401
6
+
7
+ /**
8
+ * Manages multiple Baileys socket instances (one per account/session), automatically
9
+ * restarting any session that disconnects -- except when it was logged out -- using
10
+ * exponential backoff with jitter, instead of every project re-implementing its own
11
+ * reconnect loop.
12
+ *
13
+ * @param {{
14
+ * makeSocket: (sessionId: string) => Promise<any> | any,
15
+ * logger?: any,
16
+ * maxBackoffMs?: number,
17
+ * onSessionUpdate?: (sessionId: string, sock: any) => void,
18
+ * onLoggedOut?: (sessionId: string) => void
19
+ * }} options
20
+ * @returns {{
21
+ * add: (sessionId: string) => Promise<void>,
22
+ * remove: (sessionId: string) => void,
23
+ * get: (sessionId: string) => any,
24
+ * list: () => string[]
25
+ * }}
26
+ */
27
+ const createSessionPool = options => {
28
+ const logger = options.logger
29
+ const maxBackoffMs = options.maxBackoffMs ?? 60000
30
+ const sessions = new Map() // sessionId -> { sock, attempts, stopped }
31
+
32
+ const computeBackoffMs = attempts => {
33
+ const base = Math.min(1000 * 2 ** attempts, maxBackoffMs)
34
+ return base + Math.floor(Math.random() * (base * 0.2))
35
+ }
36
+
37
+ const start = async sessionId => {
38
+ const entry = sessions.get(sessionId) || { attempts: 0, stopped: false }
39
+ sessions.set(sessionId, entry)
40
+ if (entry.stopped) return
41
+ try {
42
+ const sock = await options.makeSocket(sessionId)
43
+ entry.sock = sock
44
+ options.onSessionUpdate?.(sessionId, sock)
45
+ sock.ev.on('connection.update', update => {
46
+ if (update.connection === 'open') {
47
+ entry.attempts = 0
48
+ }
49
+ if (update.connection === 'close') {
50
+ const statusCode = update.lastDisconnect?.error?.output?.statusCode
51
+ if (statusCode === DISCONNECT_REASON_LOGGED_OUT) {
52
+ logger?.info?.({ sessionId }, 'session logged out, removing from pool')
53
+ sessions.delete(sessionId)
54
+ options.onLoggedOut?.(sessionId)
55
+ return
56
+ }
57
+ if (entry.stopped) return
58
+ entry.attempts += 1
59
+ const backoffMs = computeBackoffMs(entry.attempts)
60
+ logger?.warn?.(
61
+ { sessionId, attempt: entry.attempts, backoffMs },
62
+ 'session disconnected, reconnecting with backoff'
63
+ )
64
+ setTimeout(() => start(sessionId), backoffMs)
65
+ }
66
+ })
67
+ } catch (error) {
68
+ entry.attempts += 1
69
+ const backoffMs = computeBackoffMs(entry.attempts)
70
+ logger?.error?.({ error, sessionId, backoffMs }, 'failed to start session, retrying with backoff')
71
+ if (!entry.stopped) {
72
+ setTimeout(() => start(sessionId), backoffMs)
73
+ }
74
+ }
75
+ }
76
+
77
+ const add = sessionId => start(sessionId)
78
+ const remove = sessionId => {
79
+ const entry = sessions.get(sessionId)
80
+ if (!entry) return
81
+ entry.stopped = true
82
+ if (entry.sock?.end) {
83
+ try {
84
+ entry.sock.end(undefined)
85
+ } catch {}
86
+ }
87
+ sessions.delete(sessionId)
88
+ }
89
+ const get = sessionId => sessions.get(sessionId)?.sock
90
+ const list = () => [...sessions.keys()]
91
+
92
+ return { add, remove, get, list }
93
+ }
94
+ exports.createSessionPool = createSessionPool
@@ -0,0 +1,224 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.getNextPreKeysNode =
4
+ exports.getNextPreKeys =
5
+ exports.extractDeviceJids =
6
+ exports.parseAndInjectE2ESessions =
7
+ exports.extractE2ESessionFromRetryReceipt =
8
+ exports.xmppPreKey =
9
+ exports.xmppSignedPreKey =
10
+ exports.generateOrGetPreKeys =
11
+ exports.getPreKeys =
12
+ exports.createSignalIdentity =
13
+ void 0
14
+ const Defaults_1 = require('../Defaults')
15
+ const WABinary_1 = require('../WABinary')
16
+ const crypto_1 = require('./crypto')
17
+ const generics_1 = require('./generics')
18
+ function chunk(array, size) {
19
+ const chunks = []
20
+ for (let i = 0; i < array.length; i += size) {
21
+ chunks.push(array.slice(i, i + size))
22
+ }
23
+ return chunks
24
+ }
25
+ const createSignalIdentity = (wid, accountSignatureKey) => {
26
+ return {
27
+ identifier: { name: wid, deviceId: 0 },
28
+ identifierKey: (0, crypto_1.generateSignalPubKey)(accountSignatureKey)
29
+ }
30
+ }
31
+ exports.createSignalIdentity = createSignalIdentity
32
+ const getPreKeys = async ({ get }, min, limit) => {
33
+ const idList = []
34
+ for (let id = min; id < limit; id++) {
35
+ idList.push(id.toString())
36
+ }
37
+ return get('pre-key', idList)
38
+ }
39
+ exports.getPreKeys = getPreKeys
40
+ const generateOrGetPreKeys = (creds, range) => {
41
+ const avaliable = creds.nextPreKeyId - creds.firstUnuploadedPreKeyId
42
+ const remaining = range - avaliable
43
+ const lastPreKeyId = creds.nextPreKeyId + remaining - 1
44
+ const newPreKeys = {}
45
+ if (remaining > 0) {
46
+ for (let i = creds.nextPreKeyId; i <= lastPreKeyId; i++) {
47
+ newPreKeys[i] = crypto_1.Curve.generateKeyPair()
48
+ }
49
+ }
50
+ return {
51
+ newPreKeys,
52
+ lastPreKeyId,
53
+ preKeysRange: [creds.firstUnuploadedPreKeyId, range]
54
+ }
55
+ }
56
+ exports.generateOrGetPreKeys = generateOrGetPreKeys
57
+ const xmppSignedPreKey = key => ({
58
+ tag: 'skey',
59
+ attrs: {},
60
+ content: [
61
+ { tag: 'id', attrs: {}, content: (0, generics_1.encodeBigEndian)(key.keyId, 3) },
62
+ { tag: 'value', attrs: {}, content: key.keyPair.public },
63
+ { tag: 'signature', attrs: {}, content: key.signature }
64
+ ]
65
+ })
66
+ exports.xmppSignedPreKey = xmppSignedPreKey
67
+ const xmppPreKey = (pair, id) => ({
68
+ tag: 'key',
69
+ attrs: {},
70
+ content: [
71
+ { tag: 'id', attrs: {}, content: (0, generics_1.encodeBigEndian)(id, 3) },
72
+ { tag: 'value', attrs: {}, content: pair.public }
73
+ ]
74
+ })
75
+ exports.xmppPreKey = xmppPreKey
76
+ const isValidUInt = n => typeof n === 'number' && Number.isInteger(n)
77
+ const extractE2ESessionFromRetryReceipt = receipt => {
78
+ const keysNode = (0, WABinary_1.getBinaryNodeChild)(receipt, 'keys')
79
+ if (!keysNode) return null
80
+ const typeBuf = (0, WABinary_1.getBinaryNodeChildBuffer)(keysNode, 'type')
81
+ if (!typeBuf || typeBuf.length !== 1 || typeBuf[0] !== Defaults_1.KEY_BUNDLE_TYPE[0]) return null
82
+ const identity = (0, WABinary_1.getBinaryNodeChildBuffer)(keysNode, 'identity')
83
+ const skey = (0, WABinary_1.getBinaryNodeChild)(keysNode, 'skey')
84
+ if (!identity || identity.length !== 32 || !skey) return null
85
+ const registrationId = (0, WABinary_1.getBinaryNodeChildUInt)(receipt, 'registration', 4)
86
+ if (!isValidUInt(registrationId)) return null
87
+ const signedPubKey = (0, WABinary_1.getBinaryNodeChildBuffer)(skey, 'value')
88
+ const signedSig = (0, WABinary_1.getBinaryNodeChildBuffer)(skey, 'signature')
89
+ const signedKeyId = (0, WABinary_1.getBinaryNodeChildUInt)(skey, 'id', 3)
90
+ if (!signedPubKey || signedPubKey.length !== 32 || !signedSig || !isValidUInt(signedKeyId)) {
91
+ return null
92
+ }
93
+ const preKeyNode = (0, WABinary_1.getBinaryNodeChild)(keysNode, 'key')
94
+ let preKey
95
+ if (preKeyNode) {
96
+ const preKeyPub = (0, WABinary_1.getBinaryNodeChildBuffer)(preKeyNode, 'value')
97
+ const preKeyId = (0, WABinary_1.getBinaryNodeChildUInt)(preKeyNode, 'id', 3)
98
+ if (!preKeyPub || preKeyPub.length !== 32 || !isValidUInt(preKeyId)) {
99
+ return null
100
+ }
101
+ preKey = { keyId: preKeyId, publicKey: (0, crypto_1.generateSignalPubKey)(preKeyPub) }
102
+ }
103
+ return {
104
+ registrationId,
105
+ identityKey: (0, crypto_1.generateSignalPubKey)(identity),
106
+ signedPreKey: {
107
+ keyId: signedKeyId,
108
+ publicKey: (0, crypto_1.generateSignalPubKey)(signedPubKey),
109
+ signature: signedSig
110
+ },
111
+ preKey
112
+ }
113
+ }
114
+ exports.extractE2ESessionFromRetryReceipt = extractE2ESessionFromRetryReceipt
115
+ const parseAndInjectE2ESessions = async (node, repository) => {
116
+ const extractKey = key =>
117
+ key
118
+ ? {
119
+ keyId: (0, WABinary_1.getBinaryNodeChildUInt)(key, 'id', 3),
120
+ publicKey: (0, crypto_1.generateSignalPubKey)((0, WABinary_1.getBinaryNodeChildBuffer)(key, 'value')),
121
+ signature: (0, WABinary_1.getBinaryNodeChildBuffer)(key, 'signature')
122
+ }
123
+ : undefined
124
+ const nodes = (0, WABinary_1.getBinaryNodeChildren)((0, WABinary_1.getBinaryNodeChild)(node, 'list'), 'user')
125
+ for (const node of nodes) {
126
+ ;(0, WABinary_1.assertNodeErrorFree)(node)
127
+ }
128
+ // Most of the work in repository.injectE2ESession is CPU intensive, not IO
129
+ // So Promise.all doesn't really help here,
130
+ // but blocks even loop if we're using it inside keys.transaction, and it makes it "sync" actually
131
+ // This way we chunk it in smaller parts and between those parts we can yield to the event loop
132
+ // It's rare case when you need to E2E sessions for so many users, but it's possible
133
+ const chunkSize = 100
134
+ const chunks = chunk(nodes, chunkSize)
135
+ for (const nodesChunk of chunks) {
136
+ for (const node of nodesChunk) {
137
+ const signedKey = (0, WABinary_1.getBinaryNodeChild)(node, 'skey')
138
+ const key = (0, WABinary_1.getBinaryNodeChild)(node, 'key')
139
+ const identity = (0, WABinary_1.getBinaryNodeChildBuffer)(node, 'identity')
140
+ const jid = node.attrs.jid
141
+ const registrationId = (0, WABinary_1.getBinaryNodeChildUInt)(node, 'registration', 4)
142
+ await repository.injectE2ESession({
143
+ jid,
144
+ session: {
145
+ registrationId: registrationId,
146
+ identityKey: (0, crypto_1.generateSignalPubKey)(identity),
147
+ signedPreKey: extractKey(signedKey),
148
+ preKey: extractKey(key)
149
+ }
150
+ })
151
+ }
152
+ }
153
+ }
154
+ exports.parseAndInjectE2ESessions = parseAndInjectE2ESessions
155
+ const extractDeviceJids = (result, myJid, myLid, excludeZeroDevices) => {
156
+ const { user: myUser, device: myDevice } = (0, WABinary_1.jidDecode)(myJid)
157
+ const extracted = []
158
+ for (const userResult of result) {
159
+ const { devices, id } = userResult
160
+ const decoded = (0, WABinary_1.jidDecode)(id),
161
+ { user, server } = decoded
162
+ let { domainType } = decoded
163
+ const deviceList = devices?.deviceList
164
+ if (!Array.isArray(deviceList)) continue
165
+ for (const { id: device, keyIndex, isHosted } of deviceList) {
166
+ if (
167
+ (!excludeZeroDevices || device !== 0) && // if zero devices are not-excluded, or device is non zero
168
+ ((myUser !== user && myLid !== user) || myDevice !== device) && // either different user or if me user, not this device
169
+ (device === 0 || !!keyIndex) // ensure that "key-index" is specified for "non-zero" devices, produces a bad req otherwise
170
+ ) {
171
+ if (isHosted) {
172
+ domainType =
173
+ domainType === WABinary_1.WAJIDDomains.LID
174
+ ? WABinary_1.WAJIDDomains.HOSTED_LID
175
+ : WABinary_1.WAJIDDomains.HOSTED
176
+ }
177
+ extracted.push({
178
+ user,
179
+ device,
180
+ domainType,
181
+ server: (0, WABinary_1.getServerFromDomainType)(server, domainType)
182
+ })
183
+ }
184
+ }
185
+ }
186
+ return extracted
187
+ }
188
+ exports.extractDeviceJids = extractDeviceJids
189
+ /**
190
+ * get the next N keys for upload or processing
191
+ * @param count number of pre-keys to get or generate
192
+ */
193
+ const getNextPreKeys = async ({ creds, keys }, count) => {
194
+ const { newPreKeys, lastPreKeyId, preKeysRange } = (0, exports.generateOrGetPreKeys)(creds, count)
195
+ const update = {
196
+ nextPreKeyId: Math.max(lastPreKeyId + 1, creds.nextPreKeyId),
197
+ firstUnuploadedPreKeyId: Math.max(creds.firstUnuploadedPreKeyId, lastPreKeyId + 1)
198
+ }
199
+ await keys.set({ 'pre-key': newPreKeys })
200
+ const preKeys = await (0, exports.getPreKeys)(keys, preKeysRange[0], preKeysRange[0] + preKeysRange[1])
201
+ return { update, preKeys }
202
+ }
203
+ exports.getNextPreKeys = getNextPreKeys
204
+ const getNextPreKeysNode = async (state, count) => {
205
+ const { creds } = state
206
+ const { update, preKeys } = await (0, exports.getNextPreKeys)(state, count)
207
+ const node = {
208
+ tag: 'iq',
209
+ attrs: {
210
+ xmlns: 'encrypt',
211
+ type: 'set',
212
+ to: WABinary_1.S_WHATSAPP_NET
213
+ },
214
+ content: [
215
+ { tag: 'registration', attrs: {}, content: (0, generics_1.encodeBigEndian)(creds.registrationId) },
216
+ { tag: 'type', attrs: {}, content: Defaults_1.KEY_BUNDLE_TYPE },
217
+ { tag: 'identity', attrs: {}, content: creds.signedIdentityKey.public },
218
+ { tag: 'list', attrs: {}, content: Object.keys(preKeys).map(k => (0, exports.xmppPreKey)(preKeys[+k], +k)) },
219
+ (0, exports.xmppSignedPreKey)(creds.signedPreKey)
220
+ ]
221
+ }
222
+ return { update, node }
223
+ }
224
+ exports.getNextPreKeysNode = getNextPreKeysNode
@@ -0,0 +1,40 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.buildAckStanza = buildAckStanza
4
+ /**
5
+ * Builds an ACK stanza for a received node.
6
+ * Pure function -- no I/O, no side effects.
7
+ *
8
+ * Mirrors WhatsApp Web's ACK construction:
9
+ * - WAWebHandleMsgSendAck.sendAck / sendNack
10
+ * - WAWebCreateNackFromStanza.createNackFromStanza
11
+ */
12
+ function buildAckStanza(node, errorCode, meId) {
13
+ const { tag, attrs } = node
14
+ const stanza = {
15
+ tag: 'ack',
16
+ attrs: {
17
+ id: attrs.id,
18
+ to: attrs.from,
19
+ class: tag
20
+ }
21
+ }
22
+ if (errorCode) {
23
+ stanza.attrs.error = errorCode.toString()
24
+ }
25
+ if (attrs.participant) {
26
+ stanza.attrs.participant = attrs.participant
27
+ }
28
+ if (attrs.recipient) {
29
+ stanza.attrs.recipient = attrs.recipient
30
+ }
31
+ // WA Web always includes type when present: `n.type || DROP_ATTR`
32
+ if (attrs.type) {
33
+ stanza.attrs.type = attrs.type
34
+ }
35
+ // WA Web WAWebHandleMsgSendAck.sendAck/sendNack always include `from` for message-class ACKs
36
+ if (tag === 'message' && meId) {
37
+ stanza.attrs.from = meId
38
+ }
39
+ return stanza
40
+ }