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