@modzneverdie/baileys 17.1.2 → 17.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/WAProto/GenerateStatics.sh +3 -0
- package/WAProto/WAProto.proto +6035 -0
- package/WAProto/fix-imports.js +81 -0
- package/WAProto/index.d.ts +2 -0
- package/WAProto/index.js +59469 -96804
- package/lib/Defaults/index.d.ts +29 -8
- package/lib/Defaults/index.d.ts.map +1 -0
- package/lib/Defaults/index.js +134 -141
- package/lib/Defaults/index.js.map +1 -0
- package/lib/Signal/Group/ciphertext-message.d.ts +1 -0
- package/lib/Signal/Group/ciphertext-message.d.ts.map +1 -0
- package/lib/Signal/Group/ciphertext-message.js +2 -5
- package/lib/Signal/Group/ciphertext-message.js.map +1 -0
- package/lib/Signal/Group/group-session-builder.d.ts +4 -3
- package/lib/Signal/Group/group-session-builder.d.ts.map +1 -0
- package/lib/Signal/Group/group-session-builder.js +7 -41
- package/lib/Signal/Group/group-session-builder.js.map +1 -0
- package/lib/Signal/Group/group_cipher.d.ts +4 -4
- package/lib/Signal/Group/group_cipher.d.ts.map +1 -0
- package/lib/Signal/Group/group_cipher.js +37 -51
- package/lib/Signal/Group/group_cipher.js.map +1 -0
- package/lib/Signal/Group/index.d.ts +12 -11
- package/lib/Signal/Group/index.d.ts.map +1 -0
- package/lib/Signal/Group/index.js +12 -57
- package/lib/Signal/Group/index.js.map +1 -0
- package/lib/Signal/Group/keyhelper.d.ts +2 -1
- package/lib/Signal/Group/keyhelper.d.ts.map +1 -0
- package/lib/Signal/Group/keyhelper.js +7 -44
- package/lib/Signal/Group/keyhelper.js.map +1 -0
- package/lib/Signal/Group/sender-chain-key.d.ts +3 -2
- package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -0
- package/lib/Signal/Group/sender-chain-key.js +7 -15
- package/lib/Signal/Group/sender-chain-key.js.map +1 -0
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +2 -1
- package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +8 -11
- package/lib/Signal/Group/sender-key-distribution-message.js.map +1 -0
- package/lib/Signal/Group/sender-key-message.d.ts +2 -1
- package/lib/Signal/Group/sender-key-message.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-message.js +9 -12
- package/lib/Signal/Group/sender-key-message.js.map +1 -0
- package/lib/Signal/Group/sender-key-name.d.ts +1 -0
- package/lib/Signal/Group/sender-key-name.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-name.js +2 -5
- package/lib/Signal/Group/sender-key-name.js.map +1 -0
- package/lib/Signal/Group/sender-key-record.d.ts +3 -2
- package/lib/Signal/Group/sender-key-record.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-record.js +9 -21
- package/lib/Signal/Group/sender-key-record.js.map +1 -0
- package/lib/Signal/Group/sender-key-state.d.ts +7 -6
- package/lib/Signal/Group/sender-key-state.d.ts.map +1 -0
- package/lib/Signal/Group/sender-key-state.js +27 -42
- package/lib/Signal/Group/sender-key-state.js.map +1 -0
- package/lib/Signal/Group/sender-message-key.d.ts +1 -0
- package/lib/Signal/Group/sender-message-key.d.ts.map +1 -0
- package/lib/Signal/Group/sender-message-key.js +4 -7
- package/lib/Signal/Group/sender-message-key.js.map +1 -0
- package/lib/Signal/libsignal.d.ts +5 -3
- package/lib/Signal/libsignal.d.ts.map +1 -0
- package/lib/Signal/libsignal.js +319 -90
- package/lib/Signal/libsignal.js.map +1 -0
- package/lib/Signal/lid-mapping.d.ts +19 -0
- package/lib/Signal/lid-mapping.d.ts.map +1 -0
- package/lib/Signal/lid-mapping.js +271 -0
- package/lib/Signal/lid-mapping.js.map +1 -0
- package/lib/Socket/Client/index.d.ts +3 -3
- package/lib/Socket/Client/index.d.ts.map +1 -0
- package/lib/Socket/Client/index.js +3 -19
- package/lib/Socket/Client/index.js.map +1 -0
- package/lib/Socket/Client/{abstract-socket-client.d.ts → types.d.ts} +4 -5
- package/lib/Socket/Client/types.d.ts.map +1 -0
- package/lib/Socket/Client/types.js +11 -0
- package/lib/Socket/Client/types.js.map +1 -0
- package/lib/Socket/Client/{web-socket-client.d.ts → websocket.d.ts} +3 -2
- package/lib/Socket/Client/websocket.d.ts.map +1 -0
- package/lib/Socket/Client/websocket.js +54 -0
- package/lib/Socket/Client/websocket.js.map +1 -0
- package/lib/Socket/business.d.ts +533 -168
- package/lib/Socket/business.d.ts.map +1 -0
- package/lib/Socket/business.js +405 -243
- package/lib/Socket/business.js.map +1 -0
- package/lib/Socket/chats.d.ts +84 -240
- package/lib/Socket/chats.d.ts.map +1 -0
- package/lib/Socket/chats.js +406 -385
- package/lib/Socket/chats.js.map +1 -0
- package/lib/Socket/communities.d.ts +645 -0
- package/lib/Socket/communities.d.ts.map +1 -0
- package/lib/Socket/communities.js +431 -0
- package/lib/Socket/communities.js.map +1 -0
- package/lib/Socket/dugong.d.ts +125 -249
- package/lib/Socket/dugong.d.ts.map +1 -0
- package/lib/Socket/dugong.js +749 -465
- package/lib/Socket/dugong.js.map +1 -0
- package/lib/Socket/groups.d.ts +93 -58
- package/lib/Socket/groups.d.ts.map +1 -0
- package/lib/Socket/groups.js +105 -95
- package/lib/Socket/groups.js.map +1 -0
- package/lib/Socket/index.d.ts +632 -169
- package/lib/Socket/index.d.ts.map +1 -0
- package/lib/Socket/index.js +15 -11
- package/lib/Socket/index.js.map +1 -0
- package/lib/Socket/messages-recv.d.ts +162 -85
- package/lib/Socket/messages-recv.d.ts.map +1 -0
- package/lib/Socket/messages-recv.js +806 -608
- package/lib/Socket/messages-recv.js.map +1 -0
- package/lib/Socket/messages-send.d.ts +576 -146
- package/lib/Socket/messages-send.d.ts.map +1 -0
- package/lib/Socket/messages-send.js +1563 -861
- package/lib/Socket/messages-send.js.map +1 -0
- package/lib/Socket/mex.d.ts +3 -0
- package/lib/Socket/mex.d.ts.map +1 -0
- package/lib/Socket/mex.js +48 -0
- package/lib/Socket/mex.js.map +1 -0
- package/lib/Socket/newsletter.d.ts +129 -86
- package/lib/Socket/newsletter.d.ts.map +1 -0
- package/lib/Socket/newsletter.js +438 -297
- package/lib/Socket/newsletter.js.map +1 -0
- package/lib/Socket/socket.d.ts +31 -19
- package/lib/Socket/socket.d.ts.map +1 -0
- package/lib/Socket/socket.js +512 -241
- package/lib/Socket/socket.js.map +1 -0
- package/lib/Types/Auth.d.ts +18 -12
- package/lib/Types/Auth.d.ts.map +1 -0
- package/lib/Types/Auth.js +2 -2
- package/lib/Types/Auth.js.map +1 -0
- package/lib/Types/Bussines.d.ts +37 -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 +3 -1
- package/lib/Types/Call.d.ts.map +1 -0
- package/lib/Types/Call.js +2 -2
- package/lib/Types/Call.js.map +1 -0
- package/lib/Types/Chat.d.ts +34 -13
- package/lib/Types/Chat.d.ts.map +1 -0
- package/lib/Types/Chat.js +8 -4
- package/lib/Types/Chat.js.map +1 -0
- package/lib/Types/Contact.d.ts +6 -1
- package/lib/Types/Contact.d.ts.map +1 -0
- package/lib/Types/Contact.js +2 -2
- package/lib/Types/Contact.js.map +1 -0
- package/lib/Types/Events.d.ts +97 -17
- package/lib/Types/Events.d.ts.map +1 -0
- package/lib/Types/Events.js +2 -2
- package/lib/Types/Events.js.map +1 -0
- package/lib/Types/GroupMetadata.d.ts +18 -5
- package/lib/Types/GroupMetadata.d.ts.map +1 -0
- package/lib/Types/GroupMetadata.js +2 -2
- package/lib/Types/GroupMetadata.js.map +1 -0
- package/lib/Types/Label.d.ts +12 -0
- package/lib/Types/Label.d.ts.map +1 -0
- package/lib/Types/Label.js +3 -5
- package/lib/Types/Label.js.map +1 -0
- package/lib/Types/LabelAssociation.d.ts +1 -0
- package/lib/Types/LabelAssociation.d.ts.map +1 -0
- package/lib/Types/LabelAssociation.js +3 -5
- package/lib/Types/LabelAssociation.js.map +1 -0
- package/lib/Types/Message.d.ts +355 -206
- package/lib/Types/Message.d.ts.map +1 -0
- package/lib/Types/Message.js +11 -9
- package/lib/Types/Message.js.map +1 -0
- package/lib/Types/Newsletter.d.ts +130 -98
- package/lib/Types/Newsletter.d.ts.map +1 -0
- package/lib/Types/Newsletter.js +31 -38
- package/lib/Types/Newsletter.js.map +1 -0
- package/lib/Types/Product.d.ts +2 -1
- package/lib/Types/Product.d.ts.map +1 -0
- package/lib/Types/Product.js +2 -2
- package/lib/Types/Product.js.map +1 -0
- package/lib/Types/Signal.d.ts +20 -1
- package/lib/Types/Signal.d.ts.map +1 -0
- package/lib/Types/Signal.js +2 -2
- package/lib/Types/Signal.js.map +1 -0
- package/lib/Types/Socket.d.ts +152 -105
- package/lib/Types/Socket.d.ts.map +1 -0
- package/lib/Types/Socket.js +3 -2
- package/lib/Types/Socket.js.map +1 -0
- package/lib/Types/State.d.ts +14 -2
- package/lib/Types/State.d.ts.map +1 -0
- package/lib/Types/State.js +13 -2
- package/lib/Types/State.js.map +1 -0
- package/lib/Types/USync.d.ts +3 -2
- package/lib/Types/USync.d.ts.map +1 -0
- package/lib/Types/USync.js +2 -2
- package/lib/Types/USync.js.map +1 -0
- package/lib/Types/index.d.ts +54 -45
- package/lib/Types/index.d.ts.map +1 -0
- package/lib/Types/index.js +32 -41
- package/lib/Types/index.js.map +1 -0
- package/lib/Utils/auth-utils.d.ts +7 -6
- package/lib/Utils/auth-utils.d.ts.map +1 -0
- package/lib/Utils/auth-utils.js +228 -144
- package/lib/Utils/auth-utils.js.map +1 -0
- package/lib/Utils/browser-utils.d.ts +4 -0
- package/lib/Utils/browser-utils.d.ts.map +1 -0
- package/lib/Utils/browser-utils.js +28 -0
- package/lib/Utils/browser-utils.js.map +1 -0
- package/lib/Utils/business.d.ts +3 -2
- package/lib/Utils/business.d.ts.map +1 -0
- package/lib/Utils/business.js +66 -69
- package/lib/Utils/business.js.map +1 -0
- package/lib/Utils/chat-utils.d.ts +19 -20
- package/lib/Utils/chat-utils.d.ts.map +1 -0
- package/lib/Utils/chat-utils.js +331 -248
- package/lib/Utils/chat-utils.js.map +1 -0
- package/lib/Utils/crypto.d.ts +10 -14
- package/lib/Utils/crypto.d.ts.map +1 -0
- package/lib/Utils/crypto.js +57 -90
- package/lib/Utils/crypto.js.map +1 -0
- package/lib/Utils/decode-wa-message.d.ts +37 -8
- package/lib/Utils/decode-wa-message.d.ts.map +1 -0
- package/lib/Utils/decode-wa-message.js +169 -84
- package/lib/Utils/decode-wa-message.js.map +1 -0
- package/lib/Utils/event-buffer.d.ts +7 -8
- package/lib/Utils/event-buffer.d.ts.map +1 -0
- package/lib/Utils/event-buffer.js +138 -78
- package/lib/Utils/event-buffer.js.map +1 -0
- package/lib/Utils/generics.d.ts +26 -27
- package/lib/Utils/generics.d.ts.map +1 -0
- package/lib/Utils/generics.js +170 -209
- package/lib/Utils/generics.js.map +1 -0
- package/lib/Utils/history.d.ts +16 -9
- package/lib/Utils/history.d.ts.map +1 -0
- package/lib/Utils/history.js +83 -48
- package/lib/Utils/history.js.map +1 -0
- package/lib/Utils/identity-change-handler.d.ts +37 -0
- package/lib/Utils/identity-change-handler.d.ts.map +1 -0
- package/lib/Utils/identity-change-handler.js +49 -0
- package/lib/Utils/identity-change-handler.js.map +1 -0
- package/lib/Utils/index.d.ts +23 -17
- package/lib/Utils/index.d.ts.map +1 -0
- package/lib/Utils/index.js +23 -33
- package/lib/Utils/index.js.map +1 -0
- package/lib/Utils/link-preview.d.ts +5 -5
- package/lib/Utils/link-preview.d.ts.map +1 -0
- package/lib/Utils/link-preview.js +14 -22
- package/lib/Utils/link-preview.js.map +1 -0
- package/lib/Utils/logger.d.ts +12 -3
- package/lib/Utils/logger.d.ts.map +1 -0
- package/lib/Utils/logger.js +3 -7
- package/lib/Utils/logger.js.map +1 -0
- package/lib/Utils/lt-hash.d.ts +8 -12
- package/lib/Utils/lt-hash.d.ts.map +1 -0
- package/lib/Utils/lt-hash.js +3 -46
- package/lib/Utils/lt-hash.js.map +1 -0
- package/lib/Utils/make-mutex.d.ts +4 -2
- package/lib/Utils/make-mutex.d.ts.map +1 -0
- package/lib/Utils/make-mutex.js +24 -34
- package/lib/Utils/make-mutex.js.map +1 -0
- package/lib/Utils/message-retry-manager.d.ts +110 -0
- package/lib/Utils/message-retry-manager.d.ts.map +1 -0
- package/lib/Utils/message-retry-manager.js +225 -0
- package/lib/Utils/message-retry-manager.js.map +1 -0
- package/lib/Utils/messages-media.d.ts +56 -42
- package/lib/Utils/messages-media.d.ts.map +1 -0
- package/lib/Utils/messages-media.js +411 -448
- package/lib/Utils/messages-media.js.map +1 -0
- package/lib/Utils/messages.d.ts +32 -18
- package/lib/Utils/messages.d.ts.map +1 -0
- package/lib/Utils/messages.js +1132 -710
- package/lib/Utils/messages.js.map +1 -0
- package/lib/Utils/noise-handler.d.ts +12 -13
- package/lib/Utils/noise-handler.d.ts.map +1 -0
- package/lib/Utils/noise-handler.js +145 -99
- package/lib/Utils/noise-handler.js.map +1 -0
- package/lib/Utils/offline-node-processor.d.ts +17 -0
- package/lib/Utils/offline-node-processor.d.ts.map +1 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/offline-node-processor.js.map +1 -0
- package/lib/Utils/pre-key-manager.d.ts +28 -0
- package/lib/Utils/pre-key-manager.d.ts.map +1 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/pre-key-manager.js.map +1 -0
- package/lib/Utils/process-message.d.ts +31 -12
- package/lib/Utils/process-message.d.ts.map +1 -0
- package/lib/Utils/process-message.js +357 -150
- package/lib/Utils/process-message.js.map +1 -0
- package/lib/Utils/reporting-utils.d.ts +11 -0
- package/lib/Utils/reporting-utils.d.ts.map +1 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/reporting-utils.js.map +1 -0
- package/lib/Utils/rich-messages.d.ts +277 -0
- package/lib/Utils/rich-messages.d.ts.map +1 -0
- package/lib/Utils/rich-messages.js +1144 -0
- package/lib/Utils/rich-messages.js.map +1 -0
- package/lib/Utils/signal.d.ts +7 -5
- package/lib/Utils/signal.d.ts.map +1 -0
- package/lib/Utils/signal.js +78 -72
- package/lib/Utils/signal.js.map +1 -0
- package/lib/Utils/stanza-ack.d.ts +11 -0
- package/lib/Utils/stanza-ack.d.ts.map +1 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/stanza-ack.js.map +1 -0
- package/lib/Utils/sticker-pack.d.ts +10 -0
- package/lib/Utils/sticker-pack.js +111 -0
- package/lib/Utils/sync-action-utils.d.ts +19 -0
- package/lib/Utils/sync-action-utils.d.ts.map +1 -0
- package/lib/Utils/sync-action-utils.js +48 -0
- package/lib/Utils/sync-action-utils.js.map +1 -0
- package/lib/Utils/tc-token-utils.d.ts +12 -0
- package/lib/Utils/tc-token-utils.d.ts.map +1 -0
- package/lib/Utils/tc-token-utils.js +18 -0
- package/lib/Utils/tc-token-utils.js.map +1 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts +2 -2
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -0
- package/lib/Utils/use-multi-file-auth-state.js +29 -27
- package/lib/Utils/use-multi-file-auth-state.js.map +1 -0
- package/lib/Utils/validate-connection.d.ts +7 -7
- package/lib/Utils/validate-connection.d.ts.map +1 -0
- package/lib/Utils/validate-connection.js +70 -99
- 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 +1281 -20
- package/lib/WABinary/constants.js.map +1 -0
- package/lib/WABinary/decode.d.ts +5 -5
- package/lib/WABinary/decode.d.ts.map +1 -0
- package/lib/WABinary/decode.js +52 -42
- package/lib/WABinary/decode.js.map +1 -0
- package/lib/WABinary/encode.d.ts +3 -3
- package/lib/WABinary/encode.d.ts.map +1 -0
- package/lib/WABinary/encode.js +110 -155
- package/lib/WABinary/encode.js.map +1 -0
- package/lib/WABinary/generic-utils.d.ts +8 -8
- package/lib/WABinary/generic-utils.d.ts.map +1 -0
- package/lib/WABinary/generic-utils.js +142 -149
- 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 -21
- package/lib/WABinary/index.js.map +1 -0
- package/lib/WABinary/jid-utils.d.ts +25 -8
- package/lib/WABinary/jid-utils.d.ts.map +1 -0
- package/lib/WABinary/jid-utils.js +74 -40
- package/lib/WABinary/jid-utils.js.map +1 -0
- package/lib/WABinary/types.d.ts +2 -1
- package/lib/WABinary/types.d.ts.map +1 -0
- package/lib/WABinary/types.js +2 -2
- package/lib/WABinary/types.js.map +1 -0
- package/lib/WAM/BinaryInfo.d.ts +3 -11
- package/lib/WAM/BinaryInfo.d.ts.map +1 -0
- package/lib/WAM/BinaryInfo.js +2 -5
- package/lib/WAM/BinaryInfo.js.map +1 -0
- package/lib/WAM/constants.d.ts +5 -3
- package/lib/WAM/constants.d.ts.map +1 -0
- package/lib/WAM/constants.js +19071 -11568
- package/lib/WAM/constants.js.map +1 -0
- package/lib/WAM/encode.d.ts +2 -2
- package/lib/WAM/encode.d.ts.map +1 -0
- package/lib/WAM/encode.js +17 -22
- 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 -19
- package/lib/WAM/index.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +4 -3
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +8 -11
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +3 -2
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -14
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +3 -2
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +9 -12
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +3 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -13
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +4 -3
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -22
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +5 -3
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +13 -8
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -0
- package/lib/WAUSync/Protocols/index.d.ts +5 -4
- package/lib/WAUSync/Protocols/index.d.ts.map +1 -0
- package/lib/WAUSync/Protocols/index.js +5 -20
- package/lib/WAUSync/Protocols/index.js.map +1 -0
- package/lib/WAUSync/USyncQuery.d.ts +5 -4
- package/lib/WAUSync/USyncQuery.d.ts.map +1 -0
- package/lib/WAUSync/USyncQuery.js +40 -35
- package/lib/WAUSync/USyncQuery.js.map +1 -0
- package/lib/WAUSync/USyncUser.d.ts +6 -5
- package/lib/WAUSync/USyncUser.d.ts.map +1 -0
- package/lib/WAUSync/USyncUser.js +2 -5
- 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 -19
- package/lib/WAUSync/index.js.map +1 -0
- package/lib/index.d.ts +10 -9
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +12 -33
- package/lib/index.js.map +1 -0
- package/package.json +64 -105
- package/README.md +0 -364
- package/engine-requirements.js +0 -10
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Signal/Group/queue-job.d.ts +0 -1
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Socket/Client/abstract-socket-client.js +0 -13
- package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
- package/lib/Socket/Client/mobile-socket-client.js +0 -65
- package/lib/Socket/Client/web-socket-client.js +0 -62
- package/lib/Socket/registration.d.ts +0 -267
- package/lib/Socket/registration.js +0 -166
- package/lib/Socket/usync.d.ts +0 -36
- package/lib/Socket/usync.js +0 -70
- package/lib/Store/index.d.ts +0 -3
- package/lib/Store/index.js +0 -10
- package/lib/Store/make-cache-manager-store.d.ts +0 -13
- package/lib/Store/make-cache-manager-store.js +0 -83
- package/lib/Store/make-in-memory-store.d.ts +0 -118
- package/lib/Store/make-in-memory-store.js +0 -427
- package/lib/Store/make-ordered-dictionary.d.ts +0 -13
- package/lib/Store/make-ordered-dictionary.js +0 -81
- package/lib/Store/object-repository.d.ts +0 -10
- package/lib/Store/object-repository.js +0 -27
- package/lib/Utils/baileys-event-stream.d.ts +0 -16
- package/lib/Utils/baileys-event-stream.js +0 -63
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.getStatusCodeForMediaRetry = exports.decryptMediaRetryData = exports.decodeMediaRetryNode = exports.encryptMediaRetryRequest = exports.getWAUploadToServer = exports.extensionForMediaMessage = exports.downloadEncryptedContent = exports.downloadContentFromMessage = exports.getUrlFromDirectPath = exports.encryptedStream = exports.prepareStream = exports.getHttpStream = exports.generateThumbnail = exports.getStream = exports.toBuffer = exports.toReadable = exports.getAudioWaveform = exports.getAudioDuration = exports.mediaMessageSHA256B64 = exports.generateProfilePicture = exports.encodeBase64EncodedStringForUpload = exports.extractImageThumb = exports.getMediaKeys = exports.hkdfInfoKey = void 0;
|
|
27
|
-
const boom_1 = require("@hapi/boom");
|
|
28
|
-
const child_process_1 = require("child_process");
|
|
29
|
-
const Crypto = __importStar(require("crypto"));
|
|
30
|
-
const events_1 = require("events");
|
|
31
|
-
const fs_1 = require("fs");
|
|
32
|
-
const os_1 = require("os");
|
|
33
|
-
const path_1 = require("path");
|
|
34
|
-
const stream_1 = require("stream");
|
|
35
|
-
const WAProto_1 = require("../../WAProto");
|
|
36
|
-
const Defaults_1 = require("../Defaults");
|
|
37
|
-
const WABinary_1 = require("../WABinary");
|
|
38
|
-
const crypto_1 = require("./crypto");
|
|
39
|
-
const generics_1 = require("./generics");
|
|
40
|
-
const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
|
|
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();
|
|
41
16
|
const getImageProcessingLibrary = async () => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const jimp = await (import('jimp')
|
|
45
|
-
.catch(() => { }));
|
|
46
|
-
return jimp;
|
|
47
|
-
})(),
|
|
48
|
-
(async () => {
|
|
49
|
-
const sharp = await (import('sharp')
|
|
50
|
-
.catch(() => { }));
|
|
51
|
-
return sharp;
|
|
52
|
-
})()
|
|
53
|
-
]);
|
|
17
|
+
//@ts-ignore
|
|
18
|
+
const [jimp, sharp] = await Promise.all([import('jimp').catch(() => { }), import('sharp').catch(() => { })]);
|
|
54
19
|
if (sharp) {
|
|
55
20
|
return { sharp };
|
|
56
21
|
}
|
|
57
|
-
const jimp = (_jimp === null || _jimp === void 0 ? void 0 : _jimp.default) || _jimp;
|
|
58
22
|
if (jimp) {
|
|
59
23
|
return { jimp };
|
|
60
24
|
}
|
|
61
|
-
throw new
|
|
25
|
+
throw new Boom('No image processing library available');
|
|
62
26
|
};
|
|
63
|
-
const hkdfInfoKey = (type) => {
|
|
64
|
-
const hkdfInfo =
|
|
27
|
+
export const hkdfInfoKey = (type) => {
|
|
28
|
+
const hkdfInfo = MEDIA_HKDF_KEY_MAPPING[type];
|
|
65
29
|
return `WhatsApp ${hkdfInfo} Keys`;
|
|
66
30
|
};
|
|
67
|
-
|
|
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;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
68
69
|
/** generates all the keys required to encrypt/decrypt & sign a media message */
|
|
69
|
-
function getMediaKeys(buffer, mediaType) {
|
|
70
|
+
export async function getMediaKeys(buffer, mediaType) {
|
|
70
71
|
if (!buffer) {
|
|
71
|
-
throw new
|
|
72
|
+
throw new Boom('Cannot derive from empty media key');
|
|
72
73
|
}
|
|
73
74
|
if (typeof buffer === 'string') {
|
|
74
75
|
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
|
|
75
76
|
}
|
|
76
77
|
// expand using HKDF to 112 bytes, also pass in the relevant app info
|
|
77
|
-
const expandedMediaKey =
|
|
78
|
+
const expandedMediaKey = hkdf(buffer, 112, { info: hkdfInfoKey(mediaType) });
|
|
78
79
|
return {
|
|
79
80
|
iv: expandedMediaKey.slice(0, 16),
|
|
80
81
|
cipherKey: expandedMediaKey.slice(16, 48),
|
|
81
|
-
macKey: expandedMediaKey.slice(48, 80)
|
|
82
|
+
macKey: expandedMediaKey.slice(48, 80)
|
|
82
83
|
};
|
|
83
84
|
}
|
|
84
|
-
exports.getMediaKeys = getMediaKeys;
|
|
85
85
|
/** Extracts video thumb using FFMPEG */
|
|
86
86
|
const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
|
|
87
87
|
const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
|
|
88
|
-
|
|
88
|
+
exec(cmd, err => {
|
|
89
89
|
if (err) {
|
|
90
90
|
reject(err);
|
|
91
91
|
}
|
|
@@ -94,240 +94,151 @@ const extractVideoThumb = async (path, destPath, time, size) => new Promise((res
|
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
96
|
});
|
|
97
|
-
const extractImageThumb = async (bufferOrFilePath, width = 32) => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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);
|
|
101
102
|
}
|
|
102
103
|
const lib = await getImageProcessingLibrary();
|
|
103
|
-
if ('sharp' in lib && typeof
|
|
104
|
+
if ('sharp' in lib && typeof lib.sharp?.default === 'function') {
|
|
104
105
|
const img = lib.sharp.default(bufferOrFilePath);
|
|
105
106
|
const dimensions = await img.metadata();
|
|
106
|
-
const buffer = await img
|
|
107
|
-
.resize(width)
|
|
108
|
-
.jpeg({ quality: 50 })
|
|
109
|
-
.toBuffer();
|
|
107
|
+
const buffer = await img.resize(width).jpeg({ quality: 50 }).toBuffer();
|
|
110
108
|
return {
|
|
111
109
|
buffer,
|
|
112
110
|
original: {
|
|
113
111
|
width: dimensions.width,
|
|
114
|
-
height: dimensions.height
|
|
115
|
-
}
|
|
112
|
+
height: dimensions.height
|
|
113
|
+
}
|
|
116
114
|
};
|
|
117
115
|
}
|
|
118
|
-
else if ('jimp' in lib && typeof
|
|
119
|
-
const
|
|
120
|
-
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);
|
|
121
118
|
const dimensions = {
|
|
122
|
-
width: jimp.
|
|
123
|
-
height: jimp.
|
|
119
|
+
width: jimp.width,
|
|
120
|
+
height: jimp.height
|
|
124
121
|
};
|
|
125
122
|
const buffer = await jimp
|
|
126
|
-
.
|
|
127
|
-
.
|
|
128
|
-
.getBufferAsync(MIME_JPEG);
|
|
123
|
+
.resize({ w: width, mode: lib.jimp.ResizeStrategy.BILINEAR })
|
|
124
|
+
.getBuffer('image/jpeg', { quality: 50 });
|
|
129
125
|
return {
|
|
130
126
|
buffer,
|
|
131
127
|
original: dimensions
|
|
132
128
|
};
|
|
133
129
|
}
|
|
134
130
|
else {
|
|
135
|
-
throw new
|
|
131
|
+
throw new Boom('No image processing library available');
|
|
136
132
|
}
|
|
137
133
|
};
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
.replace(/\=+$/, '')));
|
|
143
|
-
exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
|
|
144
|
-
const generateProfilePicture = async (mediaUpload) => {
|
|
145
|
-
var _a, _b;
|
|
146
|
-
let bufferOrFilePath;
|
|
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 || {};
|
|
147
138
|
if (Buffer.isBuffer(mediaUpload)) {
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
else if ('url' in mediaUpload) {
|
|
151
|
-
bufferOrFilePath = mediaUpload.url.toString();
|
|
139
|
+
buffer = mediaUpload;
|
|
152
140
|
}
|
|
153
141
|
else {
|
|
154
|
-
|
|
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);
|
|
155
146
|
}
|
|
156
147
|
const lib = await getImageProcessingLibrary();
|
|
157
148
|
let img;
|
|
158
|
-
if ('sharp' in lib && typeof
|
|
159
|
-
img = lib.sharp
|
|
160
|
-
.
|
|
149
|
+
if ('sharp' in lib && typeof lib.sharp?.default === 'function') {
|
|
150
|
+
img = lib.sharp
|
|
151
|
+
.default(buffer)
|
|
152
|
+
.resize(w, h)
|
|
161
153
|
.jpeg({
|
|
162
|
-
quality: 50
|
|
154
|
+
quality: 50
|
|
163
155
|
})
|
|
164
156
|
.toBuffer();
|
|
165
157
|
}
|
|
166
|
-
else if ('jimp' in lib && typeof
|
|
167
|
-
const
|
|
168
|
-
const
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
img = cropped
|
|
172
|
-
.quality(50)
|
|
173
|
-
.resize(640, 640, RESIZE_BILINEAR)
|
|
174
|
-
.getBufferAsync(MIME_JPEG);
|
|
158
|
+
else if ('jimp' in lib && typeof lib.jimp?.Jimp === 'function') {
|
|
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 });
|
|
175
163
|
}
|
|
176
164
|
else {
|
|
177
|
-
throw new
|
|
165
|
+
throw new Boom('No image processing library available');
|
|
178
166
|
}
|
|
179
167
|
return {
|
|
180
|
-
img: await img
|
|
168
|
+
img: await img
|
|
181
169
|
};
|
|
182
170
|
};
|
|
183
|
-
exports.generateProfilePicture = generateProfilePicture;
|
|
184
171
|
/** gets the SHA256 of the given media message */
|
|
185
|
-
const mediaMessageSHA256B64 = (message) => {
|
|
172
|
+
export const mediaMessageSHA256B64 = (message) => {
|
|
186
173
|
const media = Object.values(message)[0];
|
|
187
|
-
return
|
|
174
|
+
return media?.fileSha256 && Buffer.from(media.fileSha256).toString('base64');
|
|
188
175
|
};
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
} catch (error) {
|
|
206
|
-
const musicMetadata = await import('music-metadata');
|
|
207
|
-
let metadata;
|
|
208
|
-
if (Buffer.isBuffer(buffer)) {
|
|
209
|
-
metadata = await musicMetadata.parseBuffer(buffer, undefined, {
|
|
210
|
-
duration: true
|
|
211
|
-
});
|
|
212
|
-
} else if (typeof buffer === 'string') {
|
|
213
|
-
const rStream = (0, fs_1.createReadStream)(buffer);
|
|
214
|
-
try {
|
|
215
|
-
metadata = await musicMetadata.parseStream(rStream, undefined, {
|
|
216
|
-
duration: true
|
|
217
|
-
});
|
|
218
|
-
} finally {
|
|
219
|
-
rStream.destroy();
|
|
220
|
-
}
|
|
221
|
-
} else {
|
|
222
|
-
metadata = await musicMetadata.parseStream(buffer, undefined, {
|
|
223
|
-
duration: true
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
return metadata.format.duration;
|
|
176
|
+
export async function getAudioDuration(buffer) {
|
|
177
|
+
const musicMetadata = await import('music-metadata');
|
|
178
|
+
let metadata;
|
|
179
|
+
const options = {
|
|
180
|
+
duration: true
|
|
181
|
+
};
|
|
182
|
+
if (Buffer.isBuffer(buffer)) {
|
|
183
|
+
metadata = await musicMetadata.parseBuffer(buffer, undefined, options);
|
|
184
|
+
}
|
|
185
|
+
else if (typeof buffer === 'string') {
|
|
186
|
+
metadata = await musicMetadata.parseFile(buffer, options);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
metadata = await musicMetadata.parseStream(buffer, undefined, options);
|
|
227
190
|
}
|
|
191
|
+
return metadata.format.duration;
|
|
228
192
|
}
|
|
229
|
-
|
|
230
|
-
|
|
193
|
+
/**
|
|
194
|
+
referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
|
|
195
|
+
*/
|
|
196
|
+
export async function getAudioWaveform(buffer, logger) {
|
|
231
197
|
try {
|
|
232
|
-
|
|
233
|
-
const
|
|
234
|
-
|
|
198
|
+
// @ts-ignore
|
|
199
|
+
const { default: decoder } = await import('audio-decode');
|
|
235
200
|
let audioData;
|
|
236
201
|
if (Buffer.isBuffer(buffer)) {
|
|
237
202
|
audioData = buffer;
|
|
238
|
-
} else if (typeof buffer === 'string') {
|
|
239
|
-
const rStream = require('fs').createReadStream(buffer);
|
|
240
|
-
audioData = await exports.toBuffer(rStream);
|
|
241
|
-
} else {
|
|
242
|
-
audioData = await exports.toBuffer(buffer);
|
|
243
203
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const max = Math.max(...avg);
|
|
273
|
-
const normalized = avg.map(v => Math.floor((v / max) * 100));
|
|
274
|
-
resolve(new Uint8Array(normalized));
|
|
275
|
-
})
|
|
276
|
-
.pipe()
|
|
277
|
-
.on('data', chunk => chunks.push(chunk));
|
|
278
|
-
});
|
|
279
|
-
} catch (e) {
|
|
280
|
-
logger?.debug(e);
|
|
204
|
+
else if (typeof buffer === 'string') {
|
|
205
|
+
const rStream = createReadStream(buffer);
|
|
206
|
+
audioData = await toBuffer(rStream);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
audioData = await toBuffer(buffer);
|
|
210
|
+
}
|
|
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 = [];
|
|
216
|
+
for (let i = 0; i < samples; i++) {
|
|
217
|
+
const blockStart = blockSize * i; // the location of the first sample in the block
|
|
218
|
+
let sum = 0;
|
|
219
|
+
for (let j = 0; j < blockSize; j++) {
|
|
220
|
+
sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
|
|
221
|
+
}
|
|
222
|
+
filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
|
|
223
|
+
}
|
|
224
|
+
// 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);
|
|
227
|
+
// Generate waveform like WhatsApp
|
|
228
|
+
const waveform = new Uint8Array(normalizedData.map(n => Math.floor(100 * n)));
|
|
229
|
+
return waveform;
|
|
281
230
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
async function convertToOpusBuffer(buffer, logger) {
|
|
285
|
-
try {
|
|
286
|
-
const { PassThrough } = require('stream');
|
|
287
|
-
const ff = require('fluent-ffmpeg');
|
|
288
|
-
|
|
289
|
-
return await new Promise((resolve, reject) => {
|
|
290
|
-
const inStream = new PassThrough();
|
|
291
|
-
const outStream = new PassThrough();
|
|
292
|
-
const chunks = [];
|
|
293
|
-
inStream.end(buffer);
|
|
294
|
-
|
|
295
|
-
ff(inStream)
|
|
296
|
-
.noVideo()
|
|
297
|
-
.audioCodec('libopus')
|
|
298
|
-
.format('ogg')
|
|
299
|
-
.audioBitrate('48k')
|
|
300
|
-
.audioChannels(1)
|
|
301
|
-
.audioFrequency(48000)
|
|
302
|
-
.outputOptions([
|
|
303
|
-
'-vn',
|
|
304
|
-
'-b:a 64k',
|
|
305
|
-
'-ac 2',
|
|
306
|
-
'-ar 48000',
|
|
307
|
-
'-map_metadata', '-1',
|
|
308
|
-
'-application', 'voip'
|
|
309
|
-
])
|
|
310
|
-
.on('error', reject)
|
|
311
|
-
.on('end', () => resolve(Buffer.concat(chunks)))
|
|
312
|
-
.pipe(outStream, {
|
|
313
|
-
end: true
|
|
314
|
-
});
|
|
315
|
-
outStream.on('data', c => chunks.push(c));
|
|
316
|
-
});
|
|
317
|
-
} catch (e) {
|
|
318
|
-
logger?.debug(e);
|
|
319
|
-
throw e;
|
|
231
|
+
catch (e) {
|
|
232
|
+
logger?.debug('Failed to generate waveform: ' + e);
|
|
320
233
|
}
|
|
321
234
|
}
|
|
322
|
-
|
|
323
|
-
const
|
|
324
|
-
const readable = new stream_1.Readable({ read: () => { } });
|
|
235
|
+
export const toReadable = (buffer) => {
|
|
236
|
+
const readable = new Readable({ read: () => { } });
|
|
325
237
|
readable.push(buffer);
|
|
326
238
|
readable.push(null);
|
|
327
239
|
return readable;
|
|
328
240
|
};
|
|
329
|
-
|
|
330
|
-
const toBuffer = async (stream) => {
|
|
241
|
+
export const toBuffer = async (stream) => {
|
|
331
242
|
const chunks = [];
|
|
332
243
|
for await (const chunk of stream) {
|
|
333
244
|
chunks.push(chunk);
|
|
@@ -335,45 +246,47 @@ const toBuffer = async (stream) => {
|
|
|
335
246
|
stream.destroy();
|
|
336
247
|
return Buffer.concat(chunks);
|
|
337
248
|
};
|
|
338
|
-
|
|
339
|
-
const getStream = async (item, opts) => {
|
|
249
|
+
export const getStream = async (item, opts) => {
|
|
340
250
|
if (Buffer.isBuffer(item)) {
|
|
341
|
-
return { stream:
|
|
251
|
+
return { stream: toReadable(item), type: 'buffer' };
|
|
342
252
|
}
|
|
343
253
|
if ('stream' in item) {
|
|
344
254
|
return { stream: item.stream, type: 'readable' };
|
|
345
255
|
}
|
|
346
|
-
|
|
347
|
-
|
|
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' };
|
|
348
260
|
}
|
|
349
|
-
|
|
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' };
|
|
350
265
|
};
|
|
351
|
-
exports.getStream = getStream;
|
|
352
266
|
/** generates a thumbnail for a given media, if required */
|
|
353
|
-
async function generateThumbnail(file, mediaType, options) {
|
|
354
|
-
var _a;
|
|
267
|
+
export async function generateThumbnail(file, mediaType, options) {
|
|
355
268
|
let thumbnail;
|
|
356
269
|
let originalImageDimensions;
|
|
357
270
|
if (mediaType === 'image') {
|
|
358
|
-
const { buffer, original } = await
|
|
271
|
+
const { buffer, original } = await extractImageThumb(file);
|
|
359
272
|
thumbnail = buffer.toString('base64');
|
|
360
273
|
if (original.width && original.height) {
|
|
361
274
|
originalImageDimensions = {
|
|
362
275
|
width: original.width,
|
|
363
|
-
height: original.height
|
|
276
|
+
height: original.height
|
|
364
277
|
};
|
|
365
278
|
}
|
|
366
279
|
}
|
|
367
280
|
else if (mediaType === 'video') {
|
|
368
|
-
const imgFilename =
|
|
281
|
+
const imgFilename = join(getTmpFilesDirectory(), generateMessageIDV2() + '.jpg');
|
|
369
282
|
try {
|
|
370
283
|
await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
|
|
371
|
-
const buff = await
|
|
284
|
+
const buff = await fs.readFile(imgFilename);
|
|
372
285
|
thumbnail = buff.toString('base64');
|
|
373
|
-
await
|
|
286
|
+
await fs.unlink(imgFilename);
|
|
374
287
|
}
|
|
375
288
|
catch (err) {
|
|
376
|
-
|
|
289
|
+
options.logger?.debug('could not generate video thumb: ' + err);
|
|
377
290
|
}
|
|
378
291
|
}
|
|
379
292
|
return {
|
|
@@ -381,125 +294,73 @@ async function generateThumbnail(file, mediaType, options) {
|
|
|
381
294
|
originalImageDimensions
|
|
382
295
|
};
|
|
383
296
|
}
|
|
384
|
-
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const { stream, type } = await (0, exports.getStream)(media, opts);
|
|
393
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
|
|
394
|
-
let bodyPath;
|
|
395
|
-
let didSaveToTmpPath = false;
|
|
396
|
-
try {
|
|
397
|
-
const buffer = await (0, exports.toBuffer)(stream);
|
|
398
|
-
if (type === 'file') {
|
|
399
|
-
bodyPath = media.url;
|
|
400
|
-
}
|
|
401
|
-
else if (saveOriginalFileIfRequired) {
|
|
402
|
-
bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
|
|
403
|
-
(0, fs_1.writeFileSync)(bodyPath, buffer);
|
|
404
|
-
didSaveToTmpPath = true;
|
|
405
|
-
}
|
|
406
|
-
const fileLength = buffer.length;
|
|
407
|
-
const fileSha256 = Crypto.createHash('sha256').update(buffer).digest();
|
|
408
|
-
stream === null || stream === void 0 ? void 0 : stream.destroy();
|
|
409
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('prepare stream data successfully');
|
|
410
|
-
return {
|
|
411
|
-
mediaKey: undefined,
|
|
412
|
-
encWriteStream: buffer,
|
|
413
|
-
fileLength,
|
|
414
|
-
fileSha256,
|
|
415
|
-
fileEncSha256: undefined,
|
|
416
|
-
bodyPath,
|
|
417
|
-
didSaveToTmpPath
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
catch (error) {
|
|
421
|
-
// destroy all streams with error
|
|
422
|
-
stream.destroy();
|
|
423
|
-
if (didSaveToTmpPath) {
|
|
424
|
-
try {
|
|
425
|
-
await fs_1.promises.unlink(bodyPath);
|
|
426
|
-
}
|
|
427
|
-
catch (err) {
|
|
428
|
-
logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
throw error;
|
|
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 } });
|
|
432
305
|
}
|
|
306
|
+
// @ts-ignore Node18+ Readable.fromWeb exists
|
|
307
|
+
return response.body instanceof Readable ? response.body : Readable.fromWeb(response.body);
|
|
433
308
|
};
|
|
434
|
-
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
try {
|
|
441
|
-
const buffer = await (0, exports.toBuffer)(stream);
|
|
442
|
-
const opusBuffer = await exports.convertToOpusBuffer(buffer, logger);
|
|
443
|
-
finalStream = (0, exports.toReadable)(opusBuffer);
|
|
444
|
-
} catch (error) {
|
|
445
|
-
const { stream: newStream } = await (0, exports.getStream)(media, opts);
|
|
446
|
-
finalStream = newStream;
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
const mediaKey = Crypto.randomBytes(32);
|
|
451
|
-
const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
|
|
452
|
-
const encWriteStream = new stream_1.Readable({ read: () => { } });
|
|
309
|
+
export const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, mediaKey: providedMediaKey } = {}) => {
|
|
310
|
+
const { stream, type } = await getStream(media, opts);
|
|
311
|
+
let finalStream = stream;
|
|
312
|
+
const mediaKey = providedMediaKey || Crypto.randomBytes(32);
|
|
313
|
+
const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
|
|
314
|
+
const encWriteStream = new Readable({ read: () => {}, highWaterMark: 64 * 1024 });
|
|
453
315
|
let bodyPath;
|
|
454
316
|
let writeStream;
|
|
455
317
|
let didSaveToTmpPath = false;
|
|
456
|
-
|
|
457
318
|
if (type === 'file') {
|
|
458
|
-
bodyPath = media.url;
|
|
319
|
+
bodyPath = media.url?.toString?.() || media.url;
|
|
459
320
|
}
|
|
460
321
|
else if (saveOriginalFileIfRequired) {
|
|
461
|
-
bodyPath =
|
|
462
|
-
writeStream =
|
|
322
|
+
bodyPath = join(getTmpFilesDirectory(), mediaType + generateMessageIDV2());
|
|
323
|
+
writeStream = createWriteStream(bodyPath);
|
|
463
324
|
didSaveToTmpPath = true;
|
|
464
325
|
}
|
|
465
|
-
|
|
466
326
|
let fileLength = 0;
|
|
467
327
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
|
|
468
328
|
let hmac = Crypto.createHmac('sha256', macKey).update(iv);
|
|
469
329
|
let sha256Plain = Crypto.createHash('sha256');
|
|
470
330
|
let sha256Enc = Crypto.createHash('sha256');
|
|
471
|
-
|
|
331
|
+
const onChunk = (buff) => {
|
|
332
|
+
sha256Enc = sha256Enc.update(buff);
|
|
333
|
+
hmac = hmac.update(buff);
|
|
334
|
+
encWriteStream.push(buff);
|
|
335
|
+
};
|
|
472
336
|
try {
|
|
473
337
|
for await (const data of finalStream) {
|
|
474
338
|
fileLength += data.length;
|
|
475
|
-
if (type === 'remote'
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
throw new
|
|
339
|
+
if (type === 'remote' &&
|
|
340
|
+
opts?.maxContentLength &&
|
|
341
|
+
fileLength + data.length > opts.maxContentLength) {
|
|
342
|
+
throw new Boom(`content length exceeded when encrypting "${type}"`, {
|
|
479
343
|
data: { media, type }
|
|
480
344
|
});
|
|
481
345
|
}
|
|
482
|
-
|
|
483
346
|
sha256Plain = sha256Plain.update(data);
|
|
484
347
|
if (writeStream) {
|
|
485
348
|
if (!writeStream.write(data)) {
|
|
486
|
-
await
|
|
349
|
+
await once(writeStream, 'drain');
|
|
487
350
|
}
|
|
488
351
|
}
|
|
489
352
|
onChunk(aes.update(data));
|
|
490
353
|
}
|
|
491
|
-
|
|
492
354
|
onChunk(aes.final());
|
|
493
355
|
const mac = hmac.digest().slice(0, 10);
|
|
494
356
|
sha256Enc = sha256Enc.update(mac);
|
|
495
357
|
const fileSha256 = sha256Plain.digest();
|
|
496
358
|
const fileEncSha256 = sha256Enc.digest();
|
|
497
|
-
|
|
498
359
|
encWriteStream.push(mac);
|
|
499
360
|
encWriteStream.push(null);
|
|
500
|
-
writeStream
|
|
361
|
+
writeStream?.end?.();
|
|
362
|
+
if (writeStream) await once(writeStream, 'finish');
|
|
501
363
|
finalStream.destroy();
|
|
502
|
-
|
|
503
364
|
return {
|
|
504
365
|
mediaKey,
|
|
505
366
|
encWriteStream,
|
|
@@ -513,48 +374,39 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
|
|
|
513
374
|
}
|
|
514
375
|
catch (error) {
|
|
515
376
|
encWriteStream.destroy();
|
|
516
|
-
writeStream
|
|
377
|
+
writeStream?.destroy?.();
|
|
517
378
|
aes.destroy();
|
|
518
379
|
hmac.destroy();
|
|
519
380
|
sha256Plain.destroy();
|
|
520
381
|
sha256Enc.destroy();
|
|
521
|
-
|
|
522
|
-
|
|
382
|
+
stream.destroy();
|
|
523
383
|
if (didSaveToTmpPath) {
|
|
524
|
-
try {
|
|
525
|
-
await fs_1.promises.unlink(bodyPath);
|
|
526
|
-
}
|
|
527
|
-
catch (err) {
|
|
528
|
-
}
|
|
384
|
+
try { await fs.unlink(bodyPath); } catch (_) {}
|
|
529
385
|
}
|
|
530
386
|
throw error;
|
|
531
387
|
}
|
|
532
|
-
|
|
533
|
-
function onChunk(buff) {
|
|
534
|
-
sha256Enc = sha256Enc.update(buff);
|
|
535
|
-
hmac = hmac.update(buff);
|
|
536
|
-
encWriteStream.push(buff);
|
|
537
|
-
}
|
|
538
388
|
};
|
|
539
|
-
|
|
389
|
+
|
|
540
390
|
const DEF_HOST = 'mmg.whatsapp.net';
|
|
541
391
|
const AES_CHUNK_SIZE = 16;
|
|
542
392
|
const toSmallestChunkSize = (num) => {
|
|
543
393
|
return Math.floor(num / AES_CHUNK_SIZE) * AES_CHUNK_SIZE;
|
|
544
394
|
};
|
|
545
|
-
const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
|
|
546
|
-
|
|
547
|
-
const
|
|
548
|
-
const downloadUrl = url
|
|
549
|
-
|
|
550
|
-
|
|
395
|
+
export const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
|
|
396
|
+
export const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
|
|
397
|
+
const isValidMediaUrl = url?.startsWith('https://mmg.whatsapp.net/');
|
|
398
|
+
const downloadUrl = isValidMediaUrl ? url : getUrlFromDirectPath(directPath);
|
|
399
|
+
if (!downloadUrl) {
|
|
400
|
+
throw new Boom('No valid media URL or directPath present in message', { statusCode: 400 });
|
|
401
|
+
}
|
|
402
|
+
const keys = await getMediaKeys(mediaKey, type);
|
|
403
|
+
return downloadEncryptedContent(downloadUrl, keys, opts);
|
|
551
404
|
};
|
|
552
|
-
exports.downloadContentFromMessage = downloadContentFromMessage;
|
|
553
405
|
/**
|
|
554
406
|
* Decrypts and downloads an AES256-CBC encrypted file given the keys.
|
|
555
407
|
* Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
|
|
556
408
|
* */
|
|
557
|
-
const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
|
|
409
|
+
export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
|
|
558
410
|
let bytesFetched = 0;
|
|
559
411
|
let startChunk = 0;
|
|
560
412
|
let firstBlockIsIV = false;
|
|
@@ -568,9 +420,14 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
568
420
|
}
|
|
569
421
|
}
|
|
570
422
|
const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined;
|
|
423
|
+
const headersInit = options?.headers ? options.headers : undefined;
|
|
571
424
|
const headers = {
|
|
572
|
-
...(
|
|
573
|
-
|
|
425
|
+
...(headersInit
|
|
426
|
+
? Array.isArray(headersInit)
|
|
427
|
+
? Object.fromEntries(headersInit)
|
|
428
|
+
: headersInit
|
|
429
|
+
: {}),
|
|
430
|
+
Origin: DEFAULT_ORIGIN
|
|
574
431
|
};
|
|
575
432
|
if (startChunk || endChunk) {
|
|
576
433
|
headers.Range = `bytes=${startChunk}-`;
|
|
@@ -579,11 +436,9 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
579
436
|
}
|
|
580
437
|
}
|
|
581
438
|
// download the message
|
|
582
|
-
const fetched = await
|
|
583
|
-
...options || {},
|
|
584
|
-
headers
|
|
585
|
-
maxBodyLength: Infinity,
|
|
586
|
-
maxContentLength: Infinity,
|
|
439
|
+
const fetched = await getHttpStream(downloadUrl, {
|
|
440
|
+
...(options || {}),
|
|
441
|
+
headers
|
|
587
442
|
});
|
|
588
443
|
let remainingBytes = Buffer.from([]);
|
|
589
444
|
let aes;
|
|
@@ -598,7 +453,7 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
598
453
|
push(bytes);
|
|
599
454
|
}
|
|
600
455
|
};
|
|
601
|
-
const output = new
|
|
456
|
+
const output = new Transform({
|
|
602
457
|
transform(chunk, _, callback) {
|
|
603
458
|
let data = Buffer.concat([remainingBytes, chunk]);
|
|
604
459
|
const decryptLength = toSmallestChunkSize(data.length);
|
|
@@ -633,18 +488,15 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
|
|
|
633
488
|
catch (error) {
|
|
634
489
|
callback(error);
|
|
635
490
|
}
|
|
636
|
-
}
|
|
491
|
+
}
|
|
637
492
|
});
|
|
638
493
|
return fetched.pipe(output, { end: true });
|
|
639
494
|
};
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
const getExtension = (mimetype) => mimetype.split(';')[0].split('/')[1];
|
|
495
|
+
export function extensionForMediaMessage(message) {
|
|
496
|
+
const getExtension = (mimetype) => mimetype.split(';')[0]?.split('/')[1];
|
|
643
497
|
const type = Object.keys(message)[0];
|
|
644
498
|
let extension;
|
|
645
|
-
if (type === 'locationMessage' ||
|
|
646
|
-
type === 'liveLocationMessage' ||
|
|
647
|
-
type === 'productMessage') {
|
|
499
|
+
if (type === 'locationMessage' || type === 'liveLocationMessage' || type === 'productMessage') {
|
|
648
500
|
extension = '.jpeg';
|
|
649
501
|
}
|
|
650
502
|
else {
|
|
@@ -653,55 +505,173 @@ function extensionForMediaMessage(message) {
|
|
|
653
505
|
}
|
|
654
506
|
return extension;
|
|
655
507
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
508
|
+
const isNodeRuntime = () => {
|
|
509
|
+
return (typeof process !== 'undefined' &&
|
|
510
|
+
process.versions?.node !== null &&
|
|
511
|
+
typeof process.versions.bun === 'undefined' &&
|
|
512
|
+
typeof globalThis.Deno === 'undefined');
|
|
513
|
+
};
|
|
514
|
+
export const uploadWithNodeHttp = async ({ url, filePath, headers, timeoutMs, agent }, redirectCount = 0) => {
|
|
515
|
+
if (redirectCount > 5) {
|
|
516
|
+
throw new Error('Too many redirects');
|
|
517
|
+
}
|
|
518
|
+
const parsedUrl = new URL(url);
|
|
519
|
+
const httpModule = parsedUrl.protocol === 'https:' ? await import('https') : await import('http');
|
|
520
|
+
// Get file size for Content-Length header (required for Node.js streaming)
|
|
521
|
+
const fileStats = await fs.stat(filePath);
|
|
522
|
+
const fileSize = fileStats.size;
|
|
523
|
+
return new Promise((resolve, reject) => {
|
|
524
|
+
const req = httpModule.request({
|
|
525
|
+
hostname: parsedUrl.hostname,
|
|
526
|
+
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
|
|
527
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
528
|
+
method: 'POST',
|
|
529
|
+
headers: {
|
|
530
|
+
...headers,
|
|
531
|
+
'Content-Length': fileSize
|
|
532
|
+
},
|
|
533
|
+
agent,
|
|
534
|
+
timeout: timeoutMs
|
|
535
|
+
}, res => {
|
|
536
|
+
// Handle redirects (3xx)
|
|
537
|
+
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
538
|
+
res.resume(); // Consume response to free resources
|
|
539
|
+
const newUrl = new URL(res.headers.location, url).toString();
|
|
540
|
+
resolve(uploadWithNodeHttp({
|
|
541
|
+
url: newUrl,
|
|
542
|
+
filePath,
|
|
543
|
+
headers,
|
|
544
|
+
timeoutMs,
|
|
545
|
+
agent
|
|
546
|
+
}, redirectCount + 1));
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
let body = '';
|
|
550
|
+
res.on('data', chunk => (body += chunk));
|
|
551
|
+
res.on('end', () => {
|
|
552
|
+
try {
|
|
553
|
+
resolve(JSON.parse(body));
|
|
554
|
+
}
|
|
555
|
+
catch {
|
|
556
|
+
resolve(undefined);
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
req.on('error', reject);
|
|
561
|
+
req.on('timeout', () => {
|
|
562
|
+
req.destroy();
|
|
563
|
+
reject(new Error('Upload timeout'));
|
|
564
|
+
});
|
|
565
|
+
const stream = createReadStream(filePath);
|
|
566
|
+
stream.pipe(req);
|
|
567
|
+
stream.on('error', err => {
|
|
568
|
+
req.destroy();
|
|
569
|
+
reject(err);
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
};
|
|
573
|
+
const uploadWithFetch = async ({ url, filePath, headers, timeoutMs, agent }) => {
|
|
574
|
+
// Convert Node.js Readable to Web ReadableStream
|
|
575
|
+
const nodeStream = createReadStream(filePath);
|
|
576
|
+
const webStream = Readable.toWeb(nodeStream);
|
|
577
|
+
const response = await fetch(url, {
|
|
578
|
+
dispatcher: agent,
|
|
579
|
+
method: 'POST',
|
|
580
|
+
body: webStream,
|
|
581
|
+
headers,
|
|
582
|
+
duplex: 'half',
|
|
583
|
+
signal: timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined
|
|
584
|
+
});
|
|
585
|
+
try {
|
|
586
|
+
return (await response.json());
|
|
587
|
+
}
|
|
588
|
+
catch {
|
|
589
|
+
return undefined;
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
/**
|
|
593
|
+
* Uploads media to WhatsApp servers.
|
|
594
|
+
*
|
|
595
|
+
* ## Why we have two upload implementations:
|
|
596
|
+
*
|
|
597
|
+
* Node.js's native `fetch` (powered by undici) has a known bug where it buffers
|
|
598
|
+
* the entire request body in memory before sending, even when using streams.
|
|
599
|
+
* This causes memory issues with large files (e.g., 1GB file = 1GB+ memory usage).
|
|
600
|
+
* See: https://github.com/nodejs/undici/issues/4058
|
|
601
|
+
*
|
|
602
|
+
* Other runtimes (Bun, Deno, browsers) correctly stream the request body without
|
|
603
|
+
* buffering, so we can use the web-standard Fetch API there.
|
|
604
|
+
*
|
|
605
|
+
* ## Future considerations:
|
|
606
|
+
* Once the undici bug is fixed, we can simplify this to use only the Fetch API
|
|
607
|
+
* across all runtimes. Monitor the GitHub issue for updates.
|
|
608
|
+
*/
|
|
609
|
+
const uploadMedia = async (params, logger) => {
|
|
610
|
+
if (isNodeRuntime()) {
|
|
611
|
+
logger?.debug('Using Node.js https module for upload (avoids undici buffering bug)');
|
|
612
|
+
return uploadWithNodeHttp(params);
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
logger?.debug('Using web-standard Fetch API for upload');
|
|
616
|
+
return uploadWithFetch(params);
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
620
|
+
return async (streamOrPath, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
|
|
662
621
|
let uploadInfo = await refreshMediaConn(false);
|
|
663
622
|
let urls;
|
|
664
623
|
const hosts = [...customUploadHosts, ...uploadInfo.hosts];
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
624
|
+
fileEncSha256B64 = encodeBase64EncodedStringForUpload(fileEncSha256B64);
|
|
625
|
+
const customHeaders = (() => {
|
|
626
|
+
const hdrs = options?.headers;
|
|
627
|
+
if (!hdrs) return {};
|
|
628
|
+
return Array.isArray(hdrs) ? Object.fromEntries(hdrs) : hdrs;
|
|
629
|
+
})();
|
|
630
|
+
const headers = {
|
|
631
|
+
...customHeaders,
|
|
632
|
+
'Content-Type': 'application/octet-stream',
|
|
633
|
+
Origin: DEFAULT_ORIGIN
|
|
634
|
+
};
|
|
635
|
+
let reqBuffer;
|
|
636
|
+
if (Buffer.isBuffer(streamOrPath)) {
|
|
637
|
+
reqBuffer = streamOrPath;
|
|
638
|
+
}
|
|
639
|
+
else if (typeof streamOrPath === 'string') {
|
|
640
|
+
reqBuffer = await fs.readFile(streamOrPath);
|
|
670
641
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
media = media === null || media === void 0 ? void 0 : media.replace('/mms/', '/newsletter/newsletter-');
|
|
642
|
+
else {
|
|
643
|
+
const chunks = [];
|
|
644
|
+
for await (const chunk of streamOrPath) chunks.push(chunk);
|
|
645
|
+
reqBuffer = Buffer.concat(chunks);
|
|
676
646
|
}
|
|
677
|
-
|
|
647
|
+
let mediaPath = MEDIA_PATH_MAP[mediaType];
|
|
648
|
+
if (newsletter && mediaPath) {
|
|
649
|
+
mediaPath = mediaPath.replace('/mms/', '/newsletter/newsletter-');
|
|
650
|
+
}
|
|
651
|
+
for (const { hostname } of hosts) {
|
|
678
652
|
logger.debug(`uploading to "${hostname}"`);
|
|
679
|
-
const auth = encodeURIComponent(uploadInfo.auth);
|
|
680
|
-
const url = `https://${hostname}${
|
|
653
|
+
const auth = encodeURIComponent(uploadInfo.auth);
|
|
654
|
+
const url = `https://${hostname}${mediaPath}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
681
655
|
let result;
|
|
682
656
|
try {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
const body = await axios.post(url, reqBody, {
|
|
687
|
-
...options,
|
|
688
|
-
headers: {
|
|
689
|
-
...options.headers || {},
|
|
690
|
-
'Content-Type': 'application/octet-stream',
|
|
691
|
-
'Origin': Defaults_1.DEFAULT_ORIGIN
|
|
692
|
-
},
|
|
657
|
+
const axios = (await import('axios')).default;
|
|
658
|
+
const body = await axios.post(url, reqBuffer, {
|
|
659
|
+
headers,
|
|
693
660
|
httpsAgent: fetchAgent,
|
|
694
661
|
timeout: timeoutMs,
|
|
695
662
|
responseType: 'json',
|
|
696
663
|
maxBodyLength: Infinity,
|
|
697
|
-
maxContentLength: Infinity
|
|
664
|
+
maxContentLength: Infinity
|
|
698
665
|
});
|
|
699
666
|
result = body.data;
|
|
700
|
-
if (
|
|
667
|
+
if (result?.url || result?.direct_path) {
|
|
701
668
|
urls = {
|
|
702
669
|
mediaUrl: result.url,
|
|
703
670
|
directPath: result.direct_path,
|
|
704
|
-
handle: result.handle
|
|
671
|
+
handle: result.handle,
|
|
672
|
+
meta_hmac: result.meta_hmac,
|
|
673
|
+
fbid: result.fbid,
|
|
674
|
+
ts: result.ts
|
|
705
675
|
};
|
|
706
676
|
break;
|
|
707
677
|
}
|
|
@@ -711,37 +681,34 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
|
|
|
711
681
|
}
|
|
712
682
|
}
|
|
713
683
|
catch (error) {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
}
|
|
717
|
-
const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
|
|
718
|
-
logger.warn({ trace: error.stack, uploadResult: result }, `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`);
|
|
684
|
+
const isLast = hostname === hosts[uploadInfo.hosts.length - 1]?.hostname;
|
|
685
|
+
logger.warn({ trace: error?.stack, uploadResult: result }, `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`);
|
|
719
686
|
}
|
|
720
687
|
}
|
|
721
688
|
if (!urls) {
|
|
722
|
-
throw new
|
|
689
|
+
throw new Boom('Media upload failed on all hosts', { statusCode: 500 });
|
|
723
690
|
}
|
|
724
691
|
return urls;
|
|
725
692
|
};
|
|
726
693
|
};
|
|
727
|
-
|
|
694
|
+
|
|
728
695
|
const getMediaRetryKey = (mediaKey) => {
|
|
729
|
-
return
|
|
696
|
+
return hkdf(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
|
|
730
697
|
};
|
|
731
698
|
/**
|
|
732
699
|
* Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
|
|
733
700
|
*/
|
|
734
|
-
const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
701
|
+
export const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
735
702
|
const recp = { stanzaId: key.id };
|
|
736
|
-
const recpBuffer =
|
|
703
|
+
const recpBuffer = proto.ServerErrorReceipt.encode(recp).finish();
|
|
737
704
|
const iv = Crypto.randomBytes(12);
|
|
738
705
|
const retryKey = getMediaRetryKey(mediaKey);
|
|
739
|
-
const ciphertext =
|
|
706
|
+
const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id));
|
|
740
707
|
const req = {
|
|
741
708
|
tag: 'receipt',
|
|
742
709
|
attrs: {
|
|
743
710
|
id: key.id,
|
|
744
|
-
to:
|
|
711
|
+
to: jidNormalizedUser(meId),
|
|
745
712
|
type: 'server-error'
|
|
746
713
|
},
|
|
747
714
|
content: [
|
|
@@ -760,7 +727,7 @@ const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
|
760
727
|
tag: 'rmr',
|
|
761
728
|
attrs: {
|
|
762
729
|
jid: key.remoteJid,
|
|
763
|
-
|
|
730
|
+
from_me: (!!key.fromMe).toString(),
|
|
764
731
|
// @ts-ignore
|
|
765
732
|
participant: key.participant || undefined
|
|
766
733
|
}
|
|
@@ -769,9 +736,8 @@ const encryptMediaRetryRequest = (key, mediaKey, meId) => {
|
|
|
769
736
|
};
|
|
770
737
|
return req;
|
|
771
738
|
};
|
|
772
|
-
|
|
773
|
-
const
|
|
774
|
-
const rmrNode = (0, WABinary_1.getBinaryNodeChild)(node, 'rmr');
|
|
739
|
+
export const decodeMediaRetryNode = (node) => {
|
|
740
|
+
const rmrNode = getBinaryNodeChild(node, 'rmr');
|
|
775
741
|
const event = {
|
|
776
742
|
key: {
|
|
777
743
|
id: node.attrs.id,
|
|
@@ -780,40 +746,37 @@ const decodeMediaRetryNode = (node) => {
|
|
|
780
746
|
participant: rmrNode.attrs.participant
|
|
781
747
|
}
|
|
782
748
|
};
|
|
783
|
-
const errorNode =
|
|
749
|
+
const errorNode = getBinaryNodeChild(node, 'error');
|
|
784
750
|
if (errorNode) {
|
|
785
751
|
const errorCode = +errorNode.attrs.code;
|
|
786
|
-
event.error = new
|
|
752
|
+
event.error = new Boom(`Failed to re-upload media (${errorCode})`, {
|
|
753
|
+
data: errorNode.attrs,
|
|
754
|
+
statusCode: getStatusCodeForMediaRetry(errorCode)
|
|
755
|
+
});
|
|
787
756
|
}
|
|
788
757
|
else {
|
|
789
|
-
const encryptedInfoNode =
|
|
790
|
-
const ciphertext =
|
|
791
|
-
const iv =
|
|
758
|
+
const encryptedInfoNode = getBinaryNodeChild(node, 'encrypt');
|
|
759
|
+
const ciphertext = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_p');
|
|
760
|
+
const iv = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_iv');
|
|
792
761
|
if (ciphertext && iv) {
|
|
793
762
|
event.media = { ciphertext, iv };
|
|
794
763
|
}
|
|
795
764
|
else {
|
|
796
|
-
event.error = new
|
|
765
|
+
event.error = new Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 });
|
|
797
766
|
}
|
|
798
767
|
}
|
|
799
768
|
return event;
|
|
800
769
|
};
|
|
801
|
-
|
|
802
|
-
const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
770
|
+
export const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
|
|
803
771
|
const retryKey = getMediaRetryKey(mediaKey);
|
|
804
|
-
const plaintext =
|
|
805
|
-
return
|
|
772
|
+
const plaintext = aesDecryptGCM(ciphertext, retryKey, iv, Buffer.from(msgId));
|
|
773
|
+
return proto.MediaRetryNotification.decode(plaintext);
|
|
806
774
|
};
|
|
807
|
-
|
|
808
|
-
const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code];
|
|
809
|
-
exports.getStatusCodeForMediaRetry = getStatusCodeForMediaRetry;
|
|
775
|
+
export const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code];
|
|
810
776
|
const MEDIA_RETRY_STATUS_MAP = {
|
|
811
|
-
[
|
|
812
|
-
[
|
|
813
|
-
[
|
|
814
|
-
[
|
|
777
|
+
[proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
|
|
778
|
+
[proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
|
|
779
|
+
[proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
|
|
780
|
+
[proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418
|
|
815
781
|
};
|
|
816
|
-
|
|
817
|
-
function __importStar(arg0) {
|
|
818
|
-
throw new Error('Function not implemented.');
|
|
819
|
-
}
|
|
782
|
+
//# sourceMappingURL=messages-media.js.map
|