@neelegirl/baileys 1.5.6 → 1.5.8
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/README.md +24 -27
- package/WAProto/WAProto.proto +665 -291
- package/WAProto/index.d.ts +48037 -2294
- package/WAProto/index.js +139804 -45203
- package/lib/Defaults/baileys-version.json +3 -0
- package/lib/Defaults/index.d.ts +64 -58
- package/lib/Defaults/index.js +96 -74
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Signal/WASignalGroup/GroupProtocol.js +1909 -0
- package/lib/Signal/WASignalGroup/ciphertext_message.js +16 -0
- package/lib/Signal/WASignalGroup/generate-proto.sh +1 -0
- package/lib/Signal/WASignalGroup/group.proto +42 -0
- package/lib/Signal/WASignalGroup/group_cipher.js +120 -0
- package/lib/Signal/WASignalGroup/group_session_builder.js +46 -0
- package/lib/Signal/WASignalGroup/index.js +6 -0
- package/lib/Signal/WASignalGroup/keyhelper.js +21 -0
- package/lib/Signal/WASignalGroup/protobufs.js +3 -0
- package/lib/Signal/WASignalGroup/queue_job.js +69 -0
- package/lib/Signal/WASignalGroup/readme.md +6 -0
- package/lib/Signal/WASignalGroup/sender_chain_key.js +50 -0
- package/lib/Signal/WASignalGroup/sender_key_distribution_message.js +78 -0
- package/lib/Signal/WASignalGroup/sender_key_message.js +92 -0
- package/lib/Signal/WASignalGroup/sender_key_name.js +70 -0
- package/lib/Signal/WASignalGroup/sender_key_record.js +56 -0
- package/lib/Signal/WASignalGroup/sender_key_state.js +129 -0
- package/lib/Signal/{Group/sender-message-key.js → WASignalGroup/sender_message_key.js} +16 -3
- package/lib/Signal/libsignal.d.ts +4 -5
- package/lib/Signal/libsignal.js +112 -292
- package/lib/Socket/Client/abstract-socket-client.d.ts +15 -0
- package/lib/Socket/Client/abstract-socket-client.js +13 -0
- package/lib/Socket/Client/index.d.ts +2 -3
- package/lib/Socket/Client/index.js +22 -3
- package/lib/Socket/Client/mobile-socket-client.d.ts +12 -0
- package/lib/Socket/Client/mobile-socket-client.js +65 -0
- package/lib/Socket/Client/types.d.ts +15 -15
- package/lib/Socket/Client/types.js +15 -8
- package/lib/Socket/Client/websocket.d.ts +12 -12
- package/lib/Socket/Client/websocket.js +36 -24
- package/lib/Socket/business.d.ts +177 -178
- package/lib/Socket/business.js +71 -179
- package/lib/Socket/chats.d.ts +93 -93
- package/lib/Socket/chats.js +625 -474
- package/lib/Socket/communities.d.ts +62 -83
- package/lib/Socket/communities.js +414 -412
- package/lib/Socket/groups.d.ts +112 -118
- package/lib/Socket/groups.js +171 -146
- package/lib/Socket/index.d.ts +182 -222
- package/lib/Socket/index.js +17 -12
- package/lib/Socket/messages-recv.d.ts +169 -165
- package/lib/Socket/messages-recv.js +1721 -1185
- package/lib/Socket/messages-send.d.ts +160 -161
- package/lib/Socket/messages-send.js +992 -642
- package/lib/Socket/mex.d.ts +0 -1
- package/lib/Socket/mex.js +9 -4
- package/lib/Socket/newsletter.d.ts +139 -139
- package/lib/Socket/newsletter.js +258 -153
- package/lib/Socket/registration.d.ts +266 -0
- package/lib/Socket/registration.js +166 -0
- package/lib/Socket/socket.d.ts +36 -42
- package/lib/Socket/socket.js +615 -533
- package/lib/Socket/usync.d.ts +37 -0
- package/lib/Socket/usync.js +83 -0
- package/lib/Store/index.d.ts +4 -0
- package/lib/Store/index.js +24 -0
- package/lib/Store/make-cache-manager-store.d.ts +14 -0
- package/lib/Store/make-cache-manager-store.js +90 -0
- package/lib/Store/make-in-memory-store.d.ts +123 -0
- package/lib/Store/make-in-memory-store.js +429 -0
- package/lib/Store/make-ordered-dictionary.d.ts +12 -0
- package/lib/Store/make-ordered-dictionary.js +86 -0
- package/lib/Store/object-repository.d.ts +10 -0
- package/lib/Store/object-repository.js +31 -0
- package/lib/Types/Auth.d.ts +96 -87
- package/lib/Types/Auth.js +3 -2
- package/lib/Types/Call.d.ts +13 -13
- package/lib/Types/Call.js +3 -2
- package/lib/Types/Chat.d.ts +94 -79
- package/lib/Types/Chat.js +9 -8
- package/lib/Types/Contact.d.ts +9 -13
- package/lib/Types/Contact.js +3 -2
- package/lib/Types/Events.d.ts +179 -152
- package/lib/Types/Events.js +3 -2
- package/lib/Types/GroupMetadata.d.ts +48 -49
- package/lib/Types/GroupMetadata.js +3 -2
- package/lib/Types/Label.d.ts +14 -13
- package/lib/Types/Label.js +30 -24
- package/lib/Types/LabelAssociation.d.ts +20 -15
- package/lib/Types/LabelAssociation.js +12 -6
- package/lib/Types/Message.d.ts +404 -234
- package/lib/Types/Message.js +13 -11
- package/lib/Types/MexUpdates.d.ts +9 -0
- package/lib/Types/MexUpdates.js +18 -0
- package/lib/Types/Newsletter.d.ts +104 -130
- package/lib/Types/Newsletter.js +40 -31
- package/lib/Types/Product.d.ts +71 -58
- package/lib/Types/Product.js +3 -2
- package/lib/Types/Signal.d.ts +55 -63
- package/lib/Types/Signal.js +3 -2
- package/lib/Types/Socket.d.ts +66 -77
- package/lib/Types/Socket.js +3 -3
- package/lib/Types/State.d.ts +19 -17
- package/lib/Types/State.js +14 -13
- package/lib/Types/USync.d.ts +8 -8
- package/lib/Types/USync.js +3 -2
- package/lib/Types/index.d.ts +61 -47
- package/lib/Types/index.js +48 -26
- package/lib/Utils/auth-utils.d.ts +10 -8
- package/lib/Utils/auth-utils.js +154 -206
- package/lib/Utils/baileys-event-stream.d.ts +7 -6
- package/lib/Utils/baileys-event-stream.js +43 -29
- package/lib/Utils/business.d.ts +20 -14
- package/lib/Utils/business.js +134 -110
- package/lib/Utils/chat-utils.d.ts +69 -57
- package/lib/Utils/chat-utils.js +380 -362
- package/lib/Utils/check-npm-version.d.ts +15 -0
- package/lib/Utils/check-npm-version.js +52 -0
- package/lib/Utils/crypto.d.ts +45 -30
- package/lib/Utils/crypto.js +178 -141
- package/lib/Utils/decode-wa-message.d.ts +35 -42
- package/lib/Utils/decode-wa-message.js +150 -176
- package/lib/Utils/event-buffer.d.ts +17 -12
- package/lib/Utils/event-buffer.js +286 -269
- package/lib/Utils/generics.d.ts +99 -60
- package/lib/Utils/generics.js +481 -244
- package/lib/Utils/history.d.ts +22 -18
- package/lib/Utils/history.js +80 -54
- package/lib/Utils/index.d.ts +19 -20
- package/lib/Utils/index.js +41 -19
- package/lib/Utils/link-preview.d.ts +14 -12
- package/lib/Utils/link-preview.js +75 -40
- package/lib/Utils/logger.d.ts +11 -10
- package/lib/Utils/logger.js +7 -3
- package/lib/Utils/lt-hash.d.ts +13 -12
- package/lib/Utils/lt-hash.js +37 -27
- package/lib/Utils/make-mutex.d.ts +7 -6
- package/lib/Utils/make-mutex.js +29 -20
- package/lib/Utils/message-retry-manager.d.ts +6 -6
- package/lib/Utils/message-retry-manager.js +36 -8
- package/lib/Utils/messages-media.d.ts +102 -87
- package/lib/Utils/messages-media.js +570 -427
- package/lib/Utils/messages.d.ts +64 -37
- package/lib/Utils/messages.js +1270 -511
- package/lib/Utils/noise-handler.d.ts +18 -18
- package/lib/Utils/noise-handler.js +109 -101
- package/lib/Utils/process-message.d.ts +32 -25
- package/lib/Utils/process-message.js +281 -266
- package/lib/Utils/signal.d.ts +32 -24
- package/lib/Utils/signal.js +105 -98
- package/lib/Utils/use-mongo-file-auth-state.d.ts +6 -0
- package/lib/Utils/use-mongo-file-auth-state.js +84 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts +10 -5
- package/lib/Utils/use-multi-file-auth-state.js +186 -69
- package/lib/Utils/use-single-file-auth-state.d.ts +13 -0
- package/lib/Utils/use-single-file-auth-state.js +80 -0
- package/lib/Utils/validate-connection.d.ts +13 -11
- package/lib/Utils/validate-connection.js +116 -124
- package/lib/WABinary/constants.d.ts +27 -25
- package/lib/WABinary/constants.js +1292 -1277
- package/lib/WABinary/decode.d.ts +9 -7
- package/lib/WABinary/decode.js +189 -139
- package/lib/WABinary/encode.d.ts +3 -3
- package/lib/WABinary/encode.js +154 -105
- package/lib/WABinary/generic-utils.d.ts +27 -14
- package/lib/WABinary/generic-utils.js +102 -62
- package/lib/WABinary/index.d.ts +5 -6
- package/lib/WABinary/index.js +25 -6
- package/lib/WABinary/jid-utils.d.ts +46 -41
- package/lib/WABinary/jid-utils.js +80 -84
- package/lib/WABinary/types.d.ts +13 -10
- package/lib/WABinary/types.js +3 -2
- package/lib/WAM/BinaryInfo.d.ts +15 -8
- package/lib/WAM/BinaryInfo.js +14 -7
- package/lib/WAM/constants.d.ts +37 -30
- package/lib/WAM/constants.js +11983 -19465
- package/lib/WAM/encode.d.ts +3 -3
- package/lib/WAM/encode.js +110 -95
- package/lib/WAM/index.d.ts +3 -4
- package/lib/WAM/index.js +23 -4
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +28 -0
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +69 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -9
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +19 -12
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -19
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +26 -18
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -11
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +20 -12
- package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +9 -0
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +30 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -11
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +24 -16
- package/lib/WAUSync/Protocols/index.d.ts +6 -5
- package/lib/WAUSync/Protocols/index.js +26 -5
- package/lib/WAUSync/USyncQuery.d.ts +28 -26
- package/lib/WAUSync/USyncQuery.js +62 -64
- package/lib/WAUSync/USyncUser.d.ts +10 -11
- package/lib/WAUSync/USyncUser.js +19 -12
- package/lib/WAUSync/index.d.ts +3 -4
- package/lib/WAUSync/index.js +23 -4
- package/lib/index.d.ts +11 -10
- package/lib/index.js +33 -11
- package/package.json +43 -48
- package/WAProto/GenerateStatics.sh +0 -3
- package/WAProto/fix-imports.js +0 -29
- package/engine-requirements.js +0 -10
- 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 -171
- 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.map +0 -1
- package/lib/Socket/Client/websocket.d.ts.map +0 -1
- 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.map +0 -1
- 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.map +0 -1
- 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/Newsletter.d.ts.map +0 -1
- package/lib/Types/Newsletter.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/baileys-event-stream.d.ts.map +0 -1
- package/lib/Utils/baileys-event-stream.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 -28
- 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/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/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.map +0 -1
- 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/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/signal.d.ts.map +0 -1
- package/lib/Utils/signal.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/UsyncBotProfileProtocol.d.ts +0 -26
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -51
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -29
- 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.map +0 -1
- package/lib/index.js.map +0 -1
|
@@ -1,362 +1,474 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k)
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k] } }
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc)
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k
|
|
12
|
+
o[k2] = m[k]
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v })
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
22
|
+
if (mod && mod.__esModule) return mod
|
|
23
|
+
var result = {}
|
|
24
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k)
|
|
25
|
+
__setModuleDefault(result, mod)
|
|
26
|
+
return result
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
30
|
+
return (mod && mod.__esModule) ? mod : { "default": mod }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
34
|
+
|
|
35
|
+
const boom_1 = require("@hapi/boom")
|
|
36
|
+
const axios_1 = __importDefault(require("axios"))
|
|
37
|
+
const child_process_1 = require("child_process")
|
|
38
|
+
const Crypto = __importStar(require("crypto"))
|
|
39
|
+
const events_1 = require("events")
|
|
40
|
+
const fs_1 = require("fs")
|
|
41
|
+
const os_1 = require("os")
|
|
42
|
+
const path_1 = require("path")
|
|
43
|
+
const stream_1 = require("stream")
|
|
44
|
+
const WAProto_1 = require("../../WAProto")
|
|
45
|
+
const Defaults_1 = require("../Defaults")
|
|
46
|
+
const WABinary_1 = require("../WABinary")
|
|
47
|
+
const crypto_1 = require("./crypto")
|
|
48
|
+
const generics_1 = require("./generics")
|
|
49
|
+
|
|
16
50
|
const getImageProcessingLibrary = async () => {
|
|
17
|
-
|
|
18
|
-
|
|
51
|
+
const [_jimp, sharp] = await Promise.all([
|
|
52
|
+
(async () => {
|
|
53
|
+
const jimp = await (Promise.resolve().then(() => __importStar(require('jimp'))).catch(() => { }))
|
|
54
|
+
return jimp
|
|
55
|
+
})(),
|
|
56
|
+
(async () => {
|
|
57
|
+
const sharp = await (Promise.resolve().then(() => __importStar(require('sharp'))).catch(() => { }))
|
|
58
|
+
return sharp
|
|
59
|
+
})()
|
|
60
|
+
])
|
|
19
61
|
if (sharp) {
|
|
20
|
-
return { sharp }
|
|
62
|
+
return { sharp }
|
|
21
63
|
}
|
|
64
|
+
const jimp = _jimp?.default || _jimp
|
|
22
65
|
if (jimp) {
|
|
23
|
-
return { jimp }
|
|
24
|
-
}
|
|
25
|
-
throw new Boom('No image processing library available');
|
|
26
|
-
};
|
|
27
|
-
export const hkdfInfoKey = (type) => {
|
|
28
|
-
const hkdfInfo = MEDIA_HKDF_KEY_MAPPING[type];
|
|
29
|
-
return `WhatsApp ${hkdfInfo} Keys`;
|
|
30
|
-
};
|
|
31
|
-
export const getRawMediaUploadData = async (media, mediaType, logger) => {
|
|
32
|
-
const { stream } = await getStream(media);
|
|
33
|
-
logger?.debug('got stream for raw upload');
|
|
34
|
-
const hasher = Crypto.createHash('sha256');
|
|
35
|
-
const filePath = join(tmpdir(), mediaType + generateMessageIDV2());
|
|
36
|
-
const fileWriteStream = createWriteStream(filePath);
|
|
37
|
-
let fileLength = 0;
|
|
38
|
-
try {
|
|
39
|
-
for await (const data of stream) {
|
|
40
|
-
fileLength += data.length;
|
|
41
|
-
hasher.update(data);
|
|
42
|
-
if (!fileWriteStream.write(data)) {
|
|
43
|
-
await once(fileWriteStream, 'drain');
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
fileWriteStream.end();
|
|
47
|
-
await once(fileWriteStream, 'finish');
|
|
48
|
-
stream.destroy();
|
|
49
|
-
const fileSha256 = hasher.digest();
|
|
50
|
-
logger?.debug('hashed data for raw upload');
|
|
51
|
-
return {
|
|
52
|
-
filePath: filePath,
|
|
53
|
-
fileSha256,
|
|
54
|
-
fileLength
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
fileWriteStream.destroy();
|
|
59
|
-
stream.destroy();
|
|
60
|
-
try {
|
|
61
|
-
await fs.unlink(filePath);
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
//
|
|
65
|
-
}
|
|
66
|
-
throw error;
|
|
66
|
+
return { jimp }
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
throw new boom_1.Boom('No image processing library available')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const hkdfInfoKey = (type) => {
|
|
72
|
+
const hkdfInfo = Defaults_1.MEDIA_HKDF_KEY_MAPPING[type]
|
|
73
|
+
return `WhatsApp ${hkdfInfo} Keys`
|
|
74
|
+
}
|
|
75
|
+
|
|
69
76
|
/** generates all the keys required to encrypt/decrypt & sign a media message */
|
|
70
|
-
|
|
77
|
+
async function getMediaKeys(buffer, mediaType) {
|
|
71
78
|
if (!buffer) {
|
|
72
|
-
throw new Boom('Cannot derive from empty media key')
|
|
79
|
+
throw new boom_1.Boom('Cannot derive from empty media key')
|
|
73
80
|
}
|
|
74
81
|
if (typeof buffer === 'string') {
|
|
75
|
-
buffer = Buffer.from(buffer.replace('data
|
|
82
|
+
buffer = Buffer.from(buffer.replace('data:base64,', ''), 'base64')
|
|
76
83
|
}
|
|
77
84
|
// expand using HKDF to 112 bytes, also pass in the relevant app info
|
|
78
|
-
const expandedMediaKey = await hkdf(buffer, 112, { info: hkdfInfoKey(mediaType) })
|
|
85
|
+
const expandedMediaKey = await crypto_1.hkdf(buffer, 112, { info: hkdfInfoKey(mediaType) })
|
|
79
86
|
return {
|
|
80
87
|
iv: expandedMediaKey.slice(0, 16),
|
|
81
88
|
cipherKey: expandedMediaKey.slice(16, 48),
|
|
82
|
-
macKey: expandedMediaKey.slice(48, 80)
|
|
83
|
-
}
|
|
89
|
+
macKey: expandedMediaKey.slice(48, 80),
|
|
90
|
+
}
|
|
84
91
|
}
|
|
92
|
+
|
|
85
93
|
/** Extracts video thumb using FFMPEG */
|
|
86
|
-
const extractVideoThumb =
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
94
|
+
const extractVideoThumb = (videoPath, time = '00:00:00', size = { width: 320 }) => {
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
const args = [
|
|
97
|
+
'-ss', time,
|
|
98
|
+
'-i', videoPath,
|
|
99
|
+
'-y',
|
|
100
|
+
'-vf', `scale=${size.width}:-1`,
|
|
101
|
+
'-vframes', '1',
|
|
102
|
+
'-f', 'image2',
|
|
103
|
+
'-vcodec', 'mjpeg',
|
|
104
|
+
'pipe:1'
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
const ffmpeg = child_process_1.spawn('ffmpeg', args)
|
|
108
|
+
const chunks = []
|
|
109
|
+
let errorOutput = ''
|
|
110
|
+
|
|
111
|
+
ffmpeg.stdout.on('data', chunk => chunks.push(chunk))
|
|
112
|
+
ffmpeg.stderr.on('data', data => {
|
|
113
|
+
errorOutput += data.toString()
|
|
114
|
+
})
|
|
115
|
+
ffmpeg.on('error', reject)
|
|
116
|
+
ffmpeg.on('close', code => {
|
|
117
|
+
if (code === 0) return resolve(Buffer.concat(chunks))
|
|
118
|
+
reject(new Error(`ffmpeg exited with code ${code}\n${errorOutput}`))
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const extractImageThumb = async (bufferOrFilePath, width = 32, quality = 50) => {
|
|
124
|
+
if (typeof bufferOrFilePath === "string" && bufferOrFilePath.startsWith("http")) {
|
|
125
|
+
const response = await axios_1.default.get(bufferOrFilePath, { responseType: "arraybuffer" })
|
|
126
|
+
bufferOrFilePath = Buffer.from(response.data)
|
|
127
|
+
}
|
|
128
|
+
if (bufferOrFilePath instanceof stream_1.Readable) {
|
|
129
|
+
bufferOrFilePath = await toBuffer(bufferOrFilePath)
|
|
130
|
+
}
|
|
131
|
+
const lib = await getImageProcessingLibrary()
|
|
104
132
|
if ('sharp' in lib && typeof lib.sharp?.default === 'function') {
|
|
105
|
-
const img = lib.sharp.default(bufferOrFilePath)
|
|
106
|
-
const dimensions = await img.metadata()
|
|
107
|
-
const buffer = await img
|
|
133
|
+
const img = lib.sharp.default(bufferOrFilePath)
|
|
134
|
+
const dimensions = await img.metadata()
|
|
135
|
+
const buffer = await img
|
|
136
|
+
.resize({
|
|
137
|
+
width,
|
|
138
|
+
height: width,
|
|
139
|
+
fit: 'contain',
|
|
140
|
+
background: { r: 255, g: 255, b: 255, alpha: 0 }
|
|
141
|
+
})
|
|
142
|
+
.jpeg({ quality })
|
|
143
|
+
.toBuffer()
|
|
108
144
|
return {
|
|
109
145
|
buffer,
|
|
110
146
|
original: {
|
|
111
147
|
width: dimensions.width,
|
|
112
|
-
height: dimensions.height
|
|
113
|
-
}
|
|
114
|
-
}
|
|
148
|
+
height: dimensions.height,
|
|
149
|
+
},
|
|
150
|
+
}
|
|
115
151
|
}
|
|
116
|
-
else if ('jimp' in lib && typeof lib.jimp?.
|
|
117
|
-
const
|
|
152
|
+
else if ('jimp' in lib && typeof lib.jimp?.read === 'function') {
|
|
153
|
+
const { read, MIME_JPEG, RESIZE_BEZIER, AUTO } = lib.jimp
|
|
154
|
+
const jimp = await read(bufferOrFilePath)
|
|
118
155
|
const dimensions = {
|
|
119
|
-
width: jimp.
|
|
120
|
-
height: jimp.
|
|
121
|
-
}
|
|
156
|
+
width: jimp.getWidth(),
|
|
157
|
+
height: jimp.getHeight()
|
|
158
|
+
}
|
|
122
159
|
const buffer = await jimp
|
|
123
|
-
|
|
124
|
-
|
|
160
|
+
.quality(quality)
|
|
161
|
+
.resize(width, AUTO, RESIZE_BEZIER)
|
|
162
|
+
.getBufferAsync(MIME_JPEG)
|
|
125
163
|
return {
|
|
126
164
|
buffer,
|
|
127
165
|
original: dimensions
|
|
128
|
-
}
|
|
166
|
+
}
|
|
129
167
|
}
|
|
130
168
|
else {
|
|
131
|
-
throw new Boom('No image processing library available')
|
|
169
|
+
throw new boom_1.Boom('No image processing library available')
|
|
132
170
|
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
|
|
174
|
+
.replace(/\+/g, '-')
|
|
175
|
+
.replace(/\//g, '_')
|
|
176
|
+
.replace(/\=+$/, '')))
|
|
177
|
+
|
|
178
|
+
const generateProfilePicture = async (mediaUpload) => {
|
|
179
|
+
let bufferOrFilePath
|
|
138
180
|
if (Buffer.isBuffer(mediaUpload)) {
|
|
139
|
-
|
|
181
|
+
bufferOrFilePath = mediaUpload
|
|
182
|
+
}
|
|
183
|
+
else if ('url' in mediaUpload) {
|
|
184
|
+
bufferOrFilePath = mediaUpload.url.toString()
|
|
140
185
|
}
|
|
141
186
|
else {
|
|
142
|
-
|
|
143
|
-
const { stream } = await getStream(mediaUpload);
|
|
144
|
-
// Convert the resulting stream to a buffer
|
|
145
|
-
buffer = await toBuffer(stream);
|
|
187
|
+
bufferOrFilePath = await toBuffer(mediaUpload.stream)
|
|
146
188
|
}
|
|
147
|
-
const lib = await getImageProcessingLibrary()
|
|
148
|
-
let img
|
|
189
|
+
const lib = await getImageProcessingLibrary()
|
|
190
|
+
let img
|
|
149
191
|
if ('sharp' in lib && typeof lib.sharp?.default === 'function') {
|
|
150
|
-
img = lib.sharp
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
.jpeg({
|
|
154
|
-
quality: 50
|
|
192
|
+
img = await lib.sharp.default(bufferOrFilePath)
|
|
193
|
+
.resize(720, 720, {
|
|
194
|
+
fit: 'inside',
|
|
155
195
|
})
|
|
156
|
-
|
|
196
|
+
.jpeg({ quality: 50 })
|
|
197
|
+
.toBuffer()
|
|
157
198
|
}
|
|
158
|
-
else if ('jimp' in lib && typeof lib.jimp?.
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
|
|
199
|
+
else if ('jimp' in lib && typeof lib.jimp?.read === 'function') {
|
|
200
|
+
const { read, MIME_JPEG } = lib.jimp
|
|
201
|
+
const image = await read(bufferOrFilePath)
|
|
202
|
+
const min = image.getWidth()
|
|
203
|
+
const max = image.getHeight()
|
|
204
|
+
const cropped = image.crop(0, 0, min, max)
|
|
205
|
+
img = await cropped.scaleToFit(720, 720).getBufferAsync(MIME_JPEG)
|
|
163
206
|
}
|
|
164
207
|
else {
|
|
165
|
-
throw new Boom('No image processing library available')
|
|
208
|
+
throw new boom_1.Boom('No image processing library available')
|
|
166
209
|
}
|
|
167
210
|
return {
|
|
168
|
-
img: await img
|
|
169
|
-
}
|
|
170
|
-
}
|
|
211
|
+
img: await img,
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
|
|
171
216
|
/** gets the SHA256 of the given media message */
|
|
172
|
-
|
|
173
|
-
const media = Object.values(message)[0]
|
|
174
|
-
return media
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
217
|
+
const mediaMessageSHA256B64 = (message) => {
|
|
218
|
+
const media = Object.values(message)[0]
|
|
219
|
+
return (media === null || media === void 0 ? void 0 : media.fileSha256) && Buffer.from(media.fileSha256).toString('base64')
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function getAudioDuration(buffer) {
|
|
223
|
+
const musicMetadata = await Promise.resolve().then(() => __importStar(require('music-metadata')))
|
|
179
224
|
const options = {
|
|
180
|
-
|
|
181
|
-
}
|
|
225
|
+
duration: true
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
let metadata
|
|
229
|
+
|
|
182
230
|
if (Buffer.isBuffer(buffer)) {
|
|
183
|
-
metadata = await musicMetadata.parseBuffer(buffer, undefined, options)
|
|
231
|
+
metadata = await musicMetadata.parseBuffer(buffer, undefined, options)
|
|
184
232
|
}
|
|
185
233
|
else if (typeof buffer === 'string') {
|
|
186
|
-
metadata = await musicMetadata.parseFile(buffer, options)
|
|
234
|
+
metadata = await musicMetadata.parseFile(buffer, options)
|
|
187
235
|
}
|
|
188
236
|
else {
|
|
189
|
-
metadata = await musicMetadata.parseStream(buffer, undefined, options)
|
|
237
|
+
metadata = await musicMetadata.parseStream(buffer, undefined, options)
|
|
190
238
|
}
|
|
191
|
-
return metadata.format.duration
|
|
239
|
+
return metadata.format.duration
|
|
192
240
|
}
|
|
241
|
+
|
|
193
242
|
/**
|
|
194
243
|
referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
|
|
195
244
|
*/
|
|
196
|
-
|
|
245
|
+
async function getAudioWaveform(buffer, logger) {
|
|
197
246
|
try {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
let audioData;
|
|
247
|
+
const { default: decoder } = await eval('import(\'audio-decode\')')
|
|
248
|
+
let audioData
|
|
201
249
|
if (Buffer.isBuffer(buffer)) {
|
|
202
|
-
audioData = buffer
|
|
250
|
+
audioData = buffer
|
|
203
251
|
}
|
|
204
252
|
else if (typeof buffer === 'string') {
|
|
205
|
-
const rStream = createReadStream(buffer)
|
|
206
|
-
audioData = await toBuffer(rStream)
|
|
253
|
+
const rStream = fs_1.createReadStream(buffer)
|
|
254
|
+
audioData = await toBuffer(rStream)
|
|
207
255
|
}
|
|
208
256
|
else {
|
|
209
|
-
audioData = await toBuffer(buffer)
|
|
257
|
+
audioData = await toBuffer(buffer)
|
|
210
258
|
}
|
|
211
|
-
const audioBuffer = await decoder(audioData)
|
|
212
|
-
const rawData = audioBuffer.getChannelData(0)
|
|
213
|
-
const samples = 64
|
|
214
|
-
const blockSize = Math.floor(rawData.length / samples)
|
|
215
|
-
const filteredData = []
|
|
259
|
+
const audioBuffer = await decoder(audioData)
|
|
260
|
+
const rawData = audioBuffer.getChannelData(0) // We only need to work with one channel of data
|
|
261
|
+
const samples = 64 // Number of samples we want to have in our final data set
|
|
262
|
+
const blockSize = Math.floor(rawData.length / samples) // the number of samples in each subdivision
|
|
263
|
+
const filteredData = []
|
|
216
264
|
for (let i = 0; i < samples; i++) {
|
|
217
|
-
const blockStart = blockSize * i
|
|
218
|
-
let sum = 0
|
|
265
|
+
const blockStart = blockSize * i // the location of the first sample in the block
|
|
266
|
+
let sum = 0
|
|
219
267
|
for (let j = 0; j < blockSize; j++) {
|
|
220
|
-
sum = sum + Math.abs(rawData[blockStart + j])
|
|
268
|
+
sum = sum + Math.abs(rawData[blockStart + j]) // find the sum of all the samples in the block
|
|
221
269
|
}
|
|
222
|
-
filteredData.push(sum / blockSize)
|
|
270
|
+
filteredData.push(sum / blockSize) // divide the sum by the block size to get the average
|
|
223
271
|
}
|
|
224
272
|
// This guarantees that the largest data point will be set to 1, and the rest of the data will scale proportionally.
|
|
225
|
-
const multiplier = Math.pow(Math.max(...filteredData), -1)
|
|
226
|
-
const normalizedData = filteredData.map(n => n * multiplier)
|
|
273
|
+
const multiplier = Math.pow(Math.max(...filteredData), -1)
|
|
274
|
+
const normalizedData = filteredData.map((n) => n * multiplier)
|
|
227
275
|
// Generate waveform like WhatsApp
|
|
228
|
-
const waveform = new Uint8Array(normalizedData.map(n => Math.floor(100 * n)))
|
|
229
|
-
return waveform
|
|
276
|
+
const waveform = new Uint8Array(normalizedData.map((n) => Math.floor(100 * n)))
|
|
277
|
+
return waveform
|
|
230
278
|
}
|
|
231
279
|
catch (e) {
|
|
232
|
-
logger?.debug('Failed to generate waveform: ' + e)
|
|
280
|
+
logger?.debug('Failed to generate waveform: ' + e)
|
|
233
281
|
}
|
|
234
282
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
readable.
|
|
238
|
-
readable.push(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
283
|
+
|
|
284
|
+
const toReadable = (buffer) => {
|
|
285
|
+
const readable = new stream_1.Readable({ read: () => { } })
|
|
286
|
+
readable.push(buffer)
|
|
287
|
+
readable.push(null)
|
|
288
|
+
return readable
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const toBuffer = async (stream) => {
|
|
292
|
+
const chunks = []
|
|
243
293
|
for await (const chunk of stream) {
|
|
244
|
-
chunks.push(chunk)
|
|
294
|
+
chunks.push(chunk)
|
|
245
295
|
}
|
|
246
|
-
stream.destroy()
|
|
247
|
-
return Buffer.concat(chunks)
|
|
248
|
-
}
|
|
249
|
-
|
|
296
|
+
stream.destroy()
|
|
297
|
+
return Buffer.concat(chunks)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const getStream = async (item, opts) => {
|
|
250
301
|
if (Buffer.isBuffer(item)) {
|
|
251
|
-
return { stream: toReadable(item), type: 'buffer' }
|
|
302
|
+
return { stream: toReadable(item), type: 'buffer' }
|
|
252
303
|
}
|
|
253
304
|
if ('stream' in item) {
|
|
254
|
-
return { stream: item.stream, type: 'readable' }
|
|
255
|
-
}
|
|
256
|
-
const urlStr = item.url.toString();
|
|
257
|
-
if (urlStr.startsWith('data:')) {
|
|
258
|
-
const buffer = Buffer.from(urlStr.split(',')[1], 'base64');
|
|
259
|
-
return { stream: toReadable(buffer), type: 'buffer' };
|
|
305
|
+
return { stream: item.stream, type: 'readable' }
|
|
260
306
|
}
|
|
261
|
-
if (
|
|
262
|
-
return { stream: await getHttpStream(item.url, opts), type: 'remote' }
|
|
307
|
+
if (item.url.toString().startsWith('http://') || item.url.toString().startsWith('https://')) {
|
|
308
|
+
return { stream: await getHttpStream(item.url, opts), type: 'remote' }
|
|
263
309
|
}
|
|
264
|
-
return { stream: createReadStream(item.url), type: 'file' }
|
|
265
|
-
}
|
|
310
|
+
return { stream: fs_1.createReadStream(item.url), type: 'file' }
|
|
311
|
+
}
|
|
312
|
+
|
|
266
313
|
/** generates a thumbnail for a given media, if required */
|
|
267
|
-
|
|
268
|
-
let thumbnail
|
|
269
|
-
let originalImageDimensions
|
|
314
|
+
async function generateThumbnail(file, mediaType, options) {
|
|
315
|
+
let thumbnail
|
|
316
|
+
let originalImageDimensions
|
|
270
317
|
if (mediaType === 'image') {
|
|
271
|
-
const { buffer, original } = await extractImageThumb(file)
|
|
272
|
-
thumbnail = buffer.toString('base64')
|
|
318
|
+
const { buffer, original } = await extractImageThumb(file, 256, 95)
|
|
319
|
+
thumbnail = buffer.toString('base64')
|
|
273
320
|
if (original.width && original.height) {
|
|
274
321
|
originalImageDimensions = {
|
|
275
322
|
width: original.width,
|
|
276
|
-
height: original.height
|
|
277
|
-
}
|
|
323
|
+
height: original.height,
|
|
324
|
+
}
|
|
278
325
|
}
|
|
279
326
|
}
|
|
280
327
|
else if (mediaType === 'video') {
|
|
281
|
-
const imgFilename = join(getTmpFilesDirectory(), generateMessageIDV2() + '.jpg');
|
|
282
328
|
try {
|
|
283
|
-
await extractVideoThumb(file,
|
|
284
|
-
|
|
285
|
-
thumbnail = buff.toString('base64');
|
|
286
|
-
await fs.unlink(imgFilename);
|
|
329
|
+
const buff = await extractVideoThumb(file, '00:00:00', { width: 32, height: 32 })
|
|
330
|
+
thumbnail = buff.toString('base64')
|
|
287
331
|
}
|
|
288
332
|
catch (err) {
|
|
289
|
-
options
|
|
333
|
+
options?.logger?.debug('could not generate video thumb: ' + err)
|
|
290
334
|
}
|
|
291
335
|
}
|
|
292
336
|
return {
|
|
293
337
|
thumbnail,
|
|
294
338
|
originalImageDimensions
|
|
295
|
-
}
|
|
339
|
+
}
|
|
296
340
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
341
|
+
|
|
342
|
+
const getHttpStream = async (url, options = {}) => {
|
|
343
|
+
const fetched = await axios_1.default.get(url.toString(), { ...options, responseType: 'stream' })
|
|
344
|
+
return fetched.data
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
|
348
|
+
const { stream, type } = await getStream(media, opts)
|
|
349
|
+
logger?.debug('fetched media stream')
|
|
350
|
+
|
|
351
|
+
const encFilePath = path_1.join(os_1.tmpdir(), mediaType + generics_1.generateMessageID() + '-plain')
|
|
352
|
+
const encFileWriteStream = fs_1.createWriteStream(encFilePath)
|
|
353
|
+
|
|
354
|
+
let originalFilePath
|
|
355
|
+
let originalFileStream
|
|
356
|
+
|
|
357
|
+
if (type === 'file') {
|
|
358
|
+
originalFilePath = media.url.toString()
|
|
359
|
+
} else if (saveOriginalFileIfRequired) {
|
|
360
|
+
originalFilePath = path_1.join(os_1.tmpdir(), mediaType + generics_1.generateMessageID() + '-original')
|
|
361
|
+
originalFileStream = fs_1.createWriteStream(originalFilePath)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
let fileLength = 0
|
|
365
|
+
const sha256 = Crypto.createHash('sha256')
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
for await (const data of stream) {
|
|
369
|
+
fileLength += data.length
|
|
370
|
+
|
|
371
|
+
if (type === 'remote'
|
|
372
|
+
&& opts?.maxContentLength
|
|
373
|
+
&& fileLength + data.length > opts.maxContentLength) {
|
|
374
|
+
throw new boom_1.Boom(`content length exceeded when preparing "${type}"`, {
|
|
375
|
+
data: { media, type }
|
|
376
|
+
})
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
sha256.update(data)
|
|
380
|
+
encFileWriteStream.write(data)
|
|
381
|
+
|
|
382
|
+
if (originalFileStream && !originalFileStream.write(data)) {
|
|
383
|
+
await events_1.once(originalFileStream, 'drain')
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const fileSha256 = sha256.digest()
|
|
388
|
+
encFileWriteStream.end()
|
|
389
|
+
originalFileStream?.end?.call(originalFileStream)
|
|
390
|
+
stream.destroy()
|
|
391
|
+
|
|
392
|
+
logger?.debug('prepared plain stream successfully')
|
|
393
|
+
|
|
394
|
+
return {
|
|
395
|
+
mediaKey: undefined,
|
|
396
|
+
originalFilePath,
|
|
397
|
+
encFilePath,
|
|
398
|
+
mac: undefined,
|
|
399
|
+
fileEncSha256: undefined,
|
|
400
|
+
fileSha256,
|
|
401
|
+
fileLength
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
encFileWriteStream.destroy()
|
|
406
|
+
originalFileStream?.destroy?.call(originalFileStream)
|
|
407
|
+
sha256.destroy()
|
|
408
|
+
stream.destroy()
|
|
409
|
+
try {
|
|
410
|
+
await fs_1.promises.unlink(encFilePath)
|
|
411
|
+
if (originalFilePath && didSaveToTmpPath) {
|
|
412
|
+
await fs_1.promises.unlink(originalFilePath)
|
|
413
|
+
}
|
|
414
|
+
} catch (err) {
|
|
415
|
+
logger?.error({ err }, 'failed deleting tmp files')
|
|
416
|
+
}
|
|
417
|
+
throw error
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
|
|
422
|
+
const { stream, type } = await getStream(media, opts)
|
|
423
|
+
logger?.debug('fetched media stream')
|
|
424
|
+
const mediaKey = Crypto.randomBytes(32)
|
|
425
|
+
const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType)
|
|
426
|
+
const encFilePath = path_1.join(os_1.tmpdir(), mediaType + generics_1.generateMessageID() + '-enc')
|
|
427
|
+
const encFileWriteStream = fs_1.createWriteStream(encFilePath)
|
|
428
|
+
let originalFileStream
|
|
429
|
+
let originalFilePath
|
|
318
430
|
if (saveOriginalFileIfRequired) {
|
|
319
|
-
originalFilePath = join(
|
|
320
|
-
originalFileStream = createWriteStream(originalFilePath)
|
|
321
|
-
}
|
|
322
|
-
let fileLength = 0
|
|
323
|
-
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv)
|
|
324
|
-
const hmac = Crypto.createHmac('sha256', macKey).update(iv)
|
|
325
|
-
const sha256Plain = Crypto.createHash('sha256')
|
|
326
|
-
const sha256Enc = Crypto.createHash('sha256')
|
|
431
|
+
originalFilePath = path_1.join(os_1.tmpdir(), mediaType + generics_1.generateMessageID() + '-original')
|
|
432
|
+
originalFileStream = fs_1.createWriteStream(originalFilePath)
|
|
433
|
+
}
|
|
434
|
+
let fileLength = 0
|
|
435
|
+
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv)
|
|
436
|
+
const hmac = Crypto.createHmac('sha256', macKey).update(iv)
|
|
437
|
+
const sha256Plain = Crypto.createHash('sha256')
|
|
438
|
+
const sha256Enc = Crypto.createHash('sha256')
|
|
327
439
|
const onChunk = (buff) => {
|
|
328
|
-
sha256Enc.update(buff)
|
|
329
|
-
hmac.update(buff)
|
|
330
|
-
encFileWriteStream.write(buff)
|
|
331
|
-
}
|
|
440
|
+
sha256Enc.update(buff)
|
|
441
|
+
hmac.update(buff)
|
|
442
|
+
encFileWriteStream.write(buff)
|
|
443
|
+
}
|
|
332
444
|
try {
|
|
333
445
|
for await (const data of stream) {
|
|
334
|
-
fileLength += data.length
|
|
335
|
-
if (type === 'remote'
|
|
336
|
-
opts?.maxContentLength
|
|
337
|
-
fileLength + data.length > opts.maxContentLength) {
|
|
338
|
-
throw new Boom(`content length exceeded when encrypting "${type}"`, {
|
|
446
|
+
fileLength += data.length
|
|
447
|
+
if (type === 'remote'
|
|
448
|
+
&& opts?.maxContentLength
|
|
449
|
+
&& fileLength + data.length > opts.maxContentLength) {
|
|
450
|
+
throw new boom_1.Boom(`content length exceeded when encrypting "${type}"`, {
|
|
339
451
|
data: { media, type }
|
|
340
|
-
})
|
|
452
|
+
})
|
|
341
453
|
}
|
|
342
454
|
if (originalFileStream) {
|
|
343
455
|
if (!originalFileStream.write(data)) {
|
|
344
|
-
await once(originalFileStream, 'drain')
|
|
456
|
+
await events_1.once(originalFileStream, 'drain')
|
|
345
457
|
}
|
|
346
458
|
}
|
|
347
|
-
sha256Plain.update(data)
|
|
348
|
-
onChunk(aes.update(data))
|
|
459
|
+
sha256Plain.update(data)
|
|
460
|
+
onChunk(aes.update(data))
|
|
349
461
|
}
|
|
350
|
-
onChunk(aes.final())
|
|
351
|
-
const mac = hmac.digest().slice(0, 10)
|
|
352
|
-
sha256Enc.update(mac)
|
|
353
|
-
const fileSha256 = sha256Plain.digest()
|
|
354
|
-
const fileEncSha256 = sha256Enc.digest()
|
|
355
|
-
encFileWriteStream.write(mac)
|
|
356
|
-
encFileWriteStream.end()
|
|
357
|
-
originalFileStream?.end?.()
|
|
358
|
-
stream.destroy()
|
|
359
|
-
logger?.debug('encrypted data successfully')
|
|
462
|
+
onChunk(aes.final())
|
|
463
|
+
const mac = hmac.digest().slice(0, 10)
|
|
464
|
+
sha256Enc.update(mac)
|
|
465
|
+
const fileSha256 = sha256Plain.digest()
|
|
466
|
+
const fileEncSha256 = sha256Enc.digest()
|
|
467
|
+
encFileWriteStream.write(mac)
|
|
468
|
+
encFileWriteStream.end()
|
|
469
|
+
originalFileStream?.end?.call(originalFileStream)
|
|
470
|
+
stream.destroy()
|
|
471
|
+
logger?.debug('encrypted data successfully')
|
|
360
472
|
return {
|
|
361
473
|
mediaKey,
|
|
362
474
|
originalFilePath,
|
|
@@ -365,231 +477,232 @@ export const encryptedStream = async (media, mediaType, { logger, saveOriginalFi
|
|
|
365
477
|
fileEncSha256,
|
|
366
478
|
fileSha256,
|
|
367
479
|
fileLength
|
|
368
|
-
}
|
|
480
|
+
}
|
|
369
481
|
}
|
|
370
482
|
catch (error) {
|
|
371
483
|
// destroy all streams with error
|
|
372
|
-
encFileWriteStream.destroy()
|
|
373
|
-
originalFileStream?.destroy?.()
|
|
374
|
-
aes.destroy()
|
|
375
|
-
hmac.destroy()
|
|
376
|
-
sha256Plain.destroy()
|
|
377
|
-
sha256Enc.destroy()
|
|
378
|
-
stream.destroy()
|
|
484
|
+
encFileWriteStream.destroy()
|
|
485
|
+
originalFileStream?.destroy?.call(originalFileStream)
|
|
486
|
+
aes.destroy()
|
|
487
|
+
hmac.destroy()
|
|
488
|
+
sha256Plain.destroy()
|
|
489
|
+
sha256Enc.destroy()
|
|
490
|
+
stream.destroy()
|
|
379
491
|
try {
|
|
380
|
-
await
|
|
492
|
+
await fs_1.promises.unlink(encFilePath)
|
|
381
493
|
if (originalFilePath) {
|
|
382
|
-
await
|
|
494
|
+
await fs_1.promises.unlink(originalFilePath)
|
|
383
495
|
}
|
|
384
496
|
}
|
|
385
497
|
catch (err) {
|
|
386
|
-
logger?.error({ err }, 'failed deleting tmp files')
|
|
498
|
+
logger?.error({ err }, 'failed deleting tmp files')
|
|
387
499
|
}
|
|
388
|
-
throw error
|
|
500
|
+
throw error
|
|
389
501
|
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const DEF_HOST = 'mmg.whatsapp.net'
|
|
505
|
+
|
|
506
|
+
const AES_CHUNK_SIZE = 16
|
|
507
|
+
|
|
393
508
|
const toSmallestChunkSize = (num) => {
|
|
394
|
-
return Math.floor(num / AES_CHUNK_SIZE) * AES_CHUNK_SIZE
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
509
|
+
return Math.floor(num / AES_CHUNK_SIZE) * AES_CHUNK_SIZE
|
|
510
|
+
}
|
|
511
|
+
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`
|
|
512
|
+
|
|
513
|
+
const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
|
|
514
|
+
const isValidMediaUrl = url?.startsWith('https://mmg.whatsapp.net/')
|
|
515
|
+
const downloadUrl = isValidMediaUrl ? url : getUrlFromDirectPath(directPath)
|
|
516
|
+
|
|
400
517
|
if (!downloadUrl) {
|
|
401
|
-
|
|
518
|
+
throw new boom_1.Boom('No valid media URL or directPath present in message', { statusCode: 400 })
|
|
402
519
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
520
|
+
|
|
521
|
+
const keys = await getMediaKeys(mediaKey, type)
|
|
522
|
+
return downloadEncryptedContent(downloadUrl, keys, opts)
|
|
523
|
+
}
|
|
524
|
+
|
|
406
525
|
/**
|
|
407
526
|
* Decrypts and downloads an AES256-CBC encrypted file given the keys.
|
|
408
527
|
* Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
|
|
409
528
|
* */
|
|
410
|
-
|
|
411
|
-
let bytesFetched = 0
|
|
412
|
-
let startChunk = 0
|
|
413
|
-
let firstBlockIsIV = false
|
|
529
|
+
const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
|
|
530
|
+
let bytesFetched = 0
|
|
531
|
+
let startChunk = 0
|
|
532
|
+
let firstBlockIsIV = false
|
|
414
533
|
// if a start byte is specified -- then we need to fetch the previous chunk as that will form the IV
|
|
415
534
|
if (startByte) {
|
|
416
|
-
const chunk = toSmallestChunkSize(startByte || 0)
|
|
535
|
+
const chunk = toSmallestChunkSize(startByte || 0)
|
|
417
536
|
if (chunk) {
|
|
418
|
-
startChunk = chunk - AES_CHUNK_SIZE
|
|
419
|
-
bytesFetched = chunk
|
|
420
|
-
firstBlockIsIV = true
|
|
537
|
+
startChunk = chunk - AES_CHUNK_SIZE
|
|
538
|
+
bytesFetched = chunk
|
|
539
|
+
firstBlockIsIV = true
|
|
421
540
|
}
|
|
422
541
|
}
|
|
423
|
-
const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined
|
|
424
|
-
const headersInit = options?.headers ? options.headers : undefined;
|
|
542
|
+
const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined
|
|
425
543
|
const headers = {
|
|
426
|
-
...(
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
: headersInit
|
|
430
|
-
: {}),
|
|
431
|
-
Origin: DEFAULT_ORIGIN
|
|
432
|
-
};
|
|
544
|
+
...(options?.headers) || {},
|
|
545
|
+
Origin: Defaults_1.DEFAULT_ORIGIN,
|
|
546
|
+
}
|
|
433
547
|
if (startChunk || endChunk) {
|
|
434
|
-
headers.Range = `bytes=${startChunk}
|
|
548
|
+
headers.Range = `bytes=${startChunk}-`
|
|
435
549
|
if (endChunk) {
|
|
436
|
-
headers.Range += endChunk
|
|
550
|
+
headers.Range += endChunk
|
|
437
551
|
}
|
|
438
552
|
}
|
|
439
553
|
// download the message
|
|
440
554
|
const fetched = await getHttpStream(downloadUrl, {
|
|
441
|
-
...
|
|
442
|
-
headers
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
555
|
+
...options || {},
|
|
556
|
+
headers,
|
|
557
|
+
maxBodyLength: Infinity,
|
|
558
|
+
maxContentLength: Infinity,
|
|
559
|
+
})
|
|
560
|
+
let remainingBytes = Buffer.from([])
|
|
561
|
+
let aes
|
|
446
562
|
const pushBytes = (bytes, push) => {
|
|
447
563
|
if (startByte || endByte) {
|
|
448
|
-
const start = bytesFetched >= startByte ? undefined : Math.max(startByte - bytesFetched, 0)
|
|
449
|
-
const end = bytesFetched + bytes.length < endByte ? undefined : Math.max(endByte - bytesFetched, 0)
|
|
450
|
-
push(bytes.slice(start, end))
|
|
451
|
-
bytesFetched += bytes.length
|
|
564
|
+
const start = bytesFetched >= startByte ? undefined : Math.max(startByte - bytesFetched, 0)
|
|
565
|
+
const end = bytesFetched + bytes.length < endByte ? undefined : Math.max(endByte - bytesFetched, 0)
|
|
566
|
+
push(bytes.slice(start, end))
|
|
567
|
+
bytesFetched += bytes.length
|
|
452
568
|
}
|
|
453
569
|
else {
|
|
454
|
-
push(bytes)
|
|
570
|
+
push(bytes)
|
|
455
571
|
}
|
|
456
|
-
}
|
|
457
|
-
const output = new Transform({
|
|
572
|
+
}
|
|
573
|
+
const output = new stream_1.Transform({
|
|
458
574
|
transform(chunk, _, callback) {
|
|
459
|
-
let data = Buffer.concat([remainingBytes, chunk])
|
|
460
|
-
const decryptLength = toSmallestChunkSize(data.length)
|
|
461
|
-
remainingBytes = data.slice(decryptLength)
|
|
462
|
-
data = data.slice(0, decryptLength)
|
|
575
|
+
let data = Buffer.concat([remainingBytes, chunk])
|
|
576
|
+
const decryptLength = toSmallestChunkSize(data.length)
|
|
577
|
+
remainingBytes = data.slice(decryptLength)
|
|
578
|
+
data = data.slice(0, decryptLength)
|
|
463
579
|
if (!aes) {
|
|
464
|
-
let ivValue = iv
|
|
580
|
+
let ivValue = iv
|
|
465
581
|
if (firstBlockIsIV) {
|
|
466
|
-
ivValue = data.slice(0, AES_CHUNK_SIZE)
|
|
467
|
-
data = data.slice(AES_CHUNK_SIZE)
|
|
582
|
+
ivValue = data.slice(0, AES_CHUNK_SIZE)
|
|
583
|
+
data = data.slice(AES_CHUNK_SIZE)
|
|
468
584
|
}
|
|
469
|
-
aes = Crypto.createDecipheriv('aes-256-cbc', cipherKey, ivValue)
|
|
585
|
+
aes = Crypto.createDecipheriv('aes-256-cbc', cipherKey, ivValue)
|
|
470
586
|
// if an end byte that is not EOF is specified
|
|
471
587
|
// stop auto padding (PKCS7) -- otherwise throws an error for decryption
|
|
472
588
|
if (endByte) {
|
|
473
|
-
aes.setAutoPadding(false)
|
|
589
|
+
aes.setAutoPadding(false)
|
|
474
590
|
}
|
|
475
591
|
}
|
|
476
592
|
try {
|
|
477
|
-
pushBytes(aes.update(data), b => this.push(b))
|
|
478
|
-
callback()
|
|
593
|
+
pushBytes(aes.update(data), b => this.push(b))
|
|
594
|
+
callback()
|
|
479
595
|
}
|
|
480
596
|
catch (error) {
|
|
481
|
-
callback(error)
|
|
597
|
+
callback(error)
|
|
482
598
|
}
|
|
483
599
|
},
|
|
484
600
|
final(callback) {
|
|
485
601
|
try {
|
|
486
|
-
pushBytes(aes.final(), b => this.push(b))
|
|
487
|
-
callback()
|
|
602
|
+
pushBytes(aes.final(), b => this.push(b))
|
|
603
|
+
callback()
|
|
488
604
|
}
|
|
489
605
|
catch (error) {
|
|
490
|
-
callback(error)
|
|
606
|
+
callback(error)
|
|
491
607
|
}
|
|
492
|
-
}
|
|
493
|
-
})
|
|
494
|
-
return fetched.pipe(output, { end: true })
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
608
|
+
},
|
|
609
|
+
})
|
|
610
|
+
return fetched.pipe(output, { end: true })
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function extensionForMediaMessage(message) {
|
|
614
|
+
const getExtension = (mimetype) => mimetype.split('')[0].split('/')[1]
|
|
615
|
+
const type = Object.keys(message)[0]
|
|
616
|
+
let extension
|
|
617
|
+
if (type === 'locationMessage' ||
|
|
618
|
+
type === 'liveLocationMessage' ||
|
|
619
|
+
type === 'productMessage') {
|
|
620
|
+
extension = '.jpeg'
|
|
502
621
|
}
|
|
503
622
|
else {
|
|
504
|
-
const messageContent = message[type]
|
|
505
|
-
extension = getExtension(messageContent.mimetype)
|
|
623
|
+
const messageContent = message[type]
|
|
624
|
+
extension = getExtension(messageContent.mimetype)
|
|
506
625
|
}
|
|
507
|
-
return extension
|
|
626
|
+
return extension
|
|
508
627
|
}
|
|
509
|
-
|
|
510
|
-
|
|
628
|
+
|
|
629
|
+
const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
630
|
+
return async (filePath, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
|
511
631
|
// send a query JSON to obtain the url & auth token to upload our media
|
|
512
|
-
let uploadInfo = await refreshMediaConn(false)
|
|
513
|
-
let urls
|
|
514
|
-
|
|
515
|
-
|
|
632
|
+
let uploadInfo = await refreshMediaConn(false)
|
|
633
|
+
let urls
|
|
634
|
+
let media = Defaults_1.MEDIA_PATH_MAP[mediaType]
|
|
635
|
+
const hosts = [...customUploadHosts, ...uploadInfo.hosts]
|
|
636
|
+
fileEncSha256B64 = encodeBase64EncodedStringForUpload(fileEncSha256B64)
|
|
637
|
+
if (newsletter) {
|
|
638
|
+
media = media?.replace('/mms/', '/newsletter/newsletter-')
|
|
639
|
+
}
|
|
516
640
|
for (const { hostname } of hosts) {
|
|
517
|
-
logger.debug(`uploading to "${hostname}"`)
|
|
518
|
-
const auth = encodeURIComponent(uploadInfo.auth)
|
|
519
|
-
const url = `https://${hostname}${
|
|
641
|
+
logger.debug(`uploading to "${hostname}"`)
|
|
642
|
+
const auth = encodeURIComponent(uploadInfo.auth) // the auth token
|
|
643
|
+
const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`
|
|
520
644
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
521
|
-
let result
|
|
645
|
+
let result
|
|
522
646
|
try {
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
method: 'POST',
|
|
527
|
-
body: stream,
|
|
647
|
+
const body = await axios_1.default.post(url, fs_1.createReadStream(filePath), {
|
|
648
|
+
...options,
|
|
649
|
+
maxRedirects: 0,
|
|
528
650
|
headers: {
|
|
529
|
-
...
|
|
530
|
-
const hdrs = options?.headers;
|
|
531
|
-
if (!hdrs)
|
|
532
|
-
return {};
|
|
533
|
-
return Array.isArray(hdrs) ? Object.fromEntries(hdrs) : hdrs;
|
|
534
|
-
})(),
|
|
651
|
+
...options.headers || {},
|
|
535
652
|
'Content-Type': 'application/octet-stream',
|
|
536
|
-
Origin: DEFAULT_ORIGIN
|
|
653
|
+
'Origin': Defaults_1.DEFAULT_ORIGIN
|
|
537
654
|
},
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
546
|
-
catch {
|
|
547
|
-
parsed = undefined;
|
|
548
|
-
}
|
|
549
|
-
result = parsed;
|
|
655
|
+
httpsAgent: fetchAgent,
|
|
656
|
+
timeout: timeoutMs,
|
|
657
|
+
responseType: 'json',
|
|
658
|
+
maxBodyLength: Infinity,
|
|
659
|
+
maxContentLength: Infinity,
|
|
660
|
+
})
|
|
661
|
+
result = body.data
|
|
550
662
|
if (result?.url || result?.directPath) {
|
|
551
663
|
urls = {
|
|
552
664
|
mediaUrl: result.url,
|
|
553
|
-
directPath: result.direct_path
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
ts: result.ts
|
|
557
|
-
};
|
|
558
|
-
break;
|
|
665
|
+
directPath: result.direct_path
|
|
666
|
+
}
|
|
667
|
+
break
|
|
559
668
|
}
|
|
560
669
|
else {
|
|
561
|
-
uploadInfo = await refreshMediaConn(true)
|
|
562
|
-
throw new Error(`upload failed, reason: ${JSON.stringify(result)}`)
|
|
670
|
+
uploadInfo = await refreshMediaConn(true)
|
|
671
|
+
throw new Error(`upload failed, reason: ${JSON.stringify(result)}`)
|
|
563
672
|
}
|
|
564
673
|
}
|
|
565
674
|
catch (error) {
|
|
566
|
-
|
|
567
|
-
|
|
675
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
676
|
+
result = error.response?.data
|
|
677
|
+
}
|
|
678
|
+
const isLast = hostname === hosts[uploadInfo.hosts.length - 1]?.hostname
|
|
679
|
+
logger.warn({ trace: error.stack, uploadResult: result }, `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`)
|
|
568
680
|
}
|
|
569
681
|
}
|
|
570
682
|
if (!urls) {
|
|
571
|
-
throw new Boom('Media upload failed on all hosts', { statusCode: 500 })
|
|
683
|
+
throw new boom_1.Boom('Media upload failed on all hosts', { statusCode: 500 })
|
|
572
684
|
}
|
|
573
|
-
return urls
|
|
574
|
-
}
|
|
575
|
-
}
|
|
685
|
+
return urls
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
576
689
|
const getMediaRetryKey = (mediaKey) => {
|
|
577
|
-
return hkdf(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' })
|
|
578
|
-
}
|
|
690
|
+
return crypto_1.hkdf(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' })
|
|
691
|
+
}
|
|
579
692
|
/**
|
|
580
693
|
* Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
|
|
581
694
|
*/
|
|
582
|
-
|
|
583
|
-
const recp = { stanzaId: key.id }
|
|
584
|
-
const recpBuffer = proto.ServerErrorReceipt.encode(recp).finish()
|
|
585
|
-
const iv = Crypto.randomBytes(12)
|
|
586
|
-
const retryKey = await getMediaRetryKey(mediaKey)
|
|
587
|
-
const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id))
|
|
695
|
+
const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
696
|
+
const recp = { stanzaId: key.id }
|
|
697
|
+
const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish()
|
|
698
|
+
const iv = Crypto.randomBytes(12)
|
|
699
|
+
const retryKey = await getMediaRetryKey(mediaKey)
|
|
700
|
+
const ciphertext = crypto_1.aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id))
|
|
588
701
|
const req = {
|
|
589
702
|
tag: 'receipt',
|
|
590
703
|
attrs: {
|
|
591
704
|
id: key.id,
|
|
592
|
-
to: jidNormalizedUser(meId),
|
|
705
|
+
to: WABinary_1.jidNormalizedUser(meId),
|
|
593
706
|
type: 'server-error'
|
|
594
707
|
},
|
|
595
708
|
content: [
|
|
@@ -608,17 +721,18 @@ export const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
|
|
|
608
721
|
tag: 'rmr',
|
|
609
722
|
attrs: {
|
|
610
723
|
jid: key.remoteJid,
|
|
611
|
-
from_me: (!!key.fromMe).toString(),
|
|
724
|
+
'from_me': (!!key.fromMe).toString(),
|
|
612
725
|
// @ts-ignore
|
|
613
726
|
participant: key.participant || undefined
|
|
614
727
|
}
|
|
615
728
|
}
|
|
616
729
|
]
|
|
617
|
-
}
|
|
618
|
-
return req
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
|
|
730
|
+
}
|
|
731
|
+
return req
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const decodeMediaRetryNode = (node) => {
|
|
735
|
+
const rmrNode = WABinary_1.getBinaryNodeChild(node, 'rmr')
|
|
622
736
|
const event = {
|
|
623
737
|
key: {
|
|
624
738
|
id: node.attrs.id,
|
|
@@ -626,38 +740,67 @@ export const decodeMediaRetryNode = (node) => {
|
|
|
626
740
|
fromMe: rmrNode.attrs.from_me === 'true',
|
|
627
741
|
participant: rmrNode.attrs.participant
|
|
628
742
|
}
|
|
629
|
-
}
|
|
630
|
-
const errorNode = getBinaryNodeChild(node, 'error')
|
|
743
|
+
}
|
|
744
|
+
const errorNode = WABinary_1.getBinaryNodeChild(node, 'error')
|
|
631
745
|
if (errorNode) {
|
|
632
|
-
const errorCode = +errorNode.attrs.code
|
|
633
|
-
event.error = new Boom(`Failed to re-upload media (${errorCode})`, {
|
|
634
|
-
data: errorNode.attrs,
|
|
635
|
-
statusCode: getStatusCodeForMediaRetry(errorCode)
|
|
636
|
-
});
|
|
746
|
+
const errorCode = +errorNode.attrs.code
|
|
747
|
+
event.error = new boom_1.Boom(`Failed to re-upload media (${errorCode})`, { data: errorNode.attrs, statusCode: getStatusCodeForMediaRetry(errorCode) })
|
|
637
748
|
}
|
|
638
749
|
else {
|
|
639
|
-
const encryptedInfoNode = getBinaryNodeChild(node, 'encrypt')
|
|
640
|
-
const ciphertext = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_p')
|
|
641
|
-
const iv = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_iv')
|
|
750
|
+
const encryptedInfoNode = WABinary_1.getBinaryNodeChild(node, 'encrypt')
|
|
751
|
+
const ciphertext = WABinary_1.getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_p')
|
|
752
|
+
const iv = WABinary_1.getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_iv')
|
|
642
753
|
if (ciphertext && iv) {
|
|
643
|
-
event.media = { ciphertext, iv }
|
|
754
|
+
event.media = { ciphertext, iv }
|
|
644
755
|
}
|
|
645
756
|
else {
|
|
646
|
-
event.error = new Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 })
|
|
757
|
+
event.error = new boom_1.Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 })
|
|
647
758
|
}
|
|
648
759
|
}
|
|
649
|
-
return event
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
760
|
+
return event
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
const decryptMediaRetryData = async ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
764
|
+
const retryKey = await getMediaRetryKey(mediaKey)
|
|
765
|
+
const plaintext = crypto_1.aesDecryptGCM(ciphertext, retryKey, iv, Buffer.from(msgId))
|
|
766
|
+
return WAProto_1.proto.MediaRetryNotification.decode(plaintext)
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code]
|
|
770
|
+
|
|
657
771
|
const MEDIA_RETRY_STATUS_MAP = {
|
|
658
|
-
[proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
|
|
659
|
-
[proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
|
|
660
|
-
[proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
661
|
-
[proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418
|
|
662
|
-
}
|
|
663
|
-
|
|
772
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
|
|
773
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
|
|
774
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
775
|
+
[WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
module.exports = {
|
|
779
|
+
hkdfInfoKey,
|
|
780
|
+
getMediaKeys,
|
|
781
|
+
extractVideoThumb,
|
|
782
|
+
extractImageThumb,
|
|
783
|
+
encodeBase64EncodedStringForUpload,
|
|
784
|
+
generateProfilePicture,
|
|
785
|
+
mediaMessageSHA256B64,
|
|
786
|
+
getAudioDuration,
|
|
787
|
+
getAudioWaveform,
|
|
788
|
+
toReadable,
|
|
789
|
+
toBuffer,
|
|
790
|
+
getStream,
|
|
791
|
+
generateThumbnail,
|
|
792
|
+
getHttpStream,
|
|
793
|
+
prepareStream,
|
|
794
|
+
encryptedStream,
|
|
795
|
+
getUrlFromDirectPath,
|
|
796
|
+
downloadContentFromMessage,
|
|
797
|
+
downloadEncryptedContent,
|
|
798
|
+
extensionForMediaMessage,
|
|
799
|
+
getWAUploadToServer,
|
|
800
|
+
getMediaRetryKey,
|
|
801
|
+
encryptMediaRetryRequest,
|
|
802
|
+
decodeMediaRetryNode,
|
|
803
|
+
decryptMediaRetryData,
|
|
804
|
+
getStatusCodeForMediaRetry,
|
|
805
|
+
MEDIA_RETRY_STATUS_MAP
|
|
806
|
+
}
|