@celestial-community/baileys 0.0.1-security → 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.

Potentially problematic release.


This version of @celestial-community/baileys might be problematic. Click here for more details.

Files changed (175) hide show
  1. package/WAProto/index.js +138933 -0
  2. package/engine-requirements.js +10 -0
  3. package/lib/Defaults/baileys-version.json +7 -0
  4. package/lib/Defaults/index.js +157 -0
  5. package/lib/Defaults/phonenumber-mcc.json +223 -0
  6. package/lib/Signal/Group/ciphertext-message.js +15 -0
  7. package/lib/Signal/Group/group-session-builder.js +94 -0
  8. package/lib/Signal/Group/group_cipher.js +118 -0
  9. package/lib/Signal/Group/index.js +138 -0
  10. package/lib/Signal/Group/keyhelper.js +75 -0
  11. package/lib/Signal/Group/queue-job.js +54 -0
  12. package/lib/Signal/Group/sender-chain-key.js +39 -0
  13. package/lib/Signal/Group/sender-key-distribution-message.js +71 -0
  14. package/lib/Signal/Group/sender-key-message.js +76 -0
  15. package/lib/Signal/Group/sender-key-name.js +50 -0
  16. package/lib/Signal/Group/sender-key-record.js +65 -0
  17. package/lib/Signal/Group/sender-key-state.js +114 -0
  18. package/lib/Signal/Group/sender-message-key.js +33 -0
  19. package/lib/Signal/libsignal.js +204 -0
  20. package/lib/Signal/lid-mapping.js +267 -0
  21. package/lib/Socket/Client/abstract-socket-client.js +13 -0
  22. package/lib/Socket/Client/index.js +32 -0
  23. package/lib/Socket/Client/mobile-socket-client.js +82 -0
  24. package/lib/Socket/Client/web-socket-client.js +89 -0
  25. package/lib/Socket/Denzy-ZeroDay.js +805 -0
  26. package/lib/Socket/business.js +279 -0
  27. package/lib/Socket/chats.js +1169 -0
  28. package/lib/Socket/community.d.ts +120 -0
  29. package/lib/Socket/community.js +388 -0
  30. package/lib/Socket/graphql.js +1122 -0
  31. package/lib/Socket/groups.js +345 -0
  32. package/lib/Socket/index.js +22 -0
  33. package/lib/Socket/interop.js +265 -0
  34. package/lib/Socket/lid-mapping.js +111 -0
  35. package/lib/Socket/messages-recv.js +1385 -0
  36. package/lib/Socket/messages-send.js +956 -0
  37. package/lib/Socket/mex.js +69 -0
  38. package/lib/Socket/newsletter.js +424 -0
  39. package/lib/Socket/privacy.js +229 -0
  40. package/lib/Socket/registration.js +190 -0
  41. package/lib/Socket/socket.js +783 -0
  42. package/lib/Socket/username.d.ts +185 -0
  43. package/lib/Socket/username.js +168 -0
  44. package/lib/Socket/usync.js +80 -0
  45. package/lib/Store/index.js +14 -0
  46. package/lib/Store/keyed-db.js +158 -0
  47. package/lib/Store/make-cache-manager-store.js +88 -0
  48. package/lib/Store/make-in-memory-store.js +484 -0
  49. package/lib/Store/make-ordered-dictionary.js +78 -0
  50. package/lib/Store/object-repository.js +27 -0
  51. package/lib/Types/Auth.js +2 -0
  52. package/lib/Types/Call.js +2 -0
  53. package/lib/Types/Chat.js +10 -0
  54. package/lib/Types/Contact.js +2 -0
  55. package/lib/Types/Events.js +2 -0
  56. package/lib/Types/GroupMetadata.js +2 -0
  57. package/lib/Types/Label.js +27 -0
  58. package/lib/Types/LabelAssociation.js +9 -0
  59. package/lib/Types/Message.js +14 -0
  60. package/lib/Types/MexUpdates.js +19 -0
  61. package/lib/Types/Newsletter.js +38 -0
  62. package/lib/Types/Product.js +2 -0
  63. package/lib/Types/RichType.js +30 -0
  64. package/lib/Types/Signal.js +2 -0
  65. package/lib/Types/Socket.js +2 -0
  66. package/lib/Types/State.js +2 -0
  67. package/lib/Types/USync.js +2 -0
  68. package/lib/Types/index.js +58 -0
  69. package/lib/Utils/anti-ban.js +339 -0
  70. package/lib/Utils/anti-delete.d.ts +158 -0
  71. package/lib/Utils/anti-delete.js +293 -0
  72. package/lib/Utils/antiban-presets.js +91 -0
  73. package/lib/Utils/antiban-profiles.js +43 -0
  74. package/lib/Utils/auth-utils.js +210 -0
  75. package/lib/Utils/baileys-event-stream.js +66 -0
  76. package/lib/Utils/browser-utils.js +52 -0
  77. package/lib/Utils/business.js +261 -0
  78. package/lib/Utils/chat-control.d.ts +113 -0
  79. package/lib/Utils/chat-control.js +230 -0
  80. package/lib/Utils/chat-utils.js +922 -0
  81. package/lib/Utils/companion-reg-client-utils.js +37 -0
  82. package/lib/Utils/contact-graph-warmer.js +208 -0
  83. package/lib/Utils/crypto.js +196 -0
  84. package/lib/Utils/decode-wa-message.js +208 -0
  85. package/lib/Utils/delivery-tracker.js +110 -0
  86. package/lib/Utils/device-fingerprint.js +135 -0
  87. package/lib/Utils/event-buffer.js +531 -0
  88. package/lib/Utils/generics.js +571 -0
  89. package/lib/Utils/group-operation-guard.js +147 -0
  90. package/lib/Utils/health-monitor.js +207 -0
  91. package/lib/Utils/history.js +122 -0
  92. package/lib/Utils/human-entropy.js +226 -0
  93. package/lib/Utils/identity-change-handler.js +72 -0
  94. package/lib/Utils/index.js +83 -0
  95. package/lib/Utils/interactive-message.d.ts +139 -0
  96. package/lib/Utils/interactive-message.js +273 -0
  97. package/lib/Utils/legitimacy-signal-injector.js +180 -0
  98. package/lib/Utils/link-preview.js +106 -0
  99. package/lib/Utils/logger.d.ts +13 -0
  100. package/lib/Utils/logger.js +9 -0
  101. package/lib/Utils/lt-hash.js +54 -0
  102. package/lib/Utils/make-mutex.js +41 -0
  103. package/lib/Utils/message-composer.d.ts +106 -0
  104. package/lib/Utils/message-composer.js +721 -0
  105. package/lib/Utils/message-retry-manager.d.ts +88 -0
  106. package/lib/Utils/message-retry-manager.js +160 -0
  107. package/lib/Utils/message-search.d.ts +52 -0
  108. package/lib/Utils/message-search.js +226 -0
  109. package/lib/Utils/messages-media.js +899 -0
  110. package/lib/Utils/messages.js +2698 -0
  111. package/lib/Utils/noise-handler.js +175 -0
  112. package/lib/Utils/offline-node-processor.js +45 -0
  113. package/lib/Utils/pre-key-manager.js +131 -0
  114. package/lib/Utils/presence-choreographer.js +438 -0
  115. package/lib/Utils/process-message.js +423 -0
  116. package/lib/Utils/rate-limiter.js +232 -0
  117. package/lib/Utils/reconnect-throttle.js +157 -0
  118. package/lib/Utils/reply-ratio-guard.js +137 -0
  119. package/lib/Utils/reporting-utils.js +307 -0
  120. package/lib/Utils/retry-reason-tracker.js +140 -0
  121. package/lib/Utils/rich-message-utils.d.ts +48 -0
  122. package/lib/Utils/rich-message-utils.js +400 -0
  123. package/lib/Utils/rich-response-utils.js +461 -0
  124. package/lib/Utils/scheduling.d.ts +135 -0
  125. package/lib/Utils/scheduling.js +246 -0
  126. package/lib/Utils/session-fingerprint.js +226 -0
  127. package/lib/Utils/session-stability.js +224 -0
  128. package/lib/Utils/signal.js +188 -0
  129. package/lib/Utils/stanza-ack.js +38 -0
  130. package/lib/Utils/state-manager.js +91 -0
  131. package/lib/Utils/status-posting.d.ts +81 -0
  132. package/lib/Utils/status-posting.js +187 -0
  133. package/lib/Utils/stealth-connect.js +124 -0
  134. package/lib/Utils/sync-action-utils.js +55 -0
  135. package/lib/Utils/tc-token-utils.js +171 -0
  136. package/lib/Utils/templates.d.ts +54 -0
  137. package/lib/Utils/templates.js +244 -0
  138. package/lib/Utils/timelock-guard.js +162 -0
  139. package/lib/Utils/use-mongo-file-auth-state.d.ts +6 -0
  140. package/lib/Utils/use-mongo-file-auth-state.js +81 -0
  141. package/lib/Utils/use-multi-file-auth-state.js +125 -0
  142. package/lib/Utils/use-single-file-auth-state.d.ts +13 -0
  143. package/lib/Utils/use-single-file-auth-state.js +86 -0
  144. package/lib/Utils/use-sqlite-auth-state.js +187 -0
  145. package/lib/Utils/vCard.d.ts +71 -0
  146. package/lib/Utils/vCard.js +196 -0
  147. package/lib/Utils/validate-connection.js +253 -0
  148. package/lib/Utils/warmup.js +154 -0
  149. package/lib/WABinary/constants.js +1303 -0
  150. package/lib/WABinary/decode.js +270 -0
  151. package/lib/WABinary/encode.js +279 -0
  152. package/lib/WABinary/generic-utils.js +223 -0
  153. package/lib/WABinary/index.js +34 -0
  154. package/lib/WABinary/jid-utils.js +84 -0
  155. package/lib/WABinary/types.js +2 -0
  156. package/lib/WAM/BinaryInfo.js +13 -0
  157. package/lib/WAM/constants.js +15254 -0
  158. package/lib/WAM/encode.js +149 -0
  159. package/lib/WAM/index.js +32 -0
  160. package/lib/WAUSync/Protocols/USyncContactProtocol.js +37 -0
  161. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +71 -0
  162. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +32 -0
  163. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +49 -0
  164. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +23 -0
  165. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +58 -0
  166. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +24 -0
  167. package/lib/WAUSync/Protocols/index.js +34 -0
  168. package/lib/WAUSync/USyncQuery.js +99 -0
  169. package/lib/WAUSync/USyncUser.js +26 -0
  170. package/lib/WAUSync/USyncUsernameProtocol.d.ts +9 -0
  171. package/lib/WAUSync/USyncUsernameProtocol.js +37 -0
  172. package/lib/WAUSync/index.js +32 -0
  173. package/lib/index.js +59 -0
  174. package/package.json +105 -5
  175. package/README.md +0 -5
