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