lordceaser-baileys 2.0.0 → 2.0.2
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/WAProto/index.js +136901 -78899
- package/WASignalGroup/GroupProtocol.js +1697 -0
- package/WASignalGroup/ciphertext_message.js +16 -0
- package/WASignalGroup/group_cipher.js +120 -0
- package/WASignalGroup/group_session_builder.js +46 -0
- package/WASignalGroup/index.js +5 -0
- package/WASignalGroup/keyhelper.js +21 -0
- package/WASignalGroup/protobufs.js +3 -0
- package/WASignalGroup/queue_job.js +69 -0
- package/WASignalGroup/sender_chain_key.js +50 -0
- package/WASignalGroup/sender_key_distribution_message.js +78 -0
- package/WASignalGroup/sender_key_message.js +92 -0
- package/WASignalGroup/sender_key_name.js +70 -0
- package/WASignalGroup/sender_key_record.js +56 -0
- package/WASignalGroup/sender_key_state.js +129 -0
- package/{lib/Signal/Group/sender-message-key.js → WASignalGroup/sender_message_key.js} +16 -3
- package/index.js +17 -0
- package/lib/Defaults/baileys-version.json +3 -0
- package/lib/Defaults/index.d.ts +15 -37
- package/lib/Defaults/index.js +60 -81
- package/lib/Signal/libsignal.d.ts +3 -5
- package/lib/Signal/libsignal.js +80 -359
- package/lib/Socket/Client/{types.d.ts → abstract-socket-client.d.ts} +5 -4
- package/lib/Socket/Client/abstract-socket-client.js +13 -0
- package/lib/Socket/Client/index.d.ts +3 -3
- package/lib/Socket/Client/index.js +19 -3
- package/lib/Socket/Client/mobile-socket-client.d.ts +13 -0
- package/lib/Socket/Client/mobile-socket-client.js +65 -0
- package/lib/Socket/Client/{websocket.d.ts → web-socket-client.d.ts} +2 -3
- package/lib/Socket/Client/web-socket-client.js +62 -0
- package/lib/Socket/business.d.ts +100 -147
- package/lib/Socket/business.js +43 -162
- package/lib/Socket/chats.d.ts +41 -85
- package/lib/Socket/chats.js +321 -569
- package/lib/Socket/groups.d.ts +57 -103
- package/lib/Socket/groups.js +84 -116
- package/lib/Socket/index.d.ts +106 -194
- package/lib/Socket/index.js +9 -11
- package/lib/Socket/messages-recv.d.ts +89 -134
- package/lib/Socket/messages-recv.js +475 -1275
- package/lib/Socket/messages-send.d.ts +97 -141
- package/lib/Socket/messages-send.js +633 -691
- package/lib/Socket/newsletter.d.ts +74 -112
- package/lib/Socket/newsletter.js +202 -147
- package/lib/Socket/registration.d.ts +264 -0
- package/lib/Socket/registration.js +166 -0
- package/lib/Socket/socket.d.ts +19 -34
- package/lib/Socket/socket.js +219 -547
- package/lib/Socket/usync.d.ts +37 -0
- package/lib/Socket/usync.js +70 -0
- package/lib/Store/index.d.ts +3 -0
- package/lib/Store/index.js +10 -0
- package/lib/Store/make-cache-manager-store.d.ts +14 -0
- package/lib/Store/make-cache-manager-store.js +83 -0
- package/lib/Store/make-in-memory-store.d.ts +118 -0
- package/lib/Store/make-in-memory-store.js +431 -0
- package/lib/Store/make-ordered-dictionary.d.ts +13 -0
- package/lib/Store/make-ordered-dictionary.js +81 -0
- package/lib/Store/object-repository.d.ts +10 -0
- package/lib/Store/object-repository.js +27 -0
- package/lib/Types/Auth.d.ts +11 -19
- package/lib/Types/Auth.js +2 -2
- package/lib/Types/Call.d.ts +1 -3
- package/lib/Types/Call.js +2 -2
- package/lib/Types/Chat.d.ts +8 -25
- package/lib/Types/Chat.js +4 -8
- package/lib/Types/Contact.d.ts +1 -8
- package/lib/Types/Contact.js +2 -2
- package/lib/Types/Events.d.ts +17 -101
- package/lib/Types/Events.js +2 -2
- package/lib/Types/GroupMetadata.d.ts +3 -18
- package/lib/Types/GroupMetadata.js +2 -2
- package/lib/Types/Label.d.ts +0 -1
- package/lib/Types/Label.js +5 -3
- package/lib/Types/LabelAssociation.d.ts +0 -1
- package/lib/Types/LabelAssociation.js +5 -3
- package/lib/Types/Message.d.ts +204 -91
- package/lib/Types/Message.js +9 -11
- package/lib/Types/Newsletter.d.ts +92 -0
- package/lib/Types/Newsletter.js +32 -0
- package/lib/Types/Product.d.ts +1 -2
- package/lib/Types/Product.js +2 -2
- package/lib/Types/Signal.d.ts +2 -32
- package/lib/Types/Signal.js +2 -2
- package/lib/Types/Socket.d.ts +24 -44
- package/lib/Types/Socket.js +2 -3
- package/lib/Types/State.d.ts +2 -72
- package/lib/Types/State.js +2 -56
- package/lib/Types/USync.d.ts +2 -3
- package/lib/Types/USync.js +2 -2
- package/lib/Types/index.d.ts +16 -16
- package/lib/Types/index.js +31 -15
- package/lib/Utils/auth-utils.d.ts +6 -12
- package/lib/Utils/auth-utils.js +143 -239
- package/lib/Utils/baileys-event-stream.d.ts +16 -0
- package/lib/Utils/baileys-event-stream.js +63 -0
- package/lib/Utils/business.d.ts +3 -4
- package/lib/Utils/business.js +69 -66
- package/lib/Utils/c4-compat.js +0 -8
- package/lib/Utils/chat-utils.d.ts +17 -47
- package/lib/Utils/chat-utils.js +237 -364
- package/lib/Utils/crypto.d.ts +21 -18
- package/lib/Utils/crypto.js +125 -44
- package/lib/Utils/decode-wa-message.d.ts +8 -38
- package/lib/Utils/decode-wa-message.js +90 -173
- package/lib/Utils/event-buffer.d.ts +8 -9
- package/lib/Utils/event-buffer.js +71 -176
- package/lib/Utils/generics.d.ts +22 -26
- package/lib/Utils/generics.js +175 -166
- package/lib/Utils/history.d.ts +11 -16
- package/lib/Utils/history.js +53 -93
- package/lib/Utils/index.d.ts +17 -22
- package/lib/Utils/index.js +34 -22
- package/lib/Utils/link-preview.d.ts +5 -5
- package/lib/Utils/link-preview.js +24 -16
- package/lib/Utils/logger.d.ts +1 -11
- package/lib/Utils/logger.js +7 -3
- package/lib/Utils/lt-hash.d.ts +12 -8
- package/lib/Utils/lt-hash.js +46 -3
- package/lib/Utils/make-mutex.d.ts +0 -2
- package/lib/Utils/make-mutex.js +34 -24
- package/lib/Utils/messages-media.d.ts +45 -65
- package/lib/Utils/messages-media.js +358 -425
- package/lib/Utils/messages.d.ts +18 -32
- package/lib/Utils/messages.js +720 -392
- package/lib/Utils/noise-handler.d.ts +13 -13
- package/lib/Utils/noise-handler.js +108 -149
- package/lib/Utils/process-message.d.ts +11 -30
- package/lib/Utils/process-message.js +166 -423
- package/lib/Utils/signal.d.ts +6 -20
- package/lib/Utils/signal.js +65 -107
- package/lib/Utils/use-multi-file-auth-state.d.ts +1 -2
- package/lib/Utils/use-multi-file-auth-state.js +103 -57
- package/lib/Utils/use-single-file-auth-state.d.ts +12 -0
- package/lib/Utils/use-single-file-auth-state.js +76 -0
- package/lib/Utils/validate-connection.d.ts +6 -6
- package/lib/Utils/validate-connection.js +114 -119
- package/lib/WABinary/constants.d.ts +4 -5
- package/lib/WABinary/constants.js +20 -1281
- package/lib/WABinary/decode.d.ts +3 -4
- package/lib/WABinary/decode.js +53 -51
- package/lib/WABinary/encode.d.ts +1 -2
- package/lib/WABinary/encode.js +44 -12
- package/lib/WABinary/generic-utils.d.ts +6 -7
- package/lib/WABinary/generic-utils.js +43 -46
- package/lib/WABinary/index.d.ts +5 -6
- package/lib/WABinary/index.js +21 -6
- package/lib/WABinary/jid-utils.d.ts +7 -24
- package/lib/WABinary/jid-utils.js +40 -74
- package/lib/WABinary/types.d.ts +1 -2
- package/lib/WABinary/types.js +2 -2
- package/lib/WAM/BinaryInfo.d.ts +1 -2
- package/lib/WAM/BinaryInfo.js +5 -2
- package/lib/WAM/constants.d.ts +3 -5
- package/lib/WAM/constants.js +11958 -19461
- package/lib/WAM/encode.d.ts +2 -3
- package/lib/WAM/encode.js +22 -17
- package/lib/WAM/index.d.ts +3 -4
- package/lib/WAM/index.js +19 -4
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +3 -4
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +13 -33
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +2 -3
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +14 -11
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +2 -3
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +12 -9
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +2 -3
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +13 -9
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +3 -4
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +22 -20
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +3 -5
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +8 -13
- package/lib/WAUSync/Protocols/index.d.ts +4 -6
- package/lib/WAUSync/Protocols/index.js +20 -6
- package/lib/WAUSync/USyncQuery.d.ts +4 -6
- package/lib/WAUSync/USyncQuery.js +35 -44
- package/lib/WAUSync/USyncUser.d.ts +4 -11
- package/lib/WAUSync/USyncUser.js +5 -10
- package/lib/WAUSync/index.d.ts +3 -4
- package/lib/WAUSync/index.js +19 -4
- package/lib/index.js +31 -13
- package/package.json +19 -10
- package/WAProto/GenerateStatics.sh +0 -3
- package/WAProto/WAProto.proto +0 -5479
- package/WAProto/fix-imports.js +0 -85
- package/WAProto/index.d.ts +0 -14017
- package/lib/Defaults/index.d.ts.map +0 -1
- package/lib/Defaults/index.js.map +0 -1
- package/lib/Signal/Group/ciphertext-message.d.ts +0 -10
- package/lib/Signal/Group/ciphertext-message.d.ts.map +0 -1
- package/lib/Signal/Group/ciphertext-message.js +0 -12
- package/lib/Signal/Group/ciphertext-message.js.map +0 -1
- package/lib/Signal/Group/group-session-builder.d.ts +0 -15
- package/lib/Signal/Group/group-session-builder.d.ts.map +0 -1
- package/lib/Signal/Group/group-session-builder.js +0 -30
- package/lib/Signal/Group/group-session-builder.js.map +0 -1
- package/lib/Signal/Group/group_cipher.d.ts +0 -17
- package/lib/Signal/Group/group_cipher.d.ts.map +0 -1
- package/lib/Signal/Group/group_cipher.js +0 -82
- package/lib/Signal/Group/group_cipher.js.map +0 -1
- package/lib/Signal/Group/index.d.ts +0 -12
- package/lib/Signal/Group/index.d.ts.map +0 -1
- package/lib/Signal/Group/index.js +0 -12
- package/lib/Signal/Group/index.js.map +0 -1
- package/lib/Signal/Group/keyhelper.d.ts +0 -11
- package/lib/Signal/Group/keyhelper.d.ts.map +0 -1
- package/lib/Signal/Group/keyhelper.js +0 -18
- package/lib/Signal/Group/keyhelper.js.map +0 -1
- package/lib/Signal/Group/sender-chain-key.d.ts +0 -14
- package/lib/Signal/Group/sender-chain-key.d.ts.map +0 -1
- package/lib/Signal/Group/sender-chain-key.js +0 -26
- package/lib/Signal/Group/sender-chain-key.js.map +0 -1
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -17
- package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-distribution-message.js +0 -63
- package/lib/Signal/Group/sender-key-distribution-message.js.map +0 -1
- package/lib/Signal/Group/sender-key-message.d.ts +0 -19
- package/lib/Signal/Group/sender-key-message.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-message.js +0 -66
- package/lib/Signal/Group/sender-key-message.js.map +0 -1
- package/lib/Signal/Group/sender-key-name.d.ts +0 -18
- package/lib/Signal/Group/sender-key-name.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-name.js +0 -48
- package/lib/Signal/Group/sender-key-name.js.map +0 -1
- package/lib/Signal/Group/sender-key-record.d.ts +0 -31
- package/lib/Signal/Group/sender-key-record.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-record.js +0 -41
- package/lib/Signal/Group/sender-key-record.js.map +0 -1
- package/lib/Signal/Group/sender-key-state.d.ts +0 -39
- package/lib/Signal/Group/sender-key-state.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-state.js +0 -84
- package/lib/Signal/Group/sender-key-state.js.map +0 -1
- package/lib/Signal/Group/sender-message-key.d.ts +0 -12
- package/lib/Signal/Group/sender-message-key.d.ts.map +0 -1
- package/lib/Signal/Group/sender-message-key.js.map +0 -1
- package/lib/Signal/libsignal.d.ts.map +0 -1
- package/lib/Signal/libsignal.js.map +0 -1
- package/lib/Signal/lid-mapping.d.ts +0 -23
- package/lib/Signal/lid-mapping.d.ts.map +0 -1
- package/lib/Signal/lid-mapping.js +0 -277
- package/lib/Signal/lid-mapping.js.map +0 -1
- package/lib/Socket/Client/index.d.ts.map +0 -1
- package/lib/Socket/Client/index.js.map +0 -1
- package/lib/Socket/Client/types.d.ts.map +0 -1
- package/lib/Socket/Client/types.js +0 -11
- package/lib/Socket/Client/types.js.map +0 -1
- package/lib/Socket/Client/websocket.d.ts.map +0 -1
- package/lib/Socket/Client/websocket.js +0 -54
- package/lib/Socket/Client/websocket.js.map +0 -1
- package/lib/Socket/business.d.ts.map +0 -1
- package/lib/Socket/business.js.map +0 -1
- package/lib/Socket/chats.d.ts.map +0 -1
- package/lib/Socket/chats.js.map +0 -1
- package/lib/Socket/communities.d.ts +0 -273
- package/lib/Socket/communities.d.ts.map +0 -1
- package/lib/Socket/communities.js +0 -431
- package/lib/Socket/communities.js.map +0 -1
- package/lib/Socket/groups.d.ts.map +0 -1
- package/lib/Socket/groups.js.map +0 -1
- package/lib/Socket/index.d.ts.map +0 -1
- package/lib/Socket/index.js.map +0 -1
- package/lib/Socket/messages-recv.d.ts.map +0 -1
- package/lib/Socket/messages-recv.js.map +0 -1
- package/lib/Socket/messages-send.d.ts.map +0 -1
- package/lib/Socket/messages-send.js.map +0 -1
- package/lib/Socket/mex.d.ts +0 -3
- package/lib/Socket/mex.d.ts.map +0 -1
- package/lib/Socket/mex.js +0 -42
- package/lib/Socket/mex.js.map +0 -1
- package/lib/Socket/newsletter.d.ts.map +0 -1
- package/lib/Socket/newsletter.js.map +0 -1
- package/lib/Socket/socket.d.ts.map +0 -1
- package/lib/Socket/socket.js.map +0 -1
- package/lib/Types/Auth.d.ts.map +0 -1
- package/lib/Types/Auth.js.map +0 -1
- package/lib/Types/Bussines.d.ts +0 -25
- package/lib/Types/Bussines.d.ts.map +0 -1
- package/lib/Types/Bussines.js +0 -2
- package/lib/Types/Bussines.js.map +0 -1
- package/lib/Types/Call.d.ts.map +0 -1
- package/lib/Types/Call.js.map +0 -1
- package/lib/Types/Chat.d.ts.map +0 -1
- package/lib/Types/Chat.js.map +0 -1
- package/lib/Types/Contact.d.ts.map +0 -1
- package/lib/Types/Contact.js.map +0 -1
- package/lib/Types/Events.d.ts.map +0 -1
- package/lib/Types/Events.js.map +0 -1
- package/lib/Types/GroupMetadata.d.ts.map +0 -1
- package/lib/Types/GroupMetadata.js.map +0 -1
- package/lib/Types/Label.d.ts.map +0 -1
- package/lib/Types/Label.js.map +0 -1
- package/lib/Types/LabelAssociation.d.ts.map +0 -1
- package/lib/Types/LabelAssociation.js.map +0 -1
- package/lib/Types/Message.d.ts.map +0 -1
- package/lib/Types/Message.js.map +0 -1
- package/lib/Types/Mex.d.ts +0 -141
- package/lib/Types/Mex.d.ts.map +0 -1
- package/lib/Types/Mex.js +0 -37
- package/lib/Types/Mex.js.map +0 -1
- package/lib/Types/Product.d.ts.map +0 -1
- package/lib/Types/Product.js.map +0 -1
- package/lib/Types/Signal.d.ts.map +0 -1
- package/lib/Types/Signal.js.map +0 -1
- package/lib/Types/Socket.d.ts.map +0 -1
- package/lib/Types/Socket.js.map +0 -1
- package/lib/Types/State.d.ts.map +0 -1
- package/lib/Types/State.js.map +0 -1
- package/lib/Types/USync.d.ts.map +0 -1
- package/lib/Types/USync.js.map +0 -1
- package/lib/Types/index.d.ts.map +0 -1
- package/lib/Types/index.js.map +0 -1
- package/lib/Utils/auth-utils.d.ts.map +0 -1
- package/lib/Utils/auth-utils.js.map +0 -1
- package/lib/Utils/browser-utils.d.ts +0 -4
- package/lib/Utils/browser-utils.d.ts.map +0 -1
- package/lib/Utils/browser-utils.js +0 -29
- package/lib/Utils/browser-utils.js.map +0 -1
- package/lib/Utils/business.d.ts.map +0 -1
- package/lib/Utils/business.js.map +0 -1
- package/lib/Utils/chat-utils.d.ts.map +0 -1
- package/lib/Utils/chat-utils.js.map +0 -1
- package/lib/Utils/companion-reg-client-utils.d.ts +0 -17
- package/lib/Utils/companion-reg-client-utils.d.ts.map +0 -1
- package/lib/Utils/companion-reg-client-utils.js +0 -35
- package/lib/Utils/companion-reg-client-utils.js.map +0 -1
- package/lib/Utils/crypto.d.ts.map +0 -1
- package/lib/Utils/crypto.js.map +0 -1
- package/lib/Utils/decode-wa-message.d.ts.map +0 -1
- package/lib/Utils/decode-wa-message.js.map +0 -1
- package/lib/Utils/event-buffer.d.ts.map +0 -1
- package/lib/Utils/event-buffer.js.map +0 -1
- package/lib/Utils/generics.d.ts.map +0 -1
- package/lib/Utils/generics.js.map +0 -1
- package/lib/Utils/history.d.ts.map +0 -1
- package/lib/Utils/history.js.map +0 -1
- package/lib/Utils/identity-change-handler.d.ts +0 -44
- package/lib/Utils/identity-change-handler.d.ts.map +0 -1
- package/lib/Utils/identity-change-handler.js +0 -50
- package/lib/Utils/identity-change-handler.js.map +0 -1
- package/lib/Utils/index.d.ts.map +0 -1
- package/lib/Utils/index.js.map +0 -1
- package/lib/Utils/link-preview.d.ts.map +0 -1
- package/lib/Utils/link-preview.js.map +0 -1
- package/lib/Utils/logger.d.ts.map +0 -1
- package/lib/Utils/logger.js.map +0 -1
- package/lib/Utils/lt-hash.d.ts.map +0 -1
- package/lib/Utils/lt-hash.js.map +0 -1
- package/lib/Utils/make-mutex.d.ts.map +0 -1
- package/lib/Utils/make-mutex.js.map +0 -1
- package/lib/Utils/message-retry-manager.d.ts +0 -115
- package/lib/Utils/message-retry-manager.d.ts.map +0 -1
- package/lib/Utils/message-retry-manager.js +0 -265
- package/lib/Utils/message-retry-manager.js.map +0 -1
- package/lib/Utils/messages-media.d.ts.map +0 -1
- package/lib/Utils/messages-media.js.map +0 -1
- package/lib/Utils/messages.d.ts.map +0 -1
- package/lib/Utils/messages.js.map +0 -1
- package/lib/Utils/noise-handler.d.ts.map +0 -1
- package/lib/Utils/noise-handler.js.map +0 -1
- package/lib/Utils/offline-node-processor.d.ts +0 -17
- package/lib/Utils/offline-node-processor.d.ts.map +0 -1
- package/lib/Utils/offline-node-processor.js +0 -40
- package/lib/Utils/offline-node-processor.js.map +0 -1
- package/lib/Utils/pre-key-manager.d.ts +0 -28
- package/lib/Utils/pre-key-manager.d.ts.map +0 -1
- package/lib/Utils/pre-key-manager.js +0 -106
- package/lib/Utils/pre-key-manager.js.map +0 -1
- package/lib/Utils/process-message.d.ts.map +0 -1
- package/lib/Utils/process-message.js.map +0 -1
- package/lib/Utils/reporting-utils.d.ts +0 -11
- package/lib/Utils/reporting-utils.d.ts.map +0 -1
- package/lib/Utils/reporting-utils.js +0 -258
- package/lib/Utils/reporting-utils.js.map +0 -1
- package/lib/Utils/signal.d.ts.map +0 -1
- package/lib/Utils/signal.js.map +0 -1
- package/lib/Utils/stanza-ack.d.ts +0 -11
- package/lib/Utils/stanza-ack.d.ts.map +0 -1
- package/lib/Utils/stanza-ack.js +0 -38
- package/lib/Utils/stanza-ack.js.map +0 -1
- package/lib/Utils/sync-action-utils.d.ts +0 -19
- package/lib/Utils/sync-action-utils.d.ts.map +0 -1
- package/lib/Utils/sync-action-utils.js +0 -49
- package/lib/Utils/sync-action-utils.js.map +0 -1
- package/lib/Utils/tc-token-utils.d.ts +0 -37
- package/lib/Utils/tc-token-utils.d.ts.map +0 -1
- package/lib/Utils/tc-token-utils.js +0 -164
- package/lib/Utils/tc-token-utils.js.map +0 -1
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +0 -1
- package/lib/Utils/use-multi-file-auth-state.js.map +0 -1
- package/lib/Utils/validate-connection.d.ts.map +0 -1
- package/lib/Utils/validate-connection.js.map +0 -1
- package/lib/WABinary/constants.d.ts.map +0 -1
- package/lib/WABinary/constants.js.map +0 -1
- package/lib/WABinary/decode.d.ts.map +0 -1
- package/lib/WABinary/decode.js.map +0 -1
- package/lib/WABinary/encode.d.ts.map +0 -1
- package/lib/WABinary/encode.js.map +0 -1
- package/lib/WABinary/generic-utils.d.ts.map +0 -1
- package/lib/WABinary/generic-utils.js.map +0 -1
- package/lib/WABinary/index.d.ts.map +0 -1
- package/lib/WABinary/index.js.map +0 -1
- package/lib/WABinary/jid-utils.d.ts.map +0 -1
- package/lib/WABinary/jid-utils.js.map +0 -1
- package/lib/WABinary/types.d.ts.map +0 -1
- package/lib/WABinary/types.js.map +0 -1
- package/lib/WAM/BinaryInfo.d.ts.map +0 -1
- package/lib/WAM/BinaryInfo.js.map +0 -1
- package/lib/WAM/constants.d.ts.map +0 -1
- package/lib/WAM/constants.js.map +0 -1
- package/lib/WAM/encode.d.ts.map +0 -1
- package/lib/WAM/encode.js.map +0 -1
- package/lib/WAM/index.d.ts.map +0 -1
- package/lib/WAM/index.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +0 -25
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/index.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/index.js.map +0 -1
- package/lib/WAUSync/USyncQuery.d.ts.map +0 -1
- package/lib/WAUSync/USyncQuery.js.map +0 -1
- package/lib/WAUSync/USyncUser.d.ts.map +0 -1
- package/lib/WAUSync/USyncUser.js.map +0 -1
- package/lib/WAUSync/index.d.ts.map +0 -1
- package/lib/WAUSync/index.js.map +0 -1
- package/lib/index.d.ts +0 -12
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
|
@@ -1,465 +1,157 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const {
|
|
22
|
-
const sock = makeMessagesSocket(config);
|
|
23
|
-
const { userDevicesCache, devicesMutex, ev, authState, ws, messageMutex, notificationMutex, receiptMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, messageRetryManager, registerSocketEndHandler, issuePrivacyTokens, fetchAccountReachoutTimelock, placeholderResendCache } = sock;
|
|
24
|
-
const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.makeMessagesRecvSocket = void 0;
|
|
7
|
+
const boom_1 = require("@hapi/boom");
|
|
8
|
+
const crypto_1 = require("crypto");
|
|
9
|
+
const node_cache_1 = __importDefault(require("node-cache"));
|
|
10
|
+
const WAProto_1 = require("../../WAProto");
|
|
11
|
+
const Defaults_1 = require("../Defaults");
|
|
12
|
+
const Types_1 = require("../Types");
|
|
13
|
+
const Utils_1 = require("../Utils");
|
|
14
|
+
const make_mutex_1 = require("../Utils/make-mutex");
|
|
15
|
+
const WABinary_1 = require("../WABinary");
|
|
16
|
+
const groups_1 = require("./groups");
|
|
17
|
+
const messages_send_1 = require("./messages-send");
|
|
18
|
+
const makeMessagesRecvSocket = (config) => {
|
|
19
|
+
const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid } = config;
|
|
20
|
+
const sock = (0, messages_send_1.makeMessagesSocket)(config);
|
|
21
|
+
const { ev, authState, ws, processingMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, getUSyncDevices, sendPeerDataOperationMessage, createParticipantNodes } = sock;
|
|
25
22
|
/** this mutex ensures that each retryRequest will wait for the previous one to finish */
|
|
26
|
-
const retryMutex = makeMutex();
|
|
27
|
-
const msgRetryCache = config.msgRetryCounterCache ||
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
const retryMutex = (0, make_mutex_1.makeMutex)();
|
|
24
|
+
const msgRetryCache = config.msgRetryCounterCache || new node_cache_1.default({
|
|
25
|
+
stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
26
|
+
useClones: false
|
|
27
|
+
});
|
|
28
|
+
const callOfferCache = config.callOfferCache || new node_cache_1.default({
|
|
29
|
+
stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.CALL_OFFER, // 5 mins
|
|
30
|
+
useClones: false
|
|
31
|
+
});
|
|
32
|
+
const placeholderResendCache = config.placeholderResendCache || new node_cache_1.default({
|
|
33
|
+
stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
34
|
+
useClones: false
|
|
35
|
+
});
|
|
39
36
|
let sendActiveReceipts = false;
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
oldestMsgId: oldestMsgKey.id,
|
|
49
|
-
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
50
|
-
onDemandMsgCount: count
|
|
51
|
-
},
|
|
52
|
-
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
37
|
+
const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
|
|
38
|
+
const stanza = {
|
|
39
|
+
tag: 'ack',
|
|
40
|
+
attrs: {
|
|
41
|
+
id: attrs.id,
|
|
42
|
+
to: attrs.from,
|
|
43
|
+
class: tag
|
|
44
|
+
}
|
|
53
45
|
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const requestPlaceholderResend = async (messageKey, msgData) => {
|
|
57
|
-
if (!authState.creds.me?.id) {
|
|
58
|
-
throw new Boom('Not authenticated');
|
|
46
|
+
if (!!errorCode) {
|
|
47
|
+
stanza.attrs.error = errorCode.toString();
|
|
59
48
|
}
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
return;
|
|
49
|
+
if (!!attrs.participant) {
|
|
50
|
+
stanza.attrs.participant = attrs.participant;
|
|
63
51
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// metadata (LID details, timestamps, etc.) that the phone may omit
|
|
67
|
-
await placeholderResendCache.set(messageKey?.id, msgData || true);
|
|
52
|
+
if (!!attrs.recipient) {
|
|
53
|
+
stanza.attrs.recipient = attrs.recipient;
|
|
68
54
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
logger.debug({ messageKey }, 'message received while resend requested');
|
|
72
|
-
return 'RESOLVED';
|
|
55
|
+
if (!!attrs.type && (tag !== 'message' || (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable') || errorCode !== 0)) {
|
|
56
|
+
stanza.attrs.type = attrs.type;
|
|
73
57
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
{
|
|
77
|
-
messageKey
|
|
78
|
-
}
|
|
79
|
-
],
|
|
80
|
-
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
81
|
-
};
|
|
82
|
-
setTimeout(async () => {
|
|
83
|
-
if (await placeholderResendCache.get(messageKey?.id)) {
|
|
84
|
-
logger.debug({ messageKey }, 'PDO message without response after 8 seconds. Phone possibly offline');
|
|
85
|
-
await placeholderResendCache.del(messageKey?.id);
|
|
86
|
-
}
|
|
87
|
-
}, 8000);
|
|
88
|
-
return sendPeerDataOperationMessage(pdoMessage);
|
|
89
|
-
};
|
|
90
|
-
const handleMexNotification = async (node) => {
|
|
91
|
-
const updateNode = getBinaryNodeChild(node, 'update');
|
|
92
|
-
if (updateNode) {
|
|
93
|
-
const opName = updateNode.attrs?.op_name;
|
|
94
|
-
if (!opName) {
|
|
95
|
-
logger.warn({ node: binaryNodeToString(node) }, 'mex notification missing op_name, fallback to legacy');
|
|
96
|
-
await handleLegacyMexNewsletterNotification(node);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
let mexResponse;
|
|
100
|
-
try {
|
|
101
|
-
mexResponse = JSON.parse(updateNode.content.toString());
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
logger.error({ err: error, opName }, 'failed to parse mex notification JSON');
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (mexResponse.errors?.length) {
|
|
108
|
-
logger.warn({ errors: mexResponse.errors, opName }, 'mex notification has GQL errors');
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
const data = mexResponse.data;
|
|
112
|
-
if (!data) {
|
|
113
|
-
logger.warn({ opName }, 'mex notification has null data');
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
logger.debug({ opName }, 'processing mex notification');
|
|
117
|
-
switch (opName) {
|
|
118
|
-
case 'NotificationUserReachoutTimelockUpdate':
|
|
119
|
-
handleReachoutTimelockNotification(data);
|
|
120
|
-
break;
|
|
121
|
-
case 'MessageCappingInfoNotification':
|
|
122
|
-
handleMessageCappingNotification(data);
|
|
123
|
-
break;
|
|
124
|
-
// newsletter ops still use the legacy <mex> child structure
|
|
125
|
-
case 'NotificationNewsletterUpdate':
|
|
126
|
-
case 'NotificationLinkedProfilesUpdates':
|
|
127
|
-
case 'NotificationNewsletterAdminPromote':
|
|
128
|
-
case 'NotificationNewsletterAdminDemote':
|
|
129
|
-
case 'NotificationNewsletterUserSettingChange':
|
|
130
|
-
case 'NotificationNewsletterJoin':
|
|
131
|
-
case 'NotificationNewsletterLeave':
|
|
132
|
-
case 'NotificationNewsletterStateChange':
|
|
133
|
-
case 'NotificationNewsletterAdminMetadataUpdate':
|
|
134
|
-
case 'NotificationNewsletterOwnerUpdate':
|
|
135
|
-
case 'NotificationNewsletterAdminInviteRevoke':
|
|
136
|
-
case 'NotificationNewsletterWamoSubStatusChange':
|
|
137
|
-
case 'NotificationNewsletterBlockUser':
|
|
138
|
-
case 'NotificationNewsletterPaidPartnership':
|
|
139
|
-
case 'NotificationNewsletterMilestone':
|
|
140
|
-
case 'NewsletterResponseStateUpdate':
|
|
141
|
-
await handleLegacyMexNewsletterNotification(node);
|
|
142
|
-
break;
|
|
143
|
-
default:
|
|
144
|
-
logger.debug({ opName }, 'unhandled mex notification');
|
|
145
|
-
break;
|
|
146
|
-
}
|
|
147
|
-
return;
|
|
58
|
+
if (tag === 'message' && (0, WABinary_1.getBinaryNodeChild)({ tag, attrs, content }, 'unavailable')) {
|
|
59
|
+
stanza.attrs.from = authState.creds.me.id;
|
|
148
60
|
}
|
|
149
|
-
|
|
61
|
+
logger.debug({ recv: { tag, attrs }, sent: stanza.attrs }, 'sent ack');
|
|
62
|
+
await sendNode(stanza);
|
|
150
63
|
};
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
64
|
+
const offerCall = async (toJid, isVideo = false) => {
|
|
65
|
+
const callId = (0, crypto_1.randomBytes)(16).toString('hex').toUpperCase().substring(0, 64);
|
|
66
|
+
const offerContent = [];
|
|
67
|
+
offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '16000' }, content: undefined });
|
|
68
|
+
offerContent.push({ tag: 'audio', attrs: { enc: 'opus', rate: '8000' }, content: undefined });
|
|
69
|
+
if (isVideo) {
|
|
70
|
+
offerContent.push({
|
|
71
|
+
tag: 'video',
|
|
72
|
+
attrs: { enc: 'vp8', dec: 'vp8', orientation: '0', 'screen_width': '1920', 'screen_height': '1080', 'device_orientation': '0' },
|
|
73
|
+
content: undefined
|
|
74
|
+
});
|
|
156
75
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
76
|
+
offerContent.push({ tag: 'net', attrs: { medium: '3' }, content: undefined });
|
|
77
|
+
offerContent.push({ tag: 'capability', attrs: { ver: '1' }, content: new Uint8Array([1, 4, 255, 131, 207, 4]) });
|
|
78
|
+
offerContent.push({ tag: 'encopt', attrs: { keygen: '2' }, content: undefined });
|
|
79
|
+
const encKey = (0, crypto_1.randomBytes)(32);
|
|
80
|
+
const devices = (await getUSyncDevices([toJid], true, false)).map(({ user, device }) => (0, WABinary_1.jidEncode)(user, 's.whatsapp.net', device));
|
|
81
|
+
await assertSessions(devices, true);
|
|
82
|
+
const { nodes: destinations, shouldIncludeDeviceIdentity } = await createParticipantNodes(devices, {
|
|
83
|
+
call: {
|
|
84
|
+
callKey: new Uint8Array(encKey)
|
|
85
|
+
}
|
|
86
|
+
}, { count: '0' });
|
|
87
|
+
offerContent.push({ tag: 'destination', attrs: {}, content: destinations });
|
|
88
|
+
if (shouldIncludeDeviceIdentity) {
|
|
89
|
+
offerContent.push({
|
|
90
|
+
tag: 'device-identity',
|
|
91
|
+
attrs: {},
|
|
92
|
+
content: (0, Utils_1.encodeSignedDeviceIdentity)(authState.creds.account, true)
|
|
164
93
|
});
|
|
165
|
-
return;
|
|
166
94
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
95
|
+
const stanza = ({
|
|
96
|
+
tag: 'call',
|
|
97
|
+
attrs: {
|
|
98
|
+
id: await config.generateMessageIDV2() ?? (0, Utils_1.generateMessageIDV2)(),
|
|
99
|
+
to: toJid,
|
|
100
|
+
},
|
|
101
|
+
content: [{
|
|
102
|
+
tag: 'offer',
|
|
103
|
+
attrs: {
|
|
104
|
+
'call-id': callId,
|
|
105
|
+
'call-creator': authState.creds.me.id,
|
|
106
|
+
},
|
|
107
|
+
content: offerContent,
|
|
108
|
+
}],
|
|
181
109
|
});
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
logger.info({ payload }, 'received message capping update');
|
|
190
|
-
ev.emit('message-capping.update', payload);
|
|
191
|
-
};
|
|
192
|
-
const handleLegacyMexNewsletterNotification = async (node) => {
|
|
193
|
-
const mexNode = getBinaryNodeChild(node, 'mex');
|
|
194
|
-
const updateNode = mexNode?.content ? null : getBinaryNodeChild(node, 'update') || getAllBinaryNodeChildren(node)[0];
|
|
195
|
-
const payloadNode = mexNode?.content ? mexNode : updateNode;
|
|
196
|
-
if (!payloadNode?.content) {
|
|
197
|
-
logger.warn({ node: binaryNodeToString(node) }, 'invalid mex newsletter notification');
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
let data;
|
|
201
|
-
try {
|
|
202
|
-
const payloadContent = payloadNode.content;
|
|
203
|
-
if (Array.isArray(payloadContent)) {
|
|
204
|
-
logger.warn({ payloadNode }, 'invalid mex newsletter notification payload format');
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
const contentBuf = typeof payloadContent === 'string' ? Buffer.from(payloadContent, 'binary') : Buffer.from(payloadContent);
|
|
208
|
-
data = JSON.parse(contentBuf.toString());
|
|
209
|
-
}
|
|
210
|
-
catch (error) {
|
|
211
|
-
logger.error({ err: error, node: binaryNodeToString(node) }, 'failed to parse mex newsletter notification');
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
const operation = data?.operation ?? payloadNode?.attrs?.op_name;
|
|
215
|
-
let updates = data?.updates;
|
|
216
|
-
if (!updates) {
|
|
217
|
-
const linkedProfiles = data?.data?.xwa2_notify_linked_profiles;
|
|
218
|
-
if (linkedProfiles) {
|
|
219
|
-
updates = [linkedProfiles];
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
if (!updates || !operation) {
|
|
223
|
-
logger.warn({ data }, 'invalid mex newsletter notification content');
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
logger.info({ operation, updates }, 'got mex newsletter notification');
|
|
227
|
-
switch (operation) {
|
|
228
|
-
case 'NotificationNewsletterUpdate':
|
|
229
|
-
for (const update of updates) {
|
|
230
|
-
if (update.jid && update.settings && Object.keys(update.settings).length > 0) {
|
|
231
|
-
ev.emit('newsletter-settings.update', {
|
|
232
|
-
id: update.jid,
|
|
233
|
-
update: update.settings
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
break;
|
|
238
|
-
case 'NotificationNewsletterAdminPromote':
|
|
239
|
-
for (const update of updates) {
|
|
240
|
-
if (update.jid && update.user) {
|
|
241
|
-
ev.emit('newsletter-participants.update', {
|
|
242
|
-
id: update.jid,
|
|
243
|
-
author: node.attrs.from,
|
|
244
|
-
user: update.user,
|
|
245
|
-
new_role: 'ADMIN',
|
|
246
|
-
action: 'promote'
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
break;
|
|
251
|
-
case 'NotificationLinkedProfilesUpdates':
|
|
252
|
-
for (const update of updates) {
|
|
253
|
-
const lid = update?.jid;
|
|
254
|
-
const addedProfiles = Array.isArray(update?.added_profiles) ? update.added_profiles : [];
|
|
255
|
-
const mappings = [];
|
|
256
|
-
for (const profile of addedProfiles) {
|
|
257
|
-
const pn = typeof profile === 'string' ? profile : (profile?.pn ?? profile?.jid ?? null);
|
|
258
|
-
if (lid && pn) {
|
|
259
|
-
const mapping = { lid, pn };
|
|
260
|
-
ev.emit('lid-mapping.update', mapping);
|
|
261
|
-
mappings.push(mapping);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
await signalRepository.lidMapping.storeLIDPNMappings(mappings);
|
|
265
|
-
}
|
|
266
|
-
break;
|
|
267
|
-
default:
|
|
268
|
-
logger.info({ operation, data }, 'unhandled mex newsletter notification');
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
// Handles newsletter notifications
|
|
273
|
-
const handleNewsletterNotification = async (node) => {
|
|
274
|
-
const from = node.attrs.from;
|
|
275
|
-
const children = getAllBinaryNodeChildren(node);
|
|
276
|
-
const author = node.attrs.participant;
|
|
277
|
-
for (const child of children) {
|
|
278
|
-
logger.debug({ from, child }, 'got newsletter notification');
|
|
279
|
-
switch (child.tag) {
|
|
280
|
-
case 'reaction': {
|
|
281
|
-
const reactionUpdate = {
|
|
282
|
-
id: from,
|
|
283
|
-
server_id: child.attrs.message_id,
|
|
284
|
-
reaction: {
|
|
285
|
-
code: getBinaryNodeChildString(child, 'reaction'),
|
|
286
|
-
count: 1
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
ev.emit('newsletter.reaction', reactionUpdate);
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
case 'view': {
|
|
293
|
-
const viewUpdate = {
|
|
294
|
-
id: from,
|
|
295
|
-
server_id: child.attrs.message_id,
|
|
296
|
-
count: parseInt(child.content?.toString() || '0', 10)
|
|
297
|
-
};
|
|
298
|
-
ev.emit('newsletter.view', viewUpdate);
|
|
299
|
-
break;
|
|
300
|
-
}
|
|
301
|
-
case 'participant': {
|
|
302
|
-
const participantUpdate = {
|
|
303
|
-
id: from,
|
|
304
|
-
author,
|
|
305
|
-
user: child.attrs.jid,
|
|
306
|
-
action: child.attrs.action,
|
|
307
|
-
new_role: child.attrs.role
|
|
308
|
-
};
|
|
309
|
-
ev.emit('newsletter-participants.update', participantUpdate);
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
case 'update': {
|
|
313
|
-
const settingsNode = getBinaryNodeChild(child, 'settings');
|
|
314
|
-
if (settingsNode) {
|
|
315
|
-
const update = {};
|
|
316
|
-
const nameNode = getBinaryNodeChild(settingsNode, 'name');
|
|
317
|
-
if (nameNode?.content)
|
|
318
|
-
update.name = nameNode.content.toString();
|
|
319
|
-
const descriptionNode = getBinaryNodeChild(settingsNode, 'description');
|
|
320
|
-
if (descriptionNode?.content)
|
|
321
|
-
update.description = descriptionNode.content.toString();
|
|
322
|
-
ev.emit('newsletter-settings.update', {
|
|
323
|
-
id: from,
|
|
324
|
-
update
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
break;
|
|
328
|
-
}
|
|
329
|
-
case 'message': {
|
|
330
|
-
const plaintextNode = getBinaryNodeChild(child, 'plaintext');
|
|
331
|
-
if (plaintextNode?.content) {
|
|
332
|
-
try {
|
|
333
|
-
const contentBuf = typeof plaintextNode.content === 'string'
|
|
334
|
-
? Buffer.from(plaintextNode.content, 'binary')
|
|
335
|
-
: Buffer.from(plaintextNode.content);
|
|
336
|
-
const messageProto = proto.Message.decode(contentBuf).toJSON();
|
|
337
|
-
const fullMessage = proto.WebMessageInfo.fromObject({
|
|
338
|
-
key: {
|
|
339
|
-
remoteJid: from,
|
|
340
|
-
id: child.attrs.message_id || child.attrs.server_id,
|
|
341
|
-
fromMe: false // TODO: is this really true though
|
|
342
|
-
},
|
|
343
|
-
message: messageProto,
|
|
344
|
-
messageTimestamp: +child.attrs.t
|
|
345
|
-
}).toJSON();
|
|
346
|
-
await upsertMessage(fullMessage, 'append');
|
|
347
|
-
logger.debug('Processed plaintext newsletter message');
|
|
348
|
-
}
|
|
349
|
-
catch (error) {
|
|
350
|
-
logger.error({ error }, 'Failed to decode plaintext newsletter message');
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
break;
|
|
354
|
-
}
|
|
355
|
-
default:
|
|
356
|
-
logger.warn({ node, child }, 'Unknown newsletter notification child');
|
|
357
|
-
break;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
};
|
|
361
|
-
const sendMessageAck = async (node, errorCode) => {
|
|
362
|
-
const stanza = buildAckStanza(node, errorCode, authState.creds.me.id);
|
|
363
|
-
logger.debug({ recv: { tag: node.tag, attrs: node.attrs }, sent: stanza.attrs }, 'sent ack');
|
|
364
|
-
await sendNode(stanza);
|
|
110
|
+
await query(stanza);
|
|
111
|
+
return {
|
|
112
|
+
id: callId,
|
|
113
|
+
to: toJid
|
|
114
|
+
};
|
|
365
115
|
};
|
|
366
116
|
const rejectCall = async (callId, callFrom) => {
|
|
367
|
-
const stanza = {
|
|
117
|
+
const stanza = ({
|
|
368
118
|
tag: 'call',
|
|
369
119
|
attrs: {
|
|
370
120
|
from: authState.creds.me.id,
|
|
371
|
-
to: callFrom
|
|
121
|
+
to: callFrom,
|
|
372
122
|
},
|
|
373
|
-
content: [
|
|
374
|
-
{
|
|
123
|
+
content: [{
|
|
375
124
|
tag: 'reject',
|
|
376
125
|
attrs: {
|
|
377
126
|
'call-id': callId,
|
|
378
127
|
'call-creator': callFrom,
|
|
379
|
-
count: '0'
|
|
128
|
+
count: '0',
|
|
380
129
|
},
|
|
381
|
-
content: undefined
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
};
|
|
130
|
+
content: undefined,
|
|
131
|
+
}],
|
|
132
|
+
});
|
|
385
133
|
await query(stanza);
|
|
386
134
|
};
|
|
387
135
|
const sendRetryRequest = async (node, forceIncludeKeys = false) => {
|
|
388
|
-
const { fullMessage } = decodeMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '');
|
|
136
|
+
const { fullMessage } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '');
|
|
389
137
|
const { key: msgKey } = fullMessage;
|
|
390
138
|
const msgId = msgKey.id;
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
// Increment retry count using new system
|
|
399
|
-
const retryCount = messageRetryManager.incrementRetryCount(msgId);
|
|
400
|
-
// Use the new retry count for the rest of the logic
|
|
401
|
-
const key = `${msgId}:${msgKey?.participant}`;
|
|
402
|
-
await msgRetryCache.set(key, retryCount);
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
// Fallback to old system
|
|
406
|
-
const key = `${msgId}:${msgKey?.participant}`;
|
|
407
|
-
let retryCount = (await msgRetryCache.get(key)) || 0;
|
|
408
|
-
if (retryCount >= maxMsgRetryCount) {
|
|
409
|
-
logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
|
|
410
|
-
await msgRetryCache.del(key);
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
retryCount += 1;
|
|
414
|
-
await msgRetryCache.set(key, retryCount);
|
|
139
|
+
const key = `${msgId}:${msgKey === null || msgKey === void 0 ? void 0 : msgKey.participant}`;
|
|
140
|
+
let retryCount = msgRetryCache.get(key) || 0;
|
|
141
|
+
if (retryCount >= maxMsgRetryCount) {
|
|
142
|
+
logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
|
|
143
|
+
msgRetryCache.del(key);
|
|
144
|
+
return;
|
|
415
145
|
}
|
|
416
|
-
|
|
417
|
-
|
|
146
|
+
retryCount += 1;
|
|
147
|
+
msgRetryCache.set(key, retryCount);
|
|
418
148
|
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
if (enableAutoSessionRecreation && messageRetryManager && retryCount > 1) {
|
|
424
|
-
try {
|
|
425
|
-
// Check if we have a session with this JID
|
|
426
|
-
const sessionId = signalRepository.jidToSignalProtocolAddress(fromJid);
|
|
427
|
-
const hasSession = await signalRepository.validateSession(fromJid);
|
|
428
|
-
const result = messageRetryManager.shouldRecreateSession(fromJid, hasSession.exists);
|
|
429
|
-
shouldRecreateSession = result.recreate;
|
|
430
|
-
recreateReason = result.reason;
|
|
431
|
-
if (shouldRecreateSession) {
|
|
432
|
-
logger.debug({ fromJid, retryCount, reason: recreateReason }, 'recreating session for retry');
|
|
433
|
-
// Delete existing session to force recreation
|
|
434
|
-
await authState.keys.set({ session: { [sessionId]: null } });
|
|
435
|
-
forceIncludeKeys = true;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
catch (error) {
|
|
439
|
-
logger.warn({ error, fromJid }, 'failed to check session recreation');
|
|
440
|
-
}
|
|
149
|
+
if (retryCount === 1) {
|
|
150
|
+
//request a resend via phone
|
|
151
|
+
const msgId = await requestPlaceholderResend(msgKey);
|
|
152
|
+
logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
|
|
441
153
|
}
|
|
442
|
-
|
|
443
|
-
// Use new retry manager for phone requests if available
|
|
444
|
-
if (messageRetryManager) {
|
|
445
|
-
// Schedule phone request with delay (like whatsmeow)
|
|
446
|
-
messageRetryManager.schedulePhoneRequest(msgId, async () => {
|
|
447
|
-
try {
|
|
448
|
-
const requestId = await requestPlaceholderResend(msgKey);
|
|
449
|
-
logger.debug(`sendRetryRequest: requested placeholder resend (${requestId}) for message ${msgId} (scheduled)`);
|
|
450
|
-
}
|
|
451
|
-
catch (error) {
|
|
452
|
-
logger.warn({ error, msgId }, 'failed to send scheduled phone request');
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
// Fallback to immediate request
|
|
458
|
-
const msgId = await requestPlaceholderResend(msgKey);
|
|
459
|
-
logger.debug(`sendRetryRequest: requested placeholder resend for message ${msgId}`);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
const deviceIdentity = encodeSignedDeviceIdentity(account, true);
|
|
154
|
+
const deviceIdentity = (0, Utils_1.encodeSignedDeviceIdentity)(account, true);
|
|
463
155
|
await authState.keys.transaction(async () => {
|
|
464
156
|
const receipt = {
|
|
465
157
|
tag: 'receipt',
|
|
@@ -475,15 +167,13 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
475
167
|
count: retryCount.toString(),
|
|
476
168
|
id: node.attrs.id,
|
|
477
169
|
t: node.attrs.t,
|
|
478
|
-
v: '1'
|
|
479
|
-
// ADD ERROR FIELD
|
|
480
|
-
error: '0'
|
|
170
|
+
v: '1'
|
|
481
171
|
}
|
|
482
172
|
},
|
|
483
173
|
{
|
|
484
174
|
tag: 'registration',
|
|
485
175
|
attrs: {},
|
|
486
|
-
content: encodeBigEndian(authState.creds.registrationId)
|
|
176
|
+
content: (0, Utils_1.encodeBigEndian)(authState.creds.registrationId)
|
|
487
177
|
}
|
|
488
178
|
]
|
|
489
179
|
};
|
|
@@ -493,8 +183,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
493
183
|
if (node.attrs.participant) {
|
|
494
184
|
receipt.attrs.participant = node.attrs.participant;
|
|
495
185
|
}
|
|
496
|
-
if (retryCount > 1 || forceIncludeKeys
|
|
497
|
-
const { update, preKeys } = await getNextPreKeys(authState, 1);
|
|
186
|
+
if (retryCount > 1 || forceIncludeKeys) {
|
|
187
|
+
const { update, preKeys } = await (0, Utils_1.getNextPreKeys)(authState, 1);
|
|
498
188
|
const [keyId] = Object.keys(preKeys);
|
|
499
189
|
const key = preKeys[+keyId];
|
|
500
190
|
const content = receipt.content;
|
|
@@ -502,10 +192,10 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
502
192
|
tag: 'keys',
|
|
503
193
|
attrs: {},
|
|
504
194
|
content: [
|
|
505
|
-
{ tag: 'type', attrs: {}, content: Buffer.from(KEY_BUNDLE_TYPE) },
|
|
195
|
+
{ tag: 'type', attrs: {}, content: Buffer.from(Defaults_1.KEY_BUNDLE_TYPE) },
|
|
506
196
|
{ tag: 'identity', attrs: {}, content: identityKey.public },
|
|
507
|
-
xmppPreKey(key, +keyId),
|
|
508
|
-
xmppSignedPreKey(signedPreKey),
|
|
197
|
+
(0, Utils_1.xmppPreKey)(key, +keyId),
|
|
198
|
+
(0, Utils_1.xmppSignedPreKey)(signedPreKey),
|
|
509
199
|
{ tag: 'device-identity', attrs: {}, content: deviceIdentity }
|
|
510
200
|
]
|
|
511
201
|
});
|
|
@@ -513,119 +203,63 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
513
203
|
}
|
|
514
204
|
await sendNode(receipt);
|
|
515
205
|
logger.info({ msgAttrs: node.attrs, retryCount }, 'sent retry receipt');
|
|
516
|
-
}, authState?.creds?.me?.id || 'sendRetryRequest');
|
|
517
|
-
};
|
|
518
|
-
// Mirrors WAWeb/Handle/PreKeyLow.js: skip a re-issued notification with the same stanza id.
|
|
519
|
-
const inFlightPreKeyLow = new Set();
|
|
520
|
-
/**
|
|
521
|
-
* Fire-and-forget tctoken re-issuance after a peer's device identity changed.
|
|
522
|
-
* Mirrors WAWebSendTcTokenWhenDeviceIdentityChange — runs in parallel with
|
|
523
|
-
* the session refresh (not after it).
|
|
524
|
-
*/
|
|
525
|
-
const reissueTcTokenAfterIdentityChange = (from) => {
|
|
526
|
-
void (async () => {
|
|
527
|
-
const normalizedJid = jidNormalizedUser(from);
|
|
528
|
-
const tcJid = await resolveTcTokenJid(normalizedJid, getLIDForPN);
|
|
529
|
-
const tcTokenData = await authState.keys.get('tctoken', [tcJid]);
|
|
530
|
-
const senderTs = tcTokenData?.[tcJid]?.senderTimestamp;
|
|
531
|
-
if (senderTs === null || senderTs === undefined || isTcTokenExpired(senderTs)) {
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
logger.debug({ jid: normalizedJid, senderTimestamp: senderTs }, 'identity changed, re-issuing tctoken');
|
|
535
|
-
const getPNForLID = signalRepository.lidMapping.getPNForLID.bind(signalRepository.lidMapping);
|
|
536
|
-
const issueJid = await resolveIssuanceJid(normalizedJid, sock.serverProps.lidTrustedTokenIssueToLid, getLIDForPN, getPNForLID);
|
|
537
|
-
const result = await issuePrivacyTokens([issueJid], senderTs);
|
|
538
|
-
await storeTcTokensFromIqResult({
|
|
539
|
-
result,
|
|
540
|
-
fallbackJid: tcJid,
|
|
541
|
-
keys: authState.keys,
|
|
542
|
-
getLIDForPN,
|
|
543
|
-
onNewJidStored: trackTcTokenJid
|
|
544
|
-
});
|
|
545
|
-
})().catch(err => {
|
|
546
|
-
logger.debug({ jid: from, err: err?.message }, 'failed to re-issue tctoken after identity change');
|
|
547
206
|
});
|
|
548
207
|
};
|
|
549
208
|
const handleEncryptNotification = async (node) => {
|
|
550
209
|
const from = node.attrs.from;
|
|
551
|
-
if (from === S_WHATSAPP_NET) {
|
|
552
|
-
const
|
|
553
|
-
if (stanzaId && inFlightPreKeyLow.has(stanzaId)) {
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
const countChild = getBinaryNodeChild(node, 'count');
|
|
210
|
+
if (from === WABinary_1.S_WHATSAPP_NET) {
|
|
211
|
+
const countChild = (0, WABinary_1.getBinaryNodeChild)(node, 'count');
|
|
557
212
|
const count = +countChild.attrs.value;
|
|
558
|
-
const shouldUploadMorePreKeys = count < MIN_PREKEY_COUNT;
|
|
213
|
+
const shouldUploadMorePreKeys = count < Defaults_1.MIN_PREKEY_COUNT;
|
|
559
214
|
logger.debug({ count, shouldUploadMorePreKeys }, 'recv pre-key count');
|
|
560
215
|
if (shouldUploadMorePreKeys) {
|
|
561
|
-
|
|
562
|
-
inFlightPreKeyLow.add(stanzaId);
|
|
563
|
-
try {
|
|
564
|
-
await uploadPreKeys();
|
|
565
|
-
}
|
|
566
|
-
finally {
|
|
567
|
-
if (stanzaId)
|
|
568
|
-
inFlightPreKeyLow.delete(stanzaId);
|
|
569
|
-
}
|
|
216
|
+
await uploadPreKeys();
|
|
570
217
|
}
|
|
571
218
|
}
|
|
572
219
|
else {
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
onBeforeSessionRefresh: reissueTcTokenAfterIdentityChange
|
|
581
|
-
});
|
|
582
|
-
if (result.action === 'no_identity_node') {
|
|
220
|
+
const identityNode = (0, WABinary_1.getBinaryNodeChild)(node, 'identity');
|
|
221
|
+
if (identityNode) {
|
|
222
|
+
logger.info({ jid: from }, 'identity changed');
|
|
223
|
+
// not handling right now
|
|
224
|
+
// signal will override new identity anyway
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
583
227
|
logger.info({ node }, 'unknown encrypt notification');
|
|
584
228
|
}
|
|
585
229
|
}
|
|
586
230
|
};
|
|
587
|
-
const handleGroupNotification = (
|
|
588
|
-
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
const actingParticipantUsername = fullNode.attrs.participant_username;
|
|
592
|
-
const affectedParticipantLid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || actingParticipantLid;
|
|
593
|
-
const affectedParticipantPn = getBinaryNodeChild(child, 'participant')?.attrs?.phone_number || actingParticipantPn;
|
|
594
|
-
switch (child?.tag) {
|
|
231
|
+
const handleGroupNotification = (participant, child, msg) => {
|
|
232
|
+
var _a, _b, _c, _d;
|
|
233
|
+
const participantJid = ((_b = (_a = (0, WABinary_1.getBinaryNodeChild)(child, 'participant')) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b.jid) || participant;
|
|
234
|
+
switch (child === null || child === void 0 ? void 0 : child.tag) {
|
|
595
235
|
case 'create':
|
|
596
|
-
const metadata = extractGroupMetadata(child);
|
|
597
|
-
msg.messageStubType = WAMessageStubType.GROUP_CREATE;
|
|
236
|
+
const metadata = (0, groups_1.extractGroupMetadata)(child);
|
|
237
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_CREATE;
|
|
598
238
|
msg.messageStubParameters = [metadata.subject];
|
|
599
|
-
msg.key = { participant: metadata.owner
|
|
600
|
-
ev.emit('chats.upsert', [
|
|
601
|
-
{
|
|
239
|
+
msg.key = { participant: metadata.owner };
|
|
240
|
+
ev.emit('chats.upsert', [{
|
|
602
241
|
id: metadata.id,
|
|
603
242
|
name: metadata.subject,
|
|
604
|
-
conversationTimestamp: metadata.creation
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
ev.emit('groups.upsert', [
|
|
608
|
-
{
|
|
243
|
+
conversationTimestamp: metadata.creation,
|
|
244
|
+
}]);
|
|
245
|
+
ev.emit('groups.upsert', [{
|
|
609
246
|
...metadata,
|
|
610
|
-
author:
|
|
611
|
-
|
|
612
|
-
authorUsername: actingParticipantUsername
|
|
613
|
-
}
|
|
614
|
-
]);
|
|
247
|
+
author: participant
|
|
248
|
+
}]);
|
|
615
249
|
break;
|
|
616
250
|
case 'ephemeral':
|
|
617
251
|
case 'not_ephemeral':
|
|
618
252
|
msg.message = {
|
|
619
253
|
protocolMessage: {
|
|
620
|
-
type: proto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
|
|
254
|
+
type: WAProto_1.proto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
|
|
621
255
|
ephemeralExpiration: +(child.attrs.expiration || 0)
|
|
622
256
|
}
|
|
623
257
|
};
|
|
624
258
|
break;
|
|
625
259
|
case 'modify':
|
|
626
|
-
const oldNumber = getBinaryNodeChildren(child, 'participant').map(p => p.attrs.jid);
|
|
260
|
+
const oldNumber = (0, WABinary_1.getBinaryNodeChildren)(child, 'participant').map(p => p.attrs.jid);
|
|
627
261
|
msg.messageStubParameters = oldNumber || [];
|
|
628
|
-
msg.messageStubType = WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER;
|
|
262
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER;
|
|
629
263
|
break;
|
|
630
264
|
case 'promote':
|
|
631
265
|
case 'demote':
|
|
@@ -633,224 +267,126 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
633
267
|
case 'add':
|
|
634
268
|
case 'leave':
|
|
635
269
|
const stubType = `GROUP_PARTICIPANT_${child.tag.toUpperCase()}`;
|
|
636
|
-
msg.messageStubType = WAMessageStubType[stubType];
|
|
637
|
-
const participants = getBinaryNodeChildren(child, 'participant').map(
|
|
638
|
-
// TODO: Store LID MAPPINGS
|
|
639
|
-
return {
|
|
640
|
-
id: attrs.jid,
|
|
641
|
-
phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined,
|
|
642
|
-
lid: isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined,
|
|
643
|
-
username: attrs.participant_username || attrs.username || undefined,
|
|
644
|
-
admin: (attrs.type || null)
|
|
645
|
-
};
|
|
646
|
-
});
|
|
270
|
+
msg.messageStubType = Types_1.WAMessageStubType[stubType];
|
|
271
|
+
const participants = (0, WABinary_1.getBinaryNodeChildren)(child, 'participant').map(p => p.attrs.jid);
|
|
647
272
|
if (participants.length === 1 &&
|
|
648
273
|
// if recv. "remove" message and sender removed themselves
|
|
649
274
|
// mark as left
|
|
650
|
-
(areJidsSameUser(participants[0]
|
|
651
|
-
areJidsSameUser(participants[0].id, actingParticipantPn)) &&
|
|
275
|
+
(0, WABinary_1.areJidsSameUser)(participants[0], participant) &&
|
|
652
276
|
child.tag === 'remove') {
|
|
653
|
-
msg.messageStubType = WAMessageStubType.GROUP_PARTICIPANT_LEAVE;
|
|
277
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_LEAVE;
|
|
654
278
|
}
|
|
655
|
-
msg.messageStubParameters = participants
|
|
279
|
+
msg.messageStubParameters = participants;
|
|
656
280
|
break;
|
|
657
281
|
case 'subject':
|
|
658
|
-
msg.messageStubType = WAMessageStubType.GROUP_CHANGE_SUBJECT;
|
|
282
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT;
|
|
659
283
|
msg.messageStubParameters = [child.attrs.subject];
|
|
660
284
|
break;
|
|
661
285
|
case 'description':
|
|
662
|
-
const description = getBinaryNodeChild(child, 'body')
|
|
663
|
-
msg.messageStubType = WAMessageStubType.GROUP_CHANGE_DESCRIPTION;
|
|
286
|
+
const description = (_d = (_c = (0, WABinary_1.getBinaryNodeChild)(child, 'body')) === null || _c === void 0 ? void 0 : _c.content) === null || _d === void 0 ? void 0 : _d.toString();
|
|
287
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_DESCRIPTION;
|
|
664
288
|
msg.messageStubParameters = description ? [description] : undefined;
|
|
665
289
|
break;
|
|
666
290
|
case 'announcement':
|
|
667
291
|
case 'not_announcement':
|
|
668
|
-
msg.messageStubType = WAMessageStubType.GROUP_CHANGE_ANNOUNCE;
|
|
669
|
-
msg.messageStubParameters = [child.tag === 'announcement' ? 'on' : 'off'];
|
|
292
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE;
|
|
293
|
+
msg.messageStubParameters = [(child.tag === 'announcement') ? 'on' : 'off'];
|
|
670
294
|
break;
|
|
671
295
|
case 'locked':
|
|
672
296
|
case 'unlocked':
|
|
673
|
-
msg.messageStubType = WAMessageStubType.GROUP_CHANGE_RESTRICT;
|
|
674
|
-
msg.messageStubParameters = [child.tag === 'locked' ? 'on' : 'off'];
|
|
297
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_RESTRICT;
|
|
298
|
+
msg.messageStubParameters = [(child.tag === 'locked') ? 'on' : 'off'];
|
|
675
299
|
break;
|
|
676
300
|
case 'invite':
|
|
677
|
-
msg.messageStubType = WAMessageStubType.GROUP_CHANGE_INVITE_LINK;
|
|
301
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_INVITE_LINK;
|
|
678
302
|
msg.messageStubParameters = [child.attrs.code];
|
|
679
303
|
break;
|
|
680
304
|
case 'member_add_mode':
|
|
681
305
|
const addMode = child.content;
|
|
682
306
|
if (addMode) {
|
|
683
|
-
msg.messageStubType = WAMessageStubType.GROUP_MEMBER_ADD_MODE;
|
|
307
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBER_ADD_MODE;
|
|
684
308
|
msg.messageStubParameters = [addMode.toString()];
|
|
685
309
|
}
|
|
686
310
|
break;
|
|
687
311
|
case 'membership_approval_mode':
|
|
688
|
-
const approvalMode = getBinaryNodeChild(child, 'group_join');
|
|
312
|
+
const approvalMode = (0, WABinary_1.getBinaryNodeChild)(child, 'group_join');
|
|
689
313
|
if (approvalMode) {
|
|
690
|
-
msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE;
|
|
314
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE;
|
|
691
315
|
msg.messageStubParameters = [approvalMode.attrs.state];
|
|
692
316
|
}
|
|
693
317
|
break;
|
|
694
318
|
case 'created_membership_requests':
|
|
695
|
-
msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
|
|
696
|
-
msg.messageStubParameters = [
|
|
697
|
-
JSON.stringify({ lid: affectedParticipantLid, pn: affectedParticipantPn }),
|
|
698
|
-
'created',
|
|
699
|
-
child.attrs.request_method
|
|
700
|
-
];
|
|
319
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
|
|
320
|
+
msg.messageStubParameters = [participantJid, 'created', child.attrs.request_method];
|
|
701
321
|
break;
|
|
702
322
|
case 'revoked_membership_requests':
|
|
703
|
-
const isDenied = areJidsSameUser(
|
|
704
|
-
|
|
705
|
-
msg.
|
|
706
|
-
msg.messageStubParameters = [
|
|
707
|
-
JSON.stringify({ lid: affectedParticipantLid, pn: affectedParticipantPn }),
|
|
708
|
-
isDenied ? 'revoked' : 'rejected'
|
|
709
|
-
];
|
|
323
|
+
const isDenied = (0, WABinary_1.areJidsSameUser)(participantJid, participant);
|
|
324
|
+
msg.messageStubType = Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD;
|
|
325
|
+
msg.messageStubParameters = [participantJid, isDenied ? 'revoked' : 'rejected'];
|
|
710
326
|
break;
|
|
711
327
|
}
|
|
712
328
|
};
|
|
713
|
-
const handleDevicesNotification = async (node) => {
|
|
714
|
-
const [child] = getAllBinaryNodeChildren(node);
|
|
715
|
-
const from = jidNormalizedUser(node.attrs.from);
|
|
716
|
-
if (!child) {
|
|
717
|
-
logger.debug({ from }, 'devices notification missing child, skipping');
|
|
718
|
-
return;
|
|
719
|
-
}
|
|
720
|
-
const tag = child.tag;
|
|
721
|
-
const deviceHash = child.attrs.device_hash;
|
|
722
|
-
const devices = getBinaryNodeChildren(child, 'device');
|
|
723
|
-
if (areJidsSameUser(from, authState.creds.me.id) || areJidsSameUser(from, authState.creds.me.lid)) {
|
|
724
|
-
const deviceJids = devices.map(d => d.attrs.jid);
|
|
725
|
-
logger.info({ deviceJids }, 'got my own devices');
|
|
726
|
-
}
|
|
727
|
-
if (!devices.length) {
|
|
728
|
-
logger.debug({ from, tag }, 'no devices in notification, skipping');
|
|
729
|
-
return;
|
|
730
|
-
}
|
|
731
|
-
const decoded = [];
|
|
732
|
-
for (const d of devices) {
|
|
733
|
-
const jid = d.attrs.jid;
|
|
734
|
-
if (!jid)
|
|
735
|
-
continue;
|
|
736
|
-
const parts = jidDecode(jid);
|
|
737
|
-
if (!parts) {
|
|
738
|
-
logger.debug({ jid }, 'failed to decode device jid, skipping');
|
|
739
|
-
continue;
|
|
740
|
-
}
|
|
741
|
-
decoded.push({ jid, user: parts.user, server: parts.server, device: parts.device });
|
|
742
|
-
}
|
|
743
|
-
if (!decoded.length)
|
|
744
|
-
return;
|
|
745
|
-
await devicesMutex.mutex(async () => {
|
|
746
|
-
const byUser = new Map();
|
|
747
|
-
for (const d of decoded) {
|
|
748
|
-
const list = byUser.get(d.user) || [];
|
|
749
|
-
list.push(d);
|
|
750
|
-
byUser.set(d.user, list);
|
|
751
|
-
}
|
|
752
|
-
for (const [user, entries] of byUser) {
|
|
753
|
-
if (tag === 'update') {
|
|
754
|
-
logger.debug({ user }, `${user}'s device list updated, dropping cached devices`);
|
|
755
|
-
await userDevicesCache?.del(user);
|
|
756
|
-
continue;
|
|
757
|
-
}
|
|
758
|
-
if (tag === 'remove') {
|
|
759
|
-
await signalRepository.deleteSession(entries.map(e => e.jid));
|
|
760
|
-
}
|
|
761
|
-
const existingCache = (await userDevicesCache?.get(user)) || [];
|
|
762
|
-
if (!existingCache.length) {
|
|
763
|
-
// No baseline yet; skip applying the delta so getUSyncDevices can
|
|
764
|
-
// later fetch the full device list. Caching just the notification
|
|
765
|
-
// entries would make a partial list look authoritative.
|
|
766
|
-
logger.debug({ user, tag }, 'device list not cached, deferring to USync refresh');
|
|
767
|
-
continue;
|
|
768
|
-
}
|
|
769
|
-
const affected = new Set(entries.map(e => e.device));
|
|
770
|
-
let updatedDevices;
|
|
771
|
-
switch (tag) {
|
|
772
|
-
case 'add':
|
|
773
|
-
logger.info({ deviceHash, count: entries.length }, 'devices added');
|
|
774
|
-
updatedDevices = [
|
|
775
|
-
...existingCache.filter(d => !affected.has(d.device)),
|
|
776
|
-
...entries.map(e => ({ user: e.user, server: e.server, device: e.device }))
|
|
777
|
-
];
|
|
778
|
-
break;
|
|
779
|
-
case 'remove':
|
|
780
|
-
logger.info({ deviceHash, count: entries.length }, 'devices removed');
|
|
781
|
-
updatedDevices = existingCache.filter(d => !affected.has(d.device));
|
|
782
|
-
break;
|
|
783
|
-
default:
|
|
784
|
-
logger.debug({ tag }, 'Unknown device list change tag');
|
|
785
|
-
continue;
|
|
786
|
-
}
|
|
787
|
-
if (updatedDevices.length === 0) {
|
|
788
|
-
await userDevicesCache?.del(user);
|
|
789
|
-
}
|
|
790
|
-
else {
|
|
791
|
-
await userDevicesCache?.set(user, updatedDevices);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
});
|
|
795
|
-
};
|
|
796
329
|
const processNotification = async (node) => {
|
|
330
|
+
var _a, _b, _c;
|
|
797
331
|
const result = {};
|
|
798
|
-
const [child] = getAllBinaryNodeChildren(node);
|
|
332
|
+
const [child] = (0, WABinary_1.getAllBinaryNodeChildren)(node);
|
|
799
333
|
const nodeType = node.attrs.type;
|
|
800
|
-
const from = jidNormalizedUser(node.attrs.from);
|
|
334
|
+
const from = (0, WABinary_1.jidNormalizedUser)(node.attrs.from);
|
|
801
335
|
switch (nodeType) {
|
|
802
|
-
case '
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
336
|
+
case 'privacy_token':
|
|
337
|
+
const tokenList = (0, WABinary_1.getBinaryNodeChildren)(child, 'token');
|
|
338
|
+
for (const { attrs, content } of tokenList) {
|
|
339
|
+
const jid = attrs.jid;
|
|
340
|
+
ev.emit('chats.update', [
|
|
341
|
+
{
|
|
342
|
+
id: jid,
|
|
343
|
+
tcToken: content
|
|
344
|
+
}
|
|
345
|
+
]);
|
|
346
|
+
logger.debug({ jid }, 'got privacy token update');
|
|
347
|
+
}
|
|
807
348
|
break;
|
|
808
349
|
case 'w:gp2':
|
|
809
|
-
|
|
810
|
-
handleGroupNotification(node, child, result);
|
|
350
|
+
handleGroupNotification(node.attrs.participant, child, result);
|
|
811
351
|
break;
|
|
812
352
|
case 'mediaretry':
|
|
813
|
-
const event = decodeMediaRetryNode(node);
|
|
353
|
+
const event = (0, Utils_1.decodeMediaRetryNode)(node);
|
|
814
354
|
ev.emit('messages.media-update', [event]);
|
|
815
355
|
break;
|
|
816
356
|
case 'encrypt':
|
|
817
357
|
await handleEncryptNotification(node);
|
|
818
358
|
break;
|
|
819
359
|
case 'devices':
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
logger.error({ error, node }, 'failed to handle devices notification');
|
|
360
|
+
const devices = (0, WABinary_1.getBinaryNodeChildren)(child, 'device');
|
|
361
|
+
if ((0, WABinary_1.areJidsSameUser)(child.attrs.jid, authState.creds.me.id)) {
|
|
362
|
+
const deviceJids = devices.map(d => d.attrs.jid);
|
|
363
|
+
logger.info({ deviceJids }, 'got my own devices');
|
|
825
364
|
}
|
|
826
365
|
break;
|
|
827
366
|
case 'server_sync':
|
|
828
|
-
const update = getBinaryNodeChild(node, 'collection');
|
|
367
|
+
const update = (0, WABinary_1.getBinaryNodeChild)(node, 'collection');
|
|
829
368
|
if (update) {
|
|
830
369
|
const name = update.attrs.name;
|
|
831
370
|
await resyncAppState([name], false);
|
|
832
371
|
}
|
|
833
372
|
break;
|
|
834
373
|
case 'picture':
|
|
835
|
-
const setPicture = getBinaryNodeChild(node, 'set');
|
|
836
|
-
const delPicture = getBinaryNodeChild(node, 'delete');
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
{
|
|
840
|
-
id: jidNormalizedUser(node?.attrs?.from) || (setPicture || delPicture)?.attrs?.hash || '',
|
|
374
|
+
const setPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'set');
|
|
375
|
+
const delPicture = (0, WABinary_1.getBinaryNodeChild)(node, 'delete');
|
|
376
|
+
ev.emit('contacts.update', [{
|
|
377
|
+
id: (0, WABinary_1.jidNormalizedUser)((_a = node === null || node === void 0 ? void 0 : node.attrs) === null || _a === void 0 ? void 0 : _a.from) || ((_c = (_b = (setPicture || delPicture)) === null || _b === void 0 ? void 0 : _b.attrs) === null || _c === void 0 ? void 0 : _c.hash) || '',
|
|
841
378
|
imgUrl: setPicture ? 'changed' : 'removed'
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
if (isJidGroup(from)) {
|
|
379
|
+
}]);
|
|
380
|
+
if ((0, WABinary_1.isJidGroup)(from)) {
|
|
845
381
|
const node = setPicture || delPicture;
|
|
846
|
-
result.messageStubType = WAMessageStubType.GROUP_CHANGE_ICON;
|
|
382
|
+
result.messageStubType = Types_1.WAMessageStubType.GROUP_CHANGE_ICON;
|
|
847
383
|
if (setPicture) {
|
|
848
384
|
result.messageStubParameters = [setPicture.attrs.id];
|
|
849
385
|
}
|
|
850
|
-
result.participant = node
|
|
386
|
+
result.participant = node === null || node === void 0 ? void 0 : node.attrs.author;
|
|
851
387
|
result.key = {
|
|
852
|
-
...
|
|
853
|
-
participant: setPicture
|
|
388
|
+
...result.key || {},
|
|
389
|
+
participant: setPicture === null || setPicture === void 0 ? void 0 : setPicture.attrs.author
|
|
854
390
|
};
|
|
855
391
|
}
|
|
856
392
|
break;
|
|
@@ -864,48 +400,44 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
864
400
|
...authState.creds.accountSettings,
|
|
865
401
|
defaultDisappearingMode: {
|
|
866
402
|
ephemeralExpiration: newDuration,
|
|
867
|
-
ephemeralSettingTimestamp: timestamp
|
|
868
|
-
}
|
|
403
|
+
ephemeralSettingTimestamp: timestamp,
|
|
404
|
+
},
|
|
869
405
|
}
|
|
870
406
|
});
|
|
871
407
|
}
|
|
872
408
|
else if (child.tag === 'blocklist') {
|
|
873
|
-
const blocklists = getBinaryNodeChildren(child, 'item');
|
|
409
|
+
const blocklists = (0, WABinary_1.getBinaryNodeChildren)(child, 'item');
|
|
874
410
|
for (const { attrs } of blocklists) {
|
|
875
411
|
const blocklist = [attrs.jid];
|
|
876
|
-
const type = attrs.action === 'block' ? 'add' : 'remove';
|
|
412
|
+
const type = (attrs.action === 'block') ? 'add' : 'remove';
|
|
877
413
|
ev.emit('blocklist.update', { blocklist, type });
|
|
878
414
|
}
|
|
879
415
|
}
|
|
880
416
|
break;
|
|
881
417
|
case 'link_code_companion_reg':
|
|
882
|
-
const linkCodeCompanionReg = getBinaryNodeChild(node, 'link_code_companion_reg');
|
|
883
|
-
const ref = toRequiredBuffer(getBinaryNodeChildBuffer(linkCodeCompanionReg, 'link_code_pairing_ref'));
|
|
884
|
-
const primaryIdentityPublicKey = toRequiredBuffer(getBinaryNodeChildBuffer(linkCodeCompanionReg, 'primary_identity_pub'));
|
|
885
|
-
const primaryEphemeralPublicKeyWrapped = toRequiredBuffer(getBinaryNodeChildBuffer(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub'));
|
|
418
|
+
const linkCodeCompanionReg = (0, WABinary_1.getBinaryNodeChild)(node, 'link_code_companion_reg');
|
|
419
|
+
const ref = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_ref'));
|
|
420
|
+
const primaryIdentityPublicKey = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'primary_identity_pub'));
|
|
421
|
+
const primaryEphemeralPublicKeyWrapped = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub'));
|
|
886
422
|
const codePairingPublicKey = await decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
|
|
887
|
-
const companionSharedKey = Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey);
|
|
888
|
-
const random = randomBytes(32);
|
|
889
|
-
const linkCodeSalt = randomBytes(32);
|
|
890
|
-
const linkCodePairingExpanded = hkdf(companionSharedKey, 32, {
|
|
423
|
+
const companionSharedKey = Utils_1.Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey);
|
|
424
|
+
const random = (0, crypto_1.randomBytes)(32);
|
|
425
|
+
const linkCodeSalt = (0, crypto_1.randomBytes)(32);
|
|
426
|
+
const linkCodePairingExpanded = await (0, Utils_1.hkdf)(companionSharedKey, 32, {
|
|
891
427
|
salt: linkCodeSalt,
|
|
892
428
|
info: 'link_code_pairing_key_bundle_encryption_key'
|
|
893
429
|
});
|
|
894
|
-
const encryptPayload = Buffer.concat([
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
random
|
|
898
|
-
]);
|
|
899
|
-
const encryptIv = randomBytes(12);
|
|
900
|
-
const encrypted = aesEncryptGCM(encryptPayload, linkCodePairingExpanded, encryptIv, Buffer.alloc(0));
|
|
430
|
+
const encryptPayload = Buffer.concat([Buffer.from(authState.creds.signedIdentityKey.public), primaryIdentityPublicKey, random]);
|
|
431
|
+
const encryptIv = (0, crypto_1.randomBytes)(12);
|
|
432
|
+
const encrypted = (0, Utils_1.aesEncryptGCM)(encryptPayload, linkCodePairingExpanded, encryptIv, Buffer.alloc(0));
|
|
901
433
|
const encryptedPayload = Buffer.concat([linkCodeSalt, encryptIv, encrypted]);
|
|
902
|
-
const identitySharedKey = Curve.sharedKey(authState.creds.signedIdentityKey.private, primaryIdentityPublicKey);
|
|
434
|
+
const identitySharedKey = Utils_1.Curve.sharedKey(authState.creds.signedIdentityKey.private, primaryIdentityPublicKey);
|
|
903
435
|
const identityPayload = Buffer.concat([companionSharedKey, identitySharedKey, random]);
|
|
904
|
-
authState.creds.advSecretKey =
|
|
436
|
+
authState.creds.advSecretKey = (await (0, Utils_1.hkdf)(identityPayload, 32, { info: 'adv_secret' })).toString('base64');
|
|
905
437
|
await query({
|
|
906
438
|
tag: 'iq',
|
|
907
439
|
attrs: {
|
|
908
|
-
to: S_WHATSAPP_NET,
|
|
440
|
+
to: WABinary_1.S_WHATSAPP_NET,
|
|
909
441
|
type: 'set',
|
|
910
442
|
id: sock.generateMessageTag(),
|
|
911
443
|
xmlns: 'md'
|
|
@@ -915,7 +447,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
915
447
|
tag: 'link_code_companion_reg',
|
|
916
448
|
attrs: {
|
|
917
449
|
jid: authState.creds.me.id,
|
|
918
|
-
stage: 'companion_finish'
|
|
450
|
+
stage: 'companion_finish',
|
|
919
451
|
},
|
|
920
452
|
content: [
|
|
921
453
|
{
|
|
@@ -939,208 +471,52 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
939
471
|
});
|
|
940
472
|
authState.creds.registered = true;
|
|
941
473
|
ev.emit('creds.update', authState.creds);
|
|
942
|
-
break;
|
|
943
|
-
case 'privacy_token':
|
|
944
|
-
await handlePrivacyTokenNotification(node);
|
|
945
|
-
break;
|
|
946
474
|
}
|
|
947
475
|
if (Object.keys(result).length) {
|
|
948
476
|
return result;
|
|
949
477
|
}
|
|
950
478
|
};
|
|
951
|
-
/**
|
|
952
|
-
* In-memory cache of storage JIDs with stored tctokens, seeded from the persisted index.
|
|
953
|
-
* Used to coalesce writes during a session; pruning always re-reads the persisted index
|
|
954
|
-
* to cover writes made by other layers (e.g. history sync).
|
|
955
|
-
*/
|
|
956
|
-
const tcTokenKnownJids = new Set();
|
|
957
|
-
const tcTokenIndexLoaded = (async () => {
|
|
958
|
-
try {
|
|
959
|
-
const jids = await readTcTokenIndex(authState.keys);
|
|
960
|
-
for (const jid of jids)
|
|
961
|
-
tcTokenKnownJids.add(jid);
|
|
962
|
-
logger.debug({ count: tcTokenKnownJids.size }, 'loaded tctoken index');
|
|
963
|
-
}
|
|
964
|
-
catch (err) {
|
|
965
|
-
logger.warn({ err: err?.message }, 'failed to load tctoken index');
|
|
966
|
-
}
|
|
967
|
-
})();
|
|
968
|
-
let tcTokenIndexTimer;
|
|
969
|
-
async function flushTcTokenIndex() {
|
|
970
|
-
if (tcTokenIndexTimer) {
|
|
971
|
-
clearTimeout(tcTokenIndexTimer);
|
|
972
|
-
tcTokenIndexTimer = undefined;
|
|
973
|
-
}
|
|
974
|
-
// Merge with whatever is already persisted so we don't clobber writes from other
|
|
975
|
-
// paths (history sync, concurrent sessions on the same store).
|
|
976
|
-
const write = await buildMergedTcTokenIndexWrite(authState.keys, tcTokenKnownJids);
|
|
977
|
-
return authState.keys.set({ tctoken: write });
|
|
978
|
-
}
|
|
979
|
-
function scheduleTcTokenIndexSave() {
|
|
980
|
-
if (tcTokenIndexTimer) {
|
|
981
|
-
clearTimeout(tcTokenIndexTimer);
|
|
982
|
-
}
|
|
983
|
-
tcTokenIndexTimer = setTimeout(() => {
|
|
984
|
-
tcTokenIndexTimer = undefined;
|
|
985
|
-
flushTcTokenIndex().catch(err => {
|
|
986
|
-
logger.warn({ err: err?.message }, 'failed to save tctoken index');
|
|
987
|
-
});
|
|
988
|
-
}, 5000);
|
|
989
|
-
}
|
|
990
|
-
function trackTcTokenJid(jid) {
|
|
991
|
-
if (jid && jid !== TC_TOKEN_INDEX_KEY && !tcTokenKnownJids.has(jid)) {
|
|
992
|
-
tcTokenKnownJids.add(jid);
|
|
993
|
-
scheduleTcTokenIndexSave();
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
const handlePrivacyTokenNotification = async (node) => {
|
|
997
|
-
const tokensNode = getBinaryNodeChild(node, 'tokens');
|
|
998
|
-
if (!tokensNode)
|
|
999
|
-
return;
|
|
1000
|
-
const from = jidNormalizedUser(node.attrs.from);
|
|
1001
|
-
// WA Web uses: senderLid ?? toLid(from) for the storage key
|
|
1002
|
-
// The sender_lid attribute provides the LID directly when available
|
|
1003
|
-
const senderLid = node.attrs.sender_lid && isLidUser(jidNormalizedUser(node.attrs.sender_lid))
|
|
1004
|
-
? jidNormalizedUser(node.attrs.sender_lid)
|
|
1005
|
-
: undefined;
|
|
1006
|
-
const fallbackJid = senderLid ?? (await resolveTcTokenJid(from, getLIDForPN));
|
|
1007
|
-
logger.debug({ from, storageJid: fallbackJid }, 'processing privacy token notification');
|
|
1008
|
-
await storeTcTokensFromIqResult({
|
|
1009
|
-
result: node,
|
|
1010
|
-
fallbackJid,
|
|
1011
|
-
keys: authState.keys,
|
|
1012
|
-
getLIDForPN,
|
|
1013
|
-
onNewJidStored: trackTcTokenJid
|
|
1014
|
-
});
|
|
1015
|
-
};
|
|
1016
479
|
async function decipherLinkPublicKey(data) {
|
|
1017
480
|
const buffer = toRequiredBuffer(data);
|
|
1018
481
|
const salt = buffer.slice(0, 32);
|
|
1019
|
-
const secretKey = await derivePairingCodeKey(authState.creds.pairingCode, salt);
|
|
482
|
+
const secretKey = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
|
|
1020
483
|
const iv = buffer.slice(32, 48);
|
|
1021
484
|
const payload = buffer.slice(48, 80);
|
|
1022
|
-
return aesDecryptCTR(payload, secretKey, iv);
|
|
485
|
+
return (0, Utils_1.aesDecryptCTR)(payload, secretKey, iv);
|
|
1023
486
|
}
|
|
1024
487
|
function toRequiredBuffer(data) {
|
|
1025
488
|
if (data === undefined) {
|
|
1026
|
-
throw new Boom('Invalid buffer', { statusCode: 400 });
|
|
489
|
+
throw new boom_1.Boom('Invalid buffer', { statusCode: 400 });
|
|
1027
490
|
}
|
|
1028
491
|
return data instanceof Buffer ? data : Buffer.from(data);
|
|
1029
492
|
}
|
|
1030
|
-
const willSendMessageAgain =
|
|
493
|
+
const willSendMessageAgain = (id, participant) => {
|
|
1031
494
|
const key = `${id}:${participant}`;
|
|
1032
|
-
const retryCount =
|
|
495
|
+
const retryCount = msgRetryCache.get(key) || 0;
|
|
1033
496
|
return retryCount < maxMsgRetryCount;
|
|
1034
497
|
};
|
|
1035
|
-
const updateSendMessageAgainCount =
|
|
498
|
+
const updateSendMessageAgainCount = (id, participant) => {
|
|
1036
499
|
const key = `${id}:${participant}`;
|
|
1037
|
-
const newValue = (
|
|
1038
|
-
|
|
500
|
+
const newValue = (msgRetryCache.get(key) || 0) + 1;
|
|
501
|
+
msgRetryCache.set(key, newValue);
|
|
1039
502
|
};
|
|
1040
|
-
const sendMessagesAgain = async (key, ids, retryNode
|
|
503
|
+
const sendMessagesAgain = async (key, ids, retryNode) => {
|
|
504
|
+
var _a;
|
|
505
|
+
const msgs = await Promise.all(ids.map(id => getMessage({ ...key, id })));
|
|
1041
506
|
const remoteJid = key.remoteJid;
|
|
1042
507
|
const participant = key.participant || remoteJid;
|
|
1043
|
-
const retryCount = +retryNode.attrs.count || 1;
|
|
1044
|
-
const msgId = ids[0];
|
|
1045
|
-
// Try to get messages from cache first, then fallback to getMessage
|
|
1046
|
-
const msgs = [];
|
|
1047
|
-
for (const id of ids) {
|
|
1048
|
-
let msg;
|
|
1049
|
-
// Try to get from retry cache first if enabled
|
|
1050
|
-
if (messageRetryManager) {
|
|
1051
|
-
const cachedMsg = messageRetryManager.getRecentMessage(remoteJid, id);
|
|
1052
|
-
if (cachedMsg) {
|
|
1053
|
-
msg = cachedMsg.message;
|
|
1054
|
-
logger.debug({ jid: remoteJid, id }, 'found message in retry cache');
|
|
1055
|
-
// Mark retry as successful since we found the message
|
|
1056
|
-
messageRetryManager.markRetrySuccess(id);
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
// Fallback to getMessage if not found in cache
|
|
1060
|
-
if (!msg) {
|
|
1061
|
-
msg = await getMessage({ ...key, id });
|
|
1062
|
-
if (msg) {
|
|
1063
|
-
logger.debug({ jid: remoteJid, id }, 'found message via getMessage');
|
|
1064
|
-
// Also mark as successful if found via getMessage
|
|
1065
|
-
if (messageRetryManager) {
|
|
1066
|
-
messageRetryManager.markRetrySuccess(id);
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
msgs.push(msg);
|
|
1071
|
-
}
|
|
1072
508
|
// if it's the primary jid sending the request
|
|
1073
509
|
// just re-send the message to everyone
|
|
1074
510
|
// prevents the first message decryption failure
|
|
1075
|
-
const sendToAll = !jidDecode(participant)
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
const bundle = extractE2ESessionFromRetryReceipt(receiptNode);
|
|
1079
|
-
if (bundle) {
|
|
1080
|
-
try {
|
|
1081
|
-
await signalRepository.injectE2ESession({ jid: participant, session: bundle });
|
|
1082
|
-
injectedFromBundle = true;
|
|
1083
|
-
logger.debug({ participant, retryCount }, 'injected session from retry receipt key bundle');
|
|
1084
|
-
}
|
|
1085
|
-
catch (error) {
|
|
1086
|
-
logger.warn({ error, participant }, 'failed to inject session from retry receipt');
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
if (!injectedFromBundle) {
|
|
1090
|
-
const receivedRegId = getBinaryNodeChildUInt(receiptNode, 'registration', 4);
|
|
1091
|
-
if (typeof receivedRegId === 'number' && Number.isInteger(receivedRegId)) {
|
|
1092
|
-
const info = await signalRepository.getSessionInfo(participant);
|
|
1093
|
-
if (info && info.registrationId !== 0 && info.registrationId !== receivedRegId) {
|
|
1094
|
-
logger.info({ participant, stored: info.registrationId, received: receivedRegId }, 'reg id mismatch on retry without bundle, deleting session');
|
|
1095
|
-
await authState.keys.set({ session: { [sessionId]: null } });
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
const BASE_KEY_CHECK_RETRY = 2;
|
|
1100
|
-
if (msgId && messageRetryManager) {
|
|
1101
|
-
const info = await signalRepository.getSessionInfo(participant);
|
|
1102
|
-
if (info) {
|
|
1103
|
-
if (retryCount === BASE_KEY_CHECK_RETRY) {
|
|
1104
|
-
messageRetryManager.saveBaseKey(sessionId, msgId, info.baseKey);
|
|
1105
|
-
}
|
|
1106
|
-
else if (retryCount > BASE_KEY_CHECK_RETRY) {
|
|
1107
|
-
if (messageRetryManager.hasSameBaseKey(sessionId, msgId, info.baseKey)) {
|
|
1108
|
-
logger.warn({ participant, retryCount }, 'base key collision on retry, forcing fresh session');
|
|
1109
|
-
await authState.keys.set({ session: { [sessionId]: null } });
|
|
1110
|
-
}
|
|
1111
|
-
messageRetryManager.deleteBaseKey(sessionId, msgId);
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
let shouldRecreateSession = false;
|
|
1116
|
-
let recreateReason = '';
|
|
1117
|
-
if (enableAutoSessionRecreation && messageRetryManager && retryCount > 1 && !injectedFromBundle) {
|
|
1118
|
-
try {
|
|
1119
|
-
const hasSession = await signalRepository.validateSession(participant);
|
|
1120
|
-
const result = messageRetryManager.shouldRecreateSession(participant, hasSession.exists);
|
|
1121
|
-
shouldRecreateSession = result.recreate;
|
|
1122
|
-
recreateReason = result.reason;
|
|
1123
|
-
if (shouldRecreateSession) {
|
|
1124
|
-
logger.debug({ participant, retryCount, reason: recreateReason }, 'recreating session for outgoing retry');
|
|
1125
|
-
await authState.keys.set({ session: { [sessionId]: null } });
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
catch (error) {
|
|
1129
|
-
logger.warn({ error, participant }, 'failed to check session recreation for outgoing retry');
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
if (!injectedFromBundle) {
|
|
1133
|
-
await assertSessions([participant], true);
|
|
1134
|
-
}
|
|
1135
|
-
if (isJidGroup(remoteJid)) {
|
|
511
|
+
const sendToAll = !((_a = (0, WABinary_1.jidDecode)(participant)) === null || _a === void 0 ? void 0 : _a.device);
|
|
512
|
+
await assertSessions([participant], true);
|
|
513
|
+
if ((0, WABinary_1.isJidGroup)(remoteJid)) {
|
|
1136
514
|
await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } });
|
|
1137
515
|
}
|
|
1138
|
-
logger.debug({ participant, sendToAll
|
|
516
|
+
logger.debug({ participant, sendToAll }, 'forced new session for retry recp');
|
|
1139
517
|
for (const [i, msg] of msgs.entries()) {
|
|
1140
|
-
if (
|
|
1141
|
-
|
|
1142
|
-
if (msg && (await willSendMessageAgain(ids[i], participant))) {
|
|
1143
|
-
await updateSendMessageAgainCount(ids[i], participant);
|
|
518
|
+
if (msg) {
|
|
519
|
+
updateSendMessageAgainCount(ids[i], participant);
|
|
1144
520
|
const msgRelayOpts = { messageId: ids[i] };
|
|
1145
521
|
if (sendToAll) {
|
|
1146
522
|
msgRelayOpts.useUserDevicesCache = false;
|
|
@@ -1159,37 +535,45 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1159
535
|
}
|
|
1160
536
|
};
|
|
1161
537
|
const handleReceipt = async (node) => {
|
|
538
|
+
var _a, _b;
|
|
1162
539
|
const { attrs, content } = node;
|
|
1163
540
|
const isLid = attrs.from.includes('lid');
|
|
1164
|
-
const isNodeFromMe = areJidsSameUser(attrs.participant || attrs.from, isLid ? authState.creds.me
|
|
1165
|
-
const remoteJid = !isNodeFromMe || isJidGroup(attrs.from) ? attrs.from : attrs.recipient;
|
|
1166
|
-
const fromMe = !attrs.recipient || (
|
|
541
|
+
const isNodeFromMe = (0, WABinary_1.areJidsSameUser)(attrs.participant || attrs.from, isLid ? (_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.lid : (_b = authState.creds.me) === null || _b === void 0 ? void 0 : _b.id);
|
|
542
|
+
const remoteJid = !isNodeFromMe || (0, WABinary_1.isJidGroup)(attrs.from) ? attrs.from : attrs.recipient;
|
|
543
|
+
const fromMe = !attrs.recipient || (attrs.type === 'retry' && isNodeFromMe);
|
|
1167
544
|
const key = {
|
|
1168
545
|
remoteJid,
|
|
1169
546
|
id: '',
|
|
1170
547
|
fromMe,
|
|
1171
548
|
participant: attrs.participant
|
|
1172
549
|
};
|
|
550
|
+
if (shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
|
|
551
|
+
logger.debug({ remoteJid }, 'ignoring receipt from jid');
|
|
552
|
+
await sendMessageAck(node);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
1173
555
|
const ids = [attrs.id];
|
|
1174
556
|
if (Array.isArray(content)) {
|
|
1175
|
-
const items = getBinaryNodeChildren(content[0], 'item');
|
|
557
|
+
const items = (0, WABinary_1.getBinaryNodeChildren)(content[0], 'item');
|
|
1176
558
|
ids.push(...items.map(i => i.attrs.id));
|
|
1177
559
|
}
|
|
1178
560
|
try {
|
|
1179
561
|
await Promise.all([
|
|
1180
|
-
|
|
1181
|
-
const status = getStatusFromReceiptType(attrs.type);
|
|
562
|
+
processingMutex.mutex(async () => {
|
|
563
|
+
const status = (0, Utils_1.getStatusFromReceiptType)(attrs.type);
|
|
1182
564
|
if (typeof status !== 'undefined' &&
|
|
565
|
+
(
|
|
1183
566
|
// basically, we only want to know when a message from us has been delivered to/read by the other person
|
|
1184
567
|
// or another device of ours has read some messages
|
|
1185
|
-
|
|
1186
|
-
|
|
568
|
+
status >= WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ||
|
|
569
|
+
!isNodeFromMe)) {
|
|
570
|
+
if ((0, WABinary_1.isJidGroup)(remoteJid) || (0, WABinary_1.isJidStatusBroadcast)(remoteJid)) {
|
|
1187
571
|
if (attrs.participant) {
|
|
1188
|
-
const updateKey = status === proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
|
|
572
|
+
const updateKey = status === WAProto_1.proto.WebMessageInfo.Status.DELIVERY_ACK ? 'receiptTimestamp' : 'readTimestamp';
|
|
1189
573
|
ev.emit('message-receipt.update', ids.map(id => ({
|
|
1190
574
|
key: { ...key, id },
|
|
1191
575
|
receipt: {
|
|
1192
|
-
userJid: jidNormalizedUser(attrs.participant),
|
|
576
|
+
userJid: (0, WABinary_1.jidNormalizedUser)(attrs.participant),
|
|
1193
577
|
[updateKey]: +attrs.t
|
|
1194
578
|
}
|
|
1195
579
|
})));
|
|
@@ -1198,23 +582,22 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1198
582
|
else {
|
|
1199
583
|
ev.emit('messages.update', ids.map(id => ({
|
|
1200
584
|
key: { ...key, id },
|
|
1201
|
-
update: { status
|
|
585
|
+
update: { status }
|
|
1202
586
|
})));
|
|
1203
587
|
}
|
|
1204
588
|
}
|
|
1205
589
|
if (attrs.type === 'retry') {
|
|
1206
590
|
// correctly set who is asking for the retry
|
|
1207
591
|
key.participant = key.participant || attrs.from;
|
|
1208
|
-
const retryNode = getBinaryNodeChild(node, 'retry');
|
|
1209
|
-
if (
|
|
592
|
+
const retryNode = (0, WABinary_1.getBinaryNodeChild)(node, 'retry');
|
|
593
|
+
if (willSendMessageAgain(ids[0], key.participant)) {
|
|
1210
594
|
if (key.fromMe) {
|
|
1211
595
|
try {
|
|
1212
|
-
await updateSendMessageAgainCount(ids[0], key.participant);
|
|
1213
596
|
logger.debug({ attrs, key }, 'recv retry request');
|
|
1214
|
-
await sendMessagesAgain(key, ids, retryNode
|
|
597
|
+
await sendMessagesAgain(key, ids, retryNode);
|
|
1215
598
|
}
|
|
1216
599
|
catch (error) {
|
|
1217
|
-
logger.error({ key, ids, trace: error
|
|
600
|
+
logger.error({ key, ids, trace: error.stack }, 'error in sending message again');
|
|
1218
601
|
}
|
|
1219
602
|
}
|
|
1220
603
|
else {
|
|
@@ -1229,267 +612,219 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1229
612
|
]);
|
|
1230
613
|
}
|
|
1231
614
|
finally {
|
|
1232
|
-
await sendMessageAck(node)
|
|
615
|
+
await sendMessageAck(node);
|
|
1233
616
|
}
|
|
1234
617
|
};
|
|
1235
618
|
const handleNotification = async (node) => {
|
|
1236
619
|
const remoteJid = node.attrs.from;
|
|
620
|
+
if (shouldIgnoreJid(remoteJid) && remoteJid !== '@s.whatsapp.net') {
|
|
621
|
+
logger.debug({ remoteJid, id: node.attrs.id }, 'ignored notification');
|
|
622
|
+
await sendMessageAck(node);
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
1237
625
|
try {
|
|
1238
626
|
await Promise.all([
|
|
1239
|
-
|
|
627
|
+
processingMutex.mutex(async () => {
|
|
628
|
+
var _a;
|
|
1240
629
|
const msg = await processNotification(node);
|
|
1241
630
|
if (msg) {
|
|
1242
|
-
const fromMe = areJidsSameUser(node.attrs.participant || remoteJid, authState.creds.me.id);
|
|
1243
|
-
const { senderAlt: participantAlt, addressingMode } = extractAddressingContext(node);
|
|
631
|
+
const fromMe = (0, WABinary_1.areJidsSameUser)(node.attrs.participant || remoteJid, authState.creds.me.id);
|
|
1244
632
|
msg.key = {
|
|
1245
633
|
remoteJid,
|
|
1246
634
|
fromMe,
|
|
1247
635
|
participant: node.attrs.participant,
|
|
1248
|
-
participantAlt,
|
|
1249
|
-
participantUsername: node.attrs.participant_username,
|
|
1250
|
-
addressingMode,
|
|
1251
636
|
id: node.attrs.id,
|
|
1252
637
|
...(msg.key || {})
|
|
1253
638
|
};
|
|
1254
|
-
msg.participant
|
|
639
|
+
(_a = msg.participant) !== null && _a !== void 0 ? _a : (msg.participant = node.attrs.participant);
|
|
1255
640
|
msg.messageTimestamp = +node.attrs.t;
|
|
1256
|
-
const fullMsg = proto.WebMessageInfo.fromObject(msg);
|
|
641
|
+
const fullMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
|
|
1257
642
|
await upsertMessage(fullMsg, 'append');
|
|
1258
643
|
}
|
|
1259
644
|
})
|
|
1260
645
|
]);
|
|
1261
646
|
}
|
|
1262
647
|
finally {
|
|
1263
|
-
await sendMessageAck(node)
|
|
648
|
+
await sendMessageAck(node);
|
|
1264
649
|
}
|
|
1265
650
|
};
|
|
1266
651
|
const handleMessage = async (node) => {
|
|
1267
|
-
|
|
652
|
+
var _a, _b, _c;
|
|
653
|
+
if (shouldIgnoreJid(node.attrs.from) && node.attrs.from !== '@s.whatsapp.net') {
|
|
654
|
+
logger.debug({ key: node.attrs.key }, 'ignored message');
|
|
655
|
+
await sendMessageAck(node);
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
const encNode = (0, WABinary_1.getBinaryNodeChild)(node, 'enc');
|
|
1268
659
|
// TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
|
|
1269
|
-
if (encNode
|
|
660
|
+
if (encNode && encNode.attrs.type === 'msmsg') {
|
|
1270
661
|
logger.debug({ key: node.attrs.key }, 'ignored msmsg');
|
|
1271
|
-
await sendMessageAck(node
|
|
662
|
+
await sendMessageAck(node);
|
|
1272
663
|
return;
|
|
1273
664
|
}
|
|
1274
|
-
let
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
const
|
|
1278
|
-
|
|
1279
|
-
if (
|
|
1280
|
-
|
|
1281
|
-
const primaryJid = msg.key.participant || msg.key.remoteJid;
|
|
1282
|
-
if (altServer === 'lid') {
|
|
1283
|
-
if (!(await signalRepository.lidMapping.getPNForLID(alt))) {
|
|
1284
|
-
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: alt, pn: primaryJid }]);
|
|
1285
|
-
await signalRepository.migrateSession(primaryJid, alt);
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
else {
|
|
1289
|
-
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: primaryJid, pn: alt }]);
|
|
1290
|
-
await signalRepository.migrateSession(alt, primaryJid);
|
|
1291
|
-
}
|
|
665
|
+
let response;
|
|
666
|
+
if ((0, WABinary_1.getBinaryNodeChild)(node, 'unavailable') && !encNode) {
|
|
667
|
+
await sendMessageAck(node);
|
|
668
|
+
const { key } = (0, Utils_1.decodeMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '').fullMessage;
|
|
669
|
+
response = await requestPlaceholderResend(key);
|
|
670
|
+
if (response === 'RESOLVED') {
|
|
671
|
+
return;
|
|
1292
672
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
const messageAge = unixTimestampSeconds() - toNumber(msg.messageTimestamp);
|
|
1317
|
-
if (messageAge > PLACEHOLDER_MAX_AGE_SECONDS) {
|
|
1318
|
-
logger.debug({ msgId: msg.key.id, messageAge }, 'skipping placeholder resend for old message');
|
|
1319
|
-
acked = true;
|
|
1320
|
-
return sendMessageAck(node);
|
|
1321
|
-
}
|
|
1322
|
-
// Request the real content from the phone via placeholder resend PDO.
|
|
1323
|
-
// Upsert the CIPHERTEXT stub as a placeholder (like WA Web's processPlaceholderMsg),
|
|
1324
|
-
// and store the requestId in stubParameters[1] so users can correlate
|
|
1325
|
-
// with the incoming PDO response event.
|
|
1326
|
-
const cleanKey = {
|
|
1327
|
-
remoteJid: msg.key.remoteJid,
|
|
1328
|
-
fromMe: msg.key.fromMe,
|
|
1329
|
-
id: msg.key.id,
|
|
1330
|
-
participant: msg.key.participant
|
|
1331
|
-
};
|
|
1332
|
-
// Cache the original message metadata so the PDO response handler
|
|
1333
|
-
// can preserve key fields (LID details etc.) that the phone may omit
|
|
1334
|
-
const msgData = {
|
|
1335
|
-
key: msg.key,
|
|
1336
|
-
messageTimestamp: msg.messageTimestamp,
|
|
1337
|
-
pushName: msg.pushName,
|
|
1338
|
-
participant: msg.participant,
|
|
1339
|
-
verifiedBizName: msg.verifiedBizName
|
|
1340
|
-
};
|
|
1341
|
-
requestPlaceholderResend(cleanKey, msgData)
|
|
1342
|
-
.then(requestId => {
|
|
1343
|
-
if (requestId && requestId !== 'RESOLVED') {
|
|
1344
|
-
logger.debug({ msgId: msg.key.id, requestId }, 'requested placeholder resend for unavailable message');
|
|
1345
|
-
ev.emit('messages.update', [
|
|
1346
|
-
{
|
|
1347
|
-
key: msg.key,
|
|
1348
|
-
update: { messageStubParameters: [NO_MESSAGE_FOUND_ERROR_TEXT, requestId] }
|
|
1349
|
-
}
|
|
1350
|
-
]);
|
|
1351
|
-
}
|
|
1352
|
-
})
|
|
1353
|
-
.catch(err => {
|
|
1354
|
-
logger.warn({ err, msgId: msg.key.id }, 'failed to request placeholder resend for unavailable message');
|
|
1355
|
-
});
|
|
1356
|
-
acked = true;
|
|
1357
|
-
await sendMessageAck(node);
|
|
1358
|
-
// Don't return — fall through to upsertMessage so the stub is emitted
|
|
1359
|
-
}
|
|
1360
|
-
else {
|
|
1361
|
-
// Skip retry for expired status messages (>24h old)
|
|
1362
|
-
if (isJidStatusBroadcast(msg.key.remoteJid)) {
|
|
1363
|
-
const messageAge = unixTimestampSeconds() - toNumber(msg.messageTimestamp);
|
|
1364
|
-
if (messageAge > STATUS_EXPIRY_SECONDS) {
|
|
1365
|
-
logger.debug({ msgId: msg.key.id, messageAge, remoteJid: msg.key.remoteJid }, 'skipping retry for expired status message');
|
|
1366
|
-
acked = true;
|
|
1367
|
-
return sendMessageAck(node);
|
|
1368
|
-
}
|
|
673
|
+
logger.debug('received unavailable message, acked and requested resend from phone');
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
if (placeholderResendCache.get(node.attrs.id)) {
|
|
677
|
+
placeholderResendCache.del(node.attrs.id);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
const { fullMessage: msg, category, author, decrypt } = (0, Utils_1.decryptMessageNode)(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
|
|
681
|
+
if (response && ((_a = msg === null || msg === void 0 ? void 0 : msg.messageStubParameters) === null || _a === void 0 ? void 0 : _a[0]) === Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT) {
|
|
682
|
+
msg.messageStubParameters = [Utils_1.NO_MESSAGE_FOUND_ERROR_TEXT, response];
|
|
683
|
+
}
|
|
684
|
+
if (((_c = (_b = msg.message) === null || _b === void 0 ? void 0 : _b.protocolMessage) === null || _c === void 0 ? void 0 : _c.type) === WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER && node.attrs.sender_pn) {
|
|
685
|
+
ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn });
|
|
686
|
+
}
|
|
687
|
+
try {
|
|
688
|
+
await Promise.all([
|
|
689
|
+
processingMutex.mutex(async () => {
|
|
690
|
+
var _a;
|
|
691
|
+
await decrypt();
|
|
692
|
+
// message failed to decrypt
|
|
693
|
+
if (msg.messageStubType === WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT) {
|
|
694
|
+
if (((_a = msg === null || msg === void 0 ? void 0 : msg.messageStubParameters) === null || _a === void 0 ? void 0 : _a[0]) === Utils_1.MISSING_KEYS_ERROR_TEXT) {
|
|
695
|
+
return sendMessageAck(node, Utils_1.NACK_REASONS.ParsingError);
|
|
1369
696
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
try {
|
|
1374
|
-
if (!ws.isOpen) {
|
|
1375
|
-
logger.debug({ node }, 'Connection closed, skipping retry');
|
|
697
|
+
retryMutex.mutex(async () => {
|
|
698
|
+
if (ws.isOpen) {
|
|
699
|
+
if ((0, WABinary_1.getBinaryNodeChild)(node, 'unavailable')) {
|
|
1376
700
|
return;
|
|
1377
701
|
}
|
|
1378
|
-
const encNode = getBinaryNodeChild(node, 'enc');
|
|
702
|
+
const encNode = (0, WABinary_1.getBinaryNodeChild)(node, 'enc');
|
|
1379
703
|
await sendRetryRequest(node, !encNode);
|
|
1380
704
|
if (retryRequestDelayMs) {
|
|
1381
|
-
await delay(retryRequestDelayMs);
|
|
705
|
+
await (0, Utils_1.delay)(retryRequestDelayMs);
|
|
1382
706
|
}
|
|
1383
707
|
}
|
|
1384
|
-
|
|
1385
|
-
logger.
|
|
708
|
+
else {
|
|
709
|
+
logger.debug({ node }, 'connection closed, ignoring retry req');
|
|
1386
710
|
}
|
|
1387
|
-
acked = true;
|
|
1388
|
-
await sendMessageAck(node, NACK_REASONS.UnhandledError);
|
|
1389
711
|
});
|
|
1390
712
|
}
|
|
1391
|
-
|
|
1392
|
-
else {
|
|
1393
|
-
if (messageRetryManager && msg.key.id) {
|
|
1394
|
-
messageRetryManager.cancelPendingPhoneRequest(msg.key.id);
|
|
1395
|
-
}
|
|
1396
|
-
const isNewsletter = isJidNewsletter(msg.key.remoteJid);
|
|
1397
|
-
if (!isNewsletter) {
|
|
713
|
+
else {
|
|
1398
714
|
// no type in the receipt => message delivered
|
|
1399
715
|
let type = undefined;
|
|
1400
716
|
let participant = msg.key.participant;
|
|
1401
|
-
if (category === 'peer') {
|
|
1402
|
-
// special peer message
|
|
717
|
+
if (category === 'peer') { // special peer message
|
|
1403
718
|
type = 'peer_msg';
|
|
1404
719
|
}
|
|
1405
|
-
else if (msg.key.fromMe) {
|
|
1406
|
-
// message was sent by us from a different device
|
|
720
|
+
else if (msg.key.fromMe) { // message was sent by us from a different device
|
|
1407
721
|
type = 'sender';
|
|
1408
722
|
// need to specially handle this case
|
|
1409
|
-
if (
|
|
1410
|
-
participant = author;
|
|
723
|
+
if ((0, WABinary_1.isJidUser)(msg.key.remoteJid)) {
|
|
724
|
+
participant = author;
|
|
1411
725
|
}
|
|
1412
726
|
}
|
|
1413
727
|
else if (!sendActiveReceipts) {
|
|
1414
728
|
type = 'inactive';
|
|
1415
729
|
}
|
|
1416
|
-
acked = true;
|
|
1417
730
|
await sendReceipt(msg.key.remoteJid, participant, [msg.key.id], type);
|
|
1418
731
|
// send ack for history message
|
|
1419
|
-
const isAnyHistoryMsg = getHistoryMsg(msg.message);
|
|
732
|
+
const isAnyHistoryMsg = (0, Utils_1.getHistoryMsg)(msg.message);
|
|
1420
733
|
if (isAnyHistoryMsg) {
|
|
1421
|
-
const jid = jidNormalizedUser(msg.key.remoteJid);
|
|
1422
|
-
await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
|
|
734
|
+
const jid = (0, WABinary_1.jidNormalizedUser)(msg.key.remoteJid);
|
|
735
|
+
await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
|
|
1423
736
|
}
|
|
1424
737
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
}
|
|
1431
|
-
cleanMessage(msg, authState.creds.me.id, authState.creds.me.lid);
|
|
1432
|
-
await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
|
|
1433
|
-
});
|
|
738
|
+
(0, Utils_1.cleanMessage)(msg, authState.creds.me.id);
|
|
739
|
+
await sendMessageAck(node);
|
|
740
|
+
await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify');
|
|
741
|
+
})
|
|
742
|
+
]);
|
|
1434
743
|
}
|
|
1435
744
|
catch (error) {
|
|
1436
|
-
logger.error({ error, node
|
|
1437
|
-
if (!acked) {
|
|
1438
|
-
await sendMessageAck(node, NACK_REASONS.UnhandledError).catch(ackErr => logger.error({ ackErr }, 'failed to ack message after error'));
|
|
1439
|
-
}
|
|
745
|
+
logger.error({ error, node }, 'error in handling message');
|
|
1440
746
|
}
|
|
1441
747
|
};
|
|
1442
|
-
const
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
if (!infoChild) {
|
|
1447
|
-
throw new Boom('Missing call info in call node');
|
|
1448
|
-
}
|
|
1449
|
-
const status = getCallStatusFromNode(infoChild);
|
|
1450
|
-
const callId = infoChild.attrs['call-id'];
|
|
1451
|
-
const from = infoChild.attrs.from || infoChild.attrs['call-creator'];
|
|
1452
|
-
const call = {
|
|
1453
|
-
chatId: attrs.from,
|
|
1454
|
-
from,
|
|
1455
|
-
callerPn: infoChild.attrs['caller_pn'],
|
|
1456
|
-
id: callId,
|
|
1457
|
-
date: new Date(+attrs.t * 1000),
|
|
1458
|
-
offline: !!attrs.offline,
|
|
1459
|
-
status
|
|
1460
|
-
};
|
|
1461
|
-
if (status === 'relaylatency') {
|
|
1462
|
-
const latencyValue = infoChild.attrs.latency || infoChild.attrs['latency_ms'] || infoChild.attrs['latency-ms'];
|
|
1463
|
-
const latencyMs = latencyValue ? Number(latencyValue) : undefined;
|
|
1464
|
-
if (Number.isFinite(latencyMs)) {
|
|
1465
|
-
call.latencyMs = latencyMs;
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
if (status === 'offer') {
|
|
1469
|
-
call.isVideo = !!getBinaryNodeChild(infoChild, 'video');
|
|
1470
|
-
call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid'];
|
|
1471
|
-
call.groupJid = infoChild.attrs['group-jid'];
|
|
1472
|
-
await callOfferCache.set(call.id, call);
|
|
1473
|
-
}
|
|
1474
|
-
const existingCall = await callOfferCache.get(call.id);
|
|
1475
|
-
// use existing call info to populate this event
|
|
1476
|
-
if (existingCall) {
|
|
1477
|
-
call.isVideo = existingCall.isVideo;
|
|
1478
|
-
call.isGroup = existingCall.isGroup;
|
|
1479
|
-
call.callerPn = call.callerPn || existingCall.callerPn;
|
|
1480
|
-
}
|
|
1481
|
-
// delete data once call has ended
|
|
1482
|
-
if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
|
|
1483
|
-
await callOfferCache.del(call.id);
|
|
1484
|
-
}
|
|
1485
|
-
ev.emit('call', [call]);
|
|
748
|
+
const fetchMessageHistory = async (count, oldestMsgKey, oldestMsgTimestamp) => {
|
|
749
|
+
var _a;
|
|
750
|
+
if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
751
|
+
throw new boom_1.Boom('Not authenticated');
|
|
1486
752
|
}
|
|
1487
|
-
|
|
1488
|
-
|
|
753
|
+
const pdoMessage = {
|
|
754
|
+
historySyncOnDemandRequest: {
|
|
755
|
+
chatJid: oldestMsgKey.remoteJid,
|
|
756
|
+
oldestMsgFromMe: oldestMsgKey.fromMe,
|
|
757
|
+
oldestMsgId: oldestMsgKey.id,
|
|
758
|
+
oldestMsgTimestampMs: oldestMsgTimestamp,
|
|
759
|
+
onDemandMsgCount: count
|
|
760
|
+
},
|
|
761
|
+
peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.HISTORY_SYNC_ON_DEMAND
|
|
762
|
+
};
|
|
763
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
764
|
+
};
|
|
765
|
+
const requestPlaceholderResend = async (messageKey) => {
|
|
766
|
+
var _a;
|
|
767
|
+
if (!((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
768
|
+
throw new boom_1.Boom('Not authenticated');
|
|
1489
769
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
770
|
+
if (placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
|
|
771
|
+
logger.debug({ messageKey }, 'already requested resend');
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
775
|
+
placeholderResendCache.set(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id, true);
|
|
1492
776
|
}
|
|
777
|
+
await (0, Utils_1.delay)(5000);
|
|
778
|
+
if (!placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
|
|
779
|
+
logger.debug({ messageKey }, 'message received while resend requested');
|
|
780
|
+
return 'RESOLVED';
|
|
781
|
+
}
|
|
782
|
+
const pdoMessage = {
|
|
783
|
+
placeholderMessageResendRequest: [{
|
|
784
|
+
messageKey
|
|
785
|
+
}],
|
|
786
|
+
peerDataOperationRequestType: WAProto_1.proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
787
|
+
};
|
|
788
|
+
setTimeout(() => {
|
|
789
|
+
if (placeholderResendCache.get(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id)) {
|
|
790
|
+
logger.debug({ messageKey }, 'PDO message without response after 15 seconds. Phone possibly offline');
|
|
791
|
+
placeholderResendCache.del(messageKey === null || messageKey === void 0 ? void 0 : messageKey.id);
|
|
792
|
+
}
|
|
793
|
+
}, 15000);
|
|
794
|
+
return sendPeerDataOperationMessage(pdoMessage);
|
|
795
|
+
};
|
|
796
|
+
const handleCall = async (node) => {
|
|
797
|
+
const { attrs } = node;
|
|
798
|
+
const [infoChild] = (0, WABinary_1.getAllBinaryNodeChildren)(node);
|
|
799
|
+
const callId = infoChild.attrs['call-id'];
|
|
800
|
+
const from = infoChild.attrs.from || infoChild.attrs['call-creator'];
|
|
801
|
+
const status = (0, Utils_1.getCallStatusFromNode)(infoChild);
|
|
802
|
+
const call = {
|
|
803
|
+
chatId: attrs.from,
|
|
804
|
+
from,
|
|
805
|
+
id: callId,
|
|
806
|
+
date: new Date(+attrs.t * 1000),
|
|
807
|
+
offline: !!attrs.offline,
|
|
808
|
+
status,
|
|
809
|
+
};
|
|
810
|
+
if (status === 'offer') {
|
|
811
|
+
call.isVideo = !!(0, WABinary_1.getBinaryNodeChild)(infoChild, 'video');
|
|
812
|
+
call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid'];
|
|
813
|
+
call.groupJid = infoChild.attrs['group-jid'];
|
|
814
|
+
callOfferCache.set(call.id, call);
|
|
815
|
+
}
|
|
816
|
+
const existingCall = callOfferCache.get(call.id);
|
|
817
|
+
// use existing call info to populate this event
|
|
818
|
+
if (existingCall) {
|
|
819
|
+
call.isVideo = existingCall.isVideo;
|
|
820
|
+
call.isGroup = existingCall.isGroup;
|
|
821
|
+
}
|
|
822
|
+
// delete data once call has ended
|
|
823
|
+
if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
|
|
824
|
+
callOfferCache.del(call.id);
|
|
825
|
+
}
|
|
826
|
+
ev.emit('call', [call]);
|
|
827
|
+
await sendMessageAck(node);
|
|
1493
828
|
};
|
|
1494
829
|
const handleBadAck = async ({ attrs }) => {
|
|
1495
830
|
const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id };
|
|
@@ -1509,58 +844,15 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1509
844
|
// error in acknowledgement,
|
|
1510
845
|
// device could not display the message
|
|
1511
846
|
if (attrs.error) {
|
|
1512
|
-
|
|
1513
|
-
if (attrs.error === SERVER_ERROR_CODES.MessageAccountRestriction) {
|
|
1514
|
-
// 463 = 1:1 message missing privacy token (tctoken). Usually means the
|
|
1515
|
-
// account is restricted: WhatsApp blocks starting new chats but preserves
|
|
1516
|
-
// existing ones, since established chats already carry a tctoken.
|
|
1517
|
-
// WA Web prevents this client-side (disables the compose bar).
|
|
1518
|
-
// No retry — retrying counts as another "reach out" and worsens the restriction.
|
|
1519
|
-
logger.warn({ msgId: attrs.id, from: attrs.from }, 'error 463: account restricted or missing tctoken for contact');
|
|
1520
|
-
const ackFrom = attrs.from;
|
|
1521
|
-
if (ackFrom && !inFlight463Recoveries.has(ackFrom)) {
|
|
1522
|
-
inFlight463Recoveries.add(ackFrom);
|
|
1523
|
-
void (async () => {
|
|
1524
|
-
try {
|
|
1525
|
-
const getPNForLID = signalRepository.lidMapping.getPNForLID.bind(signalRepository.lidMapping);
|
|
1526
|
-
const tcStorageJid = await resolveTcTokenJid(ackFrom, getLIDForPN);
|
|
1527
|
-
const issueJid = await resolveIssuanceJid(ackFrom, sock.serverProps.lidTrustedTokenIssueToLid, getLIDForPN, getPNForLID);
|
|
1528
|
-
const result = await issuePrivacyTokens([issueJid], unixTimestampSeconds());
|
|
1529
|
-
await storeTcTokensFromIqResult({
|
|
1530
|
-
result,
|
|
1531
|
-
fallbackJid: tcStorageJid,
|
|
1532
|
-
keys: authState.keys,
|
|
1533
|
-
getLIDForPN,
|
|
1534
|
-
onNewJidStored: trackTcTokenJid
|
|
1535
|
-
});
|
|
1536
|
-
logger.debug({ from: ackFrom }, 'completed 463 token recovery issuance');
|
|
1537
|
-
}
|
|
1538
|
-
catch (err) {
|
|
1539
|
-
logger.debug({ from: ackFrom, err: err?.message }, 'failed 463 token recovery issuance');
|
|
1540
|
-
}
|
|
1541
|
-
finally {
|
|
1542
|
-
inFlight463Recoveries.delete(ackFrom);
|
|
1543
|
-
}
|
|
1544
|
-
})();
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
else if (attrs.error === SERVER_ERROR_CODES.SmaxInvalid) {
|
|
1548
|
-
logger.warn({ msgId: attrs.id, from: attrs.from }, 'smax-invalid (479): stanza rejected by server — likely stale device session or malformed addressing');
|
|
1549
|
-
}
|
|
1550
|
-
else if (isReachoutTimelocked) {
|
|
1551
|
-
// user is temporarily restricted, fetch current restriction details
|
|
1552
|
-
await fetchAccountReachoutTimelock().catch(err => logger.warn({ err }, 'failed to fetch reachout timelock'));
|
|
1553
|
-
logger.warn({ attrs }, 'received error in ack');
|
|
1554
|
-
}
|
|
1555
|
-
else {
|
|
1556
|
-
logger.warn({ attrs }, 'received error in ack');
|
|
1557
|
-
}
|
|
847
|
+
logger.warn({ attrs }, 'received error in ack');
|
|
1558
848
|
ev.emit('messages.update', [
|
|
1559
849
|
{
|
|
1560
850
|
key,
|
|
1561
851
|
update: {
|
|
1562
|
-
status: WAMessageStatus.ERROR,
|
|
1563
|
-
messageStubParameters:
|
|
852
|
+
status: Types_1.WAMessageStatus.ERROR,
|
|
853
|
+
messageStubParameters: [
|
|
854
|
+
attrs.error
|
|
855
|
+
]
|
|
1564
856
|
}
|
|
1565
857
|
}
|
|
1566
858
|
]);
|
|
@@ -1573,61 +865,69 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1573
865
|
await execTask();
|
|
1574
866
|
ev.flush();
|
|
1575
867
|
function execTask() {
|
|
1576
|
-
return exec(node, false)
|
|
868
|
+
return exec(node, false)
|
|
869
|
+
.catch(err => onUnexpectedError(err, identifier));
|
|
1577
870
|
}
|
|
1578
871
|
};
|
|
1579
|
-
const
|
|
1580
|
-
[
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
const
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
872
|
+
const makeOfflineNodeProcessor = () => {
|
|
873
|
+
const nodeProcessorMap = new Map([
|
|
874
|
+
['message', handleMessage],
|
|
875
|
+
['call', handleCall],
|
|
876
|
+
['receipt', handleReceipt],
|
|
877
|
+
['notification', handleNotification]
|
|
878
|
+
]);
|
|
879
|
+
const nodes = [];
|
|
880
|
+
let isProcessing = false;
|
|
881
|
+
const enqueue = (type, node) => {
|
|
882
|
+
nodes.push({ type, node });
|
|
883
|
+
if (isProcessing) {
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
isProcessing = true;
|
|
887
|
+
const promise = async () => {
|
|
888
|
+
while (nodes.length && ws.isOpen) {
|
|
889
|
+
const { type, node } = nodes.shift();
|
|
890
|
+
const nodeProcessor = nodeProcessorMap.get(type);
|
|
891
|
+
if (!nodeProcessor) {
|
|
892
|
+
onUnexpectedError(new Error(`unknown offline node type: ${type}`), 'processing offline node');
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
await nodeProcessor(node);
|
|
896
|
+
}
|
|
897
|
+
isProcessing = false;
|
|
898
|
+
};
|
|
899
|
+
promise().catch(error => onUnexpectedError(error, 'processing offline nodes'));
|
|
900
|
+
};
|
|
901
|
+
return { enqueue };
|
|
902
|
+
};
|
|
903
|
+
const offlineNodeProcessor = makeOfflineNodeProcessor();
|
|
904
|
+
const processNode = (type, node, identifier, exec) => {
|
|
1603
905
|
const isOffline = !!node.attrs.offline;
|
|
1604
906
|
if (isOffline) {
|
|
1605
907
|
offlineNodeProcessor.enqueue(type, node);
|
|
1606
908
|
}
|
|
1607
909
|
else {
|
|
1608
|
-
|
|
910
|
+
processNodeWithBuffer(node, identifier, exec);
|
|
1609
911
|
}
|
|
1610
912
|
};
|
|
1611
913
|
// recv a message
|
|
1612
|
-
ws.on('CB:message',
|
|
1613
|
-
|
|
914
|
+
ws.on('CB:message', (node) => {
|
|
915
|
+
processNode('message', node, 'processing message', handleMessage);
|
|
1614
916
|
});
|
|
1615
917
|
ws.on('CB:call', async (node) => {
|
|
1616
|
-
|
|
918
|
+
processNode('call', node, 'handling call', handleCall);
|
|
1617
919
|
});
|
|
1618
|
-
ws.on('CB:receipt',
|
|
1619
|
-
|
|
920
|
+
ws.on('CB:receipt', node => {
|
|
921
|
+
processNode('receipt', node, 'handling receipt', handleReceipt);
|
|
1620
922
|
});
|
|
1621
923
|
ws.on('CB:notification', async (node) => {
|
|
1622
|
-
|
|
924
|
+
processNode('notification', node, 'handling notification', handleNotification);
|
|
1623
925
|
});
|
|
1624
926
|
ws.on('CB:ack,class:message', (node) => {
|
|
1625
|
-
handleBadAck(node)
|
|
927
|
+
handleBadAck(node)
|
|
928
|
+
.catch(error => onUnexpectedError(error, 'handling bad ack'));
|
|
1626
929
|
});
|
|
1627
|
-
ev.on('call',
|
|
1628
|
-
if (!call) {
|
|
1629
|
-
return;
|
|
1630
|
-
}
|
|
930
|
+
ev.on('call', ([call]) => {
|
|
1631
931
|
// missed call + group call notification message generation
|
|
1632
932
|
if (call.status === 'timeout' || (call.status === 'offer' && call.isGroup)) {
|
|
1633
933
|
const msg = {
|
|
@@ -1636,137 +936,37 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1636
936
|
id: call.id,
|
|
1637
937
|
fromMe: false
|
|
1638
938
|
},
|
|
1639
|
-
messageTimestamp: unixTimestampSeconds(call.date)
|
|
939
|
+
messageTimestamp: (0, Utils_1.unixTimestampSeconds)(call.date),
|
|
1640
940
|
};
|
|
1641
941
|
if (call.status === 'timeout') {
|
|
1642
942
|
if (call.isGroup) {
|
|
1643
|
-
msg.messageStubType = call.isVideo
|
|
1644
|
-
? WAMessageStubType.CALL_MISSED_GROUP_VIDEO
|
|
1645
|
-
: WAMessageStubType.CALL_MISSED_GROUP_VOICE;
|
|
943
|
+
msg.messageStubType = call.isVideo ? Types_1.WAMessageStubType.CALL_MISSED_GROUP_VIDEO : Types_1.WAMessageStubType.CALL_MISSED_GROUP_VOICE;
|
|
1646
944
|
}
|
|
1647
945
|
else {
|
|
1648
|
-
msg.messageStubType = call.isVideo ? WAMessageStubType.CALL_MISSED_VIDEO : WAMessageStubType.CALL_MISSED_VOICE;
|
|
946
|
+
msg.messageStubType = call.isVideo ? Types_1.WAMessageStubType.CALL_MISSED_VIDEO : Types_1.WAMessageStubType.CALL_MISSED_VOICE;
|
|
1649
947
|
}
|
|
1650
948
|
}
|
|
1651
949
|
else {
|
|
1652
950
|
msg.message = { call: { callKey: Buffer.from(call.id) } };
|
|
1653
951
|
}
|
|
1654
|
-
const protoMsg = proto.WebMessageInfo.fromObject(msg);
|
|
1655
|
-
|
|
952
|
+
const protoMsg = WAProto_1.proto.WebMessageInfo.fromObject(msg);
|
|
953
|
+
upsertMessage(protoMsg, call.offline ? 'append' : 'notify');
|
|
1656
954
|
}
|
|
1657
955
|
});
|
|
1658
|
-
|
|
1659
|
-
let lastTcTokenPruneTs = 0;
|
|
1660
|
-
/** dedupe in-flight 463 recovery token issuance by target JID */
|
|
1661
|
-
const inFlight463Recoveries = new Set();
|
|
1662
|
-
ev.on('connection.update', ({ isOnline, connection }) => {
|
|
956
|
+
ev.on('connection.update', ({ isOnline }) => {
|
|
1663
957
|
if (typeof isOnline !== 'undefined') {
|
|
1664
958
|
sendActiveReceipts = isOnline;
|
|
1665
959
|
logger.trace(`sendActiveReceipts set to "${sendActiveReceipts}"`);
|
|
1666
960
|
}
|
|
1667
|
-
// Flush pending tctoken index save on disconnect to avoid writing after close
|
|
1668
|
-
if (connection === 'close' && tcTokenIndexTimer) {
|
|
1669
|
-
clearTimeout(tcTokenIndexTimer);
|
|
1670
|
-
tcTokenIndexTimer = undefined;
|
|
1671
|
-
// Best-effort flush — may fail if store is already closed
|
|
1672
|
-
try {
|
|
1673
|
-
void Promise.resolve(flushTcTokenIndex()).catch(() => { });
|
|
1674
|
-
}
|
|
1675
|
-
catch {
|
|
1676
|
-
/* ignore sync errors */
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
// Prune expired tctokens when coming online, at most once per 24 hours
|
|
1680
|
-
// Matches WA Web's CLEAN_TC_TOKENS task
|
|
1681
|
-
// Note: don't gate on tcTokenKnownJids.size — the index may still be loading
|
|
1682
|
-
if (isOnline) {
|
|
1683
|
-
const now = Date.now();
|
|
1684
|
-
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
1685
|
-
if (now - lastTcTokenPruneTs >= DAY_MS) {
|
|
1686
|
-
lastTcTokenPruneTs = now;
|
|
1687
|
-
void pruneExpiredTcTokens();
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
});
|
|
1691
|
-
registerSocketEndHandler(() => {
|
|
1692
|
-
if (!config.msgRetryCounterCache && msgRetryCache.close) {
|
|
1693
|
-
msgRetryCache.close();
|
|
1694
|
-
}
|
|
1695
|
-
if (!config.callOfferCache && callOfferCache.close) {
|
|
1696
|
-
callOfferCache.close();
|
|
1697
|
-
}
|
|
1698
|
-
identityAssertDebounce.close();
|
|
1699
|
-
sendActiveReceipts = false;
|
|
1700
961
|
});
|
|
1701
|
-
async function pruneExpiredTcTokens() {
|
|
1702
|
-
try {
|
|
1703
|
-
await tcTokenIndexLoaded;
|
|
1704
|
-
// Union with the persisted index picks up JIDs added by other layers
|
|
1705
|
-
// (history sync) without needing inter-module wiring.
|
|
1706
|
-
const persisted = await readTcTokenIndex(authState.keys);
|
|
1707
|
-
const allJids = new Set(tcTokenKnownJids);
|
|
1708
|
-
for (const jid of persisted)
|
|
1709
|
-
allJids.add(jid);
|
|
1710
|
-
if (!allJids.size)
|
|
1711
|
-
return;
|
|
1712
|
-
const jids = [...allJids];
|
|
1713
|
-
const allTokens = await authState.keys.get('tctoken', jids);
|
|
1714
|
-
const writes = {};
|
|
1715
|
-
const survivors = new Set();
|
|
1716
|
-
let mutated = 0;
|
|
1717
|
-
for (const jid of jids) {
|
|
1718
|
-
const entry = allTokens[jid];
|
|
1719
|
-
if (!entry) {
|
|
1720
|
-
// Tracked but nothing in store — drop from index.
|
|
1721
|
-
mutated++;
|
|
1722
|
-
continue;
|
|
1723
|
-
}
|
|
1724
|
-
const hasPeerToken = !!entry.token?.length;
|
|
1725
|
-
const peerTokenExpired = hasPeerToken && isTcTokenExpired(entry.timestamp);
|
|
1726
|
-
const hasSenderTs = entry.senderTimestamp !== undefined;
|
|
1727
|
-
const senderTsExpired = hasSenderTs && isTcTokenExpired(entry.senderTimestamp);
|
|
1728
|
-
const keepPeerToken = hasPeerToken && !peerTokenExpired;
|
|
1729
|
-
const keepSenderTs = hasSenderTs && !senderTsExpired;
|
|
1730
|
-
if (!keepPeerToken && !keepSenderTs) {
|
|
1731
|
-
writes[jid] = null;
|
|
1732
|
-
mutated++;
|
|
1733
|
-
}
|
|
1734
|
-
else if (peerTokenExpired && keepSenderTs) {
|
|
1735
|
-
writes[jid] = { token: Buffer.alloc(0), senderTimestamp: entry.senderTimestamp };
|
|
1736
|
-
survivors.add(jid);
|
|
1737
|
-
mutated++;
|
|
1738
|
-
}
|
|
1739
|
-
else {
|
|
1740
|
-
survivors.add(jid);
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
if (mutated === 0)
|
|
1744
|
-
return;
|
|
1745
|
-
await authState.keys.set({
|
|
1746
|
-
tctoken: {
|
|
1747
|
-
...writes,
|
|
1748
|
-
[TC_TOKEN_INDEX_KEY]: {
|
|
1749
|
-
token: Buffer.from(JSON.stringify([...survivors]))
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
});
|
|
1753
|
-
tcTokenKnownJids.clear();
|
|
1754
|
-
for (const jid of survivors)
|
|
1755
|
-
tcTokenKnownJids.add(jid);
|
|
1756
|
-
logger.debug({ mutated, remaining: survivors.size }, 'pruned expired tctokens');
|
|
1757
|
-
}
|
|
1758
|
-
catch (err) {
|
|
1759
|
-
logger.warn({ err: err?.message }, 'failed to prune expired tctokens');
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
962
|
return {
|
|
1763
963
|
...sock,
|
|
1764
964
|
sendMessageAck,
|
|
1765
965
|
sendRetryRequest,
|
|
966
|
+
offerCall,
|
|
1766
967
|
rejectCall,
|
|
1767
968
|
fetchMessageHistory,
|
|
1768
969
|
requestPlaceholderResend,
|
|
1769
|
-
messageRetryManager
|
|
1770
970
|
};
|
|
1771
971
|
};
|
|
1772
|
-
|
|
972
|
+
exports.makeMessagesRecvSocket = makeMessagesRecvSocket;
|