Skip to content

Commit

Permalink
Add support for v3 messages
Browse files Browse the repository at this point in the history
  • Loading branch information
tulir committed Feb 6, 2024
1 parent 72865e8 commit 4870267
Show file tree
Hide file tree
Showing 67 changed files with 42,896 additions and 20 deletions.
131 changes: 131 additions & 0 deletions armadillomessage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright (c) 2024 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package whatsmeow

import (
"fmt"

"google.golang.org/protobuf/proto"

"go.mau.fi/whatsmeow/binary/armadillo"
"go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication"
"go.mau.fi/whatsmeow/binary/armadillo/waCommon"
"go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication"
"go.mau.fi/whatsmeow/binary/armadillo/waMsgApplication"
"go.mau.fi/whatsmeow/binary/armadillo/waMsgTransport"
"go.mau.fi/whatsmeow/binary/armadillo/waMultiDevice"
"go.mau.fi/whatsmeow/types"
"go.mau.fi/whatsmeow/types/events"
)

func (cli *Client) handleDecryptedArmadillo(info *types.MessageInfo, decrypted []byte, retryCount int) bool {
dec, err := decodeArmadillo(decrypted)
if err != nil {
cli.Log.Warnf("Failed to decode armadillo message from %s: %v", info.SourceString(), err)
return false
}
if dec.Transport.GetProtocol().GetAncillary().GetSkdm() != nil {
if !info.IsGroup {
cli.Log.Warnf("Got sender key distribution message in non-group chat from %s", info.Sender)
} else {
skdm := dec.Transport.GetProtocol().GetAncillary().GetSkdm()
cli.handleSenderKeyDistributionMessage(info.Chat, info.Sender, skdm.AxolotlSenderKeyDistributionMessage)
}
}
switch evtData := dec.Message.(type) {
case *waConsumerApplication.ConsumerApplication:
evt := &events.FBConsumerMessage{
Info: *info,
Message: evtData,
RetryCount: retryCount,
Transport: dec.Transport,
Application: dec.Application,
}
cli.dispatchEvent(evt)
// TODO dispatch other events?
}
return true
}

type DecodedArmadillo struct {
Transport *waMsgTransport.MessageTransport
Application *waMsgApplication.MessageApplication
Message armadillo.MessageApplicationSub
}

func decodeArmadillo(data []byte) (dec DecodedArmadillo, err error) {
var transport waMsgTransport.MessageTransport
err = proto.Unmarshal(data, &transport)
if err != nil {
return dec, fmt.Errorf("failed to unmarshal transport: %w", err)
}
dec.Transport = &transport
if transport.GetPayload() == nil {
return
} else if transport.GetPayload().GetApplicationPayload().GetVersion() != 2 {
// TODO handle future proof behavior tag?
return dec, fmt.Errorf("unsupported application payload version: %d", transport.GetPayload().GetApplicationPayload().GetVersion())
}
var application waMsgApplication.MessageApplication
err = proto.Unmarshal(transport.GetPayload().GetApplicationPayload().GetPayload(), &application)
if err != nil {
return dec, fmt.Errorf("failed to unmarshal application: %w", err)
}
dec.Application = &application
if application.GetPayload() == nil {
return
}

switch typedContent := application.GetPayload().GetContent().(type) {
case *waMsgApplication.MessageApplication_Payload_CoreContent:
err = fmt.Errorf("unsupported core content payload")
case *waMsgApplication.MessageApplication_Payload_Signal:
err = fmt.Errorf("unsupported signal payload")
case *waMsgApplication.MessageApplication_Payload_ApplicationData:
err = fmt.Errorf("unsupported application data payload")
case *waMsgApplication.MessageApplication_Payload_SubProtocol:
var protoMsg proto.Message
var subData *waCommon.SubProtocol
switch subProtocol := typedContent.SubProtocol.GetSubProtocol().(type) {
case *waMsgApplication.MessageApplication_SubProtocolPayload_ConsumerMessage:
typedSub := &waConsumerApplication.ConsumerApplication{}
dec.Message = typedSub
protoMsg = typedSub
subData = subProtocol.ConsumerMessage
case *waMsgApplication.MessageApplication_SubProtocolPayload_BusinessMessage:
subData = subProtocol.BusinessMessage
dec.Message = (*armadillo.Unsupported_BusinessApplication)(subData)
case *waMsgApplication.MessageApplication_SubProtocolPayload_PaymentMessage:
subData = subProtocol.PaymentMessage
dec.Message = (*armadillo.Unsupported_PaymentApplication)(subData)
case *waMsgApplication.MessageApplication_SubProtocolPayload_MultiDevice:
typedSub := &waMultiDevice.MultiDevice{}
dec.Message = typedSub
protoMsg = typedSub
subData = subProtocol.MultiDevice
case *waMsgApplication.MessageApplication_SubProtocolPayload_Voip:
subData = subProtocol.Voip
dec.Message = (*armadillo.Unsupported_Voip)(subData)
case *waMsgApplication.MessageApplication_SubProtocolPayload_Armadillo:
typedSub := &waArmadilloApplication.Armadillo{}
dec.Message = typedSub
protoMsg = typedSub
subData = subProtocol.Armadillo
default:
return dec, fmt.Errorf("unsupported subprotocol type: %T", subProtocol)
}
if protoMsg != nil {
err = proto.Unmarshal(subData.GetPayload(), protoMsg)
if err != nil {
return dec, fmt.Errorf("failed to unmarshal application subprotocol payload (%T v%d): %w", protoMsg, subData.GetVersion(), err)
}
}
default:
err = fmt.Errorf("unsupported application payload content type: %T", typedContent)
}
return
}
1 change: 1 addition & 0 deletions binary/armadillo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
e2ee.js
29 changes: 29 additions & 0 deletions binary/armadillo/extra.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package armadillo

import (
"go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication"
"go.mau.fi/whatsmeow/binary/armadillo/waCommon"
"go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication"
"go.mau.fi/whatsmeow/binary/armadillo/waMultiDevice"
)

type MessageApplicationSub interface {
IsMessageApplicationSub()
}

type Unsupported_BusinessApplication waCommon.SubProtocol
type Unsupported_PaymentApplication waCommon.SubProtocol
type Unsupported_Voip waCommon.SubProtocol

var (
_ MessageApplicationSub = (*waConsumerApplication.ConsumerApplication)(nil) // 2
_ MessageApplicationSub = (*Unsupported_BusinessApplication)(nil) // 3
_ MessageApplicationSub = (*Unsupported_PaymentApplication)(nil) // 4
_ MessageApplicationSub = (*waMultiDevice.MultiDevice)(nil) // 5
_ MessageApplicationSub = (*Unsupported_Voip)(nil) // 6
_ MessageApplicationSub = (*waArmadilloApplication.Armadillo)(nil) // 7
)

func (*Unsupported_BusinessApplication) IsMessageApplicationSub() {}
func (*Unsupported_PaymentApplication) IsMessageApplicationSub() {}
func (*Unsupported_Voip) IsMessageApplicationSub() {}
9 changes: 9 additions & 0 deletions binary/armadillo/generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
cd $(dirname $0)
set -euo pipefail
if [[ ! -f "e2ee.js" ]]; then
echo "Please download the encryption javascript file and save it to e2ee.js first"
exit 1
fi
node parse-proto.js
protoc --go_out=. --go_opt=paths=source_relative --go_opt=embed_raw=true */*.proto
Loading

0 comments on commit 4870267

Please sign in to comment.