gifted-baileys 1.5.0 → 1.5.5

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 (222) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1429 -684
  3. package/package.json +11 -26
  4. package/src/Defaults/baileys-version.json +3 -0
  5. package/{lib → src}/Defaults/index.js +16 -8
  6. package/src/Defaults/index.ts +131 -0
  7. package/src/Defaults/phonenumber-mcc.json +223 -0
  8. package/src/Signal/libsignal.js +180 -0
  9. package/src/Signal/libsignal.ts +141 -0
  10. package/src/Socket/Client/abstract-socket-client.ts +19 -0
  11. package/src/Socket/Client/index.ts +3 -0
  12. package/src/Socket/Client/mobile-socket-client.js +78 -0
  13. package/src/Socket/Client/mobile-socket-client.ts +66 -0
  14. package/src/Socket/Client/web-socket-client.js +75 -0
  15. package/src/Socket/Client/web-socket-client.ts +57 -0
  16. package/{lib → src}/Socket/business.js +33 -27
  17. package/src/Socket/business.ts +281 -0
  18. package/{lib → src}/Socket/chats.js +197 -178
  19. package/src/Socket/chats.ts +1030 -0
  20. package/{lib → src}/Socket/groups.js +69 -79
  21. package/src/Socket/groups.ts +356 -0
  22. package/{lib → src}/Socket/index.js +1 -4
  23. package/src/Socket/index.ts +13 -0
  24. package/{lib → src}/Socket/messages-recv.js +160 -108
  25. package/src/Socket/messages-recv.ts +985 -0
  26. package/{lib → src}/Socket/messages-send.js +183 -100
  27. package/src/Socket/messages-send.ts +871 -0
  28. package/src/Socket/newsletter.js +227 -0
  29. package/src/Socket/newsletter.ts +282 -0
  30. package/{lib → src}/Socket/registration.js +55 -63
  31. package/src/Socket/registration.ts +250 -0
  32. package/{lib → src}/Socket/socket.js +107 -66
  33. package/src/Socket/socket.ts +777 -0
  34. package/src/Store/index.ts +3 -0
  35. package/{lib → src}/Store/make-cache-manager-store.js +34 -25
  36. package/src/Store/make-cache-manager-store.ts +100 -0
  37. package/{lib → src}/Store/make-in-memory-store.js +51 -61
  38. package/src/Store/make-in-memory-store.ts +475 -0
  39. package/src/Store/make-ordered-dictionary.ts +86 -0
  40. package/{lib → src}/Store/object-repository.js +1 -1
  41. package/src/Store/object-repository.ts +32 -0
  42. package/src/Tests/test.app-state-sync.js +204 -0
  43. package/src/Tests/test.app-state-sync.ts +207 -0
  44. package/src/Tests/test.event-buffer.js +270 -0
  45. package/src/Tests/test.event-buffer.ts +319 -0
  46. package/src/Tests/test.key-store.js +76 -0
  47. package/src/Tests/test.key-store.ts +92 -0
  48. package/src/Tests/test.libsignal.js +141 -0
  49. package/src/Tests/test.libsignal.ts +186 -0
  50. package/src/Tests/test.media-download.js +93 -0
  51. package/src/Tests/test.media-download.ts +76 -0
  52. package/src/Tests/test.messages.js +33 -0
  53. package/src/Tests/test.messages.ts +37 -0
  54. package/src/Tests/utils.js +34 -0
  55. package/src/Tests/utils.ts +36 -0
  56. package/src/Types/Auth.ts +113 -0
  57. package/src/Types/Call.ts +15 -0
  58. package/src/Types/Chat.ts +106 -0
  59. package/{lib/Types/Contact.d.ts → src/Types/Contact.ts} +9 -8
  60. package/src/Types/Events.ts +93 -0
  61. package/src/Types/GroupMetadata.ts +53 -0
  62. package/{lib → src}/Types/Label.js +1 -1
  63. package/src/Types/Label.ts +36 -0
  64. package/{lib → src}/Types/LabelAssociation.js +1 -1
  65. package/{lib/Types/LabelAssociation.d.ts → src/Types/LabelAssociation.ts} +22 -16
  66. package/src/Types/Message.ts +288 -0
  67. package/src/Types/Newsletter.js +32 -0
  68. package/src/Types/Newsletter.ts +98 -0
  69. package/src/Types/Product.ts +85 -0
  70. package/src/Types/Signal.ts +68 -0
  71. package/{lib/Types/Socket.d.ts → src/Types/Socket.ts} +68 -56
  72. package/src/Types/State.ts +29 -0
  73. package/{lib → src}/Types/index.js +2 -1
  74. package/src/Types/index.ts +59 -0
  75. package/{lib → src}/Utils/auth-utils.js +95 -76
  76. package/src/Utils/auth-utils.ts +222 -0
  77. package/src/Utils/baileys-event-stream.js +92 -0
  78. package/src/Utils/baileys-event-stream.ts +66 -0
  79. package/{lib → src}/Utils/business.js +45 -17
  80. package/src/Utils/business.ts +275 -0
  81. package/{lib → src}/Utils/chat-utils.js +74 -46
  82. package/src/Utils/chat-utils.ts +860 -0
  83. package/{lib → src}/Utils/crypto.js +31 -21
  84. package/src/Utils/crypto.ts +131 -0
  85. package/src/Utils/decode-wa-message.js +211 -0
  86. package/src/Utils/decode-wa-message.ts +228 -0
  87. package/{lib → src}/Utils/event-buffer.js +13 -4
  88. package/src/Utils/event-buffer.ts +613 -0
  89. package/{lib → src}/Utils/generics.js +98 -45
  90. package/src/Utils/generics.ts +434 -0
  91. package/{lib → src}/Utils/history.js +39 -10
  92. package/src/Utils/history.ts +112 -0
  93. package/src/Utils/index.ts +17 -0
  94. package/{lib → src}/Utils/link-preview.js +54 -17
  95. package/src/Utils/link-preview.ts +122 -0
  96. package/src/Utils/logger.ts +3 -0
  97. package/src/Utils/lt-hash.ts +61 -0
  98. package/{lib → src}/Utils/make-mutex.js +13 -4
  99. package/src/Utils/make-mutex.ts +44 -0
  100. package/{lib → src}/Utils/messages-media.js +296 -192
  101. package/src/Utils/messages-media.ts +847 -0
  102. package/{lib → src}/Utils/messages.js +124 -113
  103. package/src/Utils/messages.ts +956 -0
  104. package/{lib → src}/Utils/noise-handler.js +16 -3
  105. package/src/Utils/noise-handler.ts +197 -0
  106. package/{lib → src}/Utils/process-message.js +33 -29
  107. package/src/Utils/process-message.ts +414 -0
  108. package/{lib → src}/Utils/signal.js +23 -14
  109. package/src/Utils/signal.ts +177 -0
  110. package/{lib → src}/Utils/use-multi-file-auth-state.js +28 -19
  111. package/src/Utils/use-multi-file-auth-state.ts +90 -0
  112. package/{lib → src}/Utils/validate-connection.js +25 -42
  113. package/src/Utils/validate-connection.ts +238 -0
  114. package/src/WABinary/constants.ts +42 -0
  115. package/{lib → src}/WABinary/decode.js +17 -7
  116. package/src/WABinary/decode.ts +265 -0
  117. package/{lib → src}/WABinary/encode.js +17 -7
  118. package/src/WABinary/encode.ts +236 -0
  119. package/{lib → src}/WABinary/generic-utils.js +2 -2
  120. package/src/WABinary/generic-utils.ts +121 -0
  121. package/src/WABinary/index.ts +5 -0
  122. package/{lib → src}/WABinary/jid-utils.js +4 -1
  123. package/src/WABinary/jid-utils.ts +68 -0
  124. package/src/WABinary/types.ts +17 -0
  125. package/src/WAM/BinaryInfo.js +13 -0
  126. package/src/WAM/BinaryInfo.ts +12 -0
  127. package/src/WAM/constants.js +15350 -0
  128. package/src/WAM/constants.ts +15382 -0
  129. package/src/WAM/encode.js +155 -0
  130. package/src/WAM/encode.ts +174 -0
  131. package/src/WAM/index.js +19 -0
  132. package/src/WAM/index.ts +3 -0
  133. package/src/gifted +1 -0
  134. package/{lib → src}/index.js +1 -0
  135. package/src/index.ts +13 -0
  136. package/lib/Defaults/baileys-version.json +0 -3
  137. package/lib/Defaults/index.d.ts +0 -284
  138. package/lib/Defaults/phonenumber-mcc.json +0 -223
  139. package/lib/Signal/libsignal.d.ts +0 -3
  140. package/lib/Signal/libsignal.js +0 -152
  141. package/lib/Socket/Client/abstract-socket-client.d.ts +0 -17
  142. package/lib/Socket/Client/index.d.ts +0 -3
  143. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
  144. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  145. package/lib/Socket/Client/web-socket-client.d.ts +0 -12
  146. package/lib/Socket/Client/web-socket-client.js +0 -62
  147. package/lib/Socket/business.d.ts +0 -135
  148. package/lib/Socket/chats.d.ts +0 -79
  149. package/lib/Socket/groups.d.ts +0 -113
  150. package/lib/Socket/index.d.ts +0 -137
  151. package/lib/Socket/messages-recv.d.ts +0 -124
  152. package/lib/Socket/messages-send.d.ts +0 -119
  153. package/lib/Socket/registration.d.ts +0 -232
  154. package/lib/Socket/socket.d.ts +0 -42
  155. package/lib/Store/index.d.ts +0 -3
  156. package/lib/Store/make-cache-manager-store.d.ts +0 -13
  157. package/lib/Store/make-in-memory-store.d.ts +0 -117
  158. package/lib/Store/make-ordered-dictionary.d.ts +0 -13
  159. package/lib/Store/object-repository.d.ts +0 -10
  160. package/lib/Types/Auth.d.ts +0 -108
  161. package/lib/Types/Call.d.ts +0 -13
  162. package/lib/Types/Chat.d.ts +0 -102
  163. package/lib/Types/Events.d.ts +0 -157
  164. package/lib/Types/GroupMetadata.d.ts +0 -52
  165. package/lib/Types/Label.d.ts +0 -35
  166. package/lib/Types/Message.d.ts +0 -261
  167. package/lib/Types/Product.d.ts +0 -78
  168. package/lib/Types/Signal.d.ts +0 -57
  169. package/lib/Types/State.d.ts +0 -27
  170. package/lib/Types/index.d.ts +0 -56
  171. package/lib/Utils/auth-utils.d.ts +0 -18
  172. package/lib/Utils/baileys-event-stream.d.ts +0 -16
  173. package/lib/Utils/baileys-event-stream.js +0 -63
  174. package/lib/Utils/business.d.ts +0 -22
  175. package/lib/Utils/chat-utils.d.ts +0 -71
  176. package/lib/Utils/crypto.d.ts +0 -41
  177. package/lib/Utils/decode-wa-message.d.ts +0 -19
  178. package/lib/Utils/decode-wa-message.js +0 -174
  179. package/lib/Utils/event-buffer.d.ts +0 -35
  180. package/lib/Utils/generics.d.ts +0 -94
  181. package/lib/Utils/history.d.ts +0 -15
  182. package/lib/Utils/index.d.ts +0 -17
  183. package/lib/Utils/link-preview.d.ts +0 -21
  184. package/lib/Utils/logger.d.ts +0 -4
  185. package/lib/Utils/lt-hash.d.ts +0 -12
  186. package/lib/Utils/make-mutex.d.ts +0 -7
  187. package/lib/Utils/messages-media.d.ts +0 -107
  188. package/lib/Utils/messages.d.ts +0 -76
  189. package/lib/Utils/noise-handler.d.ts +0 -20
  190. package/lib/Utils/process-message.d.ts +0 -41
  191. package/lib/Utils/signal.d.ts +0 -32
  192. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -12
  193. package/lib/Utils/validate-connection.d.ts +0 -11
  194. package/lib/WABinary/constants.d.ts +0 -27
  195. package/lib/WABinary/decode.d.ts +0 -7
  196. package/lib/WABinary/encode.d.ts +0 -3
  197. package/lib/WABinary/generic-utils.d.ts +0 -15
  198. package/lib/WABinary/index.d.ts +0 -5
  199. package/lib/WABinary/jid-utils.d.ts +0 -29
  200. package/lib/WABinary/types.d.ts +0 -18
  201. package/lib/index.d.ts +0 -10
  202. /package/{lib → src}/Socket/Client/abstract-socket-client.js +0 -0
  203. /package/{lib → src}/Socket/Client/index.js +0 -0
  204. /package/{lib → src}/Store/index.js +0 -0
  205. /package/{lib → src}/Store/make-ordered-dictionary.js +0 -0
  206. /package/{lib → src}/Types/Auth.js +0 -0
  207. /package/{lib → src}/Types/Call.js +0 -0
  208. /package/{lib → src}/Types/Chat.js +0 -0
  209. /package/{lib → src}/Types/Contact.js +0 -0
  210. /package/{lib → src}/Types/Events.js +0 -0
  211. /package/{lib → src}/Types/GroupMetadata.js +0 -0
  212. /package/{lib → src}/Types/Message.js +0 -0
  213. /package/{lib → src}/Types/Product.js +0 -0
  214. /package/{lib → src}/Types/Signal.js +0 -0
  215. /package/{lib → src}/Types/Socket.js +0 -0
  216. /package/{lib → src}/Types/State.js +0 -0
  217. /package/{lib → src}/Utils/index.js +0 -0
  218. /package/{lib → src}/Utils/logger.js +0 -0
  219. /package/{lib → src}/Utils/lt-hash.js +0 -0
  220. /package/{lib → src}/WABinary/constants.js +0 -0
  221. /package/{lib → src}/WABinary/index.js +0 -0
  222. /package/{lib → src}/WABinary/types.js +0 -0
