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