@pontalabs/baileys 1.0.4 → 1.0.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.
- package/LICENSE +1 -1
- package/README.md +267 -839
- package/WAProto/GenerateStatics.sh +3 -4
- package/WAProto/WAProto.proto +1215 -511
- package/WAProto/fix-imports.js +85 -0
- package/WAProto/index.d.ts +14017 -55
- package/WAProto/index.js +97689 -29
- package/engine-requirements.js +10 -0
- package/lib/Defaults/index.d.ts +72 -74
- package/lib/Defaults/index.d.ts.map +1 -0
- package/lib/Defaults/index.js +94 -108
- package/lib/Defaults/index.js.map +1 -0
- package/lib/Signal/Group/ciphertext-message.d.ts +8 -7
- package/lib/Signal/Group/ciphertext-message.d.ts.map +1 -0
- package/lib/Signal/Group/ciphertext-message.js +9 -16
- package/lib/Signal/Group/ciphertext-message.js.map +1 -0
- package/lib/Signal/Group/group-session-builder.d.ts +11 -13
- package/lib/Signal/Group/group-session-builder.d.ts.map +1 -0
- package/lib/Signal/Group/group-session-builder.js +19 -61
- package/lib/Signal/Group/group-session-builder.js.map +1 -0
- package/lib/Signal/Group/group_cipher.d.ts +14 -16
- package/lib/Signal/Group/group_cipher.d.ts.map +1 -0
- package/lib/Signal/Group/group_cipher.js +41 -70
- package/lib/Signal/Group/group_cipher.js.map +1 -0
- package/lib/Signal/Group/index.d.ts +12 -11
- package/lib/Signal/Group/index.d.ts.map +1 -0
- package/lib/Signal/Group/index.js +12 -61
- package/lib/Signal/Group/index.js.map +1 -0
- package/lib/Signal/Group/keyhelper.d.ts +9 -14
- package/lib/Signal/Group/keyhelper.d.ts.map +1 -0
- package/lib/Signal/Group/keyhelper.js +10 -58
- package/lib/Signal/Group/keyhelper.js.map +1 -0
- package/lib/Signal/Group/sender-chain-key.d.ts +13 -13
- package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -0
- package/lib/Signal/Group/sender-chain-key.js +13 -34
- package/lib/Signal/Group/sender-chain-key.js.map +1 -0
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -16
- package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +28 -36
- package/lib/Signal/Group/sender-key-distribution-message.js.map +1 -0
- package/lib/Signal/Group/sender-key-message.d.ts +18 -18
- package/lib/Signal/Group/sender-key-message.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-message.js +38 -45
- package/lib/Signal/Group/sender-key-message.js.map +1 -0
- package/lib/Signal/Group/sender-key-name.d.ts +14 -15
- package/lib/Signal/Group/sender-key-name.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-name.js +20 -31
- package/lib/Signal/Group/sender-key-name.js.map +1 -0
- package/lib/Signal/Group/sender-key-record.d.ts +24 -25
- package/lib/Signal/Group/sender-key-record.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-record.js +18 -35
- package/lib/Signal/Group/sender-key-record.js.map +1 -0
- package/lib/Signal/Group/sender-key-state.d.ts +29 -34
- package/lib/Signal/Group/sender-key-state.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-state.js +37 -100
- package/lib/Signal/Group/sender-key-state.js.map +1 -0
- package/lib/Signal/Group/sender-message-key.d.ts +11 -10
- package/lib/Signal/Group/sender-message-key.d.ts.map +1 -0
- package/lib/Signal/Group/sender-message-key.js +15 -22
- package/lib/Signal/Group/sender-message-key.js.map +1 -0
- package/lib/Signal/libsignal.d.ts +5 -8
- package/lib/Signal/libsignal.d.ts.map +1 -0
- package/lib/Signal/libsignal.js +279 -121
- package/lib/Signal/libsignal.js.map +1 -0
- package/lib/Signal/lid-mapping.d.ts +23 -28
- package/lib/Signal/lid-mapping.d.ts.map +1 -0
- package/lib/Signal/lid-mapping.js +277 -184
- package/lib/Signal/lid-mapping.js.map +1 -0
- package/lib/Socket/Client/index.d.ts +3 -2
- package/lib/Socket/Client/index.d.ts.map +1 -0
- package/lib/Socket/Client/index.js +3 -22
- package/lib/Socket/Client/index.js.map +1 -0
- package/lib/Socket/Client/types.d.ts +15 -15
- package/lib/Socket/Client/types.d.ts.map +1 -0
- package/lib/Socket/Client/types.js +8 -15
- package/lib/Socket/Client/types.js.map +1 -0
- package/lib/Socket/Client/websocket.d.ts +12 -12
- package/lib/Socket/Client/websocket.d.ts.map +1 -0
- package/lib/Socket/Client/websocket.js +29 -37
- package/lib/Socket/Client/websocket.js.map +1 -0
- package/lib/Socket/business.d.ts +208 -178
- package/lib/Socket/business.d.ts.map +1 -0
- package/lib/Socket/business.js +91 -127
- package/lib/Socket/business.js.map +1 -0
- package/lib/Socket/chats.d.ts +120 -93
- package/lib/Socket/chats.d.ts.map +1 -0
- package/lib/Socket/chats.js +727 -652
- package/lib/Socket/chats.js.map +1 -0
- package/lib/Socket/communities.d.ts +273 -0
- package/lib/Socket/communities.d.ts.map +1 -0
- package/lib/Socket/communities.js +431 -0
- package/lib/Socket/communities.js.map +1 -0
- package/lib/Socket/dugong.js +261 -0
- package/lib/Socket/dugong.js.bak +204 -0
- package/lib/Socket/groups.d.ts +143 -111
- package/lib/Socket/groups.d.ts.map +1 -0
- package/lib/Socket/groups.js +165 -177
- package/lib/Socket/groups.js.map +1 -0
- package/lib/Socket/index.d.ts +252 -183
- package/lib/Socket/index.d.ts.map +1 -0
- package/lib/Socket/index.js +38 -18
- package/lib/Socket/index.js.bak +44 -0
- package/lib/Socket/index.js.map +1 -0
- package/lib/Socket/messages-recv.d.ts +196 -167
- package/lib/Socket/messages-recv.d.ts.map +1 -0
- package/lib/Socket/messages-recv.js +1443 -1563
- package/lib/Socket/messages-recv.js.map +1 -0
- package/lib/Socket/messages-send.d.ts +192 -158
- package/lib/Socket/messages-send.d.ts.map +1 -0
- package/lib/Socket/messages-send.js +1102 -1208
- package/lib/Socket/messages-send.js.bak +1400 -0
- package/lib/Socket/messages-send.js.map +1 -0
- package/lib/Socket/mex.d.ts +3 -0
- package/lib/Socket/mex.d.ts.map +1 -0
- package/lib/Socket/mex.js +42 -0
- package/lib/Socket/mex.js.map +1 -0
- package/lib/Socket/newsletter.d.ts +163 -138
- package/lib/Socket/newsletter.d.ts.map +1 -0
- package/lib/Socket/newsletter.js +153 -249
- package/lib/Socket/newsletter.js.map +1 -0
- package/lib/Socket/socket.d.ts +50 -36
- package/lib/Socket/socket.d.ts.map +1 -0
- package/lib/Socket/socket.js +749 -820
- package/lib/Socket/socket.js.map +1 -0
- package/lib/Store/index.d.ts +4 -4
- package/lib/Store/index.d.ts.map +1 -0
- package/lib/Store/index.js +4 -24
- package/lib/Store/index.js.map +1 -0
- package/lib/Store/make-in-memory-store.d.ts +44 -104
- package/lib/Store/make-in-memory-store.d.ts.map +1 -0
- package/lib/Store/make-in-memory-store.js +199 -213
- package/lib/Store/make-in-memory-store.js.map +1 -0
- package/lib/Store/make-ordered-dictionary.d.ts +13 -12
- package/lib/Store/make-ordered-dictionary.d.ts.map +1 -0
- package/lib/Store/make-ordered-dictionary.js +38 -45
- package/lib/Store/make-ordered-dictionary.js.map +1 -0
- package/lib/Store/object-repository.d.ts +11 -10
- package/lib/Store/object-repository.d.ts.map +1 -0
- package/lib/Store/object-repository.js +9 -16
- package/lib/Store/object-repository.js.map +1 -0
- package/lib/Types/Auth.d.ts +93 -97
- package/lib/Types/Auth.d.ts.map +1 -0
- package/lib/Types/Auth.js +2 -3
- package/lib/Types/Auth.js.map +1 -0
- package/lib/Types/Bussines.d.ts +25 -0
- package/lib/Types/Bussines.d.ts.map +1 -0
- package/lib/Types/Bussines.js +2 -3
- package/lib/Types/Bussines.js.map +1 -0
- package/lib/Types/Call.d.ts +14 -13
- package/lib/Types/Call.d.ts.map +1 -0
- package/lib/Types/Call.js +2 -3
- package/lib/Types/Call.js.map +1 -0
- package/lib/Types/Chat.d.ts +78 -97
- package/lib/Types/Chat.d.ts.map +1 -0
- package/lib/Types/Chat.js +8 -9
- package/lib/Types/Chat.js.map +1 -0
- package/lib/Types/Contact.d.ts +12 -9
- package/lib/Types/Contact.d.ts.map +1 -0
- package/lib/Types/Contact.js +2 -3
- package/lib/Types/Contact.js.map +1 -0
- package/lib/Types/Events.d.ts +206 -176
- package/lib/Types/Events.d.ts.map +1 -0
- package/lib/Types/Events.js +2 -3
- package/lib/Types/Events.js.map +1 -0
- package/lib/Types/GroupMetadata.d.ts +53 -48
- package/lib/Types/GroupMetadata.d.ts.map +1 -0
- package/lib/Types/GroupMetadata.js +2 -3
- package/lib/Types/GroupMetadata.js.map +1 -0
- package/lib/Types/Label.d.ts +13 -14
- package/lib/Types/Label.d.ts.map +1 -0
- package/lib/Types/Label.js +24 -30
- package/lib/Types/Label.js.map +1 -0
- package/lib/Types/LabelAssociation.d.ts +15 -20
- package/lib/Types/LabelAssociation.d.ts.map +1 -0
- package/lib/Types/LabelAssociation.js +6 -12
- package/lib/Types/LabelAssociation.js.map +1 -0
- package/lib/Types/Message.d.ts +248 -412
- package/lib/Types/Message.d.ts.map +1 -0
- package/lib/Types/Message.js +17 -19
- package/lib/Types/Message.js.map +1 -0
- package/lib/Types/Mex.d.ts +141 -0
- package/lib/Types/Mex.d.ts.map +1 -0
- package/lib/Types/Mex.js +37 -0
- package/lib/Types/Mex.js.map +1 -0
- package/lib/Types/Product.d.ts +58 -71
- package/lib/Types/Product.d.ts.map +1 -0
- package/lib/Types/Product.js +2 -3
- package/lib/Types/Product.js.map +1 -0
- package/lib/Types/RichType.d.ts +3 -0
- package/lib/Types/RichType.d.ts.map +1 -0
- package/lib/Types/RichType.js +23 -0
- package/lib/Types/RichType.js.bak +23 -0
- package/lib/Types/RichType.js.map +1 -0
- package/lib/Types/Signal.d.ts +71 -82
- package/lib/Types/Signal.d.ts.map +1 -0
- package/lib/Types/Signal.js +2 -3
- package/lib/Types/Signal.js.map +1 -0
- package/lib/Types/Socket.d.ts +76 -81
- package/lib/Types/Socket.d.ts.map +1 -0
- package/lib/Types/Socket.js +3 -3
- package/lib/Types/Socket.js.map +1 -0
- package/lib/Types/State.d.ts +75 -19
- package/lib/Types/State.d.ts.map +1 -0
- package/lib/Types/State.js +56 -14
- package/lib/Types/State.js.map +1 -0
- package/lib/Types/USync.d.ts +8 -8
- package/lib/Types/USync.d.ts.map +1 -0
- package/lib/Types/USync.js +2 -3
- package/lib/Types/USync.js.map +1 -0
- package/lib/Types/index.d.ts +47 -62
- package/lib/Types/index.d.ts.map +1 -0
- package/lib/Types/index.js +26 -50
- package/lib/Types/index.js.map +1 -0
- package/lib/Utils/auth-utils.d.ts +13 -10
- package/lib/Utils/auth-utils.d.ts.map +1 -0
- package/lib/Utils/auth-utils.js +213 -454
- package/lib/Utils/auth-utils.js.map +1 -0
- package/lib/Utils/browser-utils.d.ts +4 -0
- package/lib/Utils/browser-utils.d.ts.map +1 -0
- package/lib/Utils/browser-utils.js +28 -0
- package/lib/Utils/browser-utils.js.map +1 -0
- package/lib/Utils/business.d.ts +14 -20
- package/lib/Utils/business.d.ts.map +1 -0
- package/lib/Utils/business.js +110 -134
- package/lib/Utils/business.js.map +1 -0
- package/lib/Utils/chat-utils.d.ts +88 -70
- package/lib/Utils/chat-utils.d.ts.map +1 -0
- package/lib/Utils/chat-utils.js +466 -403
- package/lib/Utils/chat-utils.js.map +1 -0
- package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
- package/lib/Utils/companion-reg-client-utils.d.ts.map +1 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/companion-reg-client-utils.js.map +1 -0
- package/lib/Utils/crypto.d.ts +27 -46
- package/lib/Utils/crypto.d.ts.map +1 -0
- package/lib/Utils/crypto.js +117 -188
- package/lib/Utils/crypto.js.map +1 -0
- package/lib/Utils/decode-wa-message.d.ts +58 -45
- package/lib/Utils/decode-wa-message.d.ts.map +1 -0
- package/lib/Utils/decode-wa-message.js +213 -303
- package/lib/Utils/decode-wa-message.js.map +1 -0
- package/lib/Utils/event-buffer.d.ts +14 -17
- package/lib/Utils/event-buffer.d.ts.map +1 -0
- package/lib/Utils/event-buffer.js +321 -296
- package/lib/Utils/event-buffer.js.map +1 -0
- package/lib/Utils/generics.d.ts +66 -92
- package/lib/Utils/generics.d.ts.map +1 -0
- package/lib/Utils/generics.js +270 -436
- package/lib/Utils/generics.js.map +1 -0
- package/lib/Utils/history.d.ts +24 -23
- package/lib/Utils/history.d.ts.map +1 -0
- package/lib/Utils/history.js +106 -76
- package/lib/Utils/history.js.map +1 -0
- package/lib/Utils/identity-change-handler.d.ts +44 -0
- package/lib/Utils/identity-change-handler.d.ts.map +1 -0
- package/lib/Utils/identity-change-handler.js +50 -0
- package/lib/Utils/identity-change-handler.js.map +1 -0
- package/lib/Utils/index.d.ts +24 -21
- package/lib/Utils/index.d.ts.map +1 -0
- package/lib/Utils/index.js +24 -41
- package/lib/Utils/index.js.map +1 -0
- package/lib/Utils/link-preview.d.ts +12 -14
- package/lib/Utils/link-preview.d.ts.map +1 -0
- package/lib/Utils/link-preview.js +40 -75
- package/lib/Utils/link-preview.js.map +1 -0
- package/lib/Utils/logger.d.ts +10 -11
- package/lib/Utils/logger.d.ts.map +1 -0
- package/lib/Utils/logger.js +3 -7
- package/lib/Utils/logger.js.map +1 -0
- package/lib/Utils/lt-hash.d.ts +8 -14
- package/lib/Utils/lt-hash.d.ts.map +1 -0
- package/lib/Utils/lt-hash.js +3 -53
- package/lib/Utils/lt-hash.js.map +1 -0
- package/lib/Utils/make-mutex.d.ts +7 -7
- package/lib/Utils/make-mutex.d.ts.map +1 -0
- package/lib/Utils/make-mutex.js +28 -44
- package/lib/Utils/make-mutex.js.map +1 -0
- package/lib/Utils/message-retry-manager.d.ts +115 -88
- package/lib/Utils/message-retry-manager.d.ts.map +1 -0
- package/lib/Utils/message-retry-manager.js +265 -160
- package/lib/Utils/message-retry-manager.js.map +1 -0
- package/lib/Utils/messages-media.d.ts +105 -107
- package/lib/Utils/messages-media.d.ts.map +1 -0
- package/lib/Utils/messages-media.js +548 -619
- package/lib/Utils/messages-media.js.bak +786 -0
- package/lib/Utils/messages-media.js.map +1 -0
- package/lib/Utils/messages.d.ts +52 -66
- package/lib/Utils/messages.d.ts.map +1 -0
- package/lib/Utils/messages.js +1730 -1558
- package/lib/Utils/messages.js.backup +1768 -0
- package/lib/Utils/messages.js.bak +1809 -0
- package/lib/Utils/messages.js.bak2 +893 -0
- package/lib/Utils/messages.js.bak3 +1183 -0
- package/lib/Utils/messages.js.map +1 -0
- package/lib/Utils/noise-handler.d.ts +18 -18
- package/lib/Utils/noise-handler.d.ts.map +1 -0
- package/lib/Utils/noise-handler.js +176 -130
- package/lib/Utils/noise-handler.js.map +1 -0
- package/lib/Utils/offline-node-processor.d.ts +17 -0
- package/lib/Utils/offline-node-processor.d.ts.map +1 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/offline-node-processor.js.map +1 -0
- package/lib/Utils/pre-key-manager.d.ts +28 -0
- package/lib/Utils/pre-key-manager.d.ts.map +1 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/pre-key-manager.js.map +1 -0
- package/lib/Utils/process-message.d.ts +43 -32
- package/lib/Utils/process-message.d.ts.map +1 -0
- package/lib/Utils/process-message.js +484 -282
- package/lib/Utils/process-message.js.map +1 -0
- package/lib/Utils/reporting-utils.d.ts +11 -0
- package/lib/Utils/reporting-utils.d.ts.map +1 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/reporting-utils.js.map +1 -0
- package/lib/Utils/rich-message-utils.d.ts +49 -0
- package/lib/Utils/rich-message-utils.d.ts.map +1 -0
- package/lib/Utils/rich-message-utils.js +1220 -724
- package/lib/Utils/rich-message-utils.js.backup +706 -0
- package/lib/Utils/rich-message-utils.js.bak +246 -0
- package/lib/Utils/rich-message-utils.js.map +1 -0
- package/lib/Utils/rich-message-utils.js.original +1332 -0
- package/lib/Utils/signal.d.ts +37 -32
- package/lib/Utils/signal.d.ts.map +1 -0
- package/lib/Utils/signal.js +140 -105
- package/lib/Utils/signal.js.map +1 -0
- package/lib/Utils/stanza-ack.d.ts +11 -0
- package/lib/Utils/stanza-ack.d.ts.map +1 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/stanza-ack.js.map +1 -0
- package/lib/Utils/sync-action-utils.d.ts +19 -0
- package/lib/Utils/sync-action-utils.d.ts.map +1 -0
- package/lib/Utils/sync-action-utils.js +49 -0
- package/lib/Utils/sync-action-utils.js.map +1 -0
- package/lib/Utils/tc-token-utils.d.ts +37 -0
- package/lib/Utils/tc-token-utils.d.ts.map +1 -0
- package/lib/Utils/tc-token-utils.js +163 -0
- package/lib/Utils/tc-token-utils.js.map +1 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts +5 -5
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -0
- package/lib/Utils/use-multi-file-auth-state.js +70 -120
- package/lib/Utils/use-multi-file-auth-state.js.map +1 -0
- package/lib/Utils/use-single-file-auth-state.d.ts +11 -13
- package/lib/Utils/use-single-file-auth-state.d.ts.map +1 -0
- package/lib/Utils/use-single-file-auth-state.js +92 -66
- package/lib/Utils/use-single-file-auth-state.js.map +1 -0
- package/lib/Utils/use-sqlite-auth-state.d.ts +11 -0
- package/lib/Utils/use-sqlite-auth-state.d.ts.map +1 -0
- package/lib/Utils/use-sqlite-auth-state.js +109 -0
- package/lib/Utils/use-sqlite-auth-state.js.map +1 -0
- package/lib/Utils/validate-connection.d.ts +11 -13
- package/lib/Utils/validate-connection.d.ts.map +1 -0
- package/lib/Utils/validate-connection.js +128 -113
- package/lib/Utils/validate-connection.js.map +1 -0
- package/lib/WABinary/constants.d.ts +25 -27
- package/lib/WABinary/constants.d.ts.map +1 -0
- package/lib/WABinary/constants.js +1451 -1292
- package/lib/WABinary/constants.js.bak +1373 -0
- package/lib/WABinary/constants.js.map +1 -0
- package/lib/WABinary/decode.d.ts +7 -9
- package/lib/WABinary/decode.d.ts.map +1 -0
- package/lib/WABinary/decode.js +163 -189
- package/lib/WABinary/decode.js.map +1 -0
- package/lib/WABinary/encode.d.ts +3 -3
- package/lib/WABinary/encode.d.ts.map +1 -0
- package/lib/WABinary/encode.js +110 -155
- package/lib/WABinary/encode.js.map +1 -0
- package/lib/WABinary/generic-utils.d.ts +14 -27
- package/lib/WABinary/generic-utils.d.ts.map +1 -0
- package/lib/WABinary/generic-utils.js +177 -105
- package/lib/WABinary/generic-utils.js.map +1 -0
- package/lib/WABinary/index.d.ts +6 -5
- package/lib/WABinary/index.d.ts.map +1 -0
- package/lib/WABinary/index.js +6 -25
- package/lib/WABinary/index.js.map +1 -0
- package/lib/WABinary/jid-utils.d.ts +41 -51
- package/lib/WABinary/jid-utils.d.ts.map +1 -0
- package/lib/WABinary/jid-utils.js +83 -120
- package/lib/WABinary/jid-utils.js.map +1 -0
- package/lib/WABinary/types.d.ts +10 -13
- package/lib/WABinary/types.d.ts.map +1 -0
- package/lib/WABinary/types.js +2 -3
- package/lib/WABinary/types.js.map +1 -0
- package/lib/WAM/BinaryInfo.d.ts +8 -15
- package/lib/WAM/BinaryInfo.d.ts.map +1 -0
- package/lib/WAM/BinaryInfo.js +7 -14
- package/lib/WAM/BinaryInfo.js.map +1 -0
- package/lib/WAM/constants.d.ts +30 -37
- package/lib/WAM/constants.d.ts.map +1 -0
- package/lib/WAM/constants.js +19193 -11711
- package/lib/WAM/constants.js.map +1 -0
- package/lib/WAM/encode.d.ts +3 -3
- package/lib/WAM/encode.d.ts.map +1 -0
- package/lib/WAM/encode.js +95 -109
- package/lib/WAM/encode.js.map +1 -0
- package/lib/WAM/index.d.ts +4 -3
- package/lib/WAM/index.d.ts.map +1 -0
- package/lib/WAM/index.js +4 -23
- package/lib/WAM/index.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -9
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +37 -21
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +19 -22
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +18 -26
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +11 -12
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +12 -20
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +11 -12
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +16 -24
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +51 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +29 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/index.d.ts +6 -6
- package/lib/WAUSync/Protocols/index.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/index.js +6 -26
- package/lib/WAUSync/Protocols/index.js.map +1 -0
- package/lib/WAUSync/USyncQuery.d.ts +27 -28
- package/lib/WAUSync/USyncQuery.d.ts.map +1 -0
- package/lib/WAUSync/USyncQuery.js +68 -62
- package/lib/WAUSync/USyncQuery.js.map +1 -0
- package/lib/WAUSync/USyncUser.d.ts +15 -10
- package/lib/WAUSync/USyncUser.d.ts.map +1 -0
- package/lib/WAUSync/USyncUser.js +20 -19
- package/lib/WAUSync/USyncUser.js.map +1 -0
- package/lib/WAUSync/index.d.ts +4 -3
- package/lib/WAUSync/index.d.ts.map +1 -0
- package/lib/WAUSync/index.js +4 -23
- package/lib/WAUSync/index.js.map +1 -0
- package/lib/index.d.ts +11 -12
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +12 -39
- package/lib/index.js.map +1 -0
- package/package.json +86 -42
|
@@ -1,1514 +1,1408 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
signalRepository,
|
|
43
|
-
upsertMessage,
|
|
44
|
-
createCallLink,
|
|
45
|
-
query,
|
|
46
|
-
fetchPrivacySettings,
|
|
47
|
-
sendNode,
|
|
48
|
-
groupQuery,
|
|
49
|
-
groupMetadata,
|
|
50
|
-
groupToggleEphemeral,
|
|
51
|
-
newsletterWMexQuery,
|
|
52
|
-
executeUSyncQuery
|
|
53
|
-
} = sock
|
|
54
|
-
|
|
55
|
-
const userDevicesCache = config.userDevicesCache || new node_cache_1.default({
|
|
56
|
-
stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
57
|
-
useClones: false
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
const messageRetryManager = enableRecentMessageCache ? new Utils_1.MessageRetryManager(logger, maxMsgRetryCount) : null
|
|
61
|
-
const encryptionMutex = make_keyed_mutex_1.makeKeyedMutex()
|
|
62
|
-
const devicesMutex = make_keyed_mutex_1.makeMutex()
|
|
63
|
-
let mediaConn
|
|
64
|
-
|
|
1
|
+
import NodeCache from '@cacheable/node-cache';
|
|
2
|
+
import { Boom } from '@hapi/boom';
|
|
3
|
+
import { randomBytes } from 'crypto';
|
|
4
|
+
import { proto } from '../../WAProto/index.js';
|
|
5
|
+
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
6
|
+
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageContent, generateWAMessageFromContent, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/index.js';
|
|
7
|
+
import { AssociationType } from '../Types/index.js';
|
|
8
|
+
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
9
|
+
import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex.js';
|
|
10
|
+
import { getMessageReportingToken, shouldIncludeReportingToken } from '../Utils/reporting-utils.js';
|
|
11
|
+
import { buildMergedTcTokenIndexWrite, isTcTokenExpired, resolveIssuanceJid, resolveTcTokenJid, shouldSendNewTcToken, storeTcTokensFromIqResult } from '../Utils/tc-token-utils.js';
|
|
12
|
+
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, getBizBinaryNode, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isJidNewsletter, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
13
|
+
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
14
|
+
import { makeNewsletterSocket } from './newsletter.js';
|
|
15
|
+
import kikyy from './dugong.js';
|
|
16
|
+
import { generateTableContent, generateTableContentV2, generateListContent, generateCodeBlockContent, generateCodeBlockContentV2, generateLinkContent, generateLinkContentV2, generateRichMessageContent, generateUnifiedResponseContent, captureUnifiedResponse, generateLatexContent, generateLatexImageContent, generateLatexInlineImageContent } from '../Utils/rich-message-utils.js';
|
|
17
|
+
export const makeMessagesSocket = (config) => {
|
|
18
|
+
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
19
|
+
const sock = makeNewsletterSocket(config);
|
|
20
|
+
const { ev, authState, messageMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral, registerSocketEndHandler } = sock;
|
|
21
|
+
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
|
|
22
|
+
/**
|
|
23
|
+
* Set of tctoken storage JIDs with a fire-and-forget `issuePrivacyTokens` IQ in flight.
|
|
24
|
+
* Prevents duplicate IQs from rapid back-to-back sends before `senderTimestamp` persists.
|
|
25
|
+
* Entries are always removed in `.finally()`, so the set is bounded by concurrency.
|
|
26
|
+
*/
|
|
27
|
+
const inFlightTcTokenIssuance = new Set();
|
|
28
|
+
const userDevicesCache = config.userDevicesCache ||
|
|
29
|
+
new NodeCache({
|
|
30
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
31
|
+
useClones: false
|
|
32
|
+
});
|
|
33
|
+
/** Serializes writes to userDevicesCache across USync refresh and device-notification handling. */
|
|
34
|
+
const devicesMutex = makeMutex();
|
|
35
|
+
// Initialize message retry manager if enabled
|
|
36
|
+
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
|
|
37
|
+
// Prevent race conditions in Signal session encryption by user
|
|
38
|
+
const encryptionMutex = makeKeyedMutex();
|
|
39
|
+
let mediaConn;
|
|
40
|
+
/** Per-socket media host; updated whenever media_conn is fetched. Defaults to the public WhatsApp host. */
|
|
41
|
+
let mediaHost = DEF_MEDIA_HOST;
|
|
65
42
|
const refreshMediaConn = async (forceGet = false) => {
|
|
66
|
-
const media = await mediaConn
|
|
67
|
-
if (!media || forceGet ||
|
|
43
|
+
const media = await mediaConn;
|
|
44
|
+
if (!media || forceGet || new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1000) {
|
|
68
45
|
mediaConn = (async () => {
|
|
69
46
|
const result = await query({
|
|
70
47
|
tag: 'iq',
|
|
71
48
|
attrs: {
|
|
72
49
|
type: 'set',
|
|
73
50
|
xmlns: 'w:m',
|
|
74
|
-
to:
|
|
51
|
+
to: S_WHATSAPP_NET
|
|
75
52
|
},
|
|
76
|
-
content: [{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
})
|
|
81
|
-
const mediaConnNode = WABinary_1.getBinaryNodeChild(result, 'media_conn')
|
|
53
|
+
content: [{ tag: 'media_conn', attrs: {} }]
|
|
54
|
+
});
|
|
55
|
+
const mediaConnNode = getBinaryNodeChild(result, 'media_conn');
|
|
56
|
+
// TODO: explore full length of data that whatsapp provides
|
|
82
57
|
const node = {
|
|
83
|
-
hosts:
|
|
84
|
-
attrs
|
|
85
|
-
}) => ({
|
|
58
|
+
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
|
|
86
59
|
hostname: attrs.hostname,
|
|
87
|
-
maxContentLengthBytes: +attrs.maxContentLengthBytes
|
|
60
|
+
maxContentLengthBytes: +attrs.maxContentLengthBytes
|
|
88
61
|
})),
|
|
89
62
|
auth: mediaConnNode.attrs.auth,
|
|
90
63
|
ttl: +mediaConnNode.attrs.ttl,
|
|
91
64
|
fetchDate: new Date()
|
|
65
|
+
};
|
|
66
|
+
logger.debug('fetched media conn');
|
|
67
|
+
if (node.hosts[0]) {
|
|
68
|
+
mediaHost = node.hosts[0].hostname;
|
|
92
69
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
})()
|
|
70
|
+
return node;
|
|
71
|
+
})();
|
|
96
72
|
}
|
|
97
|
-
return mediaConn
|
|
98
|
-
}
|
|
99
|
-
|
|
73
|
+
return mediaConn;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* generic send receipt function
|
|
77
|
+
* used for receipts of phone call, read, delivery etc.
|
|
78
|
+
* */
|
|
100
79
|
const sendReceipt = async (jid, participant, messageIds, type) => {
|
|
80
|
+
if (!messageIds || messageIds.length === 0) {
|
|
81
|
+
throw new Boom('missing ids in receipt');
|
|
82
|
+
}
|
|
101
83
|
const node = {
|
|
102
84
|
tag: 'receipt',
|
|
103
85
|
attrs: {
|
|
104
|
-
id: messageIds[0]
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
const isReadReceipt = type === 'read' || type === 'read-self'
|
|
86
|
+
id: messageIds[0]
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const isReadReceipt = type === 'read' || type === 'read-self';
|
|
108
90
|
if (isReadReceipt) {
|
|
109
|
-
node.attrs.t =
|
|
91
|
+
node.attrs.t = unixTimestampSeconds().toString();
|
|
92
|
+
}
|
|
93
|
+
if (type === 'sender' && (isPnUser(jid) || isLidUser(jid))) {
|
|
94
|
+
node.attrs.recipient = jid;
|
|
95
|
+
node.attrs.to = participant;
|
|
110
96
|
}
|
|
111
|
-
|
|
112
|
-
node.attrs.
|
|
113
|
-
node.attrs.to = participant
|
|
114
|
-
} else {
|
|
115
|
-
node.attrs.to = jid
|
|
97
|
+
else {
|
|
98
|
+
node.attrs.to = jid;
|
|
116
99
|
if (participant) {
|
|
117
|
-
node.attrs.participant = participant
|
|
100
|
+
node.attrs.participant = participant;
|
|
118
101
|
}
|
|
119
102
|
}
|
|
120
103
|
if (type) {
|
|
121
|
-
node.attrs.type =
|
|
104
|
+
node.attrs.type = type;
|
|
122
105
|
}
|
|
123
|
-
const remainingMessageIds = messageIds.slice(1)
|
|
106
|
+
const remainingMessageIds = messageIds.slice(1);
|
|
124
107
|
if (remainingMessageIds.length) {
|
|
125
|
-
node.content = [
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
id
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
108
|
+
node.content = [
|
|
109
|
+
{
|
|
110
|
+
tag: 'list',
|
|
111
|
+
attrs: {},
|
|
112
|
+
content: remainingMessageIds.map(id => ({
|
|
113
|
+
tag: 'item',
|
|
114
|
+
attrs: { id }
|
|
115
|
+
}))
|
|
116
|
+
}
|
|
117
|
+
];
|
|
135
118
|
}
|
|
136
|
-
logger.debug({
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
await sendNode(node)
|
|
141
|
-
}
|
|
142
|
-
|
|
119
|
+
logger.debug({ attrs: node.attrs, messageIds }, 'sending receipt for messages');
|
|
120
|
+
await sendNode(node);
|
|
121
|
+
};
|
|
122
|
+
/** Correctly bulk send receipts to multiple chats, participants */
|
|
143
123
|
const sendReceipts = async (keys, type) => {
|
|
144
|
-
const recps =
|
|
124
|
+
const recps = aggregateMessageKeysNotFromMe(keys);
|
|
145
125
|
for (const { jid, participant, messageIds } of recps) {
|
|
146
|
-
await sendReceipt(jid, participant, messageIds, type)
|
|
126
|
+
await sendReceipt(jid, participant, messageIds, type);
|
|
147
127
|
}
|
|
148
|
-
}
|
|
149
|
-
|
|
128
|
+
};
|
|
129
|
+
/** Bulk read messages. Keys can be from different chats & participants */
|
|
150
130
|
const readMessages = async (keys) => {
|
|
151
|
-
const privacySettings = await fetchPrivacySettings()
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const lidUsers = new Set()
|
|
158
|
-
const filteredJids = []
|
|
159
|
-
|
|
160
|
-
for (const jid of jids) {
|
|
161
|
-
if (WABinary_1.isLidUser(jid)) {
|
|
162
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
163
|
-
if (user) lidUsers.add(user)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
for (const jid of jids) {
|
|
168
|
-
if (WABinary_1.isJidUser(jid)) {
|
|
169
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
170
|
-
if (user && lidUsers.has(user)) {
|
|
171
|
-
logger.debug({
|
|
172
|
-
jid
|
|
173
|
-
}, 'Skipping PN - LID version exists')
|
|
174
|
-
continue
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
filteredJids.push(jid)
|
|
178
|
-
}
|
|
179
|
-
return filteredJids
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const profilePictureUrl = async (jid) => {
|
|
183
|
-
if (WABinary_1.isJidNewsletter(jid)) {
|
|
184
|
-
let node = await newsletterWMexQuery(undefined, Types_1.QueryIds.METADATA, {
|
|
185
|
-
input: {
|
|
186
|
-
key: jid,
|
|
187
|
-
type: 'JID',
|
|
188
|
-
view_role: 'GUEST'
|
|
189
|
-
},
|
|
190
|
-
fetch_viewer_metadata: true,
|
|
191
|
-
fetch_full_image: true,
|
|
192
|
-
fetch_creation_time: true
|
|
193
|
-
})
|
|
194
|
-
let result = WABinary_1.getBinaryNodeChild(node, 'result')?.content?.toString()
|
|
195
|
-
let metadata = JSON.parse(result).data[Types_1.XWAPaths.NEWSLETTER]
|
|
196
|
-
return Utils_1.getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || '')
|
|
197
|
-
} else {
|
|
198
|
-
const result = await query({
|
|
199
|
-
tag: 'iq',
|
|
200
|
-
attrs: {
|
|
201
|
-
target: WABinary_1.jidNormalizedUser(jid),
|
|
202
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
203
|
-
type: 'get',
|
|
204
|
-
xmlns: 'w:profile:picture'
|
|
205
|
-
},
|
|
206
|
-
content: [{
|
|
207
|
-
tag: 'picture',
|
|
208
|
-
attrs: {
|
|
209
|
-
type: 'image',
|
|
210
|
-
query: 'url'
|
|
211
|
-
}
|
|
212
|
-
}]
|
|
213
|
-
})
|
|
214
|
-
const child = WABinary_1.getBinaryNodeChild(result, 'picture')
|
|
215
|
-
return child?.attrs?.url || null
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
131
|
+
const privacySettings = await fetchPrivacySettings();
|
|
132
|
+
// based on privacy settings, we have to change the read type
|
|
133
|
+
const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self';
|
|
134
|
+
await sendReceipts(keys, readType);
|
|
135
|
+
};
|
|
136
|
+
/** Fetch all the devices we've to send a message to */
|
|
219
137
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
220
|
-
const deviceResults = []
|
|
221
|
-
|
|
138
|
+
const deviceResults = [];
|
|
222
139
|
if (!useCache) {
|
|
223
|
-
logger.debug('not using cache for devices')
|
|
140
|
+
logger.debug('not using cache for devices');
|
|
224
141
|
}
|
|
225
|
-
|
|
226
|
-
const toFetch = []
|
|
227
|
-
|
|
228
|
-
jids = deduplicateLidPnJids(Array.from(new Set(jids)))
|
|
142
|
+
const toFetch = [];
|
|
229
143
|
const jidsWithUser = jids
|
|
230
144
|
.map(jid => {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
user
|
|
249
|
-
}
|
|
250
|
-
})
|
|
251
|
-
.filter(jid => jid !== null)
|
|
252
|
-
|
|
253
|
-
let mgetDevices
|
|
145
|
+
const decoded = jidDecode(jid);
|
|
146
|
+
const user = decoded?.user;
|
|
147
|
+
const device = decoded?.device;
|
|
148
|
+
const isExplicitDevice = typeof device === 'number' && device >= 0;
|
|
149
|
+
if (isExplicitDevice && user) {
|
|
150
|
+
deviceResults.push({
|
|
151
|
+
user,
|
|
152
|
+
device,
|
|
153
|
+
jid
|
|
154
|
+
});
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
jid = jidNormalizedUser(jid);
|
|
158
|
+
return { jid, user };
|
|
159
|
+
})
|
|
160
|
+
.filter(jid => jid !== null);
|
|
161
|
+
let mgetDevices;
|
|
254
162
|
if (useCache && userDevicesCache.mget) {
|
|
255
|
-
const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean)
|
|
256
|
-
mgetDevices = await userDevicesCache.mget(usersToFetch)
|
|
163
|
+
const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean);
|
|
164
|
+
mgetDevices = await userDevicesCache.mget(usersToFetch);
|
|
257
165
|
}
|
|
258
|
-
|
|
259
166
|
for (const { jid, user } of jidsWithUser) {
|
|
260
167
|
if (useCache) {
|
|
261
|
-
const devices = mgetDevices?.[user] ||
|
|
168
|
+
const devices = mgetDevices?.[user] ||
|
|
169
|
+
(userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)));
|
|
262
170
|
if (devices) {
|
|
263
|
-
const
|
|
264
|
-
const devicesWithWire = devices.map(d => ({
|
|
171
|
+
const devicesWithJid = devices.map(d => ({
|
|
265
172
|
...d,
|
|
266
|
-
|
|
267
|
-
}))
|
|
268
|
-
deviceResults.push(...
|
|
269
|
-
logger.trace({
|
|
270
|
-
user
|
|
271
|
-
}, 'using cache for devices')
|
|
272
|
-
} else {
|
|
273
|
-
toFetch.push(jid)
|
|
173
|
+
jid: jidEncode(d.user, d.server, d.device)
|
|
174
|
+
}));
|
|
175
|
+
deviceResults.push(...devicesWithJid);
|
|
176
|
+
logger.trace({ user }, 'using cache for devices');
|
|
274
177
|
}
|
|
275
|
-
|
|
276
|
-
|
|
178
|
+
else {
|
|
179
|
+
toFetch.push(jid);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
toFetch.push(jid);
|
|
277
184
|
}
|
|
278
185
|
}
|
|
279
|
-
|
|
280
186
|
if (!toFetch.length) {
|
|
281
|
-
return deviceResults
|
|
187
|
+
return deviceResults;
|
|
282
188
|
}
|
|
283
|
-
|
|
284
|
-
const requestedLidUsers = new Set()
|
|
189
|
+
const requestedLidUsers = new Set();
|
|
285
190
|
for (const jid of toFetch) {
|
|
286
|
-
if (
|
|
287
|
-
const user =
|
|
288
|
-
if (user)
|
|
191
|
+
if (isLidUser(jid) || isHostedLidUser(jid)) {
|
|
192
|
+
const user = jidDecode(jid)?.user;
|
|
193
|
+
if (user)
|
|
194
|
+
requestedLidUsers.add(user);
|
|
289
195
|
}
|
|
290
196
|
}
|
|
291
|
-
|
|
292
|
-
const query = new WAUSync_1.USyncQuery().withContext('message').withDeviceProtocol()
|
|
197
|
+
const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol();
|
|
293
198
|
for (const jid of toFetch) {
|
|
294
|
-
query.withUser(new
|
|
199
|
+
query.withUser(new USyncUser().withId(jid)); // todo: investigate - the idea here is that <user> should have an inline lid field with the lid being the pn equivalent
|
|
295
200
|
}
|
|
296
|
-
|
|
297
|
-
const result = await executeUSyncQuery(query)
|
|
201
|
+
const result = await sock.executeUSyncQuery(query);
|
|
298
202
|
if (result) {
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
// force-refresh session buat LID yang baru ketemu). Tanpa ini,
|
|
302
|
-
// pengiriman ke kontak yang butuh LID addressing bisa tetep pakai
|
|
303
|
-
// address PN yang salah/basi -> penerima gak bisa decrypt balasan
|
|
304
|
-
// bot ("Menunggu pesan ini...").
|
|
305
|
-
const lidResults = (result.list || []).filter(item => !!item.lid)
|
|
203
|
+
// TODO: LID MAP this stuff (lid protocol will now return lid with devices)
|
|
204
|
+
const lidResults = result.list.filter(a => !!a.lid);
|
|
306
205
|
if (lidResults.length > 0) {
|
|
206
|
+
logger.trace('Storing LID maps from device call');
|
|
207
|
+
await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })));
|
|
208
|
+
// Force-refresh sessions for newly mapped LIDs to align identity addressing
|
|
307
209
|
try {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
logger.warn({
|
|
210
|
+
const lids = lidResults.map(a => a.lid);
|
|
211
|
+
if (lids.length) {
|
|
212
|
+
await assertSessions(lids, true);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (e) {
|
|
216
|
+
logger.warn({ e, count: lidResults.length }, 'failed to assert sessions for newly mapped LIDs');
|
|
315
217
|
}
|
|
316
218
|
}
|
|
317
|
-
const extracted =
|
|
318
|
-
const deviceMap = {}
|
|
219
|
+
const extracted = extractDeviceJids(result?.list, authState.creds.me.id, authState.creds.me.lid, ignoreZeroDevices);
|
|
220
|
+
const deviceMap = {};
|
|
319
221
|
for (const item of extracted) {
|
|
320
|
-
deviceMap[item.user] = deviceMap[item.user] || []
|
|
321
|
-
deviceMap[item.user]?.push(item)
|
|
222
|
+
deviceMap[item.user] = deviceMap[item.user] || [];
|
|
223
|
+
deviceMap[item.user]?.push(item);
|
|
322
224
|
}
|
|
225
|
+
// Process each user's devices as a group for bulk LID migration
|
|
323
226
|
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
324
|
-
const isLidUser = requestedLidUsers.has(user)
|
|
227
|
+
const isLidUser = requestedLidUsers.has(user);
|
|
228
|
+
// Process all devices for this user
|
|
325
229
|
for (const item of userDevices) {
|
|
326
|
-
const
|
|
230
|
+
const finalJid = isLidUser
|
|
231
|
+
? jidEncode(user, item.server, item.device)
|
|
232
|
+
: jidEncode(item.user, item.server, item.device);
|
|
327
233
|
deviceResults.push({
|
|
328
234
|
...item,
|
|
329
|
-
|
|
235
|
+
jid: finalJid
|
|
330
236
|
});
|
|
331
237
|
logger.debug({
|
|
332
238
|
user: item.user,
|
|
333
239
|
device: item.device,
|
|
334
|
-
|
|
240
|
+
finalJid,
|
|
335
241
|
usedLid: isLidUser
|
|
336
|
-
}, 'Processed device with LID priority')
|
|
242
|
+
}, 'Processed device with LID priority');
|
|
337
243
|
}
|
|
338
244
|
}
|
|
339
|
-
|
|
340
245
|
await devicesMutex.mutex(async () => {
|
|
341
246
|
if (userDevicesCache.mset) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
} else {
|
|
247
|
+
// if the cache supports mset, we can set all devices in one go
|
|
248
|
+
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
347
251
|
for (const key in deviceMap) {
|
|
348
|
-
if (deviceMap[key])
|
|
252
|
+
if (deviceMap[key])
|
|
253
|
+
await userDevicesCache.set(key, deviceMap[key]);
|
|
349
254
|
}
|
|
350
255
|
}
|
|
351
|
-
})
|
|
256
|
+
});
|
|
257
|
+
const userDeviceUpdates = {};
|
|
258
|
+
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
259
|
+
if (devices && devices.length > 0) {
|
|
260
|
+
userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0');
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (Object.keys(userDeviceUpdates).length > 0) {
|
|
264
|
+
try {
|
|
265
|
+
await authState.keys.set({ 'device-list': userDeviceUpdates });
|
|
266
|
+
logger.debug({ userCount: Object.keys(userDeviceUpdates).length }, 'stored user device lists for bulk migration');
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
logger.warn({ error }, 'failed to store user device lists');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
352
272
|
}
|
|
353
|
-
return deviceResults
|
|
354
|
-
}
|
|
355
|
-
|
|
273
|
+
return deviceResults;
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Update Member Label
|
|
277
|
+
*/
|
|
278
|
+
const updateMemberLabel = (jid, memberLabel) => {
|
|
279
|
+
return relayMessage(jid, {
|
|
280
|
+
protocolMessage: {
|
|
281
|
+
type: proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE,
|
|
282
|
+
memberLabel: {
|
|
283
|
+
label: memberLabel?.slice(0, 30),
|
|
284
|
+
labelTimestamp: unixTimestampSeconds()
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}, {
|
|
288
|
+
additionalNodes: [
|
|
289
|
+
{
|
|
290
|
+
tag: 'meta',
|
|
291
|
+
attrs: {
|
|
292
|
+
tag_reason: 'user_update',
|
|
293
|
+
appdata: 'member_tag'
|
|
294
|
+
},
|
|
295
|
+
content: undefined
|
|
296
|
+
}
|
|
297
|
+
]
|
|
298
|
+
});
|
|
299
|
+
};
|
|
356
300
|
const assertSessions = async (jids, force) => {
|
|
357
301
|
let didFetchNewSession = false;
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
// FIX: sebelumnya cuma ngecek "ada record tersimpan atau enggak"
|
|
364
|
-
// (truthy check di authState.keys.get('session', ...)). Record
|
|
365
|
-
// yang kosong/stale/rusak (misal device grup yang session-nya
|
|
366
|
-
// kebentuk tapi gak pernah kepakai/keisi ratchet) tetep truthy,
|
|
367
|
-
// jadi dianggap "udah punya sesi" padahal libsignal-nya beneran
|
|
368
|
-
// kosong -> pas encrypt muncul "SessionError: No sessions".
|
|
369
|
-
// validateSession ngecek session-nya beneran ada & "open" enggak,
|
|
370
|
-
// bukan cuma record-nya ada.
|
|
371
|
-
for (const jid of jids) {
|
|
302
|
+
const uniqueJids = [...new Set(jids)];
|
|
303
|
+
const jidsRequiringFetch = [];
|
|
304
|
+
logger.debug({ jids }, 'assertSessions call with jids');
|
|
305
|
+
for (const jid of uniqueJids) {
|
|
306
|
+
if (!force) {
|
|
372
307
|
const sessionValidation = await signalRepository.validateSession(jid);
|
|
373
|
-
if (
|
|
374
|
-
|
|
308
|
+
if (sessionValidation.exists) {
|
|
309
|
+
continue;
|
|
375
310
|
}
|
|
376
311
|
}
|
|
312
|
+
jidsRequiringFetch.push(jid);
|
|
377
313
|
}
|
|
378
|
-
|
|
379
314
|
if (jidsRequiringFetch.length) {
|
|
380
|
-
|
|
381
|
-
|
|
315
|
+
// LID if mapped, otherwise original
|
|
316
|
+
const wireJids = [
|
|
317
|
+
...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
|
|
318
|
+
...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
|
|
319
|
+
];
|
|
320
|
+
logger.debug({ jidsRequiringFetch, wireJids }, 'fetching sessions');
|
|
382
321
|
const result = await query({
|
|
383
322
|
tag: 'iq',
|
|
384
323
|
attrs: {
|
|
385
324
|
xmlns: 'encrypt',
|
|
386
325
|
type: 'get',
|
|
387
|
-
to:
|
|
326
|
+
to: S_WHATSAPP_NET
|
|
388
327
|
},
|
|
389
328
|
content: [
|
|
390
329
|
{
|
|
391
330
|
tag: 'key',
|
|
392
331
|
attrs: {},
|
|
393
|
-
content:
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
332
|
+
content: wireJids.map(jid => {
|
|
333
|
+
const attrs = { jid };
|
|
334
|
+
if (force)
|
|
335
|
+
attrs.reason = 'identity';
|
|
336
|
+
return { tag: 'user', attrs };
|
|
337
|
+
})
|
|
397
338
|
}
|
|
398
339
|
]
|
|
399
340
|
});
|
|
400
|
-
await
|
|
341
|
+
await parseAndInjectE2ESessions(result, signalRepository);
|
|
401
342
|
didFetchNewSession = true;
|
|
402
343
|
}
|
|
403
344
|
return didFetchNewSession;
|
|
404
345
|
};
|
|
405
|
-
|
|
406
346
|
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
347
|
+
//TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
|
|
407
348
|
if (!authState.creds.me?.id) {
|
|
408
|
-
throw new
|
|
349
|
+
throw new Boom('Not authenticated');
|
|
409
350
|
}
|
|
410
|
-
|
|
411
351
|
const protocolMessage = {
|
|
412
352
|
protocolMessage: {
|
|
413
353
|
peerDataOperationRequestMessage: pdoMessage,
|
|
414
|
-
type:
|
|
354
|
+
type: proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
|
|
415
355
|
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
const meJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
|
|
356
|
+
};
|
|
357
|
+
const meJid = jidNormalizedUser(authState.creds.me.id);
|
|
419
358
|
const msgId = await relayMessage(meJid, protocolMessage, {
|
|
420
359
|
additionalAttributes: {
|
|
421
360
|
category: 'peer',
|
|
422
|
-
push_priority: 'high_force'
|
|
361
|
+
push_priority: 'high_force'
|
|
423
362
|
},
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
363
|
+
additionalNodes: [
|
|
364
|
+
{
|
|
365
|
+
tag: 'meta',
|
|
366
|
+
attrs: { appdata: 'default' }
|
|
367
|
+
}
|
|
368
|
+
]
|
|
369
|
+
});
|
|
370
|
+
return msgId;
|
|
371
|
+
};
|
|
372
|
+
const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
|
|
373
|
+
if (!recipientJids.length) {
|
|
374
|
+
return { nodes: [], shouldIncludeDeviceIdentity: false };
|
|
433
375
|
}
|
|
434
|
-
|
|
376
|
+
const patched = await patchMessageBeforeSending(message, recipientJids);
|
|
377
|
+
const patchedMessages = Array.isArray(patched)
|
|
378
|
+
? patched
|
|
379
|
+
: recipientJids.map(jid => ({ recipientJid: jid, message: patched }));
|
|
435
380
|
let shouldIncludeDeviceIdentity = false;
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
381
|
+
const meId = authState.creds.me.id;
|
|
382
|
+
const meLid = authState.creds.me?.lid;
|
|
383
|
+
const meLidUser = meLid ? jidDecode(meLid)?.user : null;
|
|
384
|
+
const encryptionPromises = patchedMessages.map(async ({ recipientJid: jid, message: patchedMessage }) => {
|
|
385
|
+
try {
|
|
386
|
+
if (!jid)
|
|
387
|
+
return null;
|
|
388
|
+
let msgToEncrypt = patchedMessage;
|
|
389
|
+
if (dsmMessage) {
|
|
390
|
+
const { user: targetUser } = jidDecode(jid);
|
|
391
|
+
const { user: ownPnUser } = jidDecode(meId);
|
|
392
|
+
const ownLidUser = meLidUser;
|
|
393
|
+
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
394
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
395
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
396
|
+
msgToEncrypt = dsmMessage;
|
|
397
|
+
logger.debug({ jid, targetUser }, 'Using DSM for own device');
|
|
398
|
+
}
|
|
453
399
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
},
|
|
464
|
-
content:
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
400
|
+
const bytes = encodeWAMessage(msgToEncrypt);
|
|
401
|
+
const mutexKey = jid;
|
|
402
|
+
const node = await encryptionMutex.mutex(mutexKey, async () => {
|
|
403
|
+
const { type, ciphertext } = await signalRepository.encryptMessage({ jid, data: bytes });
|
|
404
|
+
if (type === 'pkmsg') {
|
|
405
|
+
shouldIncludeDeviceIdentity = true;
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
tag: 'to',
|
|
409
|
+
attrs: { jid },
|
|
410
|
+
content: [
|
|
411
|
+
{
|
|
412
|
+
tag: 'enc',
|
|
413
|
+
attrs: { v: '2', type, ...(extraAttrs || {}) },
|
|
414
|
+
content: ciphertext
|
|
415
|
+
}
|
|
416
|
+
]
|
|
417
|
+
};
|
|
418
|
+
});
|
|
419
|
+
return node;
|
|
420
|
+
}
|
|
421
|
+
catch (err) {
|
|
422
|
+
logger.error({ jid, err }, 'Failed to encrypt for recipient');
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null);
|
|
427
|
+
if (recipientJids.length > 0 && nodes.length === 0) {
|
|
428
|
+
throw new Boom('All encryptions failed', { statusCode: 500 });
|
|
429
|
+
}
|
|
470
430
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
471
431
|
};
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
participant
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
const
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
const statusJid = 'status@broadcast'
|
|
495
|
-
const isGroup = server === 'g.us'
|
|
496
|
-
const isPrivate = server === 's.whatsapp.net'
|
|
497
|
-
const isNewsletter = server == 'newsletter'
|
|
498
|
-
const isStatus = jid === statusJid
|
|
499
|
-
const isLid = server === 'lid'
|
|
500
|
-
|
|
501
|
-
const finalJid = jid
|
|
502
|
-
|
|
503
|
-
let ownId = meId
|
|
504
|
-
|
|
505
|
-
if (isLid && meLid) {
|
|
506
|
-
ownId = meLid
|
|
507
|
-
logger.debug({
|
|
508
|
-
to: jid,
|
|
509
|
-
ownId
|
|
510
|
-
}, 'Using LID identity for @lid conversation')
|
|
511
|
-
} else {
|
|
512
|
-
logger.debug({
|
|
513
|
-
to: jid,
|
|
514
|
-
ownId
|
|
515
|
-
}, 'Using PN identity for @s.whatsapp.net conversation')
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
msgId = msgId || Utils_1.generateMessageID(authState.creds.me.id)
|
|
519
|
-
useUserDevicesCache = useUserDevicesCache !== false
|
|
520
|
-
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
|
|
521
|
-
|
|
522
|
-
const participants = []
|
|
523
|
-
const destinationJid = !isStatus ? finalJid : statusJid
|
|
524
|
-
const binaryNodeContent = []
|
|
525
|
-
const devices = []
|
|
526
|
-
|
|
432
|
+
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
|
|
433
|
+
const meId = assertMeId(authState.creds);
|
|
434
|
+
const meLid = authState.creds.me?.lid;
|
|
435
|
+
const isRetryResend = Boolean(participant?.jid);
|
|
436
|
+
let shouldIncludeDeviceIdentity = isRetryResend;
|
|
437
|
+
const statusJid = 'status@broadcast';
|
|
438
|
+
const { user, server } = jidDecode(jid);
|
|
439
|
+
const isGroup = server === 'g.us';
|
|
440
|
+
const isStatus = jid === statusJid;
|
|
441
|
+
const isLid = server === 'lid';
|
|
442
|
+
const isNewsletter = server === 'newsletter';
|
|
443
|
+
const isGroupOrStatus = isGroup || isStatus;
|
|
444
|
+
const finalJid = jid;
|
|
445
|
+
msgId = msgId || generateMessageIDV2(meId);
|
|
446
|
+
useUserDevicesCache = useUserDevicesCache !== false;
|
|
447
|
+
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
|
|
448
|
+
const participants = [];
|
|
449
|
+
const destinationJid = !isStatus ? finalJid : statusJid;
|
|
450
|
+
const binaryNodeContent = [];
|
|
451
|
+
const devices = [];
|
|
452
|
+
let reportingMessage;
|
|
527
453
|
const meMsg = {
|
|
528
454
|
deviceSentMessage: {
|
|
529
455
|
destinationJid,
|
|
530
456
|
message
|
|
531
457
|
},
|
|
532
|
-
messageContextInfo: message.messageContextInfo
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
const extraAttrs = {}
|
|
536
|
-
const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/
|
|
537
|
-
const messages = Utils_1.normalizeMessageContent(message)
|
|
538
|
-
const buttonType = getButtonType(messages)
|
|
539
|
-
const pollMessage = messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3
|
|
540
|
-
|
|
458
|
+
messageContextInfo: message.messageContextInfo
|
|
459
|
+
};
|
|
460
|
+
const extraAttrs = {};
|
|
541
461
|
if (participant) {
|
|
542
462
|
if (!isGroup && !isStatus) {
|
|
543
|
-
additionalAttributes = {
|
|
544
|
-
...additionalAttributes,
|
|
545
|
-
'device_fanout': 'false'
|
|
546
|
-
}
|
|
463
|
+
additionalAttributes = { ...additionalAttributes, device_fanout: 'false' };
|
|
547
464
|
}
|
|
548
|
-
|
|
549
|
-
const {
|
|
550
|
-
user,
|
|
551
|
-
device
|
|
552
|
-
} = WABinary_1.jidDecode(participant.jid)
|
|
553
|
-
|
|
465
|
+
const { user, device } = jidDecode(participant.jid);
|
|
554
466
|
devices.push({
|
|
555
467
|
user,
|
|
556
468
|
device,
|
|
557
|
-
|
|
558
|
-
})
|
|
469
|
+
jid: participant.jid
|
|
470
|
+
});
|
|
559
471
|
}
|
|
560
|
-
|
|
561
472
|
await authState.keys.transaction(async () => {
|
|
562
|
-
const
|
|
473
|
+
const normalizedMsg = normalizeMessageContent(message);
|
|
474
|
+
const isGroupStatusAudio = !!(message?.groupStatusMessageV2?.message?.audioMessage);
|
|
475
|
+
const mediaType = isGroupStatusAudio ? undefined : getMediaType(normalizedMsg || message);
|
|
563
476
|
if (mediaType) {
|
|
564
|
-
extraAttrs['mediatype'] = mediaType
|
|
477
|
+
extraAttrs['mediatype'] = mediaType;
|
|
565
478
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
479
|
+
if (isNewsletter) {
|
|
480
|
+
const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
|
|
481
|
+
// Evaluate mediaType from patched message (after patchMessageBeforeSending),
|
|
482
|
+
// and place it in plaintext attrs — NOT in stanza attrs (WA server requires it there)
|
|
483
|
+
const newsletterMediaType = getMediaType(normalizeMessageContent(patched) || patched);
|
|
484
|
+
if (newsletterMediaType) {
|
|
485
|
+
extraAttrs['mediatype'] = newsletterMediaType;
|
|
486
|
+
}
|
|
487
|
+
if (patched.interactiveMessage && !extraAttrs['mediatype']) {
|
|
488
|
+
extraAttrs['mediatype'] = 'interactive';
|
|
489
|
+
}
|
|
490
|
+
const bytes = encodeNewsletterMessage(patched);
|
|
491
|
+
binaryNodeContent.push({
|
|
492
|
+
tag: 'plaintext',
|
|
493
|
+
attrs: extraAttrs,
|
|
494
|
+
content: bytes
|
|
495
|
+
});
|
|
496
|
+
const stanza = {
|
|
497
|
+
tag: 'message',
|
|
498
|
+
attrs: {
|
|
499
|
+
to: jid,
|
|
500
|
+
id: msgId,
|
|
501
|
+
type: getMessageType(patched),
|
|
502
|
+
...(additionalAttributes || {})
|
|
503
|
+
},
|
|
504
|
+
content: binaryNodeContent
|
|
505
|
+
};
|
|
506
|
+
logger.debug({ msgId, mediaType: newsletterMediaType, extraAttrs }, `sending newsletter message to ${jid}`);
|
|
507
|
+
await sendNode(stanza);
|
|
508
|
+
return;
|
|
569
509
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
extraAttrs['native_flow_name'] = messages.interactiveResponseMessage.nativeFlowResponseMessage?.name || 'menu_options'
|
|
510
|
+
if (normalizedMsg?.pinInChatMessage || normalizedMsg?.reactionMessage) {
|
|
511
|
+
extraAttrs['decrypt-fail'] = 'hide'; // todo: expand for reactions and other types
|
|
573
512
|
}
|
|
574
|
-
|
|
575
|
-
if (isGroup || isStatus) {
|
|
513
|
+
if (isGroupOrStatus && !isRetryResend) {
|
|
576
514
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
577
515
|
(async () => {
|
|
578
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
|
|
516
|
+
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined; // todo: should we rely on the cache specially if the cache is outdated and the metadata has new fields?
|
|
579
517
|
if (groupData && Array.isArray(groupData?.participants)) {
|
|
580
|
-
logger.trace({
|
|
581
|
-
jid,
|
|
582
|
-
participants: groupData.participants.length
|
|
583
|
-
}, 'using cached group metadata')
|
|
584
|
-
} else if (!isStatus) {
|
|
585
|
-
groupData = await global.groupMetadataCache(jid)
|
|
518
|
+
logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata');
|
|
586
519
|
}
|
|
587
|
-
|
|
520
|
+
else if (!isStatus) {
|
|
521
|
+
groupData = await groupMetadata(jid); // TODO: start storing group participant list + addr mode in Signal & stop relying on this
|
|
522
|
+
}
|
|
523
|
+
return groupData;
|
|
588
524
|
})(),
|
|
589
525
|
(async () => {
|
|
590
526
|
if (!participant && !isStatus) {
|
|
591
|
-
|
|
592
|
-
|
|
527
|
+
// what if sender memory is less accurate than the cached metadata
|
|
528
|
+
// on participant change in group, we should do sender memory manipulation
|
|
529
|
+
const result = await authState.keys.get('sender-key-memory', [jid]); // TODO: check out what if the sender key memory doesn't include the LID stuff now?
|
|
530
|
+
return result[jid] || {};
|
|
593
531
|
}
|
|
594
|
-
return {}
|
|
532
|
+
return {};
|
|
595
533
|
})()
|
|
596
|
-
])
|
|
597
|
-
|
|
598
|
-
if (
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
534
|
+
]);
|
|
535
|
+
const participantsList = groupData ? groupData.participants.map(p => p.id) : [];
|
|
536
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
537
|
+
additionalAttributes = {
|
|
538
|
+
...additionalAttributes,
|
|
539
|
+
expiration: groupData.ephemeralDuration.toString()
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
if (isStatus && statusJidList) {
|
|
543
|
+
participantsList.push(...statusJidList);
|
|
544
|
+
}
|
|
545
|
+
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
|
|
546
|
+
devices.push(...additionalDevices);
|
|
547
|
+
if (isGroup) {
|
|
548
|
+
additionalAttributes = {
|
|
549
|
+
...additionalAttributes,
|
|
550
|
+
addressing_mode: groupData?.addressingMode || 'lid'
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
const patched = await patchMessageBeforeSending(message);
|
|
554
|
+
if (Array.isArray(patched)) {
|
|
555
|
+
throw new Boom('Per-jid patching is not supported in groups');
|
|
612
556
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
const
|
|
616
|
-
|
|
617
|
-
const
|
|
618
|
-
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId
|
|
619
|
-
|
|
620
|
-
const {
|
|
621
|
-
ciphertext,
|
|
622
|
-
senderKeyDistributionMessage
|
|
623
|
-
} = await signalRepository.encryptGroupMessage({
|
|
557
|
+
const bytes = encodeWAMessage(patched);
|
|
558
|
+
reportingMessage = patched;
|
|
559
|
+
const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
|
|
560
|
+
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
|
|
561
|
+
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
624
562
|
group: destinationJid,
|
|
625
563
|
data: bytes,
|
|
626
564
|
meId: groupSenderIdentity
|
|
627
|
-
})
|
|
628
|
-
|
|
629
|
-
const senderKeyJids = []
|
|
630
|
-
|
|
565
|
+
});
|
|
566
|
+
const senderKeyRecipients = [];
|
|
631
567
|
for (const device of devices) {
|
|
632
|
-
const deviceJid = device.
|
|
633
|
-
const hasKey = !!senderKeyMap[deviceJid]
|
|
634
|
-
if (!hasKey || !!participant)
|
|
635
|
-
|
|
636
|
-
|
|
568
|
+
const deviceJid = device.jid;
|
|
569
|
+
const hasKey = !!senderKeyMap[deviceJid];
|
|
570
|
+
if ((!hasKey || !!participant) &&
|
|
571
|
+
!isHostedLidUser(deviceJid) &&
|
|
572
|
+
!isHostedPnUser(deviceJid) &&
|
|
573
|
+
device.device !== 99) {
|
|
574
|
+
//todo: revamp all this logic
|
|
575
|
+
// the goal is to follow with what I said above for each group, and instead of a true false map of ids, we can set an array full of those the app has already sent pkmsgs
|
|
576
|
+
senderKeyRecipients.push(deviceJid);
|
|
577
|
+
senderKeyMap[deviceJid] = true;
|
|
637
578
|
}
|
|
638
579
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
logger.debug({
|
|
642
|
-
senderKeyJids
|
|
643
|
-
}, 'sending new sender key')
|
|
580
|
+
if (senderKeyRecipients.length) {
|
|
581
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key');
|
|
644
582
|
const senderKeyMsg = {
|
|
645
583
|
senderKeyDistributionMessage: {
|
|
646
584
|
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
647
585
|
groupId: destinationJid
|
|
648
586
|
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
await assertSessions(
|
|
652
|
-
const result = await createParticipantNodes(
|
|
653
|
-
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity
|
|
654
|
-
participants.push(...result.nodes)
|
|
587
|
+
};
|
|
588
|
+
const senderKeySessionTargets = senderKeyRecipients;
|
|
589
|
+
await assertSessions(senderKeySessionTargets);
|
|
590
|
+
const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs);
|
|
591
|
+
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
|
|
592
|
+
participants.push(...result.nodes);
|
|
655
593
|
}
|
|
656
|
-
|
|
657
594
|
binaryNodeContent.push({
|
|
658
595
|
tag: 'enc',
|
|
659
|
-
attrs: {
|
|
660
|
-
v: '2',
|
|
661
|
-
type: 'skmsg',
|
|
662
|
-
...extraAttrs
|
|
663
|
-
},
|
|
596
|
+
attrs: { v: '2', type: 'skmsg', ...extraAttrs },
|
|
664
597
|
content: ciphertext
|
|
665
|
-
})
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
message = message.protocolMessage.editedMessage
|
|
598
|
+
});
|
|
599
|
+
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
603
|
+
// TODO: investigate if this is true
|
|
604
|
+
let ownId = meId;
|
|
605
|
+
if (isLid && meLid) {
|
|
606
|
+
ownId = meLid;
|
|
607
|
+
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation');
|
|
676
608
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
msgId = message.protocolMessage.key?.id
|
|
680
|
-
message = {}
|
|
609
|
+
else {
|
|
610
|
+
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
|
|
681
611
|
}
|
|
682
|
-
|
|
683
|
-
const patched = await patchMessageBeforeSending(message, [])
|
|
684
|
-
const bytes = Utils_1.encodeNewsletterMessage(patched)
|
|
685
|
-
|
|
686
|
-
binaryNodeContent.push({
|
|
687
|
-
tag: 'plaintext',
|
|
688
|
-
attrs: extraAttrs,
|
|
689
|
-
content: bytes
|
|
690
|
-
})
|
|
691
|
-
} else {
|
|
692
|
-
const {
|
|
693
|
-
user: ownUser
|
|
694
|
-
} = WABinary_1.jidDecode(ownId)
|
|
695
|
-
|
|
612
|
+
const { user: ownUser } = jidDecode(ownId);
|
|
696
613
|
if (!participant) {
|
|
697
|
-
const
|
|
614
|
+
const patchedForReporting = await patchMessageBeforeSending(message, [jid]);
|
|
615
|
+
reportingMessage = Array.isArray(patchedForReporting)
|
|
616
|
+
? patchedForReporting.find(item => item.recipientJid === jid) || patchedForReporting[0]
|
|
617
|
+
: patchedForReporting;
|
|
618
|
+
}
|
|
619
|
+
if (!isRetryResend) {
|
|
620
|
+
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
698
621
|
devices.push({
|
|
699
622
|
user,
|
|
700
623
|
device: 0,
|
|
701
|
-
|
|
702
|
-
})
|
|
703
|
-
|
|
624
|
+
jid: jidEncode(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
|
|
625
|
+
});
|
|
704
626
|
if (user !== ownUser) {
|
|
705
627
|
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
706
|
-
const ownUserForAddressing = isLid && meLid ?
|
|
628
|
+
const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
|
|
707
629
|
devices.push({
|
|
708
630
|
user: ownUserForAddressing,
|
|
709
631
|
device: 0,
|
|
710
|
-
|
|
711
|
-
})
|
|
632
|
+
jid: jidEncode(ownUserForAddressing, ownUserServer, 0)
|
|
633
|
+
});
|
|
712
634
|
}
|
|
713
|
-
|
|
714
635
|
if (additionalAttributes?.['category'] !== 'peer') {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
636
|
+
// Clear placeholders and enumerate actual devices
|
|
637
|
+
devices.length = 0;
|
|
638
|
+
// Use conversation-appropriate sender identity
|
|
639
|
+
const senderIdentity = isLid && meLid
|
|
640
|
+
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
641
|
+
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
|
|
642
|
+
// Enumerate devices for sender and target with consistent addressing
|
|
643
|
+
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
|
|
644
|
+
devices.push(...sessionDevices);
|
|
719
645
|
logger.debug({
|
|
720
646
|
deviceCount: devices.length,
|
|
721
|
-
devices: devices.map(d => `${d.user}:${d.device}@${
|
|
722
|
-
}, 'Device enumeration complete with unified addressing')
|
|
647
|
+
devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`)
|
|
648
|
+
}, 'Device enumeration complete with unified addressing');
|
|
723
649
|
}
|
|
724
650
|
}
|
|
725
|
-
|
|
726
|
-
const
|
|
727
|
-
const
|
|
728
|
-
const
|
|
729
|
-
|
|
730
|
-
const {
|
|
731
|
-
|
|
732
|
-
} = WABinary_1.jidDecode(meId)
|
|
733
|
-
const {
|
|
734
|
-
user: meLidUser
|
|
735
|
-
} = meLid ? WABinary_1.jidDecode(meLid) : {
|
|
736
|
-
user: null
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
for (const { user, wireJid } of devices) {
|
|
740
|
-
const isExactSenderDevice = wireJid === meId || (meLid && wireJid === meLid)
|
|
651
|
+
const allRecipients = [];
|
|
652
|
+
const meRecipients = [];
|
|
653
|
+
const otherRecipients = [];
|
|
654
|
+
const { user: mePnUser } = jidDecode(meId);
|
|
655
|
+
const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null };
|
|
656
|
+
for (const { user, jid } of devices) {
|
|
657
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
741
658
|
if (isExactSenderDevice) {
|
|
742
|
-
logger.debug({
|
|
743
|
-
|
|
744
|
-
meId,
|
|
745
|
-
meLid
|
|
746
|
-
}, 'Skipping exact sender device (whatsmeow pattern)')
|
|
747
|
-
continue
|
|
659
|
+
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
|
|
660
|
+
continue;
|
|
748
661
|
}
|
|
749
|
-
|
|
750
|
-
const
|
|
662
|
+
// Check if this is our device (could match either PN or LID user)
|
|
663
|
+
const isMe = user === mePnUser || user === meLidUser;
|
|
751
664
|
if (isMe) {
|
|
752
|
-
|
|
753
|
-
} else {
|
|
754
|
-
otherJids.push(jid)
|
|
665
|
+
meRecipients.push(jid);
|
|
755
666
|
}
|
|
756
|
-
|
|
667
|
+
else {
|
|
668
|
+
otherRecipients.push(jid);
|
|
669
|
+
}
|
|
670
|
+
allRecipients.push(jid);
|
|
757
671
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
createParticipantNodes(otherJids, message, extraAttrs, meMsg)
|
|
769
|
-
])
|
|
770
|
-
|
|
771
|
-
participants.push(...meNodes)
|
|
772
|
-
participants.push(...otherNodes)
|
|
773
|
-
if (meJids.length > 0 || otherJids.length > 0) {
|
|
774
|
-
extraAttrs['phash'] = Utils_1.generateParticipantHashV2([...meJids, ...otherJids])
|
|
672
|
+
await assertSessions(allRecipients);
|
|
673
|
+
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
674
|
+
// For own devices: use DSM if available (1:1 chats only)
|
|
675
|
+
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
676
|
+
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
677
|
+
]);
|
|
678
|
+
participants.push(...meNodes);
|
|
679
|
+
participants.push(...otherNodes);
|
|
680
|
+
if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
681
|
+
extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients]);
|
|
775
682
|
}
|
|
776
|
-
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
|
|
683
|
+
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
|
|
684
|
+
}
|
|
685
|
+
if (isRetryResend) {
|
|
686
|
+
const isParticipantLid = isLidUser(participant.jid);
|
|
687
|
+
const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId);
|
|
688
|
+
let messageToSend = message;
|
|
689
|
+
if (isGroupOrStatus) {
|
|
690
|
+
let groupSenderIdentity;
|
|
691
|
+
if (meLid && (await signalRepository.hasSenderKey({ group: destinationJid, meId: meLid }))) {
|
|
692
|
+
groupSenderIdentity = meLid;
|
|
693
|
+
}
|
|
694
|
+
else if (await signalRepository.hasSenderKey({ group: destinationJid, meId })) {
|
|
695
|
+
groupSenderIdentity = meId;
|
|
696
|
+
}
|
|
697
|
+
if (groupSenderIdentity) {
|
|
698
|
+
try {
|
|
699
|
+
const skdm = await signalRepository.getSenderKeyDistributionMessage({
|
|
700
|
+
group: destinationJid,
|
|
701
|
+
meId: groupSenderIdentity
|
|
702
|
+
});
|
|
703
|
+
messageToSend = {
|
|
704
|
+
...message,
|
|
705
|
+
senderKeyDistributionMessage: {
|
|
706
|
+
groupId: destinationJid,
|
|
707
|
+
axolotlSenderKeyDistributionMessage: skdm
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
catch (err) {
|
|
712
|
+
logger.warn({ err, jid: destinationJid }, 'failed to build SKDM for retry, sending without it');
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
const encodedMessageToSend = isMe
|
|
717
|
+
? encodeWAMessage({
|
|
718
|
+
deviceSentMessage: {
|
|
719
|
+
destinationJid,
|
|
720
|
+
message: messageToSend
|
|
721
|
+
}
|
|
722
|
+
})
|
|
723
|
+
: encodeWAMessage(messageToSend);
|
|
724
|
+
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
|
725
|
+
data: encodedMessageToSend,
|
|
726
|
+
jid: participant.jid
|
|
727
|
+
});
|
|
728
|
+
binaryNodeContent.push({
|
|
729
|
+
tag: 'enc',
|
|
730
|
+
attrs: {
|
|
731
|
+
v: '2',
|
|
732
|
+
type,
|
|
733
|
+
count: participant.count.toString()
|
|
734
|
+
},
|
|
735
|
+
content: encryptedContent
|
|
736
|
+
});
|
|
777
737
|
}
|
|
778
|
-
|
|
779
738
|
if (participants.length) {
|
|
780
739
|
if (additionalAttributes?.['category'] === 'peer') {
|
|
781
|
-
const peerNode = participants[0]?.content?.[0]
|
|
740
|
+
const peerNode = participants[0]?.content?.[0];
|
|
782
741
|
if (peerNode) {
|
|
783
|
-
binaryNodeContent.push(peerNode)
|
|
742
|
+
binaryNodeContent.push(peerNode); // push only enc
|
|
784
743
|
}
|
|
785
|
-
}
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
786
746
|
binaryNodeContent.push({
|
|
787
747
|
tag: 'participants',
|
|
788
748
|
attrs: {},
|
|
789
749
|
content: participants
|
|
790
|
-
})
|
|
750
|
+
});
|
|
791
751
|
}
|
|
792
752
|
}
|
|
793
|
-
|
|
794
753
|
const stanza = {
|
|
795
754
|
tag: 'message',
|
|
796
755
|
attrs: {
|
|
797
|
-
to: destinationJid,
|
|
798
756
|
id: msgId,
|
|
799
|
-
|
|
757
|
+
to: destinationJid,
|
|
758
|
+
type: getMessageType(message),
|
|
800
759
|
...(additionalAttributes || {})
|
|
801
760
|
},
|
|
802
761
|
content: binaryNodeContent
|
|
803
|
-
}
|
|
804
|
-
|
|
762
|
+
};
|
|
763
|
+
// if the participant to send to is explicitly specified (generally retry recp)
|
|
764
|
+
// ensure the message is only sent to that person
|
|
765
|
+
// if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
|
|
805
766
|
if (participant) {
|
|
806
|
-
if (
|
|
807
|
-
stanza.attrs.to = destinationJid
|
|
808
|
-
stanza.attrs.participant = participant.jid
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
stanza.attrs.
|
|
812
|
-
|
|
813
|
-
stanza.attrs.to = participant.jid
|
|
767
|
+
if (isJidGroup(destinationJid)) {
|
|
768
|
+
stanza.attrs.to = destinationJid;
|
|
769
|
+
stanza.attrs.participant = participant.jid;
|
|
770
|
+
}
|
|
771
|
+
else if (areJidsSameUser(participant.jid, meId)) {
|
|
772
|
+
stanza.attrs.to = participant.jid;
|
|
773
|
+
stanza.attrs.recipient = destinationJid;
|
|
814
774
|
}
|
|
815
|
-
|
|
816
|
-
|
|
775
|
+
else {
|
|
776
|
+
stanza.attrs.to = participant.jid;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
stanza.attrs.to = destinationJid;
|
|
817
781
|
}
|
|
818
|
-
|
|
819
782
|
if (shouldIncludeDeviceIdentity) {
|
|
783
|
+
;
|
|
820
784
|
stanza.content.push({
|
|
821
785
|
tag: 'device-identity',
|
|
822
786
|
attrs: {},
|
|
823
|
-
content:
|
|
824
|
-
})
|
|
825
|
-
logger.debug({
|
|
826
|
-
jid
|
|
827
|
-
}, 'adding device identity')
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
|
|
831
|
-
stanza.content.push({
|
|
832
|
-
tag: 'multicast',
|
|
833
|
-
attrs: {}
|
|
834
|
-
})
|
|
787
|
+
content: encodeSignedDeviceIdentity(authState.creds.account, true)
|
|
788
|
+
});
|
|
789
|
+
logger.debug({ jid }, 'adding device identity');
|
|
835
790
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
791
|
+
if (!isNewsletter &&
|
|
792
|
+
!isRetryResend &&
|
|
793
|
+
reportingMessage?.messageContextInfo?.messageSecret &&
|
|
794
|
+
shouldIncludeReportingToken(reportingMessage)) {
|
|
795
|
+
try {
|
|
796
|
+
const encoded = encodeWAMessage(reportingMessage);
|
|
797
|
+
const reportingKey = {
|
|
798
|
+
id: msgId,
|
|
799
|
+
fromMe: true,
|
|
800
|
+
remoteJid: destinationJid,
|
|
801
|
+
participant: participant?.jid
|
|
802
|
+
};
|
|
803
|
+
const reportingNode = await getMessageReportingToken(encoded, reportingMessage, reportingKey);
|
|
804
|
+
if (reportingNode) {
|
|
805
|
+
;
|
|
806
|
+
stanza.content.push(reportingNode);
|
|
807
|
+
logger.trace({ jid }, 'added reporting token to message');
|
|
845
808
|
}
|
|
846
809
|
}
|
|
810
|
+
catch (error) {
|
|
811
|
+
logger.warn({ jid, trace: error?.stack }, 'failed to attach reporting token');
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
// WA Web never attaches tctoken to peer (AppStateSync) messages — server rejects with 479
|
|
815
|
+
const isPeerMessage = additionalAttributes?.['category'] === 'peer';
|
|
816
|
+
const is1on1Send = !isGroup && !isRetryResend && !isStatus && !isNewsletter && !isPeerMessage;
|
|
817
|
+
// Resolve destination to LID for tctoken storage — matches Signal session key pattern
|
|
818
|
+
const tcTokenJid = is1on1Send ? await resolveTcTokenJid(destinationJid, getLIDForPN) : destinationJid;
|
|
819
|
+
const contactTcTokenData = is1on1Send ? await authState.keys.get('tctoken', [tcTokenJid]) : {};
|
|
820
|
+
const existingTokenEntry = contactTcTokenData[tcTokenJid];
|
|
821
|
+
let tcTokenBuffer = existingTokenEntry?.token;
|
|
822
|
+
// Treat expired tokens the same as missing — clear from cache
|
|
823
|
+
if (tcTokenBuffer?.length && isTcTokenExpired(existingTokenEntry?.timestamp)) {
|
|
824
|
+
logger.debug({ jid: destinationJid, timestamp: existingTokenEntry?.timestamp }, 'tctoken expired, clearing');
|
|
825
|
+
tcTokenBuffer = undefined;
|
|
826
|
+
// Preserve senderTimestamp so the fire-and-forget issuance dedupe survives cleanup.
|
|
827
|
+
const cleared = existingTokenEntry?.senderTimestamp !== undefined
|
|
828
|
+
? { token: Buffer.alloc(0), senderTimestamp: existingTokenEntry.senderTimestamp }
|
|
829
|
+
: null;
|
|
830
|
+
try {
|
|
831
|
+
await authState.keys.set({ tctoken: { [tcTokenJid]: cleared } });
|
|
832
|
+
}
|
|
833
|
+
catch (err) {
|
|
834
|
+
logger.debug({ jid: destinationJid, err: err?.message }, 'failed to persist tctoken expiry cleanup');
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
if (tcTokenBuffer?.length && sock.serverProps.privacyTokenOn1to1) {
|
|
838
|
+
;
|
|
847
839
|
stanza.content.push({
|
|
848
|
-
tag: '
|
|
849
|
-
attrs:
|
|
840
|
+
tag: 'tctoken',
|
|
841
|
+
attrs: {},
|
|
842
|
+
content: tcTokenBuffer
|
|
850
843
|
});
|
|
851
844
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
const filteredButtons = WABinary_1.getBinaryFilteredButtons(additionalNodes ? additionalNodes : [])
|
|
856
|
-
if (filteredButtons) {
|
|
857
|
-
stanza.content.push(...additionalNodes)
|
|
858
|
-
additionalAlready = true
|
|
859
|
-
} else {
|
|
860
|
-
stanza.content.push(buttonsNode)
|
|
861
|
-
}
|
|
845
|
+
if (additionalNodes && additionalNodes.length > 0) {
|
|
846
|
+
;
|
|
847
|
+
stanza.content.push(...additionalNodes);
|
|
862
848
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
}
|
|
871
|
-
const filteredBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes ? additionalNodes : [])
|
|
872
|
-
if (filteredBizBot) {
|
|
873
|
-
stanza.content.push(...additionalNodes)
|
|
874
|
-
additionalAlready = true
|
|
875
|
-
} else {
|
|
876
|
-
stanza.content.push(botNode)
|
|
849
|
+
// Inject <biz> node required for buttons/interactive/list messages to render on WA
|
|
850
|
+
const _bizContent = normalizeMessageContent(message);
|
|
851
|
+
const hasExistingBizNode = additionalNodes && additionalNodes.some(node => node.tag === 'biz');
|
|
852
|
+
if (!hasExistingBizNode && (isGroup || !isGroup && !isStatus && !isNewsletter)) {
|
|
853
|
+
const bizNode = getBizBinaryNode(_bizContent || message);
|
|
854
|
+
if (bizNode) {
|
|
855
|
+
stanza.content.push(bizNode);
|
|
877
856
|
}
|
|
878
857
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
858
|
+
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
859
|
+
await sendNode(stanza);
|
|
860
|
+
// Fire-and-forget: issue our token to the contact AFTER message send.
|
|
861
|
+
// WA Web skips protocol messages and PSA/bot contacts (TcTokenChatAction: isRegularUser)
|
|
862
|
+
const isProtocolMsg = !!normalizeMessageContent(message)?.protocolMessage;
|
|
863
|
+
const isBotOrPSA = destinationJid === PSA_WID || isJidBot(destinationJid) || isJidMetaAI(destinationJid);
|
|
864
|
+
if (is1on1Send &&
|
|
865
|
+
!isProtocolMsg &&
|
|
866
|
+
!isBotOrPSA &&
|
|
867
|
+
shouldSendNewTcToken(existingTokenEntry?.senderTimestamp) &&
|
|
868
|
+
!inFlightTcTokenIssuance.has(tcTokenJid)) {
|
|
869
|
+
inFlightTcTokenIssuance.add(tcTokenJid);
|
|
870
|
+
const issueTimestamp = unixTimestampSeconds();
|
|
871
|
+
const getPNForLID = signalRepository.lidMapping.getPNForLID.bind(signalRepository.lidMapping);
|
|
872
|
+
resolveIssuanceJid(destinationJid, sock.serverProps.lidTrustedTokenIssueToLid, getLIDForPN, getPNForLID)
|
|
873
|
+
.then(issueJid => issuePrivacyTokens([issueJid], issueTimestamp))
|
|
874
|
+
.then(async (result) => {
|
|
875
|
+
await storeTcTokensFromIqResult({
|
|
876
|
+
result,
|
|
877
|
+
fallbackJid: tcTokenJid,
|
|
878
|
+
keys: authState.keys,
|
|
879
|
+
getLIDForPN
|
|
880
|
+
});
|
|
881
|
+
const currentData = await authState.keys.get('tctoken', [tcTokenJid]);
|
|
882
|
+
const currentEntry = currentData[tcTokenJid];
|
|
883
|
+
const indexWrite = await buildMergedTcTokenIndexWrite(authState.keys, [tcTokenJid]);
|
|
884
|
+
await authState.keys.set({
|
|
885
|
+
tctoken: {
|
|
886
|
+
[tcTokenJid]: {
|
|
887
|
+
token: Buffer.alloc(0),
|
|
888
|
+
...currentEntry,
|
|
889
|
+
senderTimestamp: issueTimestamp
|
|
890
|
+
},
|
|
891
|
+
...indexWrite
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
})
|
|
895
|
+
.catch(err => {
|
|
896
|
+
logger.debug({ jid: destinationJid, err: err?.message }, 'fire-and-forget tctoken issuance failed');
|
|
897
|
+
})
|
|
898
|
+
.finally(() => {
|
|
899
|
+
inFlightTcTokenIssuance.delete(tcTokenJid);
|
|
900
|
+
});
|
|
882
901
|
}
|
|
883
|
-
|
|
884
|
-
logger.debug({
|
|
885
|
-
msgId
|
|
886
|
-
}, `sending message to ${participants.length} devices`)
|
|
887
|
-
|
|
888
|
-
await sendNode(stanza)
|
|
902
|
+
// Add message to retry cache if enabled
|
|
889
903
|
if (messageRetryManager && !participant) {
|
|
890
|
-
messageRetryManager.addRecentMessage(destinationJid, msgId, message)
|
|
904
|
+
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
891
905
|
}
|
|
892
|
-
}, meId)
|
|
893
|
-
return msgId
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
906
|
+
}, meId);
|
|
907
|
+
return msgId;
|
|
908
|
+
};
|
|
909
|
+
const getMessageType = (message) => {
|
|
910
|
+
const normalizedMessage = normalizeMessageContent(message);
|
|
911
|
+
if (!normalizedMessage)
|
|
912
|
+
return 'text';
|
|
913
|
+
if (normalizedMessage.reactionMessage || normalizedMessage.encReactionMessage) {
|
|
914
|
+
return 'reaction';
|
|
915
|
+
}
|
|
916
|
+
if (normalizedMessage.pollCreationMessage ||
|
|
917
|
+
normalizedMessage.pollCreationMessageV2 ||
|
|
918
|
+
normalizedMessage.pollCreationMessageV3 ||
|
|
919
|
+
normalizedMessage.pollUpdateMessage) {
|
|
920
|
+
return 'poll';
|
|
921
|
+
}
|
|
922
|
+
if (normalizedMessage.eventMessage) {
|
|
923
|
+
return 'event';
|
|
908
924
|
}
|
|
909
|
-
|
|
910
|
-
|
|
925
|
+
// Audio wrapped in groupStatusMessageV2 → type "text" (Baileys behavior)
|
|
926
|
+
const isGroupStatusAudio = !!(message?.groupStatusMessageV2?.message?.audioMessage);
|
|
927
|
+
if (!isGroupStatusAudio && getMediaType(normalizedMessage) !== '') {
|
|
928
|
+
return 'media';
|
|
929
|
+
}
|
|
930
|
+
return 'text';
|
|
931
|
+
};
|
|
911
932
|
const getMediaType = (message) => {
|
|
912
933
|
if (message.imageMessage) {
|
|
913
|
-
return 'image'
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
return message.audioMessage.ptt ? 'ptt' : 'audio'
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
return '
|
|
926
|
-
} else if (message.documentMessage) {
|
|
927
|
-
return 'document'
|
|
928
|
-
} else if (message.stickerPackMessage) {
|
|
929
|
-
return 'sticker_pack'
|
|
930
|
-
} else if (message.contactsArrayMessage) {
|
|
931
|
-
return 'contact_array'
|
|
932
|
-
} else if (message.locationMessage) {
|
|
933
|
-
return 'location'
|
|
934
|
-
} else if (message.liveLocationMessage) {
|
|
935
|
-
return 'livelocation'
|
|
936
|
-
} else if (message.listMessage) {
|
|
937
|
-
return 'list'
|
|
938
|
-
} else if (message.listResponseMessage) {
|
|
939
|
-
return 'list_response'
|
|
940
|
-
} else if (message.buttonsResponseMessage) {
|
|
941
|
-
return 'buttons_response'
|
|
942
|
-
} else if (message.orderMessage) {
|
|
943
|
-
return 'order'
|
|
944
|
-
} else if (message.productMessage) {
|
|
945
|
-
return 'product'
|
|
946
|
-
} else if (message.interactiveResponseMessage) {
|
|
947
|
-
return 'native_flow_response'
|
|
948
|
-
} else if (/https:\/\/wa\.me\/c\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
949
|
-
return 'cataloglink'
|
|
950
|
-
} else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
951
|
-
return 'productlink'
|
|
952
|
-
} else if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) {
|
|
953
|
-
return 'url'
|
|
934
|
+
return 'image';
|
|
935
|
+
}
|
|
936
|
+
else if (message.videoMessage) {
|
|
937
|
+
return message.videoMessage.gifPlayback ? 'gif' : 'video';
|
|
938
|
+
}
|
|
939
|
+
else if (message.audioMessage) {
|
|
940
|
+
return message.audioMessage.ptt ? 'ptt' : 'audio';
|
|
941
|
+
}
|
|
942
|
+
else if (message.contactMessage) {
|
|
943
|
+
return 'vcard';
|
|
944
|
+
}
|
|
945
|
+
else if (message.documentMessage) {
|
|
946
|
+
return 'document';
|
|
954
947
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
948
|
+
else if (message.contactsArrayMessage) {
|
|
949
|
+
return 'contact_array';
|
|
950
|
+
}
|
|
951
|
+
else if (message.liveLocationMessage) {
|
|
952
|
+
return 'livelocation';
|
|
953
|
+
}
|
|
954
|
+
else if (message.stickerMessage) {
|
|
955
|
+
return 'sticker';
|
|
956
|
+
}
|
|
957
|
+
else if (message.listMessage) {
|
|
960
958
|
return 'list';
|
|
961
|
-
} else if (message_content.buttonsMessage) {
|
|
962
|
-
return 'buttons';
|
|
963
|
-
} else if (message_content.interactiveMessage?.nativeFlowMessage) {
|
|
964
|
-
return 'native_flow';
|
|
965
959
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
const getButtonArgs = (message) => {
|
|
969
|
-
const message_content = message.viewOnceMessage?.message || message;
|
|
970
|
-
const message_flow = message_content.interactiveMessage?.nativeFlowMessage;
|
|
971
|
-
const flow_buttons_first = message_flow?.buttons?.[0]?.name;
|
|
972
|
-
const flow_buttons_special = [ 'mpm', 'cta_catalog', 'send_location', 'call_permission_request', 'wa_payment_transaction_details', 'automated_greeting_message_view_catalog' ];
|
|
973
|
-
const baseArgs = {
|
|
974
|
-
tag: 'biz',
|
|
975
|
-
attrs: {
|
|
976
|
-
actual_actors: '2',
|
|
977
|
-
host_storage: '2',
|
|
978
|
-
privacy_mode_ts: Utils_1.unixTimestampSeconds().toString()
|
|
979
|
-
}
|
|
980
|
-
};
|
|
981
|
-
if (message_flow && (flow_buttons_first === 'review_and_pay' || flow_buttons_first === 'payment_info')) {
|
|
982
|
-
return {
|
|
983
|
-
tag: 'biz',
|
|
984
|
-
attrs: {
|
|
985
|
-
native_flow_name: flow_buttons_first === 'review_and_pay' ? 'order_details' : flow_buttons_first
|
|
986
|
-
}
|
|
987
|
-
};
|
|
960
|
+
else if (message.listResponseMessage) {
|
|
961
|
+
return 'list_response';
|
|
988
962
|
}
|
|
989
|
-
if (
|
|
990
|
-
return
|
|
991
|
-
...baseArgs,
|
|
992
|
-
content: [
|
|
993
|
-
{
|
|
994
|
-
tag: 'interactive',
|
|
995
|
-
attrs: { type: 'native_flow', v: '1' },
|
|
996
|
-
content: [{
|
|
997
|
-
tag: 'native_flow',
|
|
998
|
-
attrs: { v: '2', name: flow_buttons_first }
|
|
999
|
-
}]
|
|
1000
|
-
},
|
|
1001
|
-
{
|
|
1002
|
-
tag: 'quality_control',
|
|
1003
|
-
attrs: { source_type: 'third_party' }
|
|
1004
|
-
}
|
|
1005
|
-
]
|
|
1006
|
-
};
|
|
963
|
+
else if (message.buttonsResponseMessage) {
|
|
964
|
+
return 'buttons_response';
|
|
1007
965
|
}
|
|
1008
|
-
if (
|
|
1009
|
-
return
|
|
1010
|
-
...baseArgs,
|
|
1011
|
-
content: [
|
|
1012
|
-
{
|
|
1013
|
-
tag: 'interactive',
|
|
1014
|
-
attrs: { type: 'native_flow', v: '1' },
|
|
1015
|
-
content: [{
|
|
1016
|
-
tag: 'native_flow',
|
|
1017
|
-
attrs: { v: '9', name: 'mixed' }
|
|
1018
|
-
}]
|
|
1019
|
-
},
|
|
1020
|
-
{
|
|
1021
|
-
tag: 'quality_control',
|
|
1022
|
-
attrs: { source_type: 'third_party' }
|
|
1023
|
-
}
|
|
1024
|
-
]
|
|
1025
|
-
};
|
|
966
|
+
else if (message.orderMessage) {
|
|
967
|
+
return 'order';
|
|
1026
968
|
}
|
|
1027
|
-
if (
|
|
1028
|
-
return
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
tag: 'list',
|
|
1033
|
-
attrs: { v: '2', type: 'product_list' }
|
|
1034
|
-
},
|
|
1035
|
-
{
|
|
1036
|
-
tag: 'quality_control',
|
|
1037
|
-
attrs: { source_type: 'third_party' }
|
|
1038
|
-
}
|
|
1039
|
-
]
|
|
1040
|
-
};
|
|
969
|
+
else if (message.productMessage) {
|
|
970
|
+
return 'product';
|
|
971
|
+
}
|
|
972
|
+
else if (message.interactiveResponseMessage) {
|
|
973
|
+
return 'native_flow_response';
|
|
1041
974
|
}
|
|
1042
|
-
|
|
975
|
+
else if (message.groupInviteMessage) {
|
|
976
|
+
return 'url';
|
|
977
|
+
}
|
|
978
|
+
return '';
|
|
1043
979
|
};
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
const t = Utils_1.unixTimestampSeconds().toString()
|
|
1047
|
-
|
|
980
|
+
const issuePrivacyTokens = async (jids, timestamp) => {
|
|
981
|
+
const t = (timestamp ?? unixTimestampSeconds()).toString();
|
|
1048
982
|
const result = await query({
|
|
1049
983
|
tag: 'iq',
|
|
1050
984
|
attrs: {
|
|
1051
|
-
to:
|
|
985
|
+
to: S_WHATSAPP_NET,
|
|
1052
986
|
type: 'set',
|
|
1053
987
|
xmlns: 'privacy'
|
|
1054
988
|
},
|
|
1055
|
-
content: [
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
})
|
|
1068
|
-
|
|
1069
|
-
return result
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
const getEphemeralGroup = (jid) => {
|
|
1073
|
-
if (!WABinary_1.isJidGroup(jid)) throw new TypeError("Jid should originate from a group!")
|
|
1074
|
-
|
|
1075
|
-
return groupQuery(jid, 'get', [{
|
|
1076
|
-
tag: 'query',
|
|
1077
|
-
attrs: {
|
|
1078
|
-
request: 'interactive'
|
|
989
|
+
content: [
|
|
990
|
+
{
|
|
991
|
+
tag: 'tokens',
|
|
992
|
+
attrs: {},
|
|
993
|
+
content: jids.map(jid => ({
|
|
994
|
+
tag: 'token',
|
|
995
|
+
attrs: {
|
|
996
|
+
jid: jidNormalizedUser(jid),
|
|
997
|
+
t,
|
|
998
|
+
type: 'trusted_contact'
|
|
999
|
+
}
|
|
1000
|
+
}))
|
|
1079
1001
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
const
|
|
1086
|
-
|
|
1087
|
-
const
|
|
1088
|
-
|
|
1002
|
+
]
|
|
1003
|
+
});
|
|
1004
|
+
return result;
|
|
1005
|
+
};
|
|
1006
|
+
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
1007
|
+
const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
|
|
1008
|
+
// Initialize kikyy (group story / extended message handler)
|
|
1009
|
+
const rahmi = new kikyy({ generateWAMessageContent, generateWAMessageFromContent }, waUploadToServer, relayMessage, authState.creds.me?.id);
|
|
1010
|
+
registerSocketEndHandler(() => {
|
|
1011
|
+
if (!config.userDevicesCache && userDevicesCache.close) {
|
|
1012
|
+
userDevicesCache.close();
|
|
1013
|
+
}
|
|
1014
|
+
mediaConn = undefined;
|
|
1015
|
+
if (messageRetryManager) {
|
|
1016
|
+
messageRetryManager.clear();
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1089
1019
|
return {
|
|
1090
1020
|
...sock,
|
|
1091
|
-
|
|
1021
|
+
userDevicesCache,
|
|
1022
|
+
devicesMutex,
|
|
1023
|
+
issuePrivacyTokens,
|
|
1092
1024
|
assertSessions,
|
|
1093
1025
|
relayMessage,
|
|
1094
1026
|
sendReceipt,
|
|
1095
1027
|
sendReceipts,
|
|
1096
1028
|
readMessages,
|
|
1097
|
-
profilePictureUrl,
|
|
1098
|
-
getUSyncDevices,
|
|
1099
1029
|
refreshMediaConn,
|
|
1030
|
+
// Function (not getter) so the spread in chats.ts preserves the live closure binding.
|
|
1031
|
+
getMediaHost: () => mediaHost,
|
|
1100
1032
|
waUploadToServer,
|
|
1101
|
-
getEphemeralGroup,
|
|
1102
1033
|
fetchPrivacySettings,
|
|
1103
|
-
messageRetryManager,
|
|
1104
|
-
createParticipantNodes,
|
|
1105
1034
|
sendPeerDataOperationMessage,
|
|
1035
|
+
createParticipantNodes,
|
|
1036
|
+
getUSyncDevices,
|
|
1037
|
+
messageRetryManager,
|
|
1038
|
+
updateMemberLabel,
|
|
1106
1039
|
updateMediaMessage: async (message) => {
|
|
1107
|
-
const content =
|
|
1108
|
-
const mediaKey = content.mediaKey
|
|
1109
|
-
const meId = authState.creds.me.id
|
|
1110
|
-
const node =
|
|
1111
|
-
let error = undefined
|
|
1112
|
-
|
|
1040
|
+
const content = assertMediaContent(message.message);
|
|
1041
|
+
const mediaKey = content.mediaKey;
|
|
1042
|
+
const meId = authState.creds.me.id;
|
|
1043
|
+
const node = encryptMediaRetryRequest(message.key, mediaKey, meId);
|
|
1044
|
+
let error = undefined;
|
|
1113
1045
|
await Promise.all([
|
|
1114
1046
|
sendNode(node),
|
|
1115
1047
|
waitForMsgMediaUpdate(async (update) => {
|
|
1116
|
-
const result = update.find(c => c.key.id === message.key.id)
|
|
1048
|
+
const result = update.find(c => c.key.id === message.key.id);
|
|
1117
1049
|
if (result) {
|
|
1118
1050
|
if (result.error) {
|
|
1119
|
-
error = result.error
|
|
1120
|
-
}
|
|
1051
|
+
error = result.error;
|
|
1052
|
+
}
|
|
1053
|
+
else {
|
|
1121
1054
|
try {
|
|
1122
|
-
const media =
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
throw new boom_1.Boom(`Media re-upload failed by device (${resultStr})`, {
|
|
1055
|
+
const media = decryptMediaRetryData(result.media, mediaKey, result.key.id);
|
|
1056
|
+
if (media.result !== proto.MediaRetryNotification.ResultType.SUCCESS) {
|
|
1057
|
+
const resultStr = proto.MediaRetryNotification.ResultType[media.result];
|
|
1058
|
+
throw new Boom(`Media re-upload failed by device (${resultStr})`, {
|
|
1128
1059
|
data: media,
|
|
1129
|
-
statusCode:
|
|
1130
|
-
})
|
|
1060
|
+
statusCode: getStatusCodeForMediaRetry(media.result) || 404
|
|
1061
|
+
});
|
|
1131
1062
|
}
|
|
1132
|
-
|
|
1133
|
-
content.
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
directPath: media.directPath,
|
|
1139
|
-
key: result.key
|
|
1140
|
-
}, 'media update successful')
|
|
1141
|
-
} catch (err) {
|
|
1142
|
-
error = err
|
|
1063
|
+
content.directPath = media.directPath;
|
|
1064
|
+
content.url = getUrlFromDirectPath(content.directPath, mediaHost);
|
|
1065
|
+
logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful');
|
|
1066
|
+
}
|
|
1067
|
+
catch (err) {
|
|
1068
|
+
error = err;
|
|
1143
1069
|
}
|
|
1144
1070
|
}
|
|
1145
|
-
|
|
1146
|
-
return true
|
|
1071
|
+
return true;
|
|
1147
1072
|
}
|
|
1148
1073
|
})
|
|
1149
|
-
])
|
|
1150
|
-
|
|
1074
|
+
]);
|
|
1151
1075
|
if (error) {
|
|
1152
|
-
throw error
|
|
1076
|
+
throw error;
|
|
1153
1077
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
key: message.key,
|
|
1157
|
-
update: {
|
|
1158
|
-
message: message.message
|
|
1159
|
-
}
|
|
1160
|
-
}])
|
|
1161
|
-
|
|
1162
|
-
return message
|
|
1078
|
+
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
|
|
1079
|
+
return message;
|
|
1163
1080
|
},
|
|
1164
|
-
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
)
|
|
1171
|
-
|
|
1172
|
-
}
|
|
1173
|
-
const userJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
|
|
1174
|
-
let allUsers = new Set()
|
|
1175
|
-
allUsers.add(userJid)
|
|
1176
|
-
|
|
1177
|
-
for (const id of jids) {
|
|
1178
|
-
const isGroup = WABinary_1.isJidGroup(id)
|
|
1179
|
-
const isPrivate = WABinary_1.isJidUser(id)
|
|
1180
|
-
|
|
1181
|
-
if (isGroup) {
|
|
1182
|
-
try {
|
|
1183
|
-
const metadata = await cachedGroupMetadata(id) || await global.groupMetadataCache(id)
|
|
1184
|
-
const participants = metadata.participants.map(p => WABinary_1.jidNormalizedUser(p.id))
|
|
1185
|
-
participants.forEach(jid => allUsers.add(jid))
|
|
1186
|
-
} catch (error) {
|
|
1187
|
-
logger.error(`Error getting metadata for group ${id}: ${error}`)
|
|
1188
|
-
}
|
|
1189
|
-
} else if (isPrivate) {
|
|
1190
|
-
allUsers.add(WABinary_1.jidNormalizedUser(id))
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
const uniqueUsers = Array.from(allUsers)
|
|
1195
|
-
const getRandomHexColor = () => "#" + Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")
|
|
1196
|
-
|
|
1197
|
-
const isMedia = content.image || content.video || content.audio
|
|
1198
|
-
const isAudio = !!content.audio
|
|
1199
|
-
|
|
1200
|
-
const messageContent = {
|
|
1201
|
-
...content
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
if (isMedia && !isAudio) {
|
|
1205
|
-
if (messageContent.text) {
|
|
1206
|
-
messageContent.caption = messageContent.text
|
|
1207
|
-
|
|
1208
|
-
delete messageContent.text
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
delete messageContent.ptt
|
|
1212
|
-
delete messageContent.font
|
|
1213
|
-
delete messageContent.backgroundColor
|
|
1214
|
-
delete messageContent.textColor
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
if (isAudio) {
|
|
1218
|
-
delete messageContent.text
|
|
1219
|
-
delete messageContent.caption
|
|
1220
|
-
delete messageContent.font
|
|
1221
|
-
delete messageContent.textColor
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
const font = !isMedia ? (content.font || Math.floor(Math.random() * 9)) : undefined
|
|
1225
|
-
const textColor = !isMedia ? (content.textColor || getRandomHexColor()) : undefined
|
|
1226
|
-
const backgroundColor = (!isMedia || isAudio) ? (content.backgroundColor || getRandomHexColor()) : undefined
|
|
1227
|
-
const ptt = isAudio ? (typeof content.ptt === 'boolean' ? content.ptt : true) : undefined
|
|
1228
|
-
|
|
1229
|
-
let msg
|
|
1230
|
-
let mediaHandle
|
|
1231
|
-
try {
|
|
1232
|
-
msg = await Utils_1.generateWAMessage(WABinary_1.STORIES_JID, messageContent, {
|
|
1081
|
+
sendMessage: async (jid, content, options = {}) => {
|
|
1082
|
+
const userJid = authState.creds.me.id;
|
|
1083
|
+
// Update rahmi's userJid in case it changed after login
|
|
1084
|
+
if (rahmi && userJid) rahmi.userJid = userJid;
|
|
1085
|
+
if (Array.isArray(jid)) {
|
|
1086
|
+
const { delayMs = 1500 } = options;
|
|
1087
|
+
const allUsers = new Set();
|
|
1088
|
+
const fullMsg = await generateWAMessage('status@broadcast', content, {
|
|
1233
1089
|
logger,
|
|
1234
1090
|
userJid,
|
|
1235
|
-
|
|
1236
|
-
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1237
|
-
fetchOpts: {
|
|
1238
|
-
timeout: 3000,
|
|
1239
|
-
...axiosOptions || {}
|
|
1240
|
-
},
|
|
1241
|
-
logger,
|
|
1242
|
-
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
1243
|
-
}),
|
|
1244
|
-
upload: async (encFilePath, opts) => {
|
|
1245
|
-
const up = await waUploadToServer(encFilePath, {
|
|
1246
|
-
...opts
|
|
1247
|
-
})
|
|
1248
|
-
mediaHandle = up.handle
|
|
1249
|
-
return up
|
|
1250
|
-
},
|
|
1091
|
+
upload: waUploadToServer,
|
|
1251
1092
|
mediaCache: config.mediaCache,
|
|
1252
1093
|
options: config.options,
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
messageId: msg.key.id,
|
|
1265
|
-
statusJidList: uniqueUsers,
|
|
1266
|
-
additionalNodes: [{
|
|
1267
|
-
tag: 'meta',
|
|
1268
|
-
attrs: {},
|
|
1269
|
-
content: [{
|
|
1270
|
-
tag: 'mentioned_users',
|
|
1271
|
-
attrs: {},
|
|
1272
|
-
content: jids.map(jid => ({
|
|
1273
|
-
tag: 'to',
|
|
1274
|
-
attrs: {
|
|
1275
|
-
jid: WABinary_1.jidNormalizedUser(jid)
|
|
1094
|
+
...options,
|
|
1095
|
+
messageId: generateMessageIDV2(userJid)
|
|
1096
|
+
});
|
|
1097
|
+
for (const id of jid) {
|
|
1098
|
+
if (isJidGroup(id)) {
|
|
1099
|
+
try {
|
|
1100
|
+
const groupData = (cachedGroupMetadata ? await cachedGroupMetadata(id) : null) || await groupMetadata(id);
|
|
1101
|
+
for (const participant of groupData.participants) {
|
|
1102
|
+
if (allUsers.has(participant.id))
|
|
1103
|
+
continue;
|
|
1104
|
+
allUsers.add(participant.id);
|
|
1276
1105
|
}
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1106
|
+
}
|
|
1107
|
+
catch (error) {
|
|
1108
|
+
logger.error(`Error getting metadata group from ${id}: ${error}`);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
else if (!allUsers.has(id)) {
|
|
1112
|
+
allUsers.add(id);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
await relayMessage('status@broadcast', fullMsg.message, {
|
|
1116
|
+
messageId: fullMsg.key.id,
|
|
1117
|
+
statusJidList: Array.from(allUsers),
|
|
1118
|
+
additionalNodes: [
|
|
1119
|
+
{
|
|
1120
|
+
tag: 'meta',
|
|
1121
|
+
attrs: {},
|
|
1122
|
+
content: [
|
|
1123
|
+
{
|
|
1124
|
+
tag: 'mentioned_users',
|
|
1125
|
+
attrs: {},
|
|
1126
|
+
content: jid.map(id => ({
|
|
1127
|
+
tag: 'to',
|
|
1128
|
+
attrs: { jid: id },
|
|
1129
|
+
content: undefined
|
|
1130
|
+
}))
|
|
1131
|
+
}
|
|
1132
|
+
]
|
|
1133
|
+
}
|
|
1134
|
+
]
|
|
1135
|
+
});
|
|
1136
|
+
if (config.emitOwnEvents) {
|
|
1137
|
+
process.nextTick(async () => {
|
|
1138
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
for (const id of jid) {
|
|
1142
|
+
const isGroup = isJidGroup(id);
|
|
1143
|
+
const sendType = isGroup ? 'groupStatusMentionMessage' : 'statusMentionMessage';
|
|
1144
|
+
const mentionMsg = generateWAMessageFromContent(id, {
|
|
1145
|
+
messageContextInfo: {
|
|
1146
|
+
messageSecret: randomBytes(32)
|
|
1147
|
+
},
|
|
1148
|
+
[sendType]: {
|
|
1290
1149
|
message: {
|
|
1291
1150
|
protocolMessage: {
|
|
1292
|
-
key:
|
|
1151
|
+
key: fullMsg.key,
|
|
1293
1152
|
type: 25
|
|
1294
1153
|
}
|
|
1295
1154
|
}
|
|
1296
|
-
},
|
|
1297
|
-
messageContextInfo: {
|
|
1298
|
-
messageSecret: crypto_1.randomBytes(32)
|
|
1299
1155
|
}
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
await relayMessage(
|
|
1307
|
-
normalizedId,
|
|
1308
|
-
statusMsg.message, {
|
|
1309
|
-
additionalNodes: [{
|
|
1156
|
+
}, {
|
|
1157
|
+
userJid
|
|
1158
|
+
});
|
|
1159
|
+
await relayMessage(id, mentionMsg.message, {
|
|
1160
|
+
additionalNodes: [
|
|
1161
|
+
{
|
|
1310
1162
|
tag: 'meta',
|
|
1311
|
-
attrs:
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
)
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1163
|
+
attrs: isGroup ?
|
|
1164
|
+
{ is_group_status_mention: 'true' } :
|
|
1165
|
+
{ is_status_mention: 'true' },
|
|
1166
|
+
content: undefined
|
|
1167
|
+
}
|
|
1168
|
+
]
|
|
1169
|
+
});
|
|
1170
|
+
if (config.emitOwnEvents) {
|
|
1171
|
+
process.nextTick(async () => {
|
|
1172
|
+
await messageMutex.mutex(() => upsertMessage(mentionMsg, 'append'));
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
await delay(delayMs);
|
|
1323
1176
|
}
|
|
1177
|
+
return fullMsg;
|
|
1324
1178
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1179
|
+
else if (typeof content === 'object' &&
|
|
1180
|
+
'disappearingMessagesInChat' in content &&
|
|
1181
|
+
typeof content['disappearingMessagesInChat'] !== 'undefined' &&
|
|
1182
|
+
isJidGroup(jid)) {
|
|
1183
|
+
const { disappearingMessagesInChat } = content;
|
|
1184
|
+
const value = typeof disappearingMessagesInChat === 'boolean'
|
|
1185
|
+
? disappearingMessagesInChat
|
|
1186
|
+
? WA_DEFAULT_EPHEMERAL
|
|
1187
|
+
: 0
|
|
1188
|
+
: disappearingMessagesInChat;
|
|
1189
|
+
await groupToggleEphemeral(jid, value);
|
|
1332
1190
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
expectedImageCount: medias.filter(media => media.image).length,
|
|
1339
|
-
expectedVideoCount: medias.filter(media => media.video).length,
|
|
1340
|
-
...options
|
|
1191
|
+
else {
|
|
1192
|
+
// Handle GROUP_STORY (group status/story) via kikyy
|
|
1193
|
+
const messageType = rahmi.detectType(content);
|
|
1194
|
+
if (messageType === 'GROUP_STORY') {
|
|
1195
|
+
return await rahmi.handleGroupStory(content, jid, options.quoted);
|
|
1341
1196
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
...options
|
|
1345
|
-
})
|
|
1346
|
-
await relayMessage(jid, album.message, {
|
|
1347
|
-
messageId: album.key.id
|
|
1348
|
-
})
|
|
1349
|
-
let mediaHandle
|
|
1350
|
-
let msg
|
|
1351
|
-
for (const i in medias) {
|
|
1352
|
-
const media = medias[i]
|
|
1353
|
-
if (media.image) {
|
|
1354
|
-
msg = await Utils_1.generateWAMessage(jid, {
|
|
1355
|
-
image: media.image,
|
|
1356
|
-
...media,
|
|
1357
|
-
...options
|
|
1358
|
-
}, {
|
|
1359
|
-
userJid,
|
|
1360
|
-
upload: async (readStream, opts) => {
|
|
1361
|
-
const up = await waUploadToServer(readStream, {
|
|
1362
|
-
...opts,
|
|
1363
|
-
newsletter: WABinary_1.isJidNewsletter(jid)
|
|
1364
|
-
})
|
|
1365
|
-
mediaHandle = up.handle
|
|
1366
|
-
return up
|
|
1367
|
-
},
|
|
1368
|
-
...options
|
|
1369
|
-
})
|
|
1370
|
-
} else if (media.video) {
|
|
1371
|
-
msg = await Utils_1.generateWAMessage(jid, {
|
|
1372
|
-
video: media.video,
|
|
1373
|
-
...media,
|
|
1374
|
-
...options
|
|
1375
|
-
}, {
|
|
1376
|
-
userJid,
|
|
1377
|
-
upload: async (readStream, opts) => {
|
|
1378
|
-
const up = await waUploadToServer(readStream, {
|
|
1379
|
-
...opts,
|
|
1380
|
-
newsletter: WABinary_1.isJidNewsletter(jid)
|
|
1381
|
-
})
|
|
1382
|
-
mediaHandle = up.handle
|
|
1383
|
-
return up
|
|
1384
|
-
},
|
|
1385
|
-
...options,
|
|
1386
|
-
})
|
|
1197
|
+
else if (messageType === 'ALBUM') {
|
|
1198
|
+
return await rahmi.handleAlbum(content, jid, options.quoted);
|
|
1387
1199
|
}
|
|
1388
|
-
if (
|
|
1389
|
-
|
|
1390
|
-
messageSecret: crypto_1.randomBytes(32),
|
|
1391
|
-
messageAssociation: {
|
|
1392
|
-
associationType: 1,
|
|
1393
|
-
parentMessageKey: album.key
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1200
|
+
else if (messageType === 'EVENT') {
|
|
1201
|
+
return await rahmi.handleEvent(content, jid, options.quoted);
|
|
1396
1202
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
})
|
|
1400
|
-
await Utils_1.delay(time)
|
|
1401
|
-
}
|
|
1402
|
-
return album
|
|
1403
|
-
},
|
|
1404
|
-
sendMessage: async (jid, content, options = {}) => {
|
|
1405
|
-
const userJid = authState.creds.me.id
|
|
1406
|
-
const additionalAttributes = {}
|
|
1407
|
-
|
|
1408
|
-
if (typeof content === 'object' && 'disappearingMessagesInChat' in content && typeof content['disappearingMessagesInChat'] !== 'undefined' && WABinary_1.isJidGroup(jid)) {
|
|
1409
|
-
const { disappearingMessagesInChat } = content
|
|
1410
|
-
const value = typeof disappearingMessagesInChat === 'boolean' ? (disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) : disappearingMessagesInChat
|
|
1411
|
-
await groupToggleEphemeral(jid, value)
|
|
1412
|
-
} else if (typeof content === 'object' && 'album' in content && content.album) {
|
|
1413
|
-
const albumMsg = await Utils_1.prepareAlbumMessageContent(jid, content.album, {
|
|
1414
|
-
sock: {
|
|
1415
|
-
relayMessage,
|
|
1416
|
-
waUploadToServer
|
|
1417
|
-
},
|
|
1418
|
-
userJid: userJid,
|
|
1419
|
-
...options
|
|
1420
|
-
})
|
|
1421
|
-
|
|
1422
|
-
for (const media of albumMsg) {
|
|
1423
|
-
await Utils_1.delay(options.delay || 500)
|
|
1424
|
-
await relayMessage(jid, media.message, {
|
|
1425
|
-
messageId: media.key.id,
|
|
1426
|
-
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1427
|
-
additionalAttributes,
|
|
1428
|
-
statusJidList: options.statusJidList,
|
|
1429
|
-
additionalNodes: options.additionalNodes,
|
|
1430
|
-
ai: options.ai
|
|
1431
|
-
})
|
|
1203
|
+
else if (messageType === 'POLL_RESULT') {
|
|
1204
|
+
return await rahmi.handlePollResult(content, jid, options.quoted);
|
|
1432
1205
|
}
|
|
1433
|
-
|
|
1434
|
-
return albumMsg
|
|
1435
|
-
} else {
|
|
1436
|
-
let mediaHandle
|
|
1437
|
-
|
|
1438
|
-
const fullMsg = await Utils_1.generateWAMessage(jid, content, {
|
|
1206
|
+
const fullMsg = await generateWAMessage(jid, content, {
|
|
1439
1207
|
logger,
|
|
1440
1208
|
userJid,
|
|
1441
|
-
getUrlInfo: text =>
|
|
1209
|
+
getUrlInfo: text => getUrlInfo(text, {
|
|
1442
1210
|
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1443
1211
|
fetchOpts: {
|
|
1444
1212
|
timeout: 3000,
|
|
1445
|
-
...
|
|
1213
|
+
...(httpRequestOptions || {})
|
|
1446
1214
|
},
|
|
1447
1215
|
logger,
|
|
1448
1216
|
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
1449
1217
|
}),
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
...opts,
|
|
1455
|
-
newsletter: WABinary_1.isJidNewsletter(jid)
|
|
1456
|
-
})
|
|
1457
|
-
mediaHandle = up.handle
|
|
1458
|
-
return up
|
|
1459
|
-
},
|
|
1218
|
+
//TODO: CACHE
|
|
1219
|
+
getProfilePicUrl: sock.profilePictureUrl,
|
|
1220
|
+
getCallLink: sock.createCallLink,
|
|
1221
|
+
upload: waUploadToServer,
|
|
1460
1222
|
mediaCache: config.mediaCache,
|
|
1461
1223
|
options: config.options,
|
|
1462
|
-
messageId:
|
|
1463
|
-
...options
|
|
1464
|
-
})
|
|
1465
|
-
|
|
1466
|
-
const
|
|
1467
|
-
const
|
|
1468
|
-
const
|
|
1469
|
-
const
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1224
|
+
messageId: generateMessageIDV2(sock.user?.id),
|
|
1225
|
+
...options
|
|
1226
|
+
});
|
|
1227
|
+
const isNewsletter = isJidNewsletter(jid);
|
|
1228
|
+
const isEventMsg = 'event' in content && !!content.event;
|
|
1229
|
+
const isDeleteMsg = 'delete' in content && !!content.delete;
|
|
1230
|
+
const isEditMsg = 'edit' in content && !!content.edit;
|
|
1231
|
+
const isPinMsg = 'pin' in content && !!content.pin;
|
|
1232
|
+
const isKeepMsg = 'keep' in content && !!content.keep;
|
|
1233
|
+
const isPollMsg = 'poll' in content && !!content.poll;
|
|
1234
|
+
const isQuizMsg = 'poll' in content && !!content.poll.pollType;
|
|
1235
|
+
const isAiMsg = 'ai' in content && !!content.ai;
|
|
1236
|
+
const isNeedBizAttrs = 'secureMetaServiceLabel' in content && !!content.secureMetaServiceLabel;
|
|
1237
|
+
const additionalAttributes = options.additionalAttributes || {};
|
|
1238
|
+
const additionalNodes = options.additionalNodes || [];
|
|
1239
|
+
// required for delete
|
|
1240
|
+
if (isDeleteMsg || isKeepMsg) {
|
|
1241
|
+
// if the chat is a group, and I am not the author, then delete the message as an admin
|
|
1242
|
+
if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
|
|
1243
|
+
additionalAttributes.edit = '8';
|
|
1244
|
+
}
|
|
1245
|
+
else {
|
|
1246
|
+
additionalAttributes.edit = '7';
|
|
1476
1247
|
}
|
|
1477
|
-
} else if (isEdit) {
|
|
1478
|
-
additionalAttributes.edit = WABinary_1.isJidNewsletter(jid) ? '3' : '1'
|
|
1479
|
-
} else if (isPin) {
|
|
1480
|
-
additionalAttributes.edit = '2'
|
|
1481
1248
|
}
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1249
|
+
else if (isEditMsg) {
|
|
1250
|
+
additionalAttributes.edit = isNewsletter ? '3' : '1';
|
|
1251
|
+
}
|
|
1252
|
+
else if (isPinMsg) {
|
|
1253
|
+
additionalAttributes.edit = '2';
|
|
1485
1254
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1255
|
+
else if (isPollMsg) {
|
|
1256
|
+
if (!isNewsletter && isQuizMsg) {
|
|
1257
|
+
throw new Boom('Quiz are only allowed for newsletter', { statusCode: 400 });
|
|
1258
|
+
}
|
|
1259
|
+
additionalNodes.push({
|
|
1260
|
+
tag: 'meta',
|
|
1261
|
+
attrs: {
|
|
1262
|
+
polltype: isQuizMsg ? 'quiz_creation' : 'creation',
|
|
1263
|
+
contenttype: isPollMsg && isNewsletter ? 'text' : undefined
|
|
1264
|
+
},
|
|
1265
|
+
content: undefined
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
else if (isEventMsg) {
|
|
1269
|
+
additionalNodes.push({
|
|
1270
|
+
tag: 'meta',
|
|
1271
|
+
attrs: {
|
|
1272
|
+
event_type: 'creation'
|
|
1273
|
+
},
|
|
1274
|
+
content: undefined
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
else if (isAiMsg) {
|
|
1278
|
+
if (!(isPnUser(jid) || isLidUser(jid))) {
|
|
1279
|
+
throw new Boom('AI icon on message are only allowed in private chat', { statusCode: 400 });
|
|
1280
|
+
}
|
|
1281
|
+
if ('messageContextInfo' in fullMsg.message && !!fullMsg.message.messageContextInfo) {
|
|
1282
|
+
fullMsg.message.messageContextInfo.supportPayload = BIZ_BOT_SUPPORT_PAYLOAD;
|
|
1283
|
+
}
|
|
1284
|
+
additionalNodes.push({
|
|
1285
|
+
tag: 'bot',
|
|
1286
|
+
attrs: {
|
|
1287
|
+
biz_bot: '1'
|
|
1288
|
+
},
|
|
1289
|
+
content: undefined
|
|
1290
|
+
});
|
|
1291
|
+
delete content.ai;
|
|
1489
1292
|
}
|
|
1490
|
-
|
|
1491
1293
|
await relayMessage(jid, fullMsg.message, {
|
|
1492
1294
|
messageId: fullMsg.key.id,
|
|
1493
1295
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1494
|
-
|
|
1296
|
+
addBizAttributes: isNeedBizAttrs,
|
|
1495
1297
|
statusJidList: options.statusJidList,
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
})
|
|
1499
|
-
|
|
1298
|
+
additionalAttributes,
|
|
1299
|
+
additionalNodes
|
|
1300
|
+
});
|
|
1500
1301
|
if (config.emitOwnEvents) {
|
|
1501
|
-
process.nextTick(() => {
|
|
1502
|
-
|
|
1503
|
-
})
|
|
1302
|
+
process.nextTick(async () => {
|
|
1303
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1304
|
+
});
|
|
1504
1305
|
}
|
|
1505
|
-
|
|
1506
|
-
|
|
1306
|
+
if ('album' in content) {
|
|
1307
|
+
const { delayMs = 1500 } = options;
|
|
1308
|
+
for (const albumMedia of content.album) {
|
|
1309
|
+
const albumMsg = await generateWAMessage(jid, albumMedia, {
|
|
1310
|
+
logger,
|
|
1311
|
+
userJid,
|
|
1312
|
+
upload: waUploadToServer,
|
|
1313
|
+
mediaCache: config.mediaCache,
|
|
1314
|
+
options: config.options,
|
|
1315
|
+
...options,
|
|
1316
|
+
messageId: generateMessageIDV2(userJid)
|
|
1317
|
+
});
|
|
1318
|
+
if (!hasValidAlbumMedia(normalizeMessageContent(albumMsg.message))) {
|
|
1319
|
+
throw new Boom('Invalid message type for album', { statusCode: 400 });
|
|
1320
|
+
}
|
|
1321
|
+
albumMsg.message.messageContextInfo ||= {};
|
|
1322
|
+
albumMsg.message.messageContextInfo.messageAssociation = {
|
|
1323
|
+
parentMessageKey: fullMsg.key,
|
|
1324
|
+
associationType: AssociationType.MEDIA_ALBUM
|
|
1325
|
+
};
|
|
1326
|
+
await relayMessage(jid, albumMsg.message, {
|
|
1327
|
+
messageId: albumMsg.key.id,
|
|
1328
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1329
|
+
addBizAttributes: isNeedBizAttrs,
|
|
1330
|
+
statusJidList: options.statusJidList,
|
|
1331
|
+
additionalAttributes,
|
|
1332
|
+
additionalNodes
|
|
1333
|
+
});
|
|
1334
|
+
if (config.emitOwnEvents) {
|
|
1335
|
+
process.nextTick(async () => {
|
|
1336
|
+
await messageMutex.mutex(() => upsertMessage(albumMsg, 'append'));
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
await delay(delayMs);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
return fullMsg;
|
|
1507
1343
|
}
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
}
|
|
1344
|
+
},
|
|
1345
|
+
sendTable: async (jid, title, headers, rows, quoted, options = {}) => {
|
|
1346
|
+
const { message, messageId } = generateTableContent(title, headers, rows, quoted, options);
|
|
1347
|
+
await relayMessage(jid, message, { messageId });
|
|
1348
|
+
return { message, messageId };
|
|
1349
|
+
},
|
|
1350
|
+
sendTableV2: async (jid, table, quoted, options = {}) => {
|
|
1351
|
+
const { message, messageId } = generateTableContentV2(table, quoted, options);
|
|
1352
|
+
await relayMessage(jid, message, { messageId });
|
|
1353
|
+
return { message, messageId };
|
|
1354
|
+
},
|
|
1355
|
+
sendList: async (jid, title, items, quoted, options = {}) => {
|
|
1356
|
+
const { message, messageId } = generateListContent(title, items, quoted, options);
|
|
1357
|
+
await relayMessage(jid, message, { messageId });
|
|
1358
|
+
return { message, messageId };
|
|
1359
|
+
},
|
|
1360
|
+
sendCodeBlock: async (jid, code, quoted, options = {}) => {
|
|
1361
|
+
const { message, messageId } = generateCodeBlockContent(code, quoted, options);
|
|
1362
|
+
await relayMessage(jid, message, { messageId });
|
|
1363
|
+
return { message, messageId };
|
|
1364
|
+
},
|
|
1365
|
+
sendCodeBlockV2: async (jid, code, quoted, options = {}) => {
|
|
1366
|
+
const { message, messageId } = generateCodeBlockContentV2(code, quoted, options);
|
|
1367
|
+
await relayMessage(jid, message, { messageId });
|
|
1368
|
+
return { message, messageId };
|
|
1369
|
+
},
|
|
1370
|
+
sendLink: async (jid, text, links, quoted, options = {}) => {
|
|
1371
|
+
const { message, messageId } = generateLinkContent(text, links, quoted, options);
|
|
1372
|
+
await relayMessage(jid, message, { messageId });
|
|
1373
|
+
return { message, messageId };
|
|
1374
|
+
},
|
|
1375
|
+
sendLinkV2: async (jid, text, links, quoted, options = {}) => {
|
|
1376
|
+
const { message, messageId } = generateLinkContentV2(text, links, quoted, options);
|
|
1377
|
+
await relayMessage(jid, message, { messageId });
|
|
1378
|
+
return { message, messageId };
|
|
1379
|
+
},
|
|
1380
|
+
sendLatex: async (jid, quoted, options) => {
|
|
1381
|
+
const { message, messageId } = generateLatexContent(quoted, options);
|
|
1382
|
+
await relayMessage(jid, message, { messageId });
|
|
1383
|
+
return { message, messageId };
|
|
1384
|
+
},
|
|
1385
|
+
sendLatexImage: async (jid, quoted, options, renderLatexToPng, uploadFn) => {
|
|
1386
|
+
const { message, messageId } = await generateLatexImageContent(quoted, options, uploadFn, renderLatexToPng);
|
|
1387
|
+
await relayMessage(jid, message, { messageId });
|
|
1388
|
+
return { message, messageId };
|
|
1389
|
+
},
|
|
1390
|
+
sendLatexInlineImage: async (jid, quoted, options, renderLatexToPng, uploadFn) => {
|
|
1391
|
+
const { message, messageId } = await generateLatexInlineImageContent(quoted, options, uploadFn, renderLatexToPng);
|
|
1392
|
+
await relayMessage(jid, message, { messageId });
|
|
1393
|
+
return { message, messageId };
|
|
1394
|
+
},
|
|
1395
|
+
sendRichMessage: async (jid, submessages, quoted, options = {}) => {
|
|
1396
|
+
const { message, messageId } = generateRichMessageContent(submessages, quoted);
|
|
1397
|
+
await relayMessage(jid, message, { messageId });
|
|
1398
|
+
return { message, messageId };
|
|
1399
|
+
},
|
|
1400
|
+
sendUnifiedResponse: async (jid, quoted, captured) => {
|
|
1401
|
+
const { message, messageId } = generateUnifiedResponseContent(quoted, captured);
|
|
1402
|
+
await relayMessage(jid, message, { messageId });
|
|
1403
|
+
return { message, messageId };
|
|
1404
|
+
},
|
|
1405
|
+
captureUnifiedResponse,
|
|
1406
|
+
};
|
|
1407
|
+
};
|
|
1408
|
+
//# sourceMappingURL=messages-send.js.map
|