@@ -0,0 +1,414 @@
1
+ import { AxiosRequestConfig } from 'axios'
2
+ import type { Logger } from 'pino'
3
+ import { proto } from '../../WAProto'
4
+ import { AuthenticationCreds, BaileysEventEmitter, Chat, GroupMetadata, ParticipantAction, SignalKeyStoreWithTransaction, SocketConfig, WAMessageStubType } from '../Types'
5
+ import { getContentType, normalizeMessageContent } from '../Utils/messages'
6
+ import { areJidsSameUser, isJidBroadcast, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary'
7
+ import { aesDecryptGCM, hmacSign } from './crypto'
8
+ import { getKeyAuthor, toNumber } from './generics'
9
+ import { downloadAndProcessHistorySyncNotification } from './history'
10
+
11
+ type ProcessMessageContext = {
12
+ shouldProcessHistoryMsg: boolean
13
+ creds: AuthenticationCreds
14
+ keyStore: SignalKeyStoreWithTransaction
15
+ ev: BaileysEventEmitter
16
+ getMessage: SocketConfig['getMessage']
17
+ logger?: Logger
18
+ options: AxiosRequestConfig<{}>
19
+ }
20
+
21
+ const REAL_MSG_STUB_TYPES = new Set([
22
+ WAMessageStubType.CALL_MISSED_GROUP_VIDEO,
23
+ WAMessageStubType.CALL_MISSED_GROUP_VOICE,
24
+ WAMessageStubType.CALL_MISSED_VIDEO,
25
+ WAMessageStubType.CALL_MISSED_VOICE
26
+ ])
27
+
28
+ const REAL_MSG_REQ_ME_STUB_TYPES = new Set([
29
+ WAMessageStubType.GROUP_PARTICIPANT_ADD
30
+ ])
31
+
32
+ /** Cleans a received message to further processing */
33
+ export const cleanMessage = (message: proto.IWebMessageInfo, meId: string) => {
34
+ // ensure remoteJid and participant doesn't have device or agent in it
35
+ message.key.remoteJid = jidNormalizedUser(message.key.remoteJid!)
36
+ message.key.participant = message.key.participant ? jidNormalizedUser(message.key.participant!) : undefined
37
+ const content = normalizeMessageContent(message.message)
38
+ // if the message has a reaction, ensure fromMe & remoteJid are from our perspective
39
+ if(content?.reactionMessage) {
40
+ normaliseKey(content.reactionMessage.key!)
41
+ }
42
+
43
+ if(content?.pollUpdateMessage) {
44
+ normaliseKey(content.pollUpdateMessage.pollCreationMessageKey!)
45
+ }
46
+
47
+ function normaliseKey(msgKey: proto.IMessageKey) {
48
+ // if the reaction is from another user
49
+ // we've to correctly map the key to this user's perspective
50
+ if(!message.key.fromMe) {
51
+ // if the sender believed the message being reacted to is not from them
52
+ // we've to correct the key to be from them, or some other participant
53
+ msgKey.fromMe = !msgKey.fromMe
54
+ ? areJidsSameUser(msgKey.participant || msgKey.remoteJid!, meId)
55
+ // if the message being reacted to, was from them
56
+ // fromMe automatically becomes false
57
+ : false
58
+ // set the remoteJid to being the same as the chat the message came from
59
+ msgKey.remoteJid = message.key.remoteJid
60
+ // set participant of the message
61
+ msgKey.participant = msgKey.participant || message.key.participant
62
+ }
63
+ }
64
+ }
65
+
66
+ export const isRealMessage = (message: proto.IWebMessageInfo, meId: string) => {
67
+ const normalizedContent = normalizeMessageContent(message.message)
68
+ const hasSomeContent = !!getContentType(normalizedContent)
69
+ return (
70
+ !!normalizedContent
71
+ || REAL_MSG_STUB_TYPES.has(message.messageStubType!)
72
+ || (
73
+ REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType!)
74
+ && message.messageStubParameters?.some(p => areJidsSameUser(meId, p))
75
+ )
76
+ )
77
+ && hasSomeContent
78
+ && !normalizedContent?.protocolMessage
79
+ && !normalizedContent?.reactionMessage
80
+ && !normalizedContent?.pollUpdateMessage
81
+ }
82
+
83
+ export const shouldIncrementChatUnread = (message: proto.IWebMessageInfo) => (
84
+ !message.key.fromMe && !message.messageStubType
85
+ )
86
+
87
+ /**
88
+ * Get the ID of the chat from the given key.
89
+ * Typically -- that'll be the remoteJid, but for broadcasts, it'll be the participant
90
+ */
91
+ export const getChatId = ({ remoteJid, participant, fromMe }: proto.IMessageKey) => {
92
+ if(
93
+ isJidBroadcast(remoteJid!)
94
+ && !isJidStatusBroadcast(remoteJid!)
95
+ && !fromMe
96
+ ) {
97
+ return participant!
98
+ }
99
+
100
+ return remoteJid!
101
+ }
102
+
103
+ type PollContext = {
104
+ /** normalised jid of the person that created the poll */
105
+ pollCreatorJid: string
106
+ /** ID of the poll creation message */
107
+ pollMsgId: string
108
+ /** poll creation message enc key */
109
+ pollEncKey: Uint8Array
110
+ /** jid of the person that voted */
111
+ voterJid: string
112
+ }
113
+
114
+ /**
115
+ * Decrypt a poll vote
116
+ * @param vote encrypted vote
117
+ * @param ctx additional info about the poll required for decryption
118
+ * @returns list of SHA256 options
119
+ */
120
+ export function decryptPollVote(
121
+ { encPayload, encIv }: proto.Message.IPollEncValue,
122
+ {
123
+ pollCreatorJid,
124
+ pollMsgId,
125
+ pollEncKey,
126
+ voterJid,
127
+ }: PollContext
128
+ ) {
129
+ const sign = Buffer.concat(
130
+ [
131
+ toBinary(pollMsgId),
132
+ toBinary(pollCreatorJid),
133
+ toBinary(voterJid),
134
+ toBinary('Poll Vote'),
135
+ new Uint8Array([1])
136
+ ]
137
+ )
138
+
139
+ const key0 = hmacSign(pollEncKey, new Uint8Array(32), 'sha256')
140
+ const decKey = hmacSign(sign, key0, 'sha256')
141
+ const aad = toBinary(`${pollMsgId}\u0000${voterJid}`)
142
+
143
+ const decrypted = aesDecryptGCM(encPayload!, decKey, encIv!, aad)
144
+ return proto.Message.PollVoteMessage.decode(decrypted)
145
+
146
+ function toBinary(txt: string) {
147
+ return Buffer.from(txt)
148
+ }
149
+ }
150
+
151
+ const processMessage = async(
152
+ message: proto.IWebMessageInfo,
153
+ {
154
+ shouldProcessHistoryMsg,
155
+ ev,
156
+ creds,
157
+ keyStore,
158
+ logger,
159
+ options,
160
+ getMessage
161
+ }: ProcessMessageContext
162
+ ) => {
163
+ const meId = creds.me!.id
164
+ const { accountSettings } = creds
165
+
166
+ const chat: Partial<Chat> = { id: jidNormalizedUser(getChatId(message.key)) }
167
+ const isRealMsg = isRealMessage(message, meId)
168
+
169
+ if(isRealMsg) {
170
+ chat.conversationTimestamp = toNumber(message.messageTimestamp)
171
+ // only increment unread count if not CIPHERTEXT and from another person
172
+ if(shouldIncrementChatUnread(message)) {
173
+ chat.unreadCount = (chat.unreadCount || 0) + 1
174
+ }
175
+ }
176
+
177
+ const content = normalizeMessageContent(message.message)
178
+
179
+ // unarchive chat if it's a real message, or someone reacted to our message
180
+ // and we've the unarchive chats setting on
181
+ if(
182
+ (isRealMsg || content?.reactionMessage?.key?.fromMe)
183
+ && accountSettings?.unarchiveChats
184
+ ) {
185
+ chat.archived = false
186
+ chat.readOnly = false
187
+ }
188
+
189
+ const protocolMsg = content?.protocolMessage
190
+ if(protocolMsg) {
191
+ switch (protocolMsg.type) {
192
+ case proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION:
193
+ const histNotification = protocolMsg!.historySyncNotification!
194
+ const process = shouldProcessHistoryMsg
195
+ const isLatest = !creds.processedHistoryMessages?.length
196
+
197
+ logger?.info({
198
+ histNotification,
199
+ process,
200
+ id: message.key.id,
201
+ isLatest,
202
+ }, 'got history notification')
203
+
204
+ if(process) {
205
+ ev.emit('creds.update', {
206
+ processedHistoryMessages: [
207
+ ...(creds.processedHistoryMessages || []),
208
+ { key: message.key, messageTimestamp: message.messageTimestamp }
209
+ ]
210
+ })
211
+
212
+ const data = await downloadAndProcessHistorySyncNotification(
213
+ histNotification,
214
+ options
215
+ )
216
+
217
+ ev.emit('messaging-history.set', { ...data, isLatest })
218
+ }
219
+
220
+ break
221
+ case proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE:
222
+ const keys = protocolMsg.appStateSyncKeyShare!.keys
223
+ if(keys?.length) {
224
+ let newAppStateSyncKeyId = ''
225
+ await keyStore.transaction(
226
+ async() => {
227
+ const newKeys: string[] = []
228
+ for(const { keyData, keyId } of keys) {
229
+ const strKeyId = Buffer.from(keyId!.keyId!).toString('base64')
230
+ newKeys.push(strKeyId)
231
+
232
+ await keyStore.set({ 'app-state-sync-key': { [strKeyId]: keyData! } })
233
+
234
+ newAppStateSyncKeyId = strKeyId
235
+ }
236
+
237
+ logger?.info(
238
+ { newAppStateSyncKeyId, newKeys },
239
+ 'injecting new app state sync keys'
240
+ )
241
+ }
242
+ )
243
+
244
+ ev.emit('creds.update', { myAppStateKeyId: newAppStateSyncKeyId })
245
+ } else {
246
+ logger?.info({ protocolMsg }, 'recv app state sync with 0 keys')
247
+ }
248
+
249
+ break
250
+ case proto.Message.ProtocolMessage.Type.REVOKE:
251
+ ev.emit('messages.update', [
252
+ {
253
+ key: {
254
+ ...message.key,
255
+ id: protocolMsg.key!.id
256
+ },
257
+ update: { message: null, messageStubType: WAMessageStubType.REVOKE, key: message.key }
258
+ }
259
+ ])
260
+ break
261
+ case proto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING:
262
+ Object.assign(chat, {
263
+ ephemeralSettingTimestamp: toNumber(message.messageTimestamp),
264
+ ephemeralExpiration: protocolMsg.ephemeralExpiration || null
265
+ })
266
+ break
267
+ case proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
268
+ const response = protocolMsg.peerDataOperationRequestResponseMessage!
269
+ if(response) {
270
+ const { peerDataOperationResult } = response
271
+ for(const result of peerDataOperationResult!) {
272
+ const { placeholderMessageResendResponse: retryResponse } = result
273
+ if(retryResponse) {
274
+ const webMessageInfo = proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes!)
275
+ ev.emit('messages.update', [
276
+ { key: webMessageInfo.key, update: { message: webMessageInfo.message } }
277
+ ])
278
+ }
279
+ }
280
+ }
281
+
282
+ break
283
+ }
284
+ } else if(content?.reactionMessage) {
285
+ const reaction: proto.IReaction = {
286
+ ...content.reactionMessage,
287
+ key: message.key,
288
+ }
289
+ ev.emit('messages.reaction', [{
290
+ reaction,
291
+ key: content.reactionMessage!.key!,
292
+ }])
293
+ } else if(message.messageStubType) {
294
+ const jid = message.key!.remoteJid!
295
+ //let actor = whatsappID (message.participant)
296
+ let participants: string[]
297
+ const emitParticipantsUpdate = (action: ParticipantAction) => (
298
+ ev.emit('group-participants.update', { id: jid, author: message.participant!, participants, action })
299
+ )
300
+ const emitGroupUpdate = (update: Partial<GroupMetadata>) => {
301
+ ev.emit('groups.update', [{ id: jid, ...update, author: message.participant ?? undefined }])
302
+ }
303
+
304
+ const participantsIncludesMe = () => participants.find(jid => areJidsSameUser(meId, jid))
305
+
306
+ switch (message.messageStubType) {
307
+ case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
308
+ case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
309
+ participants = message.messageStubParameters || []
310
+ emitParticipantsUpdate('remove')
311
+ // mark the chat read only if you left the group
312
+ if(participantsIncludesMe()) {
313
+ chat.readOnly = true
314
+ }
315
+
316
+ break
317
+ case WAMessageStubType.GROUP_PARTICIPANT_ADD:
318
+ case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
319
+ case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
320
+ participants = message.messageStubParameters || []
321
+ if(participantsIncludesMe()) {
322
+ chat.readOnly = false
323
+ }
324
+
325
+ emitParticipantsUpdate('add')
326
+ break
327
+ case WAMessageStubType.GROUP_PARTICIPANT_DEMOTE:
328
+ participants = message.messageStubParameters || []
329
+ emitParticipantsUpdate('demote')
330
+ break
331
+ case WAMessageStubType.GROUP_PARTICIPANT_PROMOTE:
332
+ participants = message.messageStubParameters || []
333
+ emitParticipantsUpdate('promote')
334
+ break
335
+ case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
336
+ const announceValue = message.messageStubParameters?.[0]
337
+ emitGroupUpdate({ announce: announceValue === 'true' || announceValue === 'on' })
338
+ break
339
+ case WAMessageStubType.GROUP_CHANGE_RESTRICT:
340
+ const restrictValue = message.messageStubParameters?.[0]
341
+ emitGroupUpdate({ restrict: restrictValue === 'true' || restrictValue === 'on' })
342
+ break
343
+ case WAMessageStubType.GROUP_CHANGE_SUBJECT:
344
+ const name = message.messageStubParameters?.[0]
345
+ chat.name = name
346
+ emitGroupUpdate({ subject: name })
347
+ break
348
+ case WAMessageStubType.GROUP_CHANGE_INVITE_LINK:
349
+ const code = message.messageStubParameters?.[0]
350
+ emitGroupUpdate({ inviteCode: code })
351
+ break
352
+ case WAMessageStubType.GROUP_MEMBER_ADD_MODE:
353
+ const memberAddValue = message.messageStubParameters?.[0]
354
+ emitGroupUpdate({ memberAddMode: memberAddValue === 'all_member_add' })
355
+ break
356
+ case WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE:
357
+ const approvalMode = message.messageStubParameters?.[0]
358
+ emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' })
359
+ break
360
+ }
361
+ } else if(content?.pollUpdateMessage) {
362
+ const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey!
363
+ // we need to fetch the poll creation message to get the poll enc key
364
+ const pollMsg = await getMessage(creationMsgKey)
365
+ if(pollMsg) {
366
+ const meIdNormalised = jidNormalizedUser(meId)
367
+ const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised)
368
+ const voterJid = getKeyAuthor(message.key!, meIdNormalised)
369
+ const pollEncKey = pollMsg.messageContextInfo?.messageSecret!
370
+
371
+ try {
372
+ const voteMsg = decryptPollVote(
373
+ content.pollUpdateMessage.vote!,
374
+ {
375
+ pollEncKey,
376
+ pollCreatorJid,
377
+ pollMsgId: creationMsgKey.id!,
378
+ voterJid,
379
+ }
380
+ )
381
+ ev.emit('messages.update', [
382
+ {
383
+ key: creationMsgKey,
384
+ update: {
385
+ pollUpdates: [
386
+ {
387
+ pollUpdateMessageKey: message.key,
388
+ vote: voteMsg,
389
+ senderTimestampMs: (content.pollUpdateMessage.senderTimestampMs! as Long).toNumber(),
390
+ }
391
+ ]
392
+ }
393
+ }
394
+ ])
395
+ } catch(err) {
396
+ logger?.warn(
397
+ { err, creationMsgKey },
398
+ 'failed to decrypt poll vote'
399
+ )
400
+ }
401
+ } else {
402
+ logger?.warn(
403
+ { creationMsgKey },
404
+ 'poll creation message not found, cannot decrypt update'
405
+ )
406
+ }
407
+ }
408
+
409
+ if(Object.keys(chat).length > 1) {
410
+ ev.emit('chats.update', [chat])
411
+ }
412
+ }
413
+
414
+ export default processMessage
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.getNextPreKeysNode = exports.getNextPreKeys = exports.extractDeviceJids = exports.parseAndInjectE2ESessions = exports.xmppPreKey = exports.xmppSignedPreKey = exports.generateOrGetPreKeys = exports.getPreKeys = exports.createSignalIdentity = void 0;
4
13
  const Defaults_1 = require("../Defaults");
