@pontalabs/baileys 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +267 -839
- package/WAProto/GenerateStatics.sh +3 -4
- package/WAProto/WAProto.proto +1215 -511
- package/WAProto/fix-imports.js +85 -0
- package/WAProto/index.d.ts +14017 -55
- package/WAProto/index.js +97689 -29
- package/engine-requirements.js +10 -0
- package/lib/Defaults/index.d.ts +72 -74
- package/lib/Defaults/index.d.ts.map +1 -0
- package/lib/Defaults/index.js +94 -108
- package/lib/Defaults/index.js.map +1 -0
- package/lib/Signal/Group/ciphertext-message.d.ts +8 -7
- package/lib/Signal/Group/ciphertext-message.d.ts.map +1 -0
- package/lib/Signal/Group/ciphertext-message.js +9 -16
- package/lib/Signal/Group/ciphertext-message.js.map +1 -0
- package/lib/Signal/Group/group-session-builder.d.ts +11 -13
- package/lib/Signal/Group/group-session-builder.d.ts.map +1 -0
- package/lib/Signal/Group/group-session-builder.js +19 -61
- package/lib/Signal/Group/group-session-builder.js.map +1 -0
- package/lib/Signal/Group/group_cipher.d.ts +14 -16
- package/lib/Signal/Group/group_cipher.d.ts.map +1 -0
- package/lib/Signal/Group/group_cipher.js +41 -70
- package/lib/Signal/Group/group_cipher.js.map +1 -0
- package/lib/Signal/Group/index.d.ts +12 -11
- package/lib/Signal/Group/index.d.ts.map +1 -0
- package/lib/Signal/Group/index.js +12 -61
- package/lib/Signal/Group/index.js.map +1 -0
- package/lib/Signal/Group/keyhelper.d.ts +9 -14
- package/lib/Signal/Group/keyhelper.d.ts.map +1 -0
- package/lib/Signal/Group/keyhelper.js +10 -58
- package/lib/Signal/Group/keyhelper.js.map +1 -0
- package/lib/Signal/Group/sender-chain-key.d.ts +13 -13
- package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -0
- package/lib/Signal/Group/sender-chain-key.js +13 -34
- package/lib/Signal/Group/sender-chain-key.js.map +1 -0
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -16
- package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +28 -36
- package/lib/Signal/Group/sender-key-distribution-message.js.map +1 -0
- package/lib/Signal/Group/sender-key-message.d.ts +18 -18
- package/lib/Signal/Group/sender-key-message.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-message.js +38 -45
- package/lib/Signal/Group/sender-key-message.js.map +1 -0
- package/lib/Signal/Group/sender-key-name.d.ts +14 -15
- package/lib/Signal/Group/sender-key-name.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-name.js +20 -31
- package/lib/Signal/Group/sender-key-name.js.map +1 -0
- package/lib/Signal/Group/sender-key-record.d.ts +24 -25
- package/lib/Signal/Group/sender-key-record.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-record.js +18 -35
- package/lib/Signal/Group/sender-key-record.js.map +1 -0
- package/lib/Signal/Group/sender-key-state.d.ts +29 -34
- package/lib/Signal/Group/sender-key-state.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-state.js +37 -100
- package/lib/Signal/Group/sender-key-state.js.map +1 -0
- package/lib/Signal/Group/sender-message-key.d.ts +11 -10
- package/lib/Signal/Group/sender-message-key.d.ts.map +1 -0
- package/lib/Signal/Group/sender-message-key.js +15 -22
- package/lib/Signal/Group/sender-message-key.js.map +1 -0
- package/lib/Signal/libsignal.d.ts +5 -8
- package/lib/Signal/libsignal.d.ts.map +1 -0
- package/lib/Signal/libsignal.js +288 -142
- package/lib/Signal/libsignal.js.map +1 -0
- package/lib/Signal/lid-mapping.d.ts +23 -28
- package/lib/Signal/lid-mapping.d.ts.map +1 -0
- package/lib/Signal/lid-mapping.js +277 -184
- package/lib/Signal/lid-mapping.js.map +1 -0
- package/lib/Socket/Client/index.d.ts +3 -2
- package/lib/Socket/Client/index.d.ts.map +1 -0
- package/lib/Socket/Client/index.js +3 -22
- package/lib/Socket/Client/index.js.map +1 -0
- package/lib/Socket/Client/types.d.ts +15 -15
- package/lib/Socket/Client/types.d.ts.map +1 -0
- package/lib/Socket/Client/types.js +8 -15
- package/lib/Socket/Client/types.js.map +1 -0
- package/lib/Socket/Client/websocket.d.ts +12 -12
- package/lib/Socket/Client/websocket.d.ts.map +1 -0
- package/lib/Socket/Client/websocket.js +29 -37
- package/lib/Socket/Client/websocket.js.map +1 -0
- package/lib/Socket/business.d.ts +208 -178
- package/lib/Socket/business.d.ts.map +1 -0
- package/lib/Socket/business.js +91 -127
- package/lib/Socket/business.js.map +1 -0
- package/lib/Socket/chats.d.ts +120 -93
- package/lib/Socket/chats.d.ts.map +1 -0
- package/lib/Socket/chats.js +727 -652
- package/lib/Socket/chats.js.map +1 -0
- package/lib/Socket/communities.d.ts +273 -0
- package/lib/Socket/communities.d.ts.map +1 -0
- package/lib/Socket/communities.js +431 -0
- package/lib/Socket/communities.js.map +1 -0
- package/lib/Socket/dugong.js +261 -0
- package/lib/Socket/dugong.js.bak +204 -0
- package/lib/Socket/groups.d.ts +143 -111
- package/lib/Socket/groups.d.ts.map +1 -0
- package/lib/Socket/groups.js +165 -177
- package/lib/Socket/groups.js.map +1 -0
- package/lib/Socket/index.d.ts +252 -183
- package/lib/Socket/index.d.ts.map +1 -0
- package/lib/Socket/index.js +38 -18
- package/lib/Socket/index.js.bak +44 -0
- package/lib/Socket/index.js.map +1 -0
- package/lib/Socket/messages-recv.d.ts +196 -167
- package/lib/Socket/messages-recv.d.ts.map +1 -0
- package/lib/Socket/messages-recv.js +1443 -1563
- package/lib/Socket/messages-recv.js.map +1 -0
- package/lib/Socket/messages-send.d.ts +192 -158
- package/lib/Socket/messages-send.d.ts.map +1 -0
- package/lib/Socket/messages-send.js +1102 -1208
- package/lib/Socket/messages-send.js.bak +1400 -0
- package/lib/Socket/messages-send.js.map +1 -0
- package/lib/Socket/mex.d.ts +3 -0
- package/lib/Socket/mex.d.ts.map +1 -0
- package/lib/Socket/mex.js +42 -0
- package/lib/Socket/mex.js.map +1 -0
- package/lib/Socket/newsletter.d.ts +163 -138
- package/lib/Socket/newsletter.d.ts.map +1 -0
- package/lib/Socket/newsletter.js +153 -249
- package/lib/Socket/newsletter.js.map +1 -0
- package/lib/Socket/socket.d.ts +50 -36
- package/lib/Socket/socket.d.ts.map +1 -0
- package/lib/Socket/socket.js +749 -820
- package/lib/Socket/socket.js.map +1 -0
- package/lib/Store/index.d.ts +4 -4
- package/lib/Store/index.d.ts.map +1 -0
- package/lib/Store/index.js +4 -24
- package/lib/Store/index.js.map +1 -0
- package/lib/Store/make-in-memory-store.d.ts +44 -104
- package/lib/Store/make-in-memory-store.d.ts.map +1 -0
- package/lib/Store/make-in-memory-store.js +199 -213
- package/lib/Store/make-in-memory-store.js.map +1 -0
- package/lib/Store/make-ordered-dictionary.d.ts +13 -12
- package/lib/Store/make-ordered-dictionary.d.ts.map +1 -0
- package/lib/Store/make-ordered-dictionary.js +38 -45
- package/lib/Store/make-ordered-dictionary.js.map +1 -0
- package/lib/Store/object-repository.d.ts +11 -10
- package/lib/Store/object-repository.d.ts.map +1 -0
- package/lib/Store/object-repository.js +9 -16
- package/lib/Store/object-repository.js.map +1 -0
- package/lib/Types/Auth.d.ts +93 -97
- package/lib/Types/Auth.d.ts.map +1 -0
- package/lib/Types/Auth.js +2 -3
- package/lib/Types/Auth.js.map +1 -0
- package/lib/Types/Bussines.d.ts +25 -0
- package/lib/Types/Bussines.d.ts.map +1 -0
- package/lib/Types/Bussines.js +2 -3
- package/lib/Types/Bussines.js.map +1 -0
- package/lib/Types/Call.d.ts +14 -13
- package/lib/Types/Call.d.ts.map +1 -0
- package/lib/Types/Call.js +2 -3
- package/lib/Types/Call.js.map +1 -0
- package/lib/Types/Chat.d.ts +78 -97
- package/lib/Types/Chat.d.ts.map +1 -0
- package/lib/Types/Chat.js +8 -9
- package/lib/Types/Chat.js.map +1 -0
- package/lib/Types/Contact.d.ts +12 -9
- package/lib/Types/Contact.d.ts.map +1 -0
- package/lib/Types/Contact.js +2 -3
- package/lib/Types/Contact.js.map +1 -0
- package/lib/Types/Events.d.ts +206 -176
- package/lib/Types/Events.d.ts.map +1 -0
- package/lib/Types/Events.js +2 -3
- package/lib/Types/Events.js.map +1 -0
- package/lib/Types/GroupMetadata.d.ts +53 -48
- package/lib/Types/GroupMetadata.d.ts.map +1 -0
- package/lib/Types/GroupMetadata.js +2 -3
- package/lib/Types/GroupMetadata.js.map +1 -0
- package/lib/Types/Label.d.ts +13 -14
- package/lib/Types/Label.d.ts.map +1 -0
- package/lib/Types/Label.js +24 -30
- package/lib/Types/Label.js.map +1 -0
- package/lib/Types/LabelAssociation.d.ts +15 -20
- package/lib/Types/LabelAssociation.d.ts.map +1 -0
- package/lib/Types/LabelAssociation.js +6 -12
- package/lib/Types/LabelAssociation.js.map +1 -0
- package/lib/Types/Message.d.ts +248 -412
- package/lib/Types/Message.d.ts.map +1 -0
- package/lib/Types/Message.js +17 -19
- package/lib/Types/Message.js.map +1 -0
- package/lib/Types/Mex.d.ts +141 -0
- package/lib/Types/Mex.d.ts.map +1 -0
- package/lib/Types/Mex.js +37 -0
- package/lib/Types/Mex.js.map +1 -0
- package/lib/Types/Product.d.ts +58 -71
- package/lib/Types/Product.d.ts.map +1 -0
- package/lib/Types/Product.js +2 -3
- package/lib/Types/Product.js.map +1 -0
- package/lib/Types/RichType.d.ts +3 -0
- package/lib/Types/RichType.d.ts.map +1 -0
- package/lib/Types/RichType.js +23 -0
- package/lib/Types/RichType.js.bak +23 -0
- package/lib/Types/RichType.js.map +1 -0
- package/lib/Types/Signal.d.ts +71 -82
- package/lib/Types/Signal.d.ts.map +1 -0
- package/lib/Types/Signal.js +2 -3
- package/lib/Types/Signal.js.map +1 -0
- package/lib/Types/Socket.d.ts +76 -81
- package/lib/Types/Socket.d.ts.map +1 -0
- package/lib/Types/Socket.js +3 -3
- package/lib/Types/Socket.js.map +1 -0
- package/lib/Types/State.d.ts +75 -19
- package/lib/Types/State.d.ts.map +1 -0
- package/lib/Types/State.js +56 -14
- package/lib/Types/State.js.map +1 -0
- package/lib/Types/USync.d.ts +8 -8
- package/lib/Types/USync.d.ts.map +1 -0
- package/lib/Types/USync.js +2 -3
- package/lib/Types/USync.js.map +1 -0
- package/lib/Types/index.d.ts +47 -62
- package/lib/Types/index.d.ts.map +1 -0
- package/lib/Types/index.js +26 -50
- package/lib/Types/index.js.map +1 -0
- package/lib/Utils/auth-utils.d.ts +13 -10
- package/lib/Utils/auth-utils.d.ts.map +1 -0
- package/lib/Utils/auth-utils.js +213 -472
- package/lib/Utils/auth-utils.js.map +1 -0
- package/lib/Utils/browser-utils.d.ts +4 -0
- package/lib/Utils/browser-utils.d.ts.map +1 -0
- package/lib/Utils/browser-utils.js +28 -0
- package/lib/Utils/browser-utils.js.map +1 -0
- package/lib/Utils/business.d.ts +14 -20
- package/lib/Utils/business.d.ts.map +1 -0
- package/lib/Utils/business.js +110 -134
- package/lib/Utils/business.js.map +1 -0
- package/lib/Utils/chat-utils.d.ts +88 -70
- package/lib/Utils/chat-utils.d.ts.map +1 -0
- package/lib/Utils/chat-utils.js +466 -403
- package/lib/Utils/chat-utils.js.map +1 -0
- package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
- package/lib/Utils/companion-reg-client-utils.d.ts.map +1 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/companion-reg-client-utils.js.map +1 -0
- package/lib/Utils/crypto.d.ts +27 -46
- package/lib/Utils/crypto.d.ts.map +1 -0
- package/lib/Utils/crypto.js +117 -188
- package/lib/Utils/crypto.js.map +1 -0
- package/lib/Utils/decode-wa-message.d.ts +58 -45
- package/lib/Utils/decode-wa-message.d.ts.map +1 -0
- package/lib/Utils/decode-wa-message.js +213 -303
- package/lib/Utils/decode-wa-message.js.map +1 -0
- package/lib/Utils/event-buffer.d.ts +14 -17
- package/lib/Utils/event-buffer.d.ts.map +1 -0
- package/lib/Utils/event-buffer.js +321 -296
- package/lib/Utils/event-buffer.js.map +1 -0
- package/lib/Utils/generics.d.ts +66 -92
- package/lib/Utils/generics.d.ts.map +1 -0
- package/lib/Utils/generics.js +270 -436
- package/lib/Utils/generics.js.map +1 -0
- package/lib/Utils/history.d.ts +24 -23
- package/lib/Utils/history.d.ts.map +1 -0
- package/lib/Utils/history.js +106 -76
- package/lib/Utils/history.js.map +1 -0
- package/lib/Utils/identity-change-handler.d.ts +44 -0
- package/lib/Utils/identity-change-handler.d.ts.map +1 -0
- package/lib/Utils/identity-change-handler.js +50 -0
- package/lib/Utils/identity-change-handler.js.map +1 -0
- package/lib/Utils/index.d.ts +24 -21
- package/lib/Utils/index.d.ts.map +1 -0
- package/lib/Utils/index.js +24 -41
- package/lib/Utils/index.js.map +1 -0
- package/lib/Utils/link-preview.d.ts +12 -14
- package/lib/Utils/link-preview.d.ts.map +1 -0
- package/lib/Utils/link-preview.js +40 -75
- package/lib/Utils/link-preview.js.map +1 -0
- package/lib/Utils/logger.d.ts +10 -11
- package/lib/Utils/logger.d.ts.map +1 -0
- package/lib/Utils/logger.js +3 -7
- package/lib/Utils/logger.js.map +1 -0
- package/lib/Utils/lt-hash.d.ts +8 -14
- package/lib/Utils/lt-hash.d.ts.map +1 -0
- package/lib/Utils/lt-hash.js +3 -53
- package/lib/Utils/lt-hash.js.map +1 -0
- package/lib/Utils/make-mutex.d.ts +7 -7
- package/lib/Utils/make-mutex.d.ts.map +1 -0
- package/lib/Utils/make-mutex.js +28 -44
- package/lib/Utils/make-mutex.js.map +1 -0
- package/lib/Utils/message-retry-manager.d.ts +115 -88
- package/lib/Utils/message-retry-manager.d.ts.map +1 -0
- package/lib/Utils/message-retry-manager.js +265 -160
- package/lib/Utils/message-retry-manager.js.map +1 -0
- package/lib/Utils/messages-media.d.ts +105 -107
- package/lib/Utils/messages-media.d.ts.map +1 -0
- package/lib/Utils/messages-media.js +548 -619
- package/lib/Utils/messages-media.js.bak +786 -0
- package/lib/Utils/messages-media.js.map +1 -0
- package/lib/Utils/messages.d.ts +52 -66
- package/lib/Utils/messages.d.ts.map +1 -0
- package/lib/Utils/messages.js +1730 -1558
- package/lib/Utils/messages.js.backup +1768 -0
- package/lib/Utils/messages.js.bak +1809 -0
- package/lib/Utils/messages.js.bak2 +893 -0
- package/lib/Utils/messages.js.bak3 +1183 -0
- package/lib/Utils/messages.js.map +1 -0
- package/lib/Utils/noise-handler.d.ts +18 -18
- package/lib/Utils/noise-handler.d.ts.map +1 -0
- package/lib/Utils/noise-handler.js +176 -130
- package/lib/Utils/noise-handler.js.map +1 -0
- package/lib/Utils/offline-node-processor.d.ts +17 -0
- package/lib/Utils/offline-node-processor.d.ts.map +1 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/offline-node-processor.js.map +1 -0
- package/lib/Utils/pre-key-manager.d.ts +28 -0
- package/lib/Utils/pre-key-manager.d.ts.map +1 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/pre-key-manager.js.map +1 -0
- package/lib/Utils/process-message.d.ts +43 -32
- package/lib/Utils/process-message.d.ts.map +1 -0
- package/lib/Utils/process-message.js +484 -282
- package/lib/Utils/process-message.js.map +1 -0
- package/lib/Utils/reporting-utils.d.ts +11 -0
- package/lib/Utils/reporting-utils.d.ts.map +1 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/reporting-utils.js.map +1 -0
- package/lib/Utils/rich-message-utils.d.ts +49 -0
- package/lib/Utils/rich-message-utils.d.ts.map +1 -0
- package/lib/Utils/rich-message-utils.js +1220 -724
- package/lib/Utils/rich-message-utils.js.backup +706 -0
- package/lib/Utils/rich-message-utils.js.bak +246 -0
- package/lib/Utils/rich-message-utils.js.map +1 -0
- package/lib/Utils/rich-message-utils.js.original +1332 -0
- package/lib/Utils/signal.d.ts +37 -32
- package/lib/Utils/signal.d.ts.map +1 -0
- package/lib/Utils/signal.js +140 -105
- package/lib/Utils/signal.js.map +1 -0
- package/lib/Utils/stanza-ack.d.ts +11 -0
- package/lib/Utils/stanza-ack.d.ts.map +1 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/stanza-ack.js.map +1 -0
- package/lib/Utils/sync-action-utils.d.ts +19 -0
- package/lib/Utils/sync-action-utils.d.ts.map +1 -0
- package/lib/Utils/sync-action-utils.js +49 -0
- package/lib/Utils/sync-action-utils.js.map +1 -0
- package/lib/Utils/tc-token-utils.d.ts +37 -0
- package/lib/Utils/tc-token-utils.d.ts.map +1 -0
- package/lib/Utils/tc-token-utils.js +163 -0
- package/lib/Utils/tc-token-utils.js.map +1 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts +5 -5
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -0
- package/lib/Utils/use-multi-file-auth-state.js +70 -120
- package/lib/Utils/use-multi-file-auth-state.js.map +1 -0
- package/lib/Utils/use-single-file-auth-state.d.ts +11 -13
- package/lib/Utils/use-single-file-auth-state.d.ts.map +1 -0
- package/lib/Utils/use-single-file-auth-state.js +92 -66
- package/lib/Utils/use-single-file-auth-state.js.map +1 -0
- package/lib/Utils/use-sqlite-auth-state.d.ts +11 -0
- package/lib/Utils/use-sqlite-auth-state.d.ts.map +1 -0
- package/lib/Utils/use-sqlite-auth-state.js +109 -0
- package/lib/Utils/use-sqlite-auth-state.js.map +1 -0
- package/lib/Utils/validate-connection.d.ts +11 -13
- package/lib/Utils/validate-connection.d.ts.map +1 -0
- package/lib/Utils/validate-connection.js +128 -113
- package/lib/Utils/validate-connection.js.map +1 -0
- package/lib/WABinary/constants.d.ts +25 -27
- package/lib/WABinary/constants.d.ts.map +1 -0
- package/lib/WABinary/constants.js +1451 -1292
- package/lib/WABinary/constants.js.bak +1373 -0
- package/lib/WABinary/constants.js.map +1 -0
- package/lib/WABinary/decode.d.ts +7 -9
- package/lib/WABinary/decode.d.ts.map +1 -0
- package/lib/WABinary/decode.js +163 -189
- package/lib/WABinary/decode.js.map +1 -0
- package/lib/WABinary/encode.d.ts +3 -3
- package/lib/WABinary/encode.d.ts.map +1 -0
- package/lib/WABinary/encode.js +110 -155
- package/lib/WABinary/encode.js.map +1 -0
- package/lib/WABinary/generic-utils.d.ts +14 -27
- package/lib/WABinary/generic-utils.d.ts.map +1 -0
- package/lib/WABinary/generic-utils.js +177 -105
- package/lib/WABinary/generic-utils.js.map +1 -0
- package/lib/WABinary/index.d.ts +6 -5
- package/lib/WABinary/index.d.ts.map +1 -0
- package/lib/WABinary/index.js +6 -25
- package/lib/WABinary/index.js.map +1 -0
- package/lib/WABinary/jid-utils.d.ts +41 -51
- package/lib/WABinary/jid-utils.d.ts.map +1 -0
- package/lib/WABinary/jid-utils.js +83 -120
- package/lib/WABinary/jid-utils.js.map +1 -0
- package/lib/WABinary/types.d.ts +10 -13
- package/lib/WABinary/types.d.ts.map +1 -0
- package/lib/WABinary/types.js +2 -3
- package/lib/WABinary/types.js.map +1 -0
- package/lib/WAM/BinaryInfo.d.ts +8 -15
- package/lib/WAM/BinaryInfo.d.ts.map +1 -0
- package/lib/WAM/BinaryInfo.js +7 -14
- package/lib/WAM/BinaryInfo.js.map +1 -0
- package/lib/WAM/constants.d.ts +30 -37
- package/lib/WAM/constants.d.ts.map +1 -0
- package/lib/WAM/constants.js +19193 -11711
- package/lib/WAM/constants.js.map +1 -0
- package/lib/WAM/encode.d.ts +3 -3
- package/lib/WAM/encode.d.ts.map +1 -0
- package/lib/WAM/encode.js +95 -109
- package/lib/WAM/encode.js.map +1 -0
- package/lib/WAM/index.d.ts +4 -3
- package/lib/WAM/index.d.ts.map +1 -0
- package/lib/WAM/index.js +4 -23
- package/lib/WAM/index.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -9
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +37 -21
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +19 -22
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +18 -26
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +11 -12
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +12 -20
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +11 -12
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +16 -24
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +51 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +29 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/index.d.ts +6 -6
- package/lib/WAUSync/Protocols/index.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/index.js +6 -26
- package/lib/WAUSync/Protocols/index.js.map +1 -0
- package/lib/WAUSync/USyncQuery.d.ts +27 -28
- package/lib/WAUSync/USyncQuery.d.ts.map +1 -0
- package/lib/WAUSync/USyncQuery.js +68 -62
- package/lib/WAUSync/USyncQuery.js.map +1 -0
- package/lib/WAUSync/USyncUser.d.ts +15 -10
- package/lib/WAUSync/USyncUser.d.ts.map +1 -0
- package/lib/WAUSync/USyncUser.js +20 -19
- package/lib/WAUSync/USyncUser.js.map +1 -0
- package/lib/WAUSync/index.d.ts +4 -3
- package/lib/WAUSync/index.d.ts.map +1 -0
- package/lib/WAUSync/index.js +4 -23
- package/lib/WAUSync/index.js.map +1 -0
- package/lib/index.d.ts +11 -12
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +12 -39
- package/lib/index.js.map +1 -0
- package/package.json +86 -42
package/lib/Socket/socket.js
CHANGED
|
@@ -1,98 +1,178 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
const url = typeof waWebSocketUrl === 'string' ? new url_1.URL(waWebSocketUrl) : waWebSocketUrl
|
|
38
|
-
|
|
1
|
+
import { Boom } from '@hapi/boom';
|
|
2
|
+
import { randomBytes } from 'crypto';
|
|
3
|
+
import { URL } from 'url';
|
|
4
|
+
import { promisify } from 'util';
|
|
5
|
+
import { proto } from '../../WAProto/index.js';
|
|
6
|
+
import { DEF_CALLBACK_PREFIX, DEF_TAG_PREFIX, INITIAL_PREKEY_COUNT, MIN_PREKEY_COUNT, NOISE_WA_HEADER, PROCESSABLE_HISTORY_TYPES, TimeMs, UPLOAD_TIMEOUT } from '../Defaults/index.js';
|
|
7
|
+
import { QueryIds, ReachoutTimelockEnforcementType } from '../Types/index.js';
|
|
8
|
+
import { DisconnectReason, XWAPaths } from '../Types/index.js';
|
|
9
|
+
import { addTransactionCapability, aesEncryptCTR, bindWaitForConnectionUpdate, buildPairingQRData, bytesToCrockford, configureSuccessfulPairing, Curve, derivePairingCodeKey, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getCodeFromWSError, getCompanionPlatformId, getErrorCodeFromStreamError, getNextPreKeysNode, makeEventBuffer, makeNoiseHandler, promiseTimeout, signedKeyPair, xmppSignedPreKey } from '../Utils/index.js';
|
|
10
|
+
import { assertNodeErrorFree, binaryNodeToString, encodeBinaryNode, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildren, isLidUser, jidDecode, jidEncode, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
11
|
+
import { BinaryInfo } from '../WAM/BinaryInfo.js';
|
|
12
|
+
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
13
|
+
import { WebSocketClient } from './Client/index.js';
|
|
14
|
+
import { executeWMexQuery } from './mex.js';
|
|
15
|
+
/**
|
|
16
|
+
* Connects to WA servers and performs:
|
|
17
|
+
* - simple queries (no retry mechanism, wait for connection establishment)
|
|
18
|
+
* - listen to messages and emit events
|
|
19
|
+
* - query phone connection
|
|
20
|
+
*/
|
|
21
|
+
export const makeSocket = (config) => {
|
|
22
|
+
const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository } = config;
|
|
23
|
+
const publicWAMBuffer = new BinaryInfo();
|
|
24
|
+
let serverTimeOffsetMs = 0;
|
|
25
|
+
const uqTagId = generateMdTagPrefix();
|
|
26
|
+
const generateMessageTag = () => `${uqTagId}${epoch++}`;
|
|
27
|
+
if (printQRInTerminal) {
|
|
28
|
+
logger.warn({}, '⚠️ The printQRInTerminal option has been deprecated. You will no longer receive QR codes in the terminal automatically. Please listen to the connection.update event yourself and handle the QR your way. You can remove this message by removing this opttion. This message will be removed in a future version.');
|
|
29
|
+
}
|
|
30
|
+
const syncDisabled = PROCESSABLE_HISTORY_TYPES.map(syncType => config.shouldSyncHistoryMessage({ syncType })).filter(x => x === false)
|
|
31
|
+
.length === PROCESSABLE_HISTORY_TYPES.length;
|
|
32
|
+
if (syncDisabled) {
|
|
33
|
+
logger.warn('⚠️ DANGER: DISABLING ALL SYNC BY shouldSyncHistoryMsg PREVENTS BAILEYS FROM ACCESSING INITIAL LID MAPPINGS, LEADING TO INSTABILIY AND SESSION ERRORS');
|
|
34
|
+
}
|
|
35
|
+
const url = typeof waWebSocketUrl === 'string' ? new URL(waWebSocketUrl) : waWebSocketUrl;
|
|
39
36
|
if (config.mobile || url.protocol === 'tcp:') {
|
|
40
|
-
throw new
|
|
41
|
-
statusCode: Types_1.DisconnectReason.loggedOut
|
|
42
|
-
})
|
|
37
|
+
throw new Boom('Mobile API is not supported anymore', { statusCode: DisconnectReason.loggedOut });
|
|
43
38
|
}
|
|
44
|
-
|
|
45
39
|
if (url.protocol === 'wss' && authState?.creds?.routingInfo) {
|
|
46
|
-
url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'))
|
|
40
|
+
url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'));
|
|
47
41
|
}
|
|
48
|
-
|
|
42
|
+
/** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */
|
|
43
|
+
const ephemeralKeyPair = Curve.generateKeyPair();
|
|
44
|
+
/** WA noise protocol wrapper */
|
|
45
|
+
const noise = makeNoiseHandler({
|
|
46
|
+
keyPair: ephemeralKeyPair,
|
|
47
|
+
NOISE_HEADER: NOISE_WA_HEADER,
|
|
48
|
+
logger,
|
|
49
|
+
routingInfo: authState?.creds?.routingInfo
|
|
50
|
+
});
|
|
51
|
+
const ws = new WebSocketClient(url, config);
|
|
52
|
+
ws.connect();
|
|
53
|
+
const sendPromise = promisify(ws.send);
|
|
54
|
+
/** send a raw buffer */
|
|
55
|
+
const sendRawMessage = async (data) => {
|
|
56
|
+
if (!ws.isOpen) {
|
|
57
|
+
throw new Boom('Connection Closed', { statusCode: DisconnectReason.connectionClosed });
|
|
58
|
+
}
|
|
59
|
+
const bytes = noise.encodeFrame(data);
|
|
60
|
+
await promiseTimeout(connectTimeoutMs, async (resolve, reject) => {
|
|
61
|
+
try {
|
|
62
|
+
await sendPromise.call(ws, bytes);
|
|
63
|
+
resolve();
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
reject(error);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
/** send a binary node */
|
|
71
|
+
const sendNode = (frame) => {
|
|
72
|
+
if (logger.level === 'trace') {
|
|
73
|
+
logger.trace({ xml: binaryNodeToString(frame), msg: 'xml send' });
|
|
74
|
+
}
|
|
75
|
+
const buff = encodeBinaryNode(frame);
|
|
76
|
+
return sendRawMessage(buff);
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Wait for a message with a certain tag to be received
|
|
80
|
+
* @param msgId the message tag to await
|
|
81
|
+
* @param timeoutMs timeout after which the promise will reject
|
|
82
|
+
*/
|
|
49
83
|
const waitForMessage = async (msgId, timeoutMs = defaultQueryTimeoutMs) => {
|
|
50
|
-
let onRecv
|
|
51
|
-
let onErr
|
|
84
|
+
let onRecv;
|
|
85
|
+
let onErr;
|
|
52
86
|
try {
|
|
53
|
-
|
|
54
|
-
onRecv =
|
|
87
|
+
const result = await promiseTimeout(timeoutMs, (resolve, reject) => {
|
|
88
|
+
onRecv = data => {
|
|
89
|
+
resolve(data);
|
|
90
|
+
};
|
|
55
91
|
onErr = err => {
|
|
56
|
-
reject(err ||
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
ws.on(
|
|
62
|
-
ws.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
92
|
+
reject(err ||
|
|
93
|
+
new Boom('Connection Closed', {
|
|
94
|
+
statusCode: DisconnectReason.connectionClosed
|
|
95
|
+
}));
|
|
96
|
+
};
|
|
97
|
+
ws.on(`TAG:${msgId}`, onRecv);
|
|
98
|
+
ws.on('close', onErr);
|
|
99
|
+
ws.on('error', onErr);
|
|
100
|
+
return () => reject(new Boom('Query Cancelled'));
|
|
101
|
+
});
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
// Catch timeout and return undefined instead of throwing
|
|
106
|
+
if (error instanceof Boom && error.output?.statusCode === DisconnectReason.timedOut) {
|
|
107
|
+
logger?.warn?.({ msgId }, 'timed out waiting for message');
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
if (onRecv)
|
|
114
|
+
ws.off(`TAG:${msgId}`, onRecv);
|
|
115
|
+
if (onErr) {
|
|
116
|
+
ws.off('close', onErr);
|
|
117
|
+
ws.off('error', onErr);
|
|
118
|
+
}
|
|
68
119
|
}
|
|
69
|
-
}
|
|
70
|
-
|
|
120
|
+
};
|
|
121
|
+
/** send a query, and wait for its response. auto-generates message ID if not provided */
|
|
71
122
|
const query = async (node, timeoutMs) => {
|
|
72
123
|
if (!node.attrs.id) {
|
|
73
|
-
node.attrs.id = generateMessageTag()
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
124
|
+
node.attrs.id = generateMessageTag();
|
|
125
|
+
}
|
|
126
|
+
const msgId = node.attrs.id;
|
|
127
|
+
const result = await promiseTimeout(timeoutMs, async (resolve, reject) => {
|
|
128
|
+
const result = waitForMessage(msgId, timeoutMs).catch(reject);
|
|
129
|
+
sendNode(node)
|
|
130
|
+
.then(async () => resolve(await result))
|
|
131
|
+
.catch(reject);
|
|
132
|
+
});
|
|
133
|
+
if (result && 'tag' in result) {
|
|
134
|
+
assertNodeErrorFree(result);
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
};
|
|
138
|
+
// Validate current key-bundle on server; on failure, trigger pre-key upload and rethrow
|
|
139
|
+
const digestKeyBundle = async () => {
|
|
140
|
+
const res = await query({
|
|
141
|
+
tag: 'iq',
|
|
142
|
+
attrs: { to: S_WHATSAPP_NET, type: 'get', xmlns: 'encrypt' },
|
|
143
|
+
content: [{ tag: 'digest', attrs: {} }]
|
|
144
|
+
});
|
|
145
|
+
const digestNode = getBinaryNodeChild(res, 'digest');
|
|
146
|
+
if (!digestNode) {
|
|
147
|
+
await uploadPreKeys();
|
|
148
|
+
throw new Error('encrypt/get digest returned no digest node');
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
// Rotate our signed pre-key on server; on failure, run digest as fallback and rethrow
|
|
152
|
+
const rotateSignedPreKey = async () => {
|
|
153
|
+
const newId = (creds.signedPreKey.keyId || 0) + 1;
|
|
154
|
+
const skey = await signedKeyPair(creds.signedIdentityKey, newId);
|
|
155
|
+
await query({
|
|
156
|
+
tag: 'iq',
|
|
157
|
+
attrs: { to: S_WHATSAPP_NET, type: 'set', xmlns: 'encrypt' },
|
|
158
|
+
content: [
|
|
159
|
+
{
|
|
160
|
+
tag: 'rotate',
|
|
161
|
+
attrs: {},
|
|
162
|
+
content: [xmppSignedPreKey(skey)]
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
});
|
|
166
|
+
// Persist new signed pre-key in creds
|
|
167
|
+
ev.emit('creds.update', { signedPreKey: skey });
|
|
168
|
+
};
|
|
90
169
|
const executeUSyncQuery = async (usyncQuery) => {
|
|
91
170
|
if (usyncQuery.protocols.length === 0) {
|
|
92
|
-
throw new
|
|
171
|
+
throw new Boom('USyncQuery must have at least one protocol');
|
|
93
172
|
}
|
|
94
|
-
|
|
95
|
-
|
|
173
|
+
// todo: validate users, throw WARNING on no valid users
|
|
174
|
+
// variable below has only validated users
|
|
175
|
+
const validUsers = usyncQuery.users;
|
|
96
176
|
const userNodes = validUsers.map(user => {
|
|
97
177
|
return {
|
|
98
178
|
tag: 'user',
|
|
@@ -100,227 +180,158 @@ const makeSocket = (config) => {
|
|
|
100
180
|
jid: !user.phone ? user.id : undefined
|
|
101
181
|
},
|
|
102
182
|
content: usyncQuery.protocols.map(a => a.getUserElement(user)).filter(a => a !== null)
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
|
|
183
|
+
};
|
|
184
|
+
});
|
|
106
185
|
const listNode = {
|
|
107
186
|
tag: 'list',
|
|
108
187
|
attrs: {},
|
|
109
188
|
content: userNodes
|
|
110
|
-
}
|
|
111
|
-
|
|
189
|
+
};
|
|
112
190
|
const queryNode = {
|
|
113
191
|
tag: 'query',
|
|
114
192
|
attrs: {},
|
|
115
193
|
content: usyncQuery.protocols.map(a => a.getQueryElement())
|
|
116
|
-
}
|
|
117
|
-
|
|
194
|
+
};
|
|
118
195
|
const iq = {
|
|
119
196
|
tag: 'iq',
|
|
120
197
|
attrs: {
|
|
121
|
-
to:
|
|
198
|
+
to: S_WHATSAPP_NET,
|
|
122
199
|
type: 'get',
|
|
123
200
|
xmlns: 'usync'
|
|
124
201
|
},
|
|
125
|
-
content: [
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const onWhatsApp = async (...
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
usyncQuery.withUser(new WAUSync_1.USyncUser().withPhone(phone))
|
|
202
|
+
content: [
|
|
203
|
+
{
|
|
204
|
+
tag: 'usync',
|
|
205
|
+
attrs: {
|
|
206
|
+
context: usyncQuery.context,
|
|
207
|
+
mode: usyncQuery.mode,
|
|
208
|
+
sid: generateMessageTag(),
|
|
209
|
+
last: 'true',
|
|
210
|
+
index: '0'
|
|
211
|
+
},
|
|
212
|
+
content: [queryNode, listNode]
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
};
|
|
216
|
+
const result = await query(iq);
|
|
217
|
+
return usyncQuery.parseUSyncQueryResult(result);
|
|
218
|
+
};
|
|
219
|
+
const onWhatsApp = async (...phoneNumber) => {
|
|
220
|
+
let usyncQuery = new USyncQuery();
|
|
221
|
+
let contactEnabled = false;
|
|
222
|
+
for (const jid of phoneNumber) {
|
|
223
|
+
if (isLidUser(jid)) {
|
|
224
|
+
logger?.warn('LIDs are not supported with onWhatsApp');
|
|
225
|
+
continue;
|
|
150
226
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
lid: a.lid
|
|
159
|
-
})))
|
|
227
|
+
else {
|
|
228
|
+
if (!contactEnabled) {
|
|
229
|
+
contactEnabled = true;
|
|
230
|
+
usyncQuery = usyncQuery.withContactProtocol();
|
|
231
|
+
}
|
|
232
|
+
const phone = `+${jid.replace('+', '').split('@')[0]?.split(':')[0]}`;
|
|
233
|
+
usyncQuery.withUser(new USyncUser().withPhone(phone));
|
|
160
234
|
}
|
|
161
|
-
return results.list
|
|
162
|
-
.filter(a => !!a.contact)
|
|
163
|
-
.map(({
|
|
164
|
-
contact,
|
|
165
|
-
id,
|
|
166
|
-
lid
|
|
167
|
-
}) => ({
|
|
168
|
-
jid: id,
|
|
169
|
-
exists: contact,
|
|
170
|
-
lid: lid
|
|
171
|
-
}))
|
|
172
235
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const ws = new Client_1.WebSocketClient(url, config)
|
|
176
|
-
|
|
177
|
-
ws.connect()
|
|
178
|
-
const ev = Utils_1.makeEventBuffer(logger)
|
|
179
|
-
|
|
180
|
-
const ephemeralKeyPair = Utils_1.Curve.generateKeyPair()
|
|
181
|
-
|
|
182
|
-
const noise = Utils_1.makeNoiseHandler({
|
|
183
|
-
keyPair: ephemeralKeyPair,
|
|
184
|
-
NOISE_HEADER: Defaults_1.NOISE_WA_HEADER,
|
|
185
|
-
logger,
|
|
186
|
-
routingInfo: authState?.creds?.routingInfo
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
const { creds } = authState
|
|
190
|
-
|
|
191
|
-
const keys = Utils_1.addTransactionCapability(authState.keys, logger, transactionOpts)
|
|
192
|
-
const signalRepository = makeSignalRepository({
|
|
193
|
-
creds,
|
|
194
|
-
keys
|
|
195
|
-
}, onWhatsApp, logger)
|
|
196
|
-
|
|
197
|
-
let lastDateRecv
|
|
198
|
-
let epoch = 1
|
|
199
|
-
let keepAliveReq
|
|
200
|
-
// FIX: sebelumnya uploadPreKeysToServerIfRequired() cuma dipanggil SEKALI pas
|
|
201
|
-
// 'CB:success' (baru connect/reconnect). Kalau proses bot jalan lama (berhari-hari)
|
|
202
|
-
// tanpa reconnect, prekey yang kepakai server gak pernah dicek ulang sampai jumlahnya
|
|
203
|
-
// abis - baru ketahuan pas sudah kejadian error decrypt di penerima. Interval ini
|
|
204
|
-
// bikin prekey selalu "terupdate", dicek ulang berkala tanpa perlu nunggu reconnect.
|
|
205
|
-
let preKeyCheckInterval
|
|
206
|
-
let qrTimer
|
|
207
|
-
let closed = false
|
|
208
|
-
|
|
209
|
-
const sendPromise = util_1.promisify(ws.send)
|
|
210
|
-
|
|
211
|
-
const sendRawMessage = async (data) => {
|
|
212
|
-
if (!ws.isOpen) {
|
|
213
|
-
throw new boom_1.Boom('Connection Closed', {
|
|
214
|
-
statusCode: Types_1.DisconnectReason.connectionClosed
|
|
215
|
-
})
|
|
236
|
+
if (usyncQuery.users.length === 0) {
|
|
237
|
+
return []; // return early without forcing an empty query
|
|
216
238
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
239
|
+
const results = await executeUSyncQuery(usyncQuery);
|
|
240
|
+
if (results) {
|
|
241
|
+
return results.list.filter(a => !!a.contact).map(({ contact, id }) => ({ jid: id, exists: contact }));
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
const pnFromLIDUSync = async (jids) => {
|
|
245
|
+
const usyncQuery = new USyncQuery().withLIDProtocol().withContext('background');
|
|
246
|
+
for (const jid of jids) {
|
|
247
|
+
if (isLidUser(jid)) {
|
|
248
|
+
logger?.warn('LID user found in LID fetch call');
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
usyncQuery.withUser(new USyncUser().withId(jid));
|
|
225
253
|
}
|
|
226
|
-
})
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const sendNode = (frame) => {
|
|
230
|
-
if (logger.level === 'trace') {
|
|
231
|
-
logger.trace({
|
|
232
|
-
xml: WABinary_1.binaryNodeToString(frame),
|
|
233
|
-
msg: 'xml send'
|
|
234
|
-
})
|
|
235
254
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
255
|
+
if (usyncQuery.users.length === 0) {
|
|
256
|
+
return []; // return early without forcing an empty query
|
|
257
|
+
}
|
|
258
|
+
const results = await executeUSyncQuery(usyncQuery);
|
|
259
|
+
if (results) {
|
|
260
|
+
return results.list.filter(a => !!a.lid).map(({ lid, id }) => ({ pn: id, lid: lid }));
|
|
261
|
+
}
|
|
262
|
+
return [];
|
|
263
|
+
};
|
|
264
|
+
const ev = makeEventBuffer(logger);
|
|
265
|
+
const { creds } = authState;
|
|
266
|
+
// add transaction capability
|
|
267
|
+
const keys = addTransactionCapability(authState.keys, logger, transactionOpts);
|
|
268
|
+
const signalRepository = makeSignalRepository({ creds, keys }, logger, pnFromLIDUSync);
|
|
269
|
+
let lastDateRecv;
|
|
270
|
+
let epoch = 1;
|
|
271
|
+
let keepAliveReq;
|
|
272
|
+
let qrTimer;
|
|
273
|
+
let closed = false;
|
|
274
|
+
const socketEndHandlers = [];
|
|
275
|
+
/** log & process any unexpected errors */
|
|
242
276
|
const onUnexpectedError = (err, msg) => {
|
|
243
|
-
logger.error({
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
277
|
+
logger.error({ err }, `unexpected error in '${msg}'`);
|
|
278
|
+
};
|
|
279
|
+
/** await the next incoming message */
|
|
248
280
|
const awaitNextMessage = async (sendMsg) => {
|
|
249
281
|
if (!ws.isOpen) {
|
|
250
|
-
throw new
|
|
251
|
-
statusCode:
|
|
252
|
-
})
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
let
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
onOpen
|
|
260
|
-
onClose
|
|
261
|
-
ws.on('
|
|
262
|
-
ws.on('close', onClose)
|
|
263
|
-
ws.on('error', onClose)
|
|
282
|
+
throw new Boom('Connection Closed', {
|
|
283
|
+
statusCode: DisconnectReason.connectionClosed
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
let onOpen;
|
|
287
|
+
let onClose;
|
|
288
|
+
const result = promiseTimeout(connectTimeoutMs, (resolve, reject) => {
|
|
289
|
+
onOpen = resolve;
|
|
290
|
+
onClose = mapWebSocketError(reject);
|
|
291
|
+
ws.on('frame', onOpen);
|
|
292
|
+
ws.on('close', onClose);
|
|
293
|
+
ws.on('error', onClose);
|
|
264
294
|
}).finally(() => {
|
|
265
|
-
ws.off('frame', onOpen)
|
|
266
|
-
ws.off('close', onClose)
|
|
267
|
-
ws.off('error', onClose)
|
|
268
|
-
})
|
|
269
|
-
|
|
295
|
+
ws.off('frame', onOpen);
|
|
296
|
+
ws.off('close', onClose);
|
|
297
|
+
ws.off('error', onClose);
|
|
298
|
+
});
|
|
270
299
|
if (sendMsg) {
|
|
271
|
-
sendRawMessage(sendMsg).catch(onClose)
|
|
300
|
+
sendRawMessage(sendMsg).catch(onClose);
|
|
272
301
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
302
|
+
return result;
|
|
303
|
+
};
|
|
304
|
+
/** connection handshake */
|
|
277
305
|
const validateConnection = async () => {
|
|
278
306
|
let helloMsg = {
|
|
279
|
-
clientHello: {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const init = WAProto_1.proto.HandshakeMessage.encode(helloMsg).finish()
|
|
291
|
-
const result = await awaitNextMessage(init)
|
|
292
|
-
const handshake = WAProto_1.proto.HandshakeMessage.decode(result)
|
|
293
|
-
|
|
294
|
-
logger.trace({
|
|
295
|
-
handshake
|
|
296
|
-
}, 'handshake recv from WA')
|
|
297
|
-
|
|
298
|
-
const keyEnc = await noise.processHandshake(handshake, creds.noiseKey)
|
|
299
|
-
let node
|
|
300
|
-
|
|
307
|
+
clientHello: { ephemeral: ephemeralKeyPair.public }
|
|
308
|
+
};
|
|
309
|
+
helloMsg = proto.HandshakeMessage.fromObject(helloMsg);
|
|
310
|
+
logger.info({ browser, helloMsg }, 'connected to WA');
|
|
311
|
+
const init = proto.HandshakeMessage.encode(helloMsg).finish();
|
|
312
|
+
const result = await awaitNextMessage(init);
|
|
313
|
+
const handshake = proto.HandshakeMessage.decode(result);
|
|
314
|
+
logger.trace({ handshake }, 'handshake recv from WA');
|
|
315
|
+
const keyEnc = noise.processHandshake(handshake, creds.noiseKey);
|
|
316
|
+
let node;
|
|
301
317
|
if (!creds.me) {
|
|
302
|
-
node =
|
|
303
|
-
logger.info({
|
|
304
|
-
node
|
|
305
|
-
}, 'not logged in, attempting registration...')
|
|
306
|
-
} else {
|
|
307
|
-
node = Utils_1.generateLoginNode(creds.me.id, config)
|
|
308
|
-
logger.info({
|
|
309
|
-
node
|
|
310
|
-
}, 'logging in...')
|
|
318
|
+
node = generateRegistrationNode(creds, config);
|
|
319
|
+
logger.info({ node }, 'not logged in, attempting registration...');
|
|
311
320
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
321
|
+
else {
|
|
322
|
+
node = generateLoginNode(creds.me.id, config);
|
|
323
|
+
logger.info({ node }, 'logging in...');
|
|
324
|
+
}
|
|
325
|
+
const payloadEnc = noise.encrypt(proto.ClientPayload.encode(node).finish());
|
|
326
|
+
await sendRawMessage(proto.HandshakeMessage.encode({
|
|
315
327
|
clientFinish: {
|
|
316
328
|
static: keyEnc,
|
|
317
|
-
payload: payloadEnc
|
|
318
|
-
}
|
|
319
|
-
}).finish())
|
|
320
|
-
noise.finishInit()
|
|
321
|
-
startKeepAliveRequest()
|
|
322
|
-
}
|
|
323
|
-
|
|
329
|
+
payload: payloadEnc
|
|
330
|
+
}
|
|
331
|
+
}).finish());
|
|
332
|
+
await noise.finishInit();
|
|
333
|
+
startKeepAliveRequest();
|
|
334
|
+
};
|
|
324
335
|
const getAvailablePreKeysOnServer = async () => {
|
|
325
336
|
const result = await query({
|
|
326
337
|
tag: 'iq',
|
|
@@ -328,681 +339,594 @@ const makeSocket = (config) => {
|
|
|
328
339
|
id: generateMessageTag(),
|
|
329
340
|
xmlns: 'encrypt',
|
|
330
341
|
type: 'get',
|
|
331
|
-
to:
|
|
342
|
+
to: S_WHATSAPP_NET
|
|
332
343
|
},
|
|
333
|
-
content: [{
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
let uploadPreKeysPromise = null
|
|
345
|
-
let lastUploadTime = 0
|
|
346
|
-
|
|
347
|
-
const uploadPreKeys = async (count = Defaults_1.INITIAL_PREKEY_COUNT, retryCount = 0) => {
|
|
348
|
-
if (retryCount === 0) {
|
|
349
|
-
const timeSinceLastUpload = Date.now() - lastUploadTime
|
|
350
|
-
if (timeSinceLastUpload < Defaults_1.MIN_UPLOAD_INTERVAL) {
|
|
351
|
-
logger.debug(`Skipping upload, only ${timeSinceLastUpload}ms since last upload`)
|
|
352
|
-
return
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
344
|
+
content: [{ tag: 'count', attrs: {} }]
|
|
345
|
+
});
|
|
346
|
+
const countChild = getBinaryNodeChild(result, 'count');
|
|
347
|
+
return +countChild.attrs.value;
|
|
348
|
+
};
|
|
349
|
+
// WAWeb has no time throttle here; the server drives uploads via PreKeyLow notifications.
|
|
350
|
+
let uploadPreKeysPromise = null;
|
|
351
|
+
/** generates and uploads a set of pre-keys to the server */
|
|
352
|
+
const uploadPreKeys = async (count = MIN_PREKEY_COUNT) => {
|
|
356
353
|
if (uploadPreKeysPromise) {
|
|
357
|
-
logger.debug('Pre-key upload already in progress, waiting for completion')
|
|
358
|
-
|
|
354
|
+
logger.debug('Pre-key upload already in progress, waiting for completion');
|
|
355
|
+
await uploadPreKeysPromise;
|
|
356
|
+
return;
|
|
359
357
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
count,
|
|
364
|
-
retryCount
|
|
365
|
-
}, 'uploading pre-keys')
|
|
366
|
-
|
|
358
|
+
const uploadLogic = async (retryCount) => {
|
|
359
|
+
logger.info({ count, retryCount }, 'uploading pre-keys');
|
|
360
|
+
// Generate and save pre-keys atomically (prevents ID collisions on retry)
|
|
367
361
|
const node = await keys.transaction(async () => {
|
|
368
|
-
logger.debug({
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
creds,
|
|
376
|
-
keys
|
|
377
|
-
}, count)
|
|
378
|
-
|
|
379
|
-
ev.emit('creds.update', update)
|
|
380
|
-
|
|
381
|
-
return node
|
|
382
|
-
}, creds?.me?.id || 'upload-pre-keys')
|
|
383
|
-
|
|
362
|
+
logger.debug({ requestedCount: count }, 'generating pre-keys with requested count');
|
|
363
|
+
const { update, node } = await getNextPreKeysNode({ creds, keys }, count);
|
|
364
|
+
// Update credentials immediately to prevent duplicate IDs on retry
|
|
365
|
+
ev.emit('creds.update', update);
|
|
366
|
+
return node;
|
|
367
|
+
}, creds?.me?.id || 'upload-pre-keys');
|
|
368
|
+
// Upload to server (outside transaction, can fail without affecting local keys)
|
|
384
369
|
try {
|
|
385
|
-
await query(node)
|
|
386
|
-
logger.info({
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
logger.error({
|
|
392
|
-
uploadError,
|
|
393
|
-
count
|
|
394
|
-
}, 'Failed to upload pre-keys to server')
|
|
370
|
+
await query(node);
|
|
371
|
+
logger.info({ count }, 'uploaded pre-keys successfully');
|
|
372
|
+
}
|
|
373
|
+
catch (uploadError) {
|
|
374
|
+
logger.error({ uploadError: uploadError.toString(), count }, 'Failed to upload pre-keys to server');
|
|
375
|
+
// Recurse into uploadLogic; calling uploadPreKeys would await its own in-flight promise.
|
|
395
376
|
if (retryCount < 3) {
|
|
396
|
-
const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000)
|
|
397
|
-
logger.info(`Retrying pre-key upload in ${backoffDelay}ms`)
|
|
398
|
-
await new Promise(resolve => setTimeout(resolve, backoffDelay))
|
|
399
|
-
return
|
|
377
|
+
const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000);
|
|
378
|
+
logger.info(`Retrying pre-key upload in ${backoffDelay}ms`);
|
|
379
|
+
await new Promise(resolve => setTimeout(resolve, backoffDelay));
|
|
380
|
+
return uploadLogic(retryCount + 1);
|
|
400
381
|
}
|
|
401
|
-
throw uploadError
|
|
382
|
+
throw uploadError;
|
|
402
383
|
}
|
|
403
|
-
}
|
|
404
|
-
|
|
384
|
+
};
|
|
385
|
+
// Add timeout protection
|
|
405
386
|
uploadPreKeysPromise = Promise.race([
|
|
406
|
-
uploadLogic(),
|
|
407
|
-
new Promise((_, reject) => setTimeout(() => reject(new
|
|
408
|
-
|
|
409
|
-
})), Defaults_1.UPLOAD_TIMEOUT))
|
|
410
|
-
])
|
|
387
|
+
uploadLogic(0),
|
|
388
|
+
new Promise((_, reject) => setTimeout(() => reject(new Boom('Pre-key upload timeout', { statusCode: 408 })), UPLOAD_TIMEOUT))
|
|
389
|
+
]);
|
|
411
390
|
try {
|
|
412
|
-
await uploadPreKeysPromise
|
|
413
|
-
} finally {
|
|
414
|
-
uploadPreKeysPromise = null
|
|
391
|
+
await uploadPreKeysPromise;
|
|
415
392
|
}
|
|
416
|
-
|
|
417
|
-
|
|
393
|
+
finally {
|
|
394
|
+
uploadPreKeysPromise = null;
|
|
395
|
+
}
|
|
396
|
+
};
|
|
418
397
|
const verifyCurrentPreKeyExists = async () => {
|
|
419
|
-
const currentPreKeyId = creds.nextPreKeyId - 1
|
|
398
|
+
const currentPreKeyId = creds.nextPreKeyId - 1;
|
|
420
399
|
if (currentPreKeyId <= 0) {
|
|
421
|
-
return {
|
|
422
|
-
exists: false,
|
|
423
|
-
currentPreKeyId: 0
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
const preKeys = await keys.get('pre-key', [currentPreKeyId.toString()])
|
|
427
|
-
const exists = !!preKeys[currentPreKeyId.toString()]
|
|
428
|
-
return {
|
|
429
|
-
exists,
|
|
430
|
-
currentPreKeyId
|
|
400
|
+
return { exists: false, currentPreKeyId: 0 };
|
|
431
401
|
}
|
|
432
|
-
|
|
433
|
-
|
|
402
|
+
const preKeys = await keys.get('pre-key', [currentPreKeyId.toString()]);
|
|
403
|
+
const exists = !!preKeys[currentPreKeyId.toString()];
|
|
404
|
+
return { exists, currentPreKeyId };
|
|
405
|
+
};
|
|
434
406
|
const uploadPreKeysToServerIfRequired = async () => {
|
|
435
407
|
try {
|
|
436
|
-
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
logger.info(
|
|
444
|
-
|
|
445
|
-
const lowServerCount = preKeyCount <=
|
|
446
|
-
const missingCurrentPreKey = !currentPreKeyExists && currentPreKeyId > 0
|
|
447
|
-
const shouldUpload = lowServerCount || missingCurrentPreKey
|
|
448
|
-
|
|
408
|
+
let count = 0;
|
|
409
|
+
const preKeyCount = await getAvailablePreKeysOnServer();
|
|
410
|
+
if (preKeyCount === 0)
|
|
411
|
+
count = INITIAL_PREKEY_COUNT;
|
|
412
|
+
else
|
|
413
|
+
count = MIN_PREKEY_COUNT;
|
|
414
|
+
const { exists: currentPreKeyExists, currentPreKeyId } = await verifyCurrentPreKeyExists();
|
|
415
|
+
logger.info(`${preKeyCount} pre-keys found on server`);
|
|
416
|
+
logger.info(`Current prekey ID: ${currentPreKeyId}, exists in storage: ${currentPreKeyExists}`);
|
|
417
|
+
const lowServerCount = preKeyCount <= count;
|
|
418
|
+
const missingCurrentPreKey = !currentPreKeyExists && currentPreKeyId > 0;
|
|
419
|
+
const shouldUpload = lowServerCount || missingCurrentPreKey;
|
|
449
420
|
if (shouldUpload) {
|
|
450
|
-
const reasons = []
|
|
421
|
+
const reasons = [];
|
|
451
422
|
if (lowServerCount)
|
|
452
|
-
reasons.push(`server count low (${preKeyCount})`)
|
|
423
|
+
reasons.push(`server count low (${preKeyCount})`);
|
|
453
424
|
if (missingCurrentPreKey)
|
|
454
|
-
reasons.push(`current prekey ${currentPreKeyId} missing from storage`)
|
|
455
|
-
logger.info(`Uploading PreKeys due to: ${reasons.join(', ')}`)
|
|
456
|
-
await uploadPreKeys()
|
|
457
|
-
}
|
|
458
|
-
|
|
425
|
+
reasons.push(`current prekey ${currentPreKeyId} missing from storage`);
|
|
426
|
+
logger.info(`Uploading PreKeys due to: ${reasons.join(', ')}`);
|
|
427
|
+
await uploadPreKeys(count);
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
logger.info(`PreKey validation passed - Server: ${preKeyCount}, Current prekey ${currentPreKeyId} exists`);
|
|
459
431
|
}
|
|
460
|
-
} catch (error) {
|
|
461
|
-
logger.error({
|
|
462
|
-
error
|
|
463
|
-
}, 'Failed to check/upload pre-keys during initialization')
|
|
464
432
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
433
|
+
catch (error) {
|
|
434
|
+
logger.error({ error }, 'Failed to check/upload pre-keys during initialization');
|
|
435
|
+
// Don't throw - allow connection to continue even if pre-key check fails
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
const onMessageReceived = async (data) => {
|
|
439
|
+
await noise.decodeFrame(data, frame => {
|
|
440
|
+
// reset ping timeout
|
|
441
|
+
lastDateRecv = new Date();
|
|
442
|
+
let anyTriggered = false;
|
|
443
|
+
anyTriggered = ws.emit('frame', frame);
|
|
444
|
+
// if it's a binary node
|
|
474
445
|
if (!(frame instanceof Uint8Array)) {
|
|
475
|
-
const msgId = frame.attrs.id
|
|
476
|
-
|
|
446
|
+
const msgId = frame.attrs.id;
|
|
477
447
|
if (logger.level === 'trace') {
|
|
478
|
-
logger.trace({
|
|
479
|
-
xml: WABinary_1.binaryNodeToString(frame),
|
|
480
|
-
msg: 'recv xml'
|
|
481
|
-
})
|
|
448
|
+
logger.trace({ xml: binaryNodeToString(frame), msg: 'recv xml' });
|
|
482
449
|
}
|
|
483
|
-
|
|
484
|
-
anyTriggered = ws.emit(`${
|
|
485
|
-
|
|
486
|
-
const l0 = frame.tag
|
|
487
|
-
const l1 = frame.attrs || {}
|
|
488
|
-
const l2 = Array.isArray(frame.content) ? frame.content[0]?.tag : ''
|
|
489
|
-
|
|
450
|
+
/* Check if this is a response to a message we sent */
|
|
451
|
+
anyTriggered = ws.emit(`${DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered;
|
|
452
|
+
/* Check if this is a response to a message we are expecting */
|
|
453
|
+
const l0 = frame.tag;
|
|
454
|
+
const l1 = frame.attrs || {};
|
|
455
|
+
const l2 = Array.isArray(frame.content) ? frame.content[0]?.tag : '';
|
|
490
456
|
for (const key of Object.keys(l1)) {
|
|
491
|
-
anyTriggered = ws.emit(`${
|
|
492
|
-
anyTriggered = ws.emit(`${
|
|
493
|
-
anyTriggered = ws.emit(`${
|
|
457
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered;
|
|
458
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered;
|
|
459
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered;
|
|
494
460
|
}
|
|
495
|
-
|
|
496
|
-
anyTriggered = ws.emit(`${
|
|
497
|
-
anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered
|
|
498
|
-
|
|
461
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered;
|
|
462
|
+
anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered;
|
|
499
463
|
if (!anyTriggered && logger.level === 'debug') {
|
|
500
|
-
logger.debug({
|
|
501
|
-
unhandled: true,
|
|
502
|
-
msgId,
|
|
503
|
-
fromMe: false,
|
|
504
|
-
frame
|
|
505
|
-
}, 'communication recv')
|
|
464
|
+
logger.debug({ unhandled: true, msgId, fromMe: false, frame }, 'communication recv');
|
|
506
465
|
}
|
|
507
466
|
}
|
|
508
|
-
})
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
const end = (error) => {
|
|
467
|
+
});
|
|
468
|
+
};
|
|
469
|
+
const end = async (error) => {
|
|
512
470
|
if (closed) {
|
|
513
|
-
logger.trace({
|
|
514
|
-
|
|
515
|
-
}, 'connection already closed')
|
|
516
|
-
return
|
|
471
|
+
logger.trace({ trace: error?.stack }, 'connection already closed');
|
|
472
|
+
return;
|
|
517
473
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
clearTimeout(qrTimer)
|
|
527
|
-
ws.removeAllListeners('close')
|
|
528
|
-
ws.removeAllListeners('open')
|
|
529
|
-
ws.removeAllListeners('message')
|
|
530
|
-
|
|
474
|
+
closed = true;
|
|
475
|
+
logger.info({ trace: error?.stack }, error ? 'connection errored' : 'connection closed');
|
|
476
|
+
clearInterval(keepAliveReq);
|
|
477
|
+
clearTimeout(qrTimer);
|
|
478
|
+
ws.removeAllListeners('close');
|
|
479
|
+
ws.removeAllListeners('open');
|
|
480
|
+
ws.removeAllListeners('message');
|
|
481
|
+
signalRepository.close?.();
|
|
531
482
|
if (!ws.isClosed && !ws.isClosing) {
|
|
532
483
|
try {
|
|
533
|
-
ws.close()
|
|
534
|
-
}
|
|
484
|
+
await ws.close();
|
|
485
|
+
}
|
|
486
|
+
catch { }
|
|
487
|
+
}
|
|
488
|
+
for (const handler of socketEndHandlers) {
|
|
489
|
+
try {
|
|
490
|
+
await handler(error);
|
|
491
|
+
}
|
|
492
|
+
catch (err) {
|
|
493
|
+
logger.error({ err }, 'error in socket end handler');
|
|
494
|
+
}
|
|
535
495
|
}
|
|
536
|
-
|
|
537
496
|
ev.emit('connection.update', {
|
|
538
497
|
connection: 'close',
|
|
539
498
|
lastDisconnect: {
|
|
540
499
|
error,
|
|
541
500
|
date: new Date()
|
|
542
501
|
}
|
|
543
|
-
})
|
|
544
|
-
|
|
545
|
-
ev.
|
|
546
|
-
}
|
|
547
|
-
|
|
502
|
+
});
|
|
503
|
+
ev.removeAllListeners('connection.update');
|
|
504
|
+
ev.destroy();
|
|
505
|
+
};
|
|
548
506
|
const waitForSocketOpen = async () => {
|
|
549
507
|
if (ws.isOpen) {
|
|
550
|
-
return
|
|
508
|
+
return;
|
|
551
509
|
}
|
|
552
|
-
|
|
553
510
|
if (ws.isClosed || ws.isClosing) {
|
|
554
|
-
throw new
|
|
555
|
-
statusCode: Types_1.DisconnectReason.connectionClosed
|
|
556
|
-
})
|
|
511
|
+
throw new Boom('Connection Closed', { statusCode: DisconnectReason.connectionClosed });
|
|
557
512
|
}
|
|
558
|
-
|
|
559
|
-
let
|
|
560
|
-
let onClose
|
|
561
|
-
|
|
513
|
+
let onOpen;
|
|
514
|
+
let onClose;
|
|
562
515
|
await new Promise((resolve, reject) => {
|
|
563
|
-
onOpen = () => resolve(undefined)
|
|
564
|
-
onClose = mapWebSocketError(reject)
|
|
565
|
-
ws.on('open', onOpen)
|
|
566
|
-
ws.on('close', onClose)
|
|
567
|
-
ws.on('error', onClose)
|
|
516
|
+
onOpen = () => resolve(undefined);
|
|
517
|
+
onClose = mapWebSocketError(reject);
|
|
518
|
+
ws.on('open', onOpen);
|
|
519
|
+
ws.on('close', onClose);
|
|
520
|
+
ws.on('error', onClose);
|
|
568
521
|
}).finally(() => {
|
|
569
|
-
ws.off('open', onOpen)
|
|
570
|
-
ws.off('close', onClose)
|
|
571
|
-
ws.off('error', onClose)
|
|
572
|
-
})
|
|
573
|
-
}
|
|
574
|
-
|
|
522
|
+
ws.off('open', onOpen);
|
|
523
|
+
ws.off('close', onClose);
|
|
524
|
+
ws.off('error', onClose);
|
|
525
|
+
});
|
|
526
|
+
};
|
|
575
527
|
const startKeepAliveRequest = () => (keepAliveReq = setInterval(() => {
|
|
576
528
|
if (!lastDateRecv) {
|
|
577
|
-
lastDateRecv = new Date()
|
|
529
|
+
lastDateRecv = new Date();
|
|
578
530
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
531
|
+
const diff = Date.now() - lastDateRecv.getTime();
|
|
532
|
+
/*
|
|
533
|
+
check if it's been a suspicious amount of time since the server responded with our last seen
|
|
534
|
+
it could be that the network is down
|
|
535
|
+
*/
|
|
582
536
|
if (diff > keepAliveIntervalMs + 5000) {
|
|
583
|
-
end(new
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
537
|
+
void end(new Boom('Connection was lost', { statusCode: DisconnectReason.connectionLost }));
|
|
538
|
+
}
|
|
539
|
+
else if (ws.isOpen) {
|
|
540
|
+
// if its all good, send a keep alive request
|
|
587
541
|
query({
|
|
588
542
|
tag: 'iq',
|
|
589
543
|
attrs: {
|
|
590
544
|
id: generateMessageTag(),
|
|
591
|
-
to:
|
|
545
|
+
to: S_WHATSAPP_NET,
|
|
592
546
|
type: 'get',
|
|
593
|
-
xmlns: 'w:p'
|
|
547
|
+
xmlns: 'w:p'
|
|
594
548
|
},
|
|
595
|
-
content: [{
|
|
596
|
-
tag: 'ping',
|
|
597
|
-
attrs: {}
|
|
598
|
-
}]
|
|
549
|
+
content: [{ tag: 'ping', attrs: {} }]
|
|
599
550
|
}).catch(err => {
|
|
600
|
-
logger.error({
|
|
601
|
-
|
|
602
|
-
}, 'error in sending keep alive')
|
|
603
|
-
})
|
|
604
|
-
} else {
|
|
605
|
-
logger.warn('keep alive called when WS not open')
|
|
551
|
+
logger.error({ trace: err.stack }, 'error in sending keep alive');
|
|
552
|
+
});
|
|
606
553
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
554
|
+
else {
|
|
555
|
+
logger.warn('keep alive called when WS not open');
|
|
556
|
+
}
|
|
557
|
+
}, keepAliveIntervalMs));
|
|
558
|
+
/** i have no idea why this exists. pls enlighten me */
|
|
559
|
+
const sendPassiveIq = (tag) => query({
|
|
610
560
|
tag: 'iq',
|
|
611
561
|
attrs: {
|
|
612
|
-
to:
|
|
562
|
+
to: S_WHATSAPP_NET,
|
|
613
563
|
xmlns: 'passive',
|
|
614
|
-
type: 'set'
|
|
564
|
+
type: 'set'
|
|
615
565
|
},
|
|
616
|
-
content: [{
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}]
|
|
620
|
-
}))
|
|
621
|
-
|
|
566
|
+
content: [{ tag, attrs: {} }]
|
|
567
|
+
});
|
|
568
|
+
/** logout & invalidate connection */
|
|
622
569
|
const logout = async (msg) => {
|
|
623
|
-
const jid = authState.creds.me?.id
|
|
624
|
-
|
|
570
|
+
const jid = authState.creds.me?.id;
|
|
625
571
|
if (jid) {
|
|
626
572
|
await sendNode({
|
|
627
573
|
tag: 'iq',
|
|
628
574
|
attrs: {
|
|
629
|
-
to:
|
|
575
|
+
to: S_WHATSAPP_NET,
|
|
630
576
|
type: 'set',
|
|
631
577
|
id: generateMessageTag(),
|
|
632
578
|
xmlns: 'md'
|
|
633
579
|
},
|
|
634
|
-
content: [
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
580
|
+
content: [
|
|
581
|
+
{
|
|
582
|
+
tag: 'remove-companion-device',
|
|
583
|
+
attrs: {
|
|
584
|
+
jid,
|
|
585
|
+
reason: 'user_initiated'
|
|
586
|
+
}
|
|
639
587
|
}
|
|
640
|
-
|
|
641
|
-
})
|
|
588
|
+
]
|
|
589
|
+
});
|
|
642
590
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
authState.creds.pairingCode =
|
|
651
|
-
|
|
652
|
-
|
|
591
|
+
void end(new Boom(msg || 'Intentional Logout', { statusCode: DisconnectReason.loggedOut }));
|
|
592
|
+
};
|
|
593
|
+
const requestPairingCode = async (phoneNumber, customPairingCode) => {
|
|
594
|
+
const pairingCode = customPairingCode ?? bytesToCrockford(randomBytes(5));
|
|
595
|
+
if (customPairingCode && customPairingCode?.length !== 8) {
|
|
596
|
+
throw new Error('Custom pairing code must be exactly 8 chars');
|
|
597
|
+
}
|
|
598
|
+
authState.creds.pairingCode = pairingCode;
|
|
653
599
|
authState.creds.me = {
|
|
654
|
-
id:
|
|
600
|
+
id: jidEncode(phoneNumber, 's.whatsapp.net'),
|
|
655
601
|
name: '~'
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
ev.emit('creds.update', authState.creds)
|
|
659
|
-
|
|
602
|
+
};
|
|
603
|
+
ev.emit('creds.update', authState.creds);
|
|
660
604
|
await sendNode({
|
|
661
605
|
tag: 'iq',
|
|
662
606
|
attrs: {
|
|
663
|
-
to:
|
|
607
|
+
to: S_WHATSAPP_NET,
|
|
664
608
|
type: 'set',
|
|
665
609
|
id: generateMessageTag(),
|
|
666
610
|
xmlns: 'md'
|
|
667
611
|
},
|
|
668
|
-
content: [
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
content: [{
|
|
676
|
-
tag: 'link_code_pairing_wrapped_companion_ephemeral_pub',
|
|
677
|
-
attrs: {},
|
|
678
|
-
content: await generatePairingKey()
|
|
679
|
-
},
|
|
680
|
-
{
|
|
681
|
-
tag: 'companion_server_auth_key_pub',
|
|
682
|
-
attrs: {},
|
|
683
|
-
content: authState.creds.noiseKey.public
|
|
684
|
-
},
|
|
685
|
-
{
|
|
686
|
-
tag: 'companion_platform_id',
|
|
687
|
-
attrs: {},
|
|
688
|
-
content: Utils_1.getPlatformId(browser[1])
|
|
689
|
-
},
|
|
690
|
-
{
|
|
691
|
-
tag: 'companion_platform_display',
|
|
692
|
-
attrs: {},
|
|
693
|
-
content: `${browser[1]} (${browser[0]})`
|
|
612
|
+
content: [
|
|
613
|
+
{
|
|
614
|
+
tag: 'link_code_companion_reg',
|
|
615
|
+
attrs: {
|
|
616
|
+
jid: authState.creds.me.id,
|
|
617
|
+
stage: 'companion_hello',
|
|
618
|
+
should_show_push_notification: 'true'
|
|
694
619
|
},
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
620
|
+
content: [
|
|
621
|
+
{
|
|
622
|
+
tag: 'link_code_pairing_wrapped_companion_ephemeral_pub',
|
|
623
|
+
attrs: {},
|
|
624
|
+
content: await generatePairingKey()
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
tag: 'companion_server_auth_key_pub',
|
|
628
|
+
attrs: {},
|
|
629
|
+
content: authState.creds.noiseKey.public
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
tag: 'companion_platform_id',
|
|
633
|
+
attrs: {},
|
|
634
|
+
content: getCompanionPlatformId(browser)
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
tag: 'companion_platform_display',
|
|
638
|
+
attrs: {},
|
|
639
|
+
content: `${browser[1]} (${browser[0]})`
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
tag: 'link_code_pairing_nonce',
|
|
643
|
+
attrs: {},
|
|
644
|
+
content: '0'
|
|
645
|
+
}
|
|
646
|
+
]
|
|
647
|
+
}
|
|
648
|
+
]
|
|
649
|
+
});
|
|
650
|
+
return authState.creds.pairingCode;
|
|
651
|
+
};
|
|
707
652
|
async function generatePairingKey() {
|
|
708
|
-
const salt =
|
|
709
|
-
const randomIv =
|
|
710
|
-
const key = await
|
|
711
|
-
const ciphered =
|
|
712
|
-
|
|
713
|
-
return Buffer.concat([salt, randomIv, ciphered])
|
|
653
|
+
const salt = randomBytes(32);
|
|
654
|
+
const randomIv = randomBytes(16);
|
|
655
|
+
const key = await derivePairingCodeKey(authState.creds.pairingCode, salt);
|
|
656
|
+
const ciphered = aesEncryptCTR(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
|
|
657
|
+
return Buffer.concat([salt, randomIv, ciphered]);
|
|
714
658
|
}
|
|
715
|
-
|
|
716
659
|
const sendWAMBuffer = (wamBuffer) => {
|
|
717
660
|
return query({
|
|
718
661
|
tag: 'iq',
|
|
719
662
|
attrs: {
|
|
720
|
-
to:
|
|
663
|
+
to: S_WHATSAPP_NET,
|
|
721
664
|
id: generateMessageTag(),
|
|
722
665
|
xmlns: 'w:stats'
|
|
723
666
|
},
|
|
724
|
-
content: [
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
667
|
+
content: [
|
|
668
|
+
{
|
|
669
|
+
tag: 'add',
|
|
670
|
+
attrs: { t: Math.round(Date.now() / 1000) + '' },
|
|
671
|
+
content: wamBuffer
|
|
672
|
+
}
|
|
673
|
+
]
|
|
674
|
+
});
|
|
675
|
+
};
|
|
676
|
+
ws.on('message', onMessageReceived);
|
|
734
677
|
ws.on('open', async () => {
|
|
735
678
|
try {
|
|
736
|
-
await validateConnection()
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
statusCode: Types_1.DisconnectReason.connectionClosed
|
|
749
|
-
})))
|
|
750
|
-
|
|
751
|
-
ws.on('CB:xmlstreamend', () => end(new boom_1.Boom('Connection Terminated by Server', {
|
|
752
|
-
statusCode: Types_1.DisconnectReason.connectionClosed
|
|
753
|
-
})))
|
|
754
|
-
|
|
679
|
+
await validateConnection();
|
|
680
|
+
}
|
|
681
|
+
catch (err) {
|
|
682
|
+
logger.error({ err }, 'error in validating connection');
|
|
683
|
+
void end(err);
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
ws.on('error', mapWebSocketError(end));
|
|
687
|
+
ws.on('close', () => void end(new Boom('Connection Terminated', { statusCode: DisconnectReason.connectionClosed })));
|
|
688
|
+
// the server terminated the connection
|
|
689
|
+
ws.on('CB:xmlstreamend', () => void end(new Boom('Connection Terminated by Server', { statusCode: DisconnectReason.connectionClosed })));
|
|
690
|
+
// QR gen
|
|
755
691
|
ws.on('CB:iq,type:set,pair-device', async (stanza) => {
|
|
756
692
|
const iq = {
|
|
757
693
|
tag: 'iq',
|
|
758
694
|
attrs: {
|
|
759
|
-
to:
|
|
695
|
+
to: S_WHATSAPP_NET,
|
|
760
696
|
type: 'result',
|
|
761
|
-
id: stanza.attrs.id
|
|
697
|
+
id: stanza.attrs.id
|
|
762
698
|
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
const
|
|
768
|
-
const
|
|
769
|
-
const
|
|
770
|
-
|
|
771
|
-
const advB64 = creds.advSecretKey
|
|
772
|
-
|
|
773
|
-
let qrMs = qrTimeout || 60000 // time to let a QR live
|
|
774
|
-
|
|
699
|
+
};
|
|
700
|
+
await sendNode(iq);
|
|
701
|
+
const pairDeviceNode = getBinaryNodeChild(stanza, 'pair-device');
|
|
702
|
+
const refNodes = getBinaryNodeChildren(pairDeviceNode, 'ref');
|
|
703
|
+
const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64');
|
|
704
|
+
const identityKeyB64 = Buffer.from(creds.signedIdentityKey.public).toString('base64');
|
|
705
|
+
const advB64 = creds.advSecretKey;
|
|
706
|
+
let qrMs = qrTimeout || 60000; // time to let a QR live
|
|
775
707
|
const genPairQR = () => {
|
|
776
708
|
if (!ws.isOpen) {
|
|
777
|
-
return
|
|
709
|
+
return;
|
|
778
710
|
}
|
|
779
|
-
|
|
780
|
-
const refNode = refNodes.shift()
|
|
781
|
-
|
|
711
|
+
const refNode = refNodes.shift();
|
|
782
712
|
if (!refNode) {
|
|
783
|
-
end(new
|
|
784
|
-
|
|
785
|
-
}))
|
|
786
|
-
return
|
|
713
|
+
void end(new Boom('QR refs attempts ended', { statusCode: DisconnectReason.timedOut }));
|
|
714
|
+
return;
|
|
787
715
|
}
|
|
788
|
-
|
|
789
|
-
const
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
genPairQR()
|
|
800
|
-
})
|
|
801
|
-
|
|
716
|
+
const ref = refNode.content.toString('utf-8');
|
|
717
|
+
const qr = buildPairingQRData(ref, noiseKeyB64, identityKeyB64, advB64, browser);
|
|
718
|
+
ev.emit('connection.update', { qr });
|
|
719
|
+
qrTimer = setTimeout(genPairQR, qrMs);
|
|
720
|
+
qrMs = qrTimeout || 20000; // shorter subsequent qrs
|
|
721
|
+
};
|
|
722
|
+
genPairQR();
|
|
723
|
+
});
|
|
724
|
+
// device paired for the first time
|
|
725
|
+
// if device pairs successfully, the server asks to restart the connection
|
|
802
726
|
ws.on('CB:iq,,pair-success', async (stanza) => {
|
|
803
|
-
logger.debug('pair success recv')
|
|
727
|
+
logger.debug('pair success recv');
|
|
804
728
|
try {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
await sendNode(reply)
|
|
821
|
-
} catch (error) {
|
|
822
|
-
logger.info({
|
|
823
|
-
trace: error.stack
|
|
824
|
-
}, 'error in pairing')
|
|
825
|
-
end(error)
|
|
826
|
-
}
|
|
827
|
-
})
|
|
828
|
-
|
|
729
|
+
updateServerTimeOffset(stanza);
|
|
730
|
+
const { reply, creds: updatedCreds } = configureSuccessfulPairing(stanza, creds);
|
|
731
|
+
logger.info({ me: updatedCreds.me, platform: updatedCreds.platform }, 'pairing configured successfully, expect to restart the connection...');
|
|
732
|
+
ev.emit('creds.update', updatedCreds);
|
|
733
|
+
ev.emit('connection.update', { isNewLogin: true, qr: undefined });
|
|
734
|
+
await sendNode(reply);
|
|
735
|
+
void sendUnifiedSession();
|
|
736
|
+
}
|
|
737
|
+
catch (error) {
|
|
738
|
+
logger.info({ trace: error.stack }, 'error in pairing');
|
|
739
|
+
void end(error);
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
// login complete
|
|
829
743
|
ws.on('CB:success', async (node) => {
|
|
830
744
|
try {
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
//
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
preKeyCheckInterval = setInterval(() => {
|
|
838
|
-
uploadPreKeysToServerIfRequired().catch((err) => {
|
|
839
|
-
logger.warn({ err }, 'periodic pre-key check failed')
|
|
840
|
-
})
|
|
841
|
-
}, 6 * 60 * 60 * 1000)
|
|
842
|
-
await sendPassiveIq('active')
|
|
843
|
-
} catch (err) {
|
|
844
|
-
logger.warn({
|
|
845
|
-
err
|
|
846
|
-
}, 'failed to send initial passive iq');
|
|
847
|
-
}
|
|
848
|
-
logger.info('opened connection to WA')
|
|
849
|
-
clearTimeout(qrTimer);
|
|
850
|
-
ev.emit('creds.update', {
|
|
851
|
-
me: {
|
|
852
|
-
...authState.creds.me,
|
|
853
|
-
lid: node.attrs.lid
|
|
745
|
+
updateServerTimeOffset(node);
|
|
746
|
+
await uploadPreKeysToServerIfRequired();
|
|
747
|
+
await sendPassiveIq('active');
|
|
748
|
+
// After successful login, validate our key-bundle against server
|
|
749
|
+
try {
|
|
750
|
+
await digestKeyBundle();
|
|
854
751
|
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
}
|
|
752
|
+
catch (e) {
|
|
753
|
+
logger.warn({ e }, 'failed to run digest after login');
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
catch (err) {
|
|
757
|
+
logger.warn({ err }, 'failed to send initial passive iq');
|
|
758
|
+
}
|
|
759
|
+
logger.info('opened connection to WA');
|
|
760
|
+
clearTimeout(qrTimer); // will never happen in all likelyhood -- but just in case WA sends success on first try
|
|
761
|
+
ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } });
|
|
762
|
+
ev.emit('connection.update', { connection: 'open' });
|
|
763
|
+
void sendUnifiedSession();
|
|
859
764
|
if (node.attrs.lid && authState.creds.me?.id) {
|
|
860
|
-
const myLID = node.attrs.lid
|
|
765
|
+
const myLID = node.attrs.lid;
|
|
861
766
|
process.nextTick(async () => {
|
|
862
767
|
try {
|
|
863
|
-
const myPN = authState.creds.me.id
|
|
864
|
-
|
|
865
|
-
await signalRepository.lidMapping.storeLIDPNMappings([{
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
logger.
|
|
876
|
-
error,
|
|
877
|
-
lid: myLID
|
|
878
|
-
}, 'Failed to create own LID session')
|
|
768
|
+
const myPN = authState.creds.me.id;
|
|
769
|
+
// Store our own LID-PN mapping
|
|
770
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: myLID, pn: myPN }]);
|
|
771
|
+
// Create device list for our own user (needed for bulk migration)
|
|
772
|
+
const { user, device } = jidDecode(myPN);
|
|
773
|
+
await authState.keys.set({
|
|
774
|
+
'device-list': {
|
|
775
|
+
[user]: [device?.toString() || '0']
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
// migrate our own session
|
|
779
|
+
await signalRepository.migrateSession(myPN, myLID);
|
|
780
|
+
logger.info({ myPN, myLID }, 'Own LID session created successfully');
|
|
879
781
|
}
|
|
880
|
-
|
|
782
|
+
catch (error) {
|
|
783
|
+
logger.error({ error, lid: myLID }, 'Failed to create own LID session');
|
|
784
|
+
}
|
|
785
|
+
});
|
|
881
786
|
}
|
|
882
|
-
})
|
|
883
|
-
|
|
787
|
+
});
|
|
884
788
|
ws.on('CB:stream:error', (node) => {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
} = Utils_1.getErrorCodeFromStreamError(node)
|
|
892
|
-
|
|
893
|
-
end(new boom_1.Boom(`Stream Errored (${reason})`, {
|
|
894
|
-
statusCode,
|
|
895
|
-
data: node
|
|
896
|
-
}))
|
|
897
|
-
})
|
|
898
|
-
|
|
789
|
+
const [reasonNode] = getAllBinaryNodeChildren(node);
|
|
790
|
+
logger.error({ reasonNode, fullErrorNode: node }, 'stream errored out');
|
|
791
|
+
const { reason, statusCode } = getErrorCodeFromStreamError(node);
|
|
792
|
+
void end(new Boom(`Stream Errored (${reason})`, { statusCode, data: reasonNode || node }));
|
|
793
|
+
});
|
|
794
|
+
// stream fail, possible logout
|
|
899
795
|
ws.on('CB:failure', (node) => {
|
|
900
|
-
const reason = +(node.attrs.reason || 500)
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
statusCode: reason,
|
|
904
|
-
data: node.attrs
|
|
905
|
-
}))
|
|
906
|
-
})
|
|
907
|
-
|
|
796
|
+
const reason = +(node.attrs.reason || 500);
|
|
797
|
+
void end(new Boom('Connection Failure', { statusCode: reason, data: node.attrs }));
|
|
798
|
+
});
|
|
908
799
|
ws.on('CB:ib,,downgrade_webclient', () => {
|
|
909
|
-
end(new
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
ws.on('CB:ib,,offline_preview', (node) => {
|
|
915
|
-
logger.info('offline preview received', JSON.stringify(node))
|
|
916
|
-
|
|
917
|
-
sendNode({
|
|
800
|
+
void end(new Boom('Multi-device beta not joined', { statusCode: DisconnectReason.multideviceMismatch }));
|
|
801
|
+
});
|
|
802
|
+
ws.on('CB:ib,,offline_preview', async (node) => {
|
|
803
|
+
logger.info('offline preview received', JSON.stringify(node));
|
|
804
|
+
await sendNode({
|
|
918
805
|
tag: 'ib',
|
|
919
806
|
attrs: {},
|
|
920
|
-
content: [{
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
count: '100'
|
|
924
|
-
}
|
|
925
|
-
}]
|
|
926
|
-
})
|
|
927
|
-
})
|
|
928
|
-
|
|
807
|
+
content: [{ tag: 'offline_batch', attrs: { count: '100' } }]
|
|
808
|
+
});
|
|
809
|
+
});
|
|
929
810
|
ws.on('CB:ib,,edge_routing', (node) => {
|
|
930
|
-
const edgeRoutingNode =
|
|
931
|
-
const routingInfo =
|
|
932
|
-
|
|
811
|
+
const edgeRoutingNode = getBinaryNodeChild(node, 'edge_routing');
|
|
812
|
+
const routingInfo = getBinaryNodeChild(edgeRoutingNode, 'routing_info');
|
|
933
813
|
if (routingInfo?.content) {
|
|
934
|
-
authState.creds.routingInfo = Buffer.from(routingInfo?.content)
|
|
935
|
-
ev.emit('creds.update', authState.creds)
|
|
814
|
+
authState.creds.routingInfo = Buffer.from(routingInfo?.content);
|
|
815
|
+
ev.emit('creds.update', authState.creds);
|
|
936
816
|
}
|
|
937
|
-
})
|
|
938
|
-
|
|
939
|
-
let didStartBuffer = false
|
|
940
|
-
|
|
817
|
+
});
|
|
818
|
+
let didStartBuffer = false;
|
|
941
819
|
process.nextTick(() => {
|
|
942
820
|
if (creds.me?.id) {
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
})
|
|
952
|
-
})
|
|
953
|
-
|
|
821
|
+
// start buffering important events
|
|
822
|
+
// if we're logged in
|
|
823
|
+
ev.buffer();
|
|
824
|
+
didStartBuffer = true;
|
|
825
|
+
}
|
|
826
|
+
ev.emit('connection.update', { connection: 'connecting', receivedPendingNotifications: false, qr: undefined });
|
|
827
|
+
});
|
|
828
|
+
// called when all offline notifs are handled
|
|
954
829
|
ws.on('CB:ib,,offline', (node) => {
|
|
955
|
-
const child =
|
|
956
|
-
const offlineNotifs = +(child?.attrs.count || 0)
|
|
957
|
-
|
|
958
|
-
logger.info(`handled ${offlineNotifs} offline messages/notifications`)
|
|
959
|
-
|
|
830
|
+
const child = getBinaryNodeChild(node, 'offline');
|
|
831
|
+
const offlineNotifs = +(child?.attrs.count || 0);
|
|
832
|
+
logger.info(`handled ${offlineNotifs} offline messages/notifications`);
|
|
960
833
|
if (didStartBuffer) {
|
|
961
|
-
ev.flush()
|
|
962
|
-
logger.trace('flushed events for initial buffer')
|
|
834
|
+
ev.flush();
|
|
835
|
+
logger.trace('flushed events for initial buffer');
|
|
963
836
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
})
|
|
968
|
-
})
|
|
969
|
-
|
|
837
|
+
ev.emit('connection.update', { receivedPendingNotifications: true });
|
|
838
|
+
});
|
|
839
|
+
// update credentials when required
|
|
970
840
|
ev.on('creds.update', update => {
|
|
971
|
-
const name = update.me?.name
|
|
841
|
+
const name = update.me?.name;
|
|
842
|
+
// if name has just been received
|
|
972
843
|
if (creds.me?.name !== name) {
|
|
973
|
-
logger.debug({
|
|
974
|
-
name
|
|
975
|
-
}, 'updated pushName')
|
|
976
|
-
|
|
844
|
+
logger.debug({ name }, 'updated pushName');
|
|
977
845
|
sendNode({
|
|
978
846
|
tag: 'presence',
|
|
979
|
-
attrs: {
|
|
980
|
-
name
|
|
981
|
-
}
|
|
847
|
+
attrs: { name: name }
|
|
982
848
|
}).catch(err => {
|
|
983
|
-
logger.warn({
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
849
|
+
logger.warn({ trace: err.stack }, 'error in sending presence update on name change');
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
Object.assign(creds, update);
|
|
853
|
+
});
|
|
854
|
+
const updateServerTimeOffset = ({ attrs }) => {
|
|
855
|
+
const tValue = attrs?.t;
|
|
856
|
+
if (!tValue) {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
const parsed = Number(tValue);
|
|
860
|
+
if (Number.isNaN(parsed) || parsed <= 0) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const localMs = Date.now();
|
|
864
|
+
serverTimeOffsetMs = parsed * 1000 - localMs;
|
|
865
|
+
logger.debug({ offset: serverTimeOffsetMs }, 'calculated server time offset');
|
|
866
|
+
};
|
|
867
|
+
const getUnifiedSessionId = () => {
|
|
868
|
+
const offsetMs = 3 * TimeMs.Day;
|
|
869
|
+
const now = Date.now() + serverTimeOffsetMs;
|
|
870
|
+
const id = (now + offsetMs) % TimeMs.Week;
|
|
871
|
+
return id.toString();
|
|
872
|
+
};
|
|
873
|
+
const sendUnifiedSession = async () => {
|
|
874
|
+
if (!ws.isOpen) {
|
|
875
|
+
return;
|
|
987
876
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
877
|
+
const node = {
|
|
878
|
+
tag: 'ib',
|
|
879
|
+
attrs: {},
|
|
880
|
+
content: [
|
|
881
|
+
{
|
|
882
|
+
tag: 'unified_session',
|
|
883
|
+
attrs: {
|
|
884
|
+
id: getUnifiedSessionId()
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
]
|
|
888
|
+
};
|
|
889
|
+
try {
|
|
890
|
+
await sendNode(node);
|
|
891
|
+
}
|
|
892
|
+
catch (error) {
|
|
893
|
+
logger.debug({ error }, 'failed to send unified_session telemetry');
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
const registerSocketEndHandler = (handler) => {
|
|
897
|
+
socketEndHandlers.push(handler);
|
|
898
|
+
};
|
|
899
|
+
/**
|
|
900
|
+
* Fetches your account's standing when it comes to restrictions.
|
|
901
|
+
* @returns Returns the state of the restrictions.
|
|
902
|
+
*/
|
|
903
|
+
const fetchAccountReachoutTimelock = async () => {
|
|
904
|
+
const queryResult = await executeWMexQuery({}, QueryIds.REACHOUT_TIMELOCK, XWAPaths.xwa2_fetch_account_reachout_timelock, query, generateMessageTag);
|
|
905
|
+
const result = {
|
|
906
|
+
isActive: !!queryResult?.is_active,
|
|
907
|
+
timeEnforcementEnds: queryResult?.time_enforcement_ends && queryResult?.time_enforcement_ends !== '0'
|
|
908
|
+
? new Date(parseInt(queryResult.time_enforcement_ends, 10) * 1000)
|
|
909
|
+
: undefined,
|
|
910
|
+
enforcementType: queryResult?.enforcement_type ?? ReachoutTimelockEnforcementType.DEFAULT
|
|
911
|
+
};
|
|
912
|
+
ev.emit('connection.update', { reachoutTimeLock: result });
|
|
913
|
+
return result;
|
|
914
|
+
};
|
|
915
|
+
/**
|
|
916
|
+
* Fetches your account's new chat limits.
|
|
917
|
+
* @returns Returns the quota and the usage.
|
|
918
|
+
*/
|
|
919
|
+
const fetchNewChatMessageCap = async () => {
|
|
920
|
+
return executeWMexQuery({ input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } }, QueryIds.MESSAGE_CAPPING_INFO, XWAPaths.xwa2_message_capping_info, query, generateMessageTag);
|
|
921
|
+
};
|
|
995
922
|
return {
|
|
996
|
-
type: '
|
|
923
|
+
type: 'md',
|
|
997
924
|
ws,
|
|
998
925
|
ev,
|
|
999
|
-
authState: {
|
|
1000
|
-
creds,
|
|
1001
|
-
keys
|
|
1002
|
-
},
|
|
926
|
+
authState: { creds, keys },
|
|
1003
927
|
signalRepository,
|
|
1004
928
|
get user() {
|
|
1005
|
-
return authState.creds.me
|
|
929
|
+
return authState.creds.me;
|
|
1006
930
|
},
|
|
1007
931
|
generateMessageTag,
|
|
1008
932
|
query,
|
|
@@ -1012,27 +936,32 @@ const makeSocket = (config) => {
|
|
|
1012
936
|
sendNode,
|
|
1013
937
|
logout,
|
|
1014
938
|
end,
|
|
939
|
+
registerSocketEndHandler,
|
|
1015
940
|
onUnexpectedError,
|
|
1016
941
|
uploadPreKeys,
|
|
1017
942
|
uploadPreKeysToServerIfRequired,
|
|
943
|
+
digestKeyBundle,
|
|
944
|
+
rotateSignedPreKey,
|
|
1018
945
|
requestPairingCode,
|
|
1019
|
-
|
|
946
|
+
updateServerTimeOffset,
|
|
947
|
+
sendUnifiedSession,
|
|
948
|
+
wamBuffer: publicWAMBuffer,
|
|
949
|
+
/** Waits for the connection to WA to reach a state */
|
|
950
|
+
waitForConnectionUpdate: bindWaitForConnectionUpdate(ev),
|
|
1020
951
|
sendWAMBuffer,
|
|
1021
952
|
executeUSyncQuery,
|
|
1022
953
|
onWhatsApp,
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
}
|
|
1026
|
-
|
|
954
|
+
fetchAccountReachoutTimelock,
|
|
955
|
+
fetchNewChatMessageCap
|
|
956
|
+
};
|
|
957
|
+
};
|
|
958
|
+
/**
|
|
959
|
+
* map the websocket error to the right type
|
|
960
|
+
* so it can be retried by the caller
|
|
961
|
+
* */
|
|
1027
962
|
function mapWebSocketError(handler) {
|
|
1028
963
|
return (error) => {
|
|
1029
|
-
handler(new
|
|
1030
|
-
|
|
1031
|
-
data: error
|
|
1032
|
-
}))
|
|
1033
|
-
}
|
|
964
|
+
handler(new Boom(`WebSocket Error (${error?.message})`, { statusCode: getCodeFromWSError(error), data: error }));
|
|
965
|
+
};
|
|
1034
966
|
}
|
|
1035
|
-
|
|
1036
|
-
module.exports = {
|
|
1037
|
-
makeSocket
|
|
1038
|
-
}
|
|
967
|
+
//# sourceMappingURL=socket.js.map
|