diff options
Diffstat (limited to 'vendor/go.mau.fi/whatsmeow/mediaretry.go')
-rw-r--r-- | vendor/go.mau.fi/whatsmeow/mediaretry.go | 73 |
1 files changed, 26 insertions, 47 deletions
diff --git a/vendor/go.mau.fi/whatsmeow/mediaretry.go b/vendor/go.mau.fi/whatsmeow/mediaretry.go index 52b04608..e6e1fa8b 100644 --- a/vendor/go.mau.fi/whatsmeow/mediaretry.go +++ b/vendor/go.mau.fi/whatsmeow/mediaretry.go @@ -7,8 +7,6 @@ package whatsmeow import ( - "crypto/aes" - "crypto/cipher" "crypto/rand" "fmt" @@ -18,6 +16,7 @@ import ( waProto "go.mau.fi/whatsmeow/binary/proto" "go.mau.fi/whatsmeow/types" "go.mau.fi/whatsmeow/types/events" + "go.mau.fi/whatsmeow/util/gcmutil" "go.mau.fi/whatsmeow/util/hkdfutil" ) @@ -25,18 +24,6 @@ func getMediaRetryKey(mediaKey []byte) (cipherKey []byte) { return hkdfutil.SHA256(mediaKey, nil, []byte("WhatsApp Media Retry Notification"), 32) } -func prepareMediaRetryGCM(mediaKey []byte) (cipher.AEAD, error) { - block, err := aes.NewCipher(getMediaRetryKey(mediaKey)) - if err != nil { - return nil, fmt.Errorf("failed to initialize AES cipher: %w", err) - } - gcm, err := cipher.NewGCM(block) - if err != nil { - return nil, fmt.Errorf("failed to initialize GCM: %w", err) - } - return gcm, nil -} - func encryptMediaRetryReceipt(messageID types.MessageID, mediaKey []byte) (ciphertext, iv []byte, err error) { receipt := &waProto.ServerErrorReceipt{ StanzaId: proto.String(messageID), @@ -47,17 +34,12 @@ func encryptMediaRetryReceipt(messageID types.MessageID, mediaKey []byte) (ciphe err = fmt.Errorf("failed to marshal payload: %w", err) return } - var gcm cipher.AEAD - gcm, err = prepareMediaRetryGCM(mediaKey) - if err != nil { - return - } iv = make([]byte, 12) _, err = rand.Read(iv) if err != nil { panic(err) } - ciphertext = gcm.Seal(plaintext[:0], iv, plaintext, []byte(messageID)) + ciphertext, err = gcmutil.Encrypt(getMediaRetryKey(mediaKey), iv, plaintext, []byte(messageID)) return } @@ -66,35 +48,35 @@ func encryptMediaRetryReceipt(messageID types.MessageID, mediaKey []byte) (ciphe // This is mostly relevant when handling history syncs and getting a 404 or 410 error downloading media. // Rough example on how to use it (will not work out of the box, you must adjust it depending on what you need exactly): // -// var mediaRetryCache map[types.MessageID]*waProto.ImageMessage +// var mediaRetryCache map[types.MessageID]*waProto.ImageMessage // -// evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage()) -// imageMsg := evt.Message.GetImageMessage() // replace this with the part of the message you want to download -// data, err := cli.Download(imageMsg) -// if errors.Is(err, whatsmeow.ErrMediaDownloadFailedWith404) || errors.Is(err, whatsmeow.ErrMediaDownloadFailedWith410) { -// err = cli.SendMediaRetryReceipt(&evt.Info, imageMsg.GetMediaKey()) -// // You need to store the event data somewhere as it's necessary for handling the retry response. -// mediaRetryCache[evt.Info.ID] = imageMsg -// } +// evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage()) +// imageMsg := evt.Message.GetImageMessage() // replace this with the part of the message you want to download +// data, err := cli.Download(imageMsg) +// if errors.Is(err, whatsmeow.ErrMediaDownloadFailedWith404) || errors.Is(err, whatsmeow.ErrMediaDownloadFailedWith410) { +// err = cli.SendMediaRetryReceipt(&evt.Info, imageMsg.GetMediaKey()) +// // You need to store the event data somewhere as it's necessary for handling the retry response. +// mediaRetryCache[evt.Info.ID] = imageMsg +// } // // The response will come as an *events.MediaRetry. The response will then have to be decrypted // using DecryptMediaRetryNotification and the same media key passed here. If the media retry was successful, // the decrypted notification should contain an updated DirectPath, which can be used to download the file. // -// func eventHandler(rawEvt interface{}) { -// switch evt := rawEvt.(type) { -// case *events.MediaRetry: -// imageMsg := mediaRetryCache[evt.MessageID] -// retryData, err := whatsmeow.DecryptMediaRetryNotification(evt, imageMsg.GetMediaKey()) -// if err != nil || retryData.GetResult != waProto.MediaRetryNotification_SUCCESS { -// return -// } -// // Use the new path to download the attachment -// imageMsg.DirectPath = retryData.DirectPath -// data, err := cli.Download(imageMsg) -// // Alternatively, you can use cli.DownloadMediaWithPath and provide the individual fields manually. -// } -// } +// func eventHandler(rawEvt interface{}) { +// switch evt := rawEvt.(type) { +// case *events.MediaRetry: +// imageMsg := mediaRetryCache[evt.MessageID] +// retryData, err := whatsmeow.DecryptMediaRetryNotification(evt, imageMsg.GetMediaKey()) +// if err != nil || retryData.GetResult != waProto.MediaRetryNotification_SUCCESS { +// return +// } +// // Use the new path to download the attachment +// imageMsg.DirectPath = retryData.DirectPath +// data, err := cli.Download(imageMsg) +// // Alternatively, you can use cli.DownloadMediaWithPath and provide the individual fields manually. +// } +// } func (cli *Client) SendMediaRetryReceipt(message *types.MessageInfo, mediaKey []byte) error { ciphertext, iv, err := encryptMediaRetryReceipt(message.ID, mediaKey) if err != nil { @@ -136,15 +118,12 @@ func (cli *Client) SendMediaRetryReceipt(message *types.MessageInfo, mediaKey [] // See Client.SendMediaRetryReceipt for more info on how to use this. func DecryptMediaRetryNotification(evt *events.MediaRetry, mediaKey []byte) (*waProto.MediaRetryNotification, error) { var notif waProto.MediaRetryNotification - var plaintext []byte if evt.Error != nil && evt.Ciphertext == nil { if evt.Error.Code == 2 { return nil, ErrMediaNotAvailableOnPhone } return nil, fmt.Errorf("%w (code: %d)", ErrUnknownMediaRetryError, evt.Error.Code) - } else if gcm, err := prepareMediaRetryGCM(mediaKey); err != nil { - return nil, err - } else if plaintext, err = gcm.Open(nil, evt.IV, evt.Ciphertext, []byte(evt.MessageID)); err != nil { + } else if plaintext, err := gcmutil.Decrypt(getMediaRetryKey(mediaKey), evt.IV, evt.Ciphertext, []byte(evt.MessageID)); err != nil { return nil, fmt.Errorf("failed to decrypt notification: %w", err) } else if err = proto.Unmarshal(plaintext, ¬if); err != nil { return nil, fmt.Errorf("failed to unmarshal notification (invalid encryption key?): %w", err) |