@@ -12,13 +21,13 @@ const createSignalIdentity = (wid, accountSignatureKey) => {
12
21
  };
13
22
  };
14
23
  exports.createSignalIdentity = createSignalIdentity;
15
- const getPreKeys = async ({ get }, min, limit) => {
24
+ const getPreKeys = (_a, min_1, limit_1) => __awaiter(void 0, [_a, min_1, limit_1], void 0, function* ({ get }, min, limit) {
16
25
  const idList = [];
17
26
  for (let id = min; id < limit; id++) {
18
27
  idList.push(id.toString());
19
28
  }
20
29
  return get('pre-key', idList);
21
- };
30
+ });
22
31
  exports.getPreKeys = getPreKeys;
23
32
  const generateOrGetPreKeys = (creds, range) => {
24
33
  const avaliable = creds.nextPreKeyId - creds.firstUnuploadedPreKeyId;
@@ -56,7 +65,7 @@ const xmppPreKey = (pair, id) => ({
56
65
  ]
57
66
  });
58
67
  exports.xmppPreKey = xmppPreKey;
59
- const parseAndInjectE2ESessions = async (node, repository) => {
68
+ const parseAndInjectE2ESessions = (node, repository) => __awaiter(void 0, void 0, void 0, function* () {
60
69
  const extractKey = (key) => (key ? ({
61
70
  keyId: (0, WABinary_1.getBinaryNodeChildUInt)(key, 'id', 3),
62
71
  publicKey: (0, crypto_1.generateSignalPubKey)((0, WABinary_1.getBinaryNodeChildBuffer)(key, 'value')),
@@ -66,13 +75,13 @@ const parseAndInjectE2ESessions = async (node, repository) => {
66
75
  for (const node of nodes) {
67
76
  (0, WABinary_1.assertNodeErrorFree)(node);
68
77
  }
69
- await Promise.all(nodes.map(async (node) => {
78
+ yield Promise.all(nodes.map((node) => __awaiter(void 0, void 0, void 0, function* () {
70
79
  const signedKey = (0, WABinary_1.getBinaryNodeChild)(node, 'skey');
71
80
  const key = (0, WABinary_1.getBinaryNodeChild)(node, 'key');
72
81
  const identity = (0, WABinary_1.getBinaryNodeChildBuffer)(node, 'identity');
73
82
  const jid = node.attrs.jid;
74
83
  const registrationId = (0, WABinary_1.getBinaryNodeChildUInt)(node, 'registration', 4);
75
- await repository.injectE2ESession({
84
+ yield repository.injectE2ESession({
76
85
  jid,
77
86
  session: {
78
87
  registrationId: registrationId,
@@ -81,8 +90,8 @@ const parseAndInjectE2ESessions = async (node, repository) => {
81
90
  preKey: extractKey(key)
82
91
  }
83
92
  });
84
- }));
85
- };
93
+ })));
94
+ });
86
95
  exports.parseAndInjectE2ESessions = parseAndInjectE2ESessions;
87
96
  const extractDeviceJids = (result, myJid, excludeZeroDevices) => {
88
97
  var _a;
@@ -117,20 +126,20 @@ exports.extractDeviceJids = extractDeviceJids;
117
126
  * get the next N keys for upload or processing
118
127
  * @param count number of pre-keys to get or generate
119
128
  */
120
- const getNextPreKeys = async ({ creds, keys }, count) => {
129
+ const getNextPreKeys = (_a, count_1) => __awaiter(void 0, [_a, count_1], void 0, function* ({ creds, keys }, count) {
121
130
  const { newPreKeys, lastPreKeyId, preKeysRange } = (0, exports.generateOrGetPreKeys)(creds, count);
122
131
  const update = {
123
132
  nextPreKeyId: Math.max(lastPreKeyId + 1, creds.nextPreKeyId),
124
133
  firstUnuploadedPreKeyId: Math.max(creds.firstUnuploadedPreKeyId, lastPreKeyId + 1)
125
134
  };
126
- await keys.set({ 'pre-key': newPreKeys });
127
- const preKeys = await (0, exports.getPreKeys)(keys, preKeysRange[0], preKeysRange[0] + preKeysRange[1]);
135
+ yield keys.set({ 'pre-key': newPreKeys });
136
+ const preKeys = yield (0, exports.getPreKeys)(keys, preKeysRange[0], preKeysRange[0] + preKeysRange[1]);
128
137
  return { update, preKeys };
129
- };
138
+ });
130
139
  exports.getNextPreKeys = getNextPreKeys;
131
- const getNextPreKeysNode = async (state, count) => {
140
+ const getNextPreKeysNode = (state, count) => __awaiter(void 0, void 0, void 0, function* () {
132
141
  const { creds } = state;
133
- const { update, preKeys } = await (0, exports.getNextPreKeys)(state, count);
142
+ const { update, preKeys } = yield (0, exports.getNextPreKeys)(state, count);
134
143
  const node = {
135
144
  tag: 'iq',
136
145
  attrs: {
@@ -147,5 +156,5 @@ const getNextPreKeysNode = async (state, count) => {
147
156
  ]
148
157
  };
149
158
  return { update, node };
150
- };
159
+ });
151
160
  exports.getNextPreKeysNode = getNextPreKeysNode;
@@ -0,0 +1,177 @@
1
+ import { KEY_BUNDLE_TYPE } from '../Defaults'
2
+ import { SignalRepository } from '../Types'
3
+ import { AuthenticationCreds, AuthenticationState, KeyPair, SignalIdentity, SignalKeyStore, SignedKeyPair } from '../Types/Auth'
4
+ import { assertNodeErrorFree, BinaryNode, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildUInt, jidDecode, JidWithDevice, S_WHATSAPP_NET } from '../WABinary'
5
+ import { Curve, generateSignalPubKey } from './crypto'
6
+ import { encodeBigEndian } from './generics'
7
+
8
+ export const createSignalIdentity = (
9
+ wid: string,
10
+ accountSignatureKey: Uint8Array
11
+ ): SignalIdentity => {
12
+ return {
13
+ identifier: { name: wid, deviceId: 0 },
14
+ identifierKey: generateSignalPubKey(accountSignatureKey)
15
+ }
16
+ }
17
+
18
+ export const getPreKeys = async({ get }: SignalKeyStore, min: number, limit: number) => {
19
+ const idList: string[] = []
20
+ for(let id = min; id < limit;id++) {
21
+ idList.push(id.toString())
22
+ }
23
+
24
+ return get('pre-key', idList)
25
+ }
26
+
27
+ export const generateOrGetPreKeys = (creds: AuthenticationCreds, range: number) => {
28
+ const avaliable = creds.nextPreKeyId - creds.firstUnuploadedPreKeyId
29
+ const remaining = range - avaliable
30
+ const lastPreKeyId = creds.nextPreKeyId + remaining - 1
31
+ const newPreKeys: { [id: number]: KeyPair } = { }
32
+ if(remaining > 0) {
33
+ for(let i = creds.nextPreKeyId;i <= lastPreKeyId;i++) {
34
+ newPreKeys[i] = Curve.generateKeyPair()
35
+ }
36
+ }
37
+
38
+ return {
39
+ newPreKeys,
40
+ lastPreKeyId,
41
+ preKeysRange: [creds.firstUnuploadedPreKeyId, range] as const,
42
+ }
43
+ }
44
+
45
+ export const xmppSignedPreKey = (key: SignedKeyPair): BinaryNode => (
46
+ {
47
+ tag: 'skey',
48
+ attrs: { },
49
+ content: [
50
+ { tag: 'id', attrs: { }, content: encodeBigEndian(key.keyId, 3) },
51
+ { tag: 'value', attrs: { }, content: key.keyPair.public },
52
+ { tag: 'signature', attrs: { }, content: key.signature }
53
+ ]
54
+ }
55
+ )
56
+
57
+ export const xmppPreKey = (pair: KeyPair, id: number): BinaryNode => (
58
+ {
59
+ tag: 'key',
60
+ attrs: { },
61
+ content: [
62
+ { tag: 'id', attrs: { }, content: encodeBigEndian(id, 3) },
63
+ { tag: 'value', attrs: { }, content: pair.public }
64
+ ]
65
+ }
66
+ )
67
+
68
+ export const parseAndInjectE2ESessions = async(
69
+ node: BinaryNode,
70
+ repository: SignalRepository
71
+ ) => {
72
+ const extractKey = (key: BinaryNode) => (
73
+ key ? ({
74
+ keyId: getBinaryNodeChildUInt(key, 'id', 3)!,
75
+ publicKey: generateSignalPubKey(getBinaryNodeChildBuffer(key, 'value')!)!,
76
+ signature: getBinaryNodeChildBuffer(key, 'signature')!,
77
+ }) : undefined
78
+ )
79
+ const nodes = getBinaryNodeChildren(getBinaryNodeChild(node, 'list'), 'user')
80
+ for(const node of nodes) {
81
+ assertNodeErrorFree(node)
82
+ }
83
+
84
+ await Promise.all(
85
+ nodes.map(
86
+ async node => {
87
+ const signedKey = getBinaryNodeChild(node, 'skey')!
88
+ const key = getBinaryNodeChild(node, 'key')!
89
+ const identity = getBinaryNodeChildBuffer(node, 'identity')!
90
+ const jid = node.attrs.jid
91
+ const registrationId = getBinaryNodeChildUInt(node, 'registration', 4)
92
+
93
+ await repository.injectE2ESession({
94
+ jid,
95
+ session: {
96
+ registrationId: registrationId!,
97
+ identityKey: generateSignalPubKey(identity),
98
+ signedPreKey: extractKey(signedKey)!,
99
+ preKey: extractKey(key)!
100
+ }
101
+ })
102
+ }
103
+ )
104
+ )
105
+ }
106
+
107
+ export const extractDeviceJids = (result: BinaryNode, myJid: string, excludeZeroDevices: boolean) => {
108
+ const { user: myUser, device: myDevice } = jidDecode(myJid)!
109
+ const extracted: JidWithDevice[] = []
110
+ for(const node of result.content as BinaryNode[]) {
111
+ const list = getBinaryNodeChild(node, 'list')?.content
112
+ if(list && Array.isArray(list)) {
113
+ for(const item of list) {
114
+ const { user } = jidDecode(item.attrs.jid)!
115
+ const devicesNode = getBinaryNodeChild(item, 'devices')
116
+ const deviceListNode = getBinaryNodeChild(devicesNode, 'device-list')
117
+ if(Array.isArray(deviceListNode?.content)) {
118
+ for(const { tag, attrs } of deviceListNode!.content) {
119
+ const device = +attrs.id
120
+ if(
121
+ tag === 'device' && // ensure the "device" tag
122
+ (!excludeZeroDevices || device !== 0) && // if zero devices are not-excluded, or device is non zero
123
+ (myUser !== user || myDevice !== device) && // either different user or if me user, not this device
124
+ (device === 0 || !!attrs['key-index']) // ensure that "key-index" is specified for "non-zero" devices, produces a bad req otherwise
125
+ ) {
126
+ extracted.push({ user, device })
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ }
133
+
134
+ return extracted
135
+ }
136
+
137
+ /**
138
+ * get the next N keys for upload or processing
139
+ * @param count number of pre-keys to get or generate
140
+ */
141
+ export const getNextPreKeys = async({ creds, keys }: AuthenticationState, count: number) => {
142
+ const { newPreKeys, lastPreKeyId, preKeysRange } = generateOrGetPreKeys(creds, count)
143
+
144
+ const update: Partial<AuthenticationCreds> = {
145
+ nextPreKeyId: Math.max(lastPreKeyId + 1, creds.nextPreKeyId),
146
+ firstUnuploadedPreKeyId: Math.max(creds.firstUnuploadedPreKeyId, lastPreKeyId + 1)
147
+ }
148
+
149
+ await keys.set({ 'pre-key': newPreKeys })
150
+
151
+ const preKeys = await getPreKeys(keys, preKeysRange[0], preKeysRange[0] + preKeysRange[1])
152
+
153
+ return { update, preKeys }
154
+ }
155
+
156
+ export const getNextPreKeysNode = async(state: AuthenticationState, count: number) => {
157
+ const { creds } = state
158
+ const { update, preKeys } = await getNextPreKeys(state, count)
159
+
160
+ const node: BinaryNode = {
161
+ tag: 'iq',
162
+ attrs: {
163
+ xmlns: 'encrypt',
164
+ type: 'set',
165
+ to: S_WHATSAPP_NET,
166
+ },
167
+ content: [
168
+ { tag: 'registration', attrs: { }, content: encodeBigEndian(creds.registrationId) },
169
+ { tag: 'type', attrs: { }, content: KEY_BUNDLE_TYPE },
170
+ { tag: 'identity', attrs: { }, content: creds.signedIdentityKey.public },
171
+ { tag: 'list', attrs: { }, content: Object.keys(preKeys).map(k => xmppPreKey(preKeys[+k], +k)) },
172
+ xmppSignedPreKey(creds.signedPreKey)
173
+ ]
174
+ }
175
+
176
+ return { update, node }
177
+ }