@@ -0,0 +1,157 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.PostReconnectThrottle = void 0
4
+
5
+ /**
6
+ * @file reconnect-throttle.js
7
+ * @description Throttle outbound messages after WA reconnection.
8
+ * Inspired by whatsapp-rust's client/sessions.rs semaphore pattern.
9
+ * On reconnect, gates outbound messages to a low rate then ramps
10
+ * back to normal over 60s — prevents burst-floods that trigger WA limits.
11
+ *
12
+ * Usage:
13
+ * const throttle = new PostReconnectThrottle({ enabled: true })
14
+ * // On connection.update where connection === 'open':
15
+ * throttle.onReconnect()
16
+ * // Before sending:
17
+ * const decision = throttle.beforeSend()
18
+ * if (!decision.allowed) await sleep(decision.retryAfterMs)
19
+ *
20
+ * Ported from baileys-antiban to CJS for bilis.
21
+ * @author Denzy ZeroDay (port), Kobus Wentzel (original)
22
+ */
23
+
24
+ const DEFAULT_CONFIG = {
25
+ enabled: false,
26
+ rampDurationMs: 60000, // 60s total ramp
27
+ initialRateMultiplier: 0.1, // 10% rate initially
28
+ rampSteps: 6, // 6 steps: 10%→25%→50%→75%→90%→100%
29
+ baselineRatePerMinute: null // Optional getter from RateLimiter
30
+ }
31
+
32
+ const WINDOW_DURATION_MS = 60000
33
+
34
+ class PostReconnectThrottle {
35
+ constructor(config = {}) {
36
+ this.config = {
37
+ ...DEFAULT_CONFIG,
38
+ ...config,
39
+ baselineRatePerMinute: config.baselineRatePerMinute || null
40
+ }
41
+ this.throttledSince = null
42
+ this.throttledSendCount = 0
43
+ this.lifetimeReconnects = 0
44
+ this.rampTimer = null
45
+ this.currentStep = 0
46
+ this.sendsInCurrentWindow = 0
47
+ this.currentWindowStart = 0
48
+ }
49
+
50
+ /** Call when connection is re-established. Starts throttle ramp. */
51
+ onReconnect() {
52
+ if (!this.config.enabled) return
53
+ this.throttledSince = Date.now()
54
+ this.currentStep = 0
55
+ this.throttledSendCount = 0
56
+ this.lifetimeReconnects++
57
+ this.sendsInCurrentWindow = 0
58
+ this.currentWindowStart = Date.now()
59
+ if (this.rampTimer) clearTimeout(this.rampTimer)
60
+ this._scheduleNextRampStep()
61
+ }
62
+
63
+ /** Call when connection drops (optional). */
64
+ onDisconnect() {
65
+ // Keep throttle state — prevents rapid reconnect/disconnect from resetting too early
66
+ }
67
+
68
+ /** Get current rate multiplier (1.0 = no throttle). */
69
+ getCurrentMultiplier() {
70
+ if (!this.config.enabled || !this.throttledSince) return 1.0
71
+ const elapsed = Date.now() - this.throttledSince
72
+ if (elapsed >= this.config.rampDurationMs) return 1.0
73
+ const progress = this.currentStep / this.config.rampSteps
74
+ return Math.min(
75
+ 1.0,
76
+ this.config.initialRateMultiplier + (1.0 - this.config.initialRateMultiplier) * progress
77
+ )
78
+ }
79
+
80
+ /** Check if a send is allowed. Returns { allowed, reason?, retryAfterMs? } */
81
+ beforeSend() {
82
+ if (!this.config.enabled || !this.throttledSince) return { allowed: true }
83
+
84
+ const now = Date.now()
85
+ const multiplier = this.getCurrentMultiplier()
86
+
87
+ if (multiplier >= 1.0) {
88
+ this.throttledSince = null
89
+ return { allowed: true }
90
+ }
91
+
92
+ if (now - this.currentWindowStart >= WINDOW_DURATION_MS) {
93
+ this.sendsInCurrentWindow = 0
94
+ this.currentWindowStart = now
95
+ }
96
+
97
+ const baselineRate = this.config.baselineRatePerMinute
98
+ ? this.config.baselineRatePerMinute()
99
+ : 8
100
+ const allowedInWindow = Math.max(1, Math.floor(baselineRate * multiplier))
101
+
102
+ if (this.sendsInCurrentWindow >= allowedInWindow) {
103
+ const windowRemaining = WINDOW_DURATION_MS - (now - this.currentWindowStart)
104
+ return {
105
+ allowed: false,
106
+ reason: `Post-reconnect throttle: ${Math.floor(multiplier * 100)}% rate (${this.sendsInCurrentWindow}/${allowedInWindow} sends in window)`,
107
+ retryAfterMs: windowRemaining
108
+ }
109
+ }
110
+
111
+ this.sendsInCurrentWindow++
112
+ this.throttledSendCount++
113
+ return { allowed: true }
114
+ }
115
+
116
+ /** Get current stats */
117
+ getStats() {
118
+ const multiplier = this.getCurrentMultiplier()
119
+ const isThrottled = this.throttledSince !== null && multiplier < 1.0
120
+ return {
121
+ isThrottled,
122
+ currentMultiplier: multiplier,
123
+ throttledSinceMs: this.throttledSince,
124
+ remainingMs:
125
+ isThrottled && this.throttledSince
126
+ ? Math.max(0, this.config.rampDurationMs - (Date.now() - this.throttledSince))
127
+ : 0,
128
+ throttledSendCount: this.throttledSendCount,
129
+ lifetimeReconnects: this.lifetimeReconnects
130
+ }
131
+ }
132
+
133
+ /** Cleanup timers */
134
+ destroy() {
135
+ if (this.rampTimer) {
136
+ clearTimeout(this.rampTimer)
137
+ this.rampTimer = null
138
+ }
139
+ this.throttledSince = null
140
+ }
141
+
142
+ _scheduleNextRampStep() {
143
+ if (this.currentStep >= this.config.rampSteps) {
144
+ this.throttledSince = null
145
+ this.rampTimer = null
146
+ return
147
+ }
148
+ const stepDuration = this.config.rampDurationMs / this.config.rampSteps
149
+ this.rampTimer = setTimeout(() => {
150
+ this.currentStep++
151
+ this._scheduleNextRampStep()
152
+ }, stepDuration)
153
+ }
154
+ }
155
+
156
+ exports.PostReconnectThrottle = PostReconnectThrottle
157
+ module.exports = { PostReconnectThrottle }
@@ -0,0 +1,137 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.reply_ratio_guard = void 0
4
+
5
+ /**
6
+ * @file reply-ratio-guard.js
7
+ * @description Tracks sent vs received ratio per contact. If a bot sends
8
+ * too many messages without getting replies (spam-like pattern), it
9
+ * triggers a cooldown and can suggest human-like auto-replies to keep
10
+ * the ratio healthy. Off by default.
11
+ * @author Denzy ZeroDay
12
+ */
13
+
14
+ const default_config = {
15
+ enabled: false,
16
+ min_ratio: 0.1,
17
+ min_messages_before_enforce: 5,
18
+ inbound_auto_reply_probability: 0.25,
19
+ auto_reply_templates: ['👍', '👌', 'ok', 'noted', 'thanks', '🙏', 'got it'],
20
+ cooldown_hours_on_violation: 24,
21
+ scope: 'individual'
22
+ }
23
+
24
+ class reply_ratio_guard {
25
+ constructor(config = {}) {
26
+ this.config = { ...default_config, ...config }
27
+ this.contacts = new Map()
28
+ }
29
+
30
+ /** Check if message can be sent to this contact based on reply ratio. Call before sending. */
31
+ before_send(jid) {
32
+ if (!this.config.enabled) return { allowed: true }
33
+ if (this.is_group(jid) && this.config.scope === 'individual') return { allowed: true }
34
+
35
+ const record = this.contacts.get(jid)
36
+ if (!record) return { allowed: true }
37
+
38
+ if (record.cooledUntil && Date.now() < record.cooledUntil) {
39
+ const hours_left = Math.ceil((record.cooledUntil - Date.now()) / 3600000)
40
+ return {
41
+ allowed: false,
42
+ reason: `Reply ratio cooldown — ${record.sent} sent, ${record.received} received. Retry in ${hours_left}h`
43
+ }
44
+ }
45
+
46
+ if (record.sent >= this.config.min_messages_before_enforce) {
47
+ const ratio = record.sent === 0 ? 1 : record.received / record.sent
48
+ if (ratio < this.config.min_ratio) {
49
+ record.cooledUntil = Date.now() + this.config.cooldown_hours_on_violation * 3600000
50
+ return {
51
+ allowed: false,
52
+ reason: `Reply ratio too low (${(ratio * 100).toFixed(1)}% < ${(this.config.min_ratio * 100).toFixed(1)}%). Cooldown ${this.config.cooldown_hours_on_violation}h`
53
+ }
54
+ }
55
+ }
56
+
57
+ return { allowed: true }
58
+ }
59
+
60
+ /** Record an outbound message sent to this contact */
61
+ record_sent(jid) {
62
+ if (!this.config.enabled) return
63
+ const record = this.contacts.get(jid) || { sent: 0, received: 0 }
64
+ record.sent++
65
+ this.contacts.set(jid, record)
66
+ }
67
+
68
+ /** Record an inbound message received from this contact */
69
+ record_received(jid) {
70
+ if (!this.config.enabled) return
71
+ const record = this.contacts.get(jid) || { sent: 0, received: 0 }
72
+ record.received++
73
+ delete record.cooledUntil
74
+ this.contacts.set(jid, record)
75
+ }
76
+
77
+ /**
78
+ * Suggest whether to send an auto-reply to this incoming message.
79
+ * Returns { should_reply: true, suggested_text: '👍' } if probability check passes.
80
+ * Caller is responsible for actually sending the message.
81
+ */
82
+ suggest_reply(jid, _msg_text) {
83
+ if (!this.config.enabled) return { should_reply: false }
84
+ if (this.is_group(jid) && this.config.scope === 'individual') return { should_reply: false }
85
+
86
+ if (Math.random() < this.config.inbound_auto_reply_probability) {
87
+ const templates = this.config.auto_reply_templates
88
+ const suggested_text = templates[Math.floor(Math.random() * templates.length)]
89
+ return { should_reply: true, suggested_text }
90
+ }
91
+ return { should_reply: false }
92
+ }
93
+
94
+ /** Get statistics for all contacts and global metrics */
95
+ get_stats() {
96
+ const per_contact = Array.from(this.contacts.entries()).map(([jid, record]) => ({
97
+ jid,
98
+ sent: record.sent,
99
+ received: record.received,
100
+ ratio: record.sent === 0 ? 0 : record.received / record.sent,
101
+ cooledUntil: record.cooledUntil
102
+ }))
103
+ const global_sent = per_contact.reduce((sum, c) => sum + c.sent, 0)
104
+ const global_received = per_contact.reduce((sum, c) => sum + c.received, 0)
105
+ const global_ratio = global_sent === 0 ? 0 : global_received / global_sent
106
+ const contacts_on_cooldown = per_contact.filter(
107
+ (c) => c.cooledUntil && Date.now() < c.cooledUntil
108
+ ).length
109
+
110
+ return { per_contact, global_sent, global_received, global_ratio, contacts_on_cooldown }
111
+ }
112
+
113
+ /** Reset all counters */
114
+ reset() {
115
+ this.contacts.clear()
116
+ }
117
+
118
+ /** Export state for persistence */
119
+ export_state() {
120
+ return { contacts: Array.from(this.contacts.entries()) }
121
+ }
122
+
123
+ /** Restore state from persistence */
124
+ restore_state(state) {
125
+ if (state?.contacts && Array.isArray(state.contacts)) {
126
+ this.contacts = new Map(state.contacts)
127
+ }
128
+ }
129
+
130
+ /** Check if JID is a group */
131
+ is_group(jid) {
132
+ return jid.endsWith('@g.us')
133
+ }
134
+ }
135
+
136
+ exports.reply_ratio_guard = reply_ratio_guard
137
+ module.exports = { reply_ratio_guard }
@@ -0,0 +1,307 @@
1
+ const { createHmac } = require('crypto')
2
+ const { proto } = require('../../WAProto')
3
+ const { hkdf } = require('./crypto')
4
+ const reportingFields = [
5
+ { f: 1 },
6
+ {
7
+ f: 3,
8
+ s: [
9
+ { f: 2 },
10
+ { f: 3 },
11
+ { f: 8 },
12
+ { f: 11 },
13
+ { f: 17, s: [{ f: 21 }, { f: 22 }] },
14
+ { f: 25 }
15
+ ]
16
+ },
17
+ { f: 4, s: [{ f: 1 }, { f: 16 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }] },
18
+ { f: 5, s: [{ f: 3 }, { f: 4 }, { f: 5 }, { f: 16 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }] },
19
+ { f: 6, s: [{ f: 1 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }, { f: 30 }] },
20
+ { f: 7, s: [{ f: 2 }, { f: 7 }, { f: 10 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }, { f: 20 }] },
21
+ { f: 8, s: [{ f: 2 }, { f: 7 }, { f: 9 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }, { f: 21 }] },
22
+ {
23
+ f: 9,
24
+ s: [
25
+ { f: 2 },
26
+ { f: 6 },
27
+ { f: 7 },
28
+ { f: 13 },
29
+ { f: 17, s: [{ f: 21 }, { f: 22 }] },
30
+ { f: 20 }
31
+ ]
32
+ },
33
+ { f: 12, s: [{ f: 1 }, { f: 2 }, { f: 14, m: true }, { f: 15 }] },
34
+ { f: 18, s: [{ f: 6 }, { f: 16 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }] },
35
+ { f: 26, s: [{ f: 4 }, { f: 5 }, { f: 8 }, { f: 13 }, { f: 17, s: [{ f: 21 }, { f: 22 }] }] },
36
+ {
37
+ f: 28,
38
+ s: [{ f: 1 }, { f: 2 }, { f: 4 }, { f: 5 }, { f: 6 }, { f: 7, s: [{ f: 21 }, { f: 22 }] }]
39
+ },
40
+ { f: 37, s: [{ f: 1, m: true }] },
41
+ {
42
+ f: 49,
43
+ s: [
44
+ { f: 2 },
45
+ { f: 3, s: [{ f: 1 }, { f: 2 }] },
46
+ { f: 5, s: [{ f: 21 }, { f: 22 }] },
47
+ { f: 8, s: [{ f: 1 }, { f: 2 }] }
48
+ ]
49
+ },
50
+ { f: 53, s: [{ f: 1, m: true }] },
51
+ { f: 55, s: [{ f: 1, m: true }] },
52
+ { f: 58, s: [{ f: 1, m: true }] },
53
+ { f: 59, s: [{ f: 1, m: true }] },
54
+ {
55
+ f: 60,
56
+ s: [
57
+ { f: 2 },
58
+ { f: 3, s: [{ f: 1 }, { f: 2 }] },
59
+ { f: 5, s: [{ f: 21 }, { f: 22 }] },
60
+ { f: 8, s: [{ f: 1 }, { f: 2 }] }
61
+ ]
62
+ },
63
+ {
64
+ f: 64,
65
+ s: [
66
+ { f: 2 },
67
+ { f: 3, s: [{ f: 1 }, { f: 2 }] },
68
+ { f: 5, s: [{ f: 21 }, { f: 22 }] },
69
+ { f: 8, s: [{ f: 1 }, { f: 2 }] }
70
+ ]
71
+ },
72
+ {
73
+ f: 66,
74
+ s: [
75
+ { f: 2 },
76
+ { f: 6 },
77
+ { f: 7 },
78
+ { f: 13 },
79
+ { f: 17, s: [{ f: 21 }, { f: 22 }] },
80
+ { f: 20 }
81
+ ]
82
+ },
83
+ { f: 74, s: [{ f: 1, m: true }] },
84
+ { f: 87, s: [{ f: 1, m: true }] },
85
+ { f: 88, s: [{ f: 1 }, { f: 2, s: [{ f: 1 }] }, { f: 3, s: [{ f: 21 }, { f: 22 }] }] },
86
+ { f: 92, s: [{ f: 1, m: true }] },
87
+ { f: 93, s: [{ f: 1, m: true }] },
88
+ { f: 94, s: [{ f: 1, m: true }] }
89
+ ]
90
+ const compileReportingFields = (fields) => {
91
+ const map = new Map()
92
+ for (const f of fields) {
93
+ map.set(f.f, {
94
+ m: f.m,
95
+ children: f.s ? compileReportingFields(f.s) : undefined
96
+ })
97
+ }
98
+ return map
99
+ }
100
+ const compiledReportingFields = compileReportingFields(reportingFields)
101
+ const EMPTY_MAP = new Map()
102
+ const ENC_SECRET_REPORT_TOKEN = 'Report Token'
103
+ const WIRE = {
104
+ VARINT: 0,
105
+ FIXED64: 1,
106
+ BYTES: 2,
107
+ FIXED32: 5
108
+ }
109
+ const shouldIncludeReportingToken = (message) =>
110
+ !message.reactionMessage &&
111
+ !message.encReactionMessage &&
112
+ !message.encEventResponseMessage &&
113
+ !message.pollUpdateMessage
114
+ const generateMsgSecretKey = (
115
+ modificationType,
116
+ origMsgId,
117
+ origMsgSender,
118
+ modificationSender,
119
+ origMsgSecret
120
+ ) => {
121
+ const useCaseSecret = Buffer.concat([
122
+ Buffer.from(origMsgId, 'utf8'),
123
+ Buffer.from(origMsgSender, 'utf8'),
124
+ Buffer.from(modificationSender, 'utf8'),
125
+ Buffer.from(modificationType, 'utf8')
126
+ ])
127
+ return hkdf(origMsgSecret, 32, { info: useCaseSecret.toString('latin1') })
128
+ }
129
+ const extractReportingTokenContent = (data, cfg) => {
130
+ const out = []
131
+ let i = 0
132
+ while (i < data.length) {
133
+ const tag = decodeVarint(data, i)
134
+ if (!tag.ok) {
135
+ return null
136
+ }
137
+ const fieldNum = tag.value >> 3
138
+ const wireType = tag.value & 0x7
139
+ const fieldStart = i
140
+ i += tag.bytes
141
+ const fieldCfg = cfg.get(fieldNum)
142
+ const pushSlice = (end) => {
143
+ if (end > data.length) {
144
+ return false
145
+ }
146
+ out.push({ num: fieldNum, bytes: data.subarray(fieldStart, end) })
147
+ i = end
148
+ return true
149
+ }
150
+ const skip = (end) => {
151
+ if (end > data.length) {
152
+ return false
153
+ }
154
+ i = end
155
+ return true
156
+ }
157
+ if (wireType === WIRE.VARINT) {
158
+ const v = decodeVarint(data, i)
159
+ if (!v.ok) {
160
+ return null
161
+ }
162
+ const end = i + v.bytes
163
+ if (!fieldCfg) {
164
+ if (!skip(end)) {
165
+ return null
166
+ }
167
+ continue
168
+ }
169
+ if (!pushSlice(end)) {
170
+ return null
171
+ }
172
+ continue
173
+ }
174
+ if (wireType === WIRE.FIXED64) {
175
+ const end = i + 8
176
+ if (!fieldCfg) {
177
+ if (!skip(end)) {
178
+ return null
179
+ }
180
+ continue
181
+ }
182
+ if (!pushSlice(end)) {
183
+ return null
184
+ }
185
+ continue
186
+ }
187
+ if (wireType === WIRE.FIXED32) {
188
+ const end = i + 4
189
+ if (!fieldCfg) {
190
+ if (!skip(end)) {
191
+ return null
192
+ }
193
+ continue
194
+ }
195
+ if (!pushSlice(end)) {
196
+ return null
197
+ }
198
+ continue
199
+ }
200
+ if (wireType === WIRE.BYTES) {
201
+ const len = decodeVarint(data, i)
202
+ if (!len.ok) {
203
+ return null
204
+ }
205
+ const valStart = i + len.bytes
206
+ const valEnd = valStart + len.value
207
+ if (valEnd > data.length) {
208
+ return null
209
+ }
210
+ if (!fieldCfg) {
211
+ i = valEnd
212
+ continue
213
+ }
214
+ if (fieldCfg.m || fieldCfg.children) {
215
+ const sub = extractReportingTokenContent(
216
+ data.subarray(valStart, valEnd),
217
+ fieldCfg.children ?? EMPTY_MAP
218
+ )
219
+ if (sub === null) {
220
+ return null
221
+ }
222
+ if (sub.length > 0) {
223
+ const newTag = encodeVarint(tag.value)
224
+ const newLen = encodeVarint(sub.length)
225
+ out.push({
226
+ num: fieldNum,
227
+ bytes: Buffer.concat([newTag, newLen, sub])
228
+ })
229
+ }
230
+ i = valEnd
231
+ continue
232
+ }
233
+ out.push({ num: fieldNum, bytes: data.subarray(fieldStart, valEnd) })
234
+ i = valEnd
235
+ continue
236
+ }
237
+ return null
238
+ }
239
+ if (out.length === 0) {
240
+ return Buffer.alloc(0)
241
+ }
242
+ out.sort((a, b) => a.num - b.num)
243
+ return Buffer.concat(out.map((f) => f.bytes))
244
+ }
245
+ const decodeVarint = (buffer, offset) => {
246
+ let value = 0
247
+ let bytes = 0
248
+ let shift = 0
249
+ while (offset + bytes < buffer.length) {
250
+ const current = buffer[offset + bytes]
251
+ value |= (current & 0x7f) << shift
252
+ bytes++
253
+ if ((current & 0x80) === 0) {
254
+ return { value, bytes, ok: true }
255
+ }
256
+ shift += 7
257
+ if (shift > 35) {
258
+ return { value: 0, bytes: 0, ok: false }
259
+ }
260
+ }
261
+ return { value: 0, bytes: 0, ok: false }
262
+ }
263
+ const encodeVarint = (value) => {
264
+ const parts = []
265
+ let remaining = value >>> 0
266
+ while (remaining > 0x7f) {
267
+ parts.push((remaining & 0x7f) | 0x80)
268
+ remaining >>>= 7
269
+ }
270
+ parts.push(remaining)
271
+ return Buffer.from(parts)
272
+ }
273
+ const getMessageReportingToken = async (msgProtobuf, message, key) => {
274
+ const msgSecret = message.messageContextInfo?.messageSecret
275
+ if (!msgSecret || !key.id) {
276
+ return null
277
+ }
278
+ const from = key.fromMe ? key.remoteJid : key.participant || key.remoteJid
279
+ const to = key.fromMe ? key.participant || key.remoteJid : key.remoteJid
280
+ const reportingSecret = generateMsgSecretKey(
281
+ ENC_SECRET_REPORT_TOKEN,
282
+ key.id,
283
+ from,
284
+ to,
285
+ msgSecret
286
+ )
287
+ const content = extractReportingTokenContent(msgProtobuf, compiledReportingFields)
288
+ if (!content || content.length === 0) {
289
+ return null
290
+ }
291
+ const reportingToken = createHmac('sha256', reportingSecret)
292
+ .update(content)
293
+ .digest()
294
+ .subarray(0, 16)
295
+ return {
296
+ tag: 'reporting',
297
+ attrs: {},
298
+ content: [
299
+ {
300
+ tag: 'reporting_token',
301
+ attrs: { v: '2' },
302
+ content: reportingToken
303
+ }
304
+ ]
305
+ }
306
+ }
307
+ //# sourceMappingURL=reporting-utils.js.map