Merge branch 'mautrix:master' into master

This commit is contained in:
Noah Vogt 2023-12-23 18:46:02 +01:00 committed by GitHub
commit c7d05f857f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 156 additions and 90 deletions

1
.idea/icon.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 175.216 175.552"><defs><linearGradient id="b" x1="85.915" x2="86.535" y1="32.567" y2="137.092" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#57d163"/><stop offset="1" stop-color="#23b33a"/></linearGradient><filter id="a" width="1.115" height="1.114" x="-.057" y="-.057" color-interpolation-filters="sRGB"><feGaussianBlur stdDeviation="3.531"/></filter></defs><path fill="#b3b3b3" d="m54.532 138.45 2.235 1.324c9.387 5.571 20.15 8.518 31.126 8.523h.023c33.707 0 61.139-27.426 61.153-61.135.006-16.335-6.349-31.696-17.895-43.251A60.75 60.75 0 0 0 87.94 25.983c-33.733 0-61.166 27.423-61.178 61.13a60.98 60.98 0 0 0 9.349 32.535l1.455 2.312-6.179 22.558zm-40.811 23.544L24.16 123.88c-6.438-11.154-9.825-23.808-9.821-36.772.017-40.556 33.021-73.55 73.578-73.55 19.681.01 38.154 7.669 52.047 21.572s21.537 32.383 21.53 52.037c-.018 40.553-33.027 73.553-73.578 73.553h-.032c-12.313-.005-24.412-3.094-35.159-8.954zm0 0" filter="url(#a)"/><path fill="#fff" d="m12.966 161.238 10.439-38.114a73.42 73.42 0 0 1-9.821-36.772c.017-40.556 33.021-73.55 73.578-73.55 19.681.01 38.154 7.669 52.047 21.572s21.537 32.383 21.53 52.037c-.018 40.553-33.027 73.553-73.578 73.553h-.032c-12.313-.005-24.412-3.094-35.159-8.954z"/><path fill="url(#linearGradient1780)" d="M87.184 25.227c-33.733 0-61.166 27.423-61.178 61.13a60.98 60.98 0 0 0 9.349 32.535l1.455 2.312-6.179 22.559 23.146-6.069 2.235 1.324c9.387 5.571 20.15 8.518 31.126 8.524h.023c33.707 0 61.14-27.426 61.153-61.135a60.75 60.75 0 0 0-17.895-43.251 60.75 60.75 0 0 0-43.235-17.929z"/><path fill="url(#b)" d="M87.184 25.227c-33.733 0-61.166 27.423-61.178 61.13a60.98 60.98 0 0 0 9.349 32.535l1.455 2.313-6.179 22.558 23.146-6.069 2.235 1.324c9.387 5.571 20.15 8.517 31.126 8.523h.023c33.707 0 61.14-27.426 61.153-61.135a60.75 60.75 0 0 0-17.895-43.251 60.75 60.75 0 0 0-43.235-17.928z"/><path fill="#fff" fill-rule="evenodd" d="M68.772 55.603c-1.378-3.061-2.828-3.123-4.137-3.176l-3.524-.043c-1.226 0-3.218.46-4.902 2.3s-6.435 6.287-6.435 15.332 6.588 17.785 7.506 19.013 12.718 20.381 31.405 27.75c15.529 6.124 18.689 4.906 22.061 4.6s10.877-4.447 12.408-8.74 1.532-7.971 1.073-8.74-1.685-1.226-3.525-2.146-10.877-5.367-12.562-5.981-2.91-.919-4.137.921-4.746 5.979-5.819 7.206-2.144 1.381-3.984.462-7.76-2.861-14.784-9.124c-5.465-4.873-9.154-10.891-10.228-12.73s-.114-2.835.808-3.751c.825-.824 1.838-2.147 2.759-3.22s1.224-1.84 1.836-3.065.307-2.301-.153-3.22-4.032-10.011-5.666-13.647"/></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -1,3 +1,9 @@
# v0.10.5 (2023-12-16)
* Added support for sending media to channels.
* Fixed voting in polls (seems to have broken due to a server-side change).
* Improved memory usage for bridges with lots of portals.
# v0.10.4 (2023-11-16)
* Added support for channels in `join` and `open` commands.

View file

@ -1,4 +1,4 @@
FROM golang:1-alpine3.18 AS builder
FROM golang:1-alpine3.19 AS builder
RUN apk add --no-cache git ca-certificates build-base su-exec olm-dev
@ -6,7 +6,7 @@ COPY . /build
WORKDIR /build
RUN go build -o /usr/bin/mautrix-whatsapp
FROM alpine:3.18
FROM alpine:3.19
ENV UID=1337 \
GID=1337

View file

@ -1,4 +1,4 @@
FROM alpine:3.18
FROM alpine:3.19
ENV UID=1337 \
GID=1337

View file

@ -114,7 +114,7 @@ func fnSetRelay(ce *WrappedCommandEvent) {
if !ce.Bridge.Config.Bridge.Relay.Enabled {
ce.Reply("Relay mode is not enabled on this instance of the bridge")
} else if ce.Bridge.Config.Bridge.Relay.AdminOnly && !ce.User.Admin {
ce.Reply("Only admins are allowed to enable relay mode on this instance of the bridge")
ce.Reply("Only bridge admins are allowed to enable relay mode on this instance of the bridge")
} else {
ce.Portal.RelayUserID = ce.User.MXID
ce.Portal.Update(nil)
@ -136,7 +136,7 @@ func fnUnsetRelay(ce *WrappedCommandEvent) {
if !ce.Bridge.Config.Bridge.Relay.Enabled {
ce.Reply("Relay mode is not enabled on this instance of the bridge")
} else if ce.Bridge.Config.Bridge.Relay.AdminOnly && !ce.User.Admin {
ce.Reply("Only admins are allowed to enable relay mode on this instance of the bridge")
ce.Reply("Only bridge admins are allowed to enable relay mode on this instance of the bridge")
} else {
ce.Portal.RelayUserID = ""
ce.Portal.Update(nil)

View file

@ -136,8 +136,9 @@ type BridgeConfig struct {
Encryption bridgeconfig.EncryptionConfig `yaml:"encryption"`
Provisioning struct {
Prefix string `yaml:"prefix"`
SharedSecret string `yaml:"shared_secret"`
Prefix string `yaml:"prefix"`
SharedSecret string `yaml:"shared_secret"`
DebugEndpoints bool `yaml:"debug_endpoints"`
} `yaml:"provisioning"`
Permissions bridgeconfig.PermissionConfig `yaml:"permissions"`

View file

@ -160,6 +160,7 @@ func DoUpgrade(helper *up.Helper) {
} else {
helper.Copy(up.Str, "bridge", "provisioning", "prefix")
}
helper.Copy(up.Bool, "bridge", "provisioning", "debug_endpoints")
if secret, ok := helper.Get(up.Str, "appservice", "provisioning", "shared_secret"); ok && secret != "generate" {
helper.Set(up.Str, secret, "bridge", "provisioning", "shared_secret")
} else if secret, ok = helper.Get(up.Str, "bridge", "provisioning", "shared_secret"); !ok || secret == "generate" {

View file

@ -424,6 +424,8 @@ bridge:
# Shared secret for authentication. If set to "generate", a random secret will be generated,
# or if set to "disable", the provisioning API will be disabled.
shared_secret: generate
# Enable debug API at /debug with provisioning authentication.
debug_endpoints: false
# Permissions for using the bridge.
# Permitted values:

12
go.mod
View file

@ -6,17 +6,17 @@ require (
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.5.0
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.18
github.com/mattn/go-sqlite3 v1.14.19
github.com/prometheus/client_golang v1.17.0
github.com/rs/zerolog v1.31.0
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/tidwall/gjson v1.17.0
go.mau.fi/util v0.2.1
go.mau.fi/webp v0.1.0
go.mau.fi/whatsmeow v0.0.0-20231116213319-217e0c985fd6
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
go.mau.fi/whatsmeow v0.0.0-20231216213200-9d803dd92735
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611
golang.org/x/image v0.14.0
golang.org/x/net v0.18.0
golang.org/x/net v0.19.0
google.golang.org/protobuf v1.31.0
maunium.net/go/maulogger/v2 v2.4.1
maunium.net/go/mautrix v0.16.2
@ -41,8 +41,8 @@ require (
github.com/yuin/goldmark v1.6.0 // indirect
go.mau.fi/libsignal v0.1.0 // indirect
go.mau.fi/zeroconfig v0.1.2 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

24
go.sum
View file

@ -30,8 +30,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI=
github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -68,24 +68,24 @@ go.mau.fi/util v0.2.1 h1:eazulhFE/UmjOFtPrGg6zkF5YfAyiDzQb8ihLMbsPWw=
go.mau.fi/util v0.2.1/go.mod h1:MjlzCQEMzJ+G8RsPawHzpLB8rwTo3aPIjG5FzBvQT/c=
go.mau.fi/webp v0.1.0 h1:BHObH/DcFntT9KYun5pDr0Ot4eUZO8k2C7eP7vF4ueA=
go.mau.fi/webp v0.1.0/go.mod h1:e42Z+VMFrUMS9cpEwGRIor+lQWO8oUAyPyMtcL+NMt8=
go.mau.fi/whatsmeow v0.0.0-20231116213319-217e0c985fd6 h1:GLGU8Q7zoW0NjqZGXdPAjAwmJTSI09HIdhjL0DY21oc=
go.mau.fi/whatsmeow v0.0.0-20231116213319-217e0c985fd6/go.mod h1:5xTtHNaZpGni6z6aE1iEopjW7wNgsKcolZxZrOujK9M=
go.mau.fi/whatsmeow v0.0.0-20231216213200-9d803dd92735 h1:+teJYCOK6M4Kn2TYCj29levhHVwnJTmgCtEXLtgwQtM=
go.mau.fi/whatsmeow v0.0.0-20231216213200-9d803dd92735/go.mod h1:5xTtHNaZpGni6z6aE1iEopjW7wNgsKcolZxZrOujK9M=
go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto=
go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4=
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View file

@ -21,6 +21,7 @@ import (
"encoding/base64"
"fmt"
"strings"
"sync"
"time"
"github.com/rs/zerolog"
@ -452,26 +453,29 @@ func (user *User) storeHistorySync(evt *waProto.HistorySync) {
continue
}
totalMessageCount += len(conv.GetMessages())
portal := user.GetPortalByJID(jid)
log := log.With().
Str("chat_jid", portal.Key.JID.String()).
Str("chat_jid", jid.String()).
Int("msg_count", len(conv.GetMessages())).
Logger()
historySyncConversation := user.bridge.DB.HistorySync.NewConversationWithValues(
user.MXID,
conv.GetId(),
&portal.Key,
getConversationTimestamp(conv),
conv.GetMuteEndTime(),
conv.GetArchived(),
conv.GetPinned(),
conv.GetDisappearingMode().GetInitiator(),
conv.GetEndOfHistoryTransferType(),
conv.EphemeralExpiration,
conv.GetMarkedAsUnread(),
conv.GetUnreadCount())
historySyncConversation.Upsert()
initPortal := sync.OnceFunc(func() {
portal := user.GetPortalByJID(jid)
historySyncConversation := user.bridge.DB.HistorySync.NewConversationWithValues(
user.MXID,
conv.GetId(),
&portal.Key,
getConversationTimestamp(conv),
conv.GetMuteEndTime(),
conv.GetArchived(),
conv.GetPinned(),
conv.GetDisappearingMode().GetInitiator(),
conv.GetEndOfHistoryTransferType(),
conv.EphemeralExpiration,
conv.GetMarkedAsUnread(),
conv.GetUnreadCount())
historySyncConversation.Upsert()
})
var minTime, maxTime time.Time
var minTimeIndex, maxTimeIndex int
@ -479,7 +483,7 @@ func (user *User) storeHistorySync(evt *waProto.HistorySync) {
unsupportedTypes := 0
for i, rawMsg := range conv.GetMessages() {
// Don't store messages that will just be skipped.
msgEvt, err := user.Client.ParseWebMessage(portal.Key.JID, rawMsg.GetMessage())
msgEvt, err := user.Client.ParseWebMessage(jid, rawMsg.GetMessage())
if err != nil {
log.Warn().Err(err).
Int("msg_index", i).
@ -503,6 +507,8 @@ func (user *User) storeHistorySync(evt *waProto.HistorySync) {
continue
}
initPortal()
message, err := user.bridge.DB.HistorySync.NewMessageWithValues(user.MXID, conv.GetId(), msgEvt.Info.ID, rawMsg)
if err != nil {
log.Error().Err(err).

View file

@ -268,7 +268,7 @@ func main() {
Name: "mautrix-whatsapp",
URL: "https://github.com/mautrix/whatsapp",
Description: "A Matrix-WhatsApp puppeting bridge.",
Version: "0.10.4",
Version: "0.10.5",
ProtocolName: "WhatsApp",
BeeperServiceName: "whatsapp",
BeeperNetworkName: "whatsapp",

View file

@ -110,7 +110,13 @@ func (portal *Portal) MarkEncrypted() {
func (portal *Portal) ReceiveMatrixEvent(user bridge.User, evt *event.Event) {
if user.GetPermissionLevel() >= bridgeconfig.PermissionLevelUser || portal.HasRelaybot() {
portal.matrixMessages <- PortalMatrixMessage{user: user.(*User), evt: evt, receivedAt: time.Now()}
portal.events <- &PortalEvent{
MatrixMessage: &PortalMatrixMessage{
user: user.(*User),
evt: evt,
receivedAt: time.Now(),
},
}
}
}
@ -199,9 +205,7 @@ func (br *WABridge) newBlankPortal(key database.PortalKey) *Portal {
log: br.Log.Sub(fmt.Sprintf("Portal/%s", key)),
zlog: br.ZLog.With().Str("portal_key", key.String()).Logger(),
messages: make(chan PortalMessage, br.Config.Bridge.PortalMessageBuffer),
matrixMessages: make(chan PortalMatrixMessage, br.Config.Bridge.PortalMessageBuffer),
mediaRetries: make(chan PortalMediaRetry, br.Config.Bridge.PortalMessageBuffer),
events: make(chan *PortalEvent, br.Config.Bridge.PortalMessageBuffer),
mediaErrorCache: make(map[types.MessageID]*FailedMediaMeta),
}
@ -232,6 +236,12 @@ type fakeMessage struct {
Important bool
}
type PortalEvent struct {
Message *PortalMessage
MatrixMessage *PortalMatrixMessage
MediaRetry *PortalMediaRetry
}
type PortalMessage struct {
evt *events.Message
undecryptable *events.UndecryptableMessage
@ -279,9 +289,7 @@ type Portal struct {
currentlyTyping []id.UserID
currentlyTypingLock sync.Mutex
messages chan PortalMessage
matrixMessages chan PortalMatrixMessage
mediaRetries chan PortalMediaRetry
events chan *PortalEvent
mediaErrorCache map[types.MessageID]*FailedMediaMeta
@ -337,7 +345,7 @@ var (
_ bridge.TypingPortal = (*Portal)(nil)
)
func (portal *Portal) handleWhatsAppMessageLoopItem(msg PortalMessage) {
func (portal *Portal) handleWhatsAppMessageLoopItem(msg *PortalMessage) {
if len(portal.MXID) == 0 {
if msg.fake == nil && msg.undecryptable == nil && (msg.evt == nil || !containsSupportedMessage(msg.evt.Message)) {
portal.log.Debugln("Not creating portal room for incoming message: message is not a chat message")
@ -369,7 +377,7 @@ func (portal *Portal) handleWhatsAppMessageLoopItem(msg PortalMessage) {
}
}
func (portal *Portal) handleMatrixMessageLoopItem(msg PortalMatrixMessage) {
func (portal *Portal) handleMatrixMessageLoopItem(msg *PortalMatrixMessage) {
portal.latestEventBackfillLock.Lock()
defer portal.latestEventBackfillLock.Unlock()
evtTS := time.UnixMilli(msg.evt.Timestamp)
@ -422,7 +430,7 @@ func (portal *Portal) handleReceipt(receipt *events.Receipt, source *User) {
// TODO handle lids
return
}
if receipt.Type == events.ReceiptTypeDelivered {
if receipt.Type == types.ReceiptTypeDelivered {
portal.handleDeliveryReceipt(receipt, source)
return
}
@ -483,12 +491,16 @@ func (portal *Portal) handleOneMessageLoopItem() {
}
}()
select {
case msg := <-portal.messages:
portal.handleWhatsAppMessageLoopItem(msg)
case msg := <-portal.matrixMessages:
portal.handleMatrixMessageLoopItem(msg)
case retry := <-portal.mediaRetries:
portal.handleMediaRetry(retry.evt, retry.source)
case msg := <-portal.events:
if msg.Message != nil {
portal.handleWhatsAppMessageLoopItem(msg.Message)
} else if msg.MatrixMessage != nil {
portal.handleMatrixMessageLoopItem(msg.MatrixMessage)
} else if msg.MediaRetry != nil {
portal.handleMediaRetry(msg.MediaRetry.evt, msg.MediaRetry.source)
} else {
portal.log.Warn("Portal event loop returned an event without any data")
}
}
}
@ -3883,7 +3895,12 @@ func (portal *Portal) preprocessMatrixMedia(ctx context.Context, sender *User, r
portal.log.Warnfln("Failed to re-encode %s media: %v, continuing with original file", mimeType, convertErr)
}
}
uploadResp, err := sender.Client.Upload(ctx, data, mediaType)
var uploadResp whatsmeow.UploadResponse
if portal.Key.JID.Server == types.NewsletterServer {
uploadResp, err = sender.Client.UploadNewsletter(ctx, data, mediaType)
} else {
uploadResp, err = sender.Client.Upload(ctx, data, mediaType)
}
if err != nil {
return nil, exerrors.NewDualError(errMediaWhatsAppUploadFailed, err)
}
@ -4191,6 +4208,8 @@ type extraConvertMeta struct {
EditRootMsg *database.Message
GalleryExtraParts []*waProto.Message
MediaHandle string
}
func getEditError(rootMsg *database.Message, editer *User) error {
@ -4292,6 +4311,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
if media == nil {
return nil, sender, extraMeta, err
}
extraMeta.MediaHandle = media.Handle
ctxInfo.MentionedJid = media.MentionedJIDs
msg.ImageMessage = &waProto.ImageMessage{
ContextInfo: ctxInfo,
@ -4310,6 +4330,9 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
return nil, sender, extraMeta, errGalleryRelay
} else if content.BeeperGalleryCaption != "" {
return nil, sender, extraMeta, errGalleryCaption
} else if portal.Key.JID.Server == types.NewsletterServer {
// We don't handle the media handles properly for multiple messages
return nil, sender, extraMeta, fmt.Errorf("can't send gallery to newsletter")
}
for i, part := range content.BeeperGalleryImages {
// TODO support videos
@ -4341,6 +4364,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
if media == nil {
return nil, sender, extraMeta, err
}
extraMeta.MediaHandle = media.Handle
ctxInfo.MentionedJid = media.MentionedJIDs
msg.StickerMessage = &waProto.StickerMessage{
ContextInfo: ctxInfo,
@ -4360,6 +4384,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
return nil, sender, extraMeta, err
}
duration := uint32(content.GetInfo().Duration / 1000)
extraMeta.MediaHandle = media.Handle
ctxInfo.MentionedJid = media.MentionedJIDs
msg.VideoMessage = &waProto.VideoMessage{
ContextInfo: ctxInfo,
@ -4380,6 +4405,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
if media == nil {
return nil, sender, extraMeta, err
}
extraMeta.MediaHandle = media.Handle
duration := uint32(content.GetInfo().Duration / 1000)
msg.AudioMessage = &waProto.AudioMessage{
ContextInfo: ctxInfo,
@ -4404,6 +4430,7 @@ func (portal *Portal) convertMatrixMessage(ctx context.Context, sender *User, ev
if media == nil {
return nil, sender, extraMeta, err
}
extraMeta.MediaHandle = media.Handle
msg.DocumentMessage = &waProto.DocumentMessage{
ContextInfo: ctxInfo,
Caption: &media.Caption,
@ -4551,6 +4578,9 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event, timing
go ms.sendMessageMetrics(evt, err, "Error converting", true)
return
}
if extraMeta == nil {
extraMeta = &extraConvertMeta{}
}
dbMsgType := database.MsgNormal
if msg.PollCreationMessage != nil || msg.PollCreationMessageV2 != nil || msg.PollCreationMessageV3 != nil {
dbMsgType = database.MsgMatrixPoll
@ -4565,12 +4595,15 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event, timing
} else {
info.ID = dbMsg.JID
}
if dbMsgType == database.MsgMatrixPoll && extraMeta != nil && extraMeta.PollOptions != nil {
if dbMsgType == database.MsgMatrixPoll && extraMeta.PollOptions != nil {
dbMsg.PutPollOptions(extraMeta.PollOptions)
}
portal.log.Debugln("Sending event", evt.ID, "to WhatsApp", info.ID)
start = time.Now()
resp, err := sender.Client.SendMessage(ctx, portal.Key.JID, msg, whatsmeow.SendRequestExtra{ID: info.ID})
resp, err := sender.Client.SendMessage(ctx, portal.Key.JID, msg, whatsmeow.SendRequestExtra{
ID: info.ID,
MediaHandle: extraMeta.MediaHandle,
})
timings.totalSend = time.Since(start)
timings.whatsmeow = resp.DebugTimings
if err != nil {
@ -4578,7 +4611,7 @@ func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event, timing
return
}
dbMsg.MarkSent(resp.Timestamp)
if len(extraMeta.GalleryExtraParts) > 0 {
if extraMeta != nil && len(extraMeta.GalleryExtraParts) > 0 {
for i, part := range extraMeta.GalleryExtraParts {
partInfo := portal.generateMessageInfo(sender)
partDBMsg := portal.markHandled(nil, nil, partInfo, evt.ID, evt.Sender, false, true, database.MsgBeeperGallery, i+1, database.MsgNoError)
@ -4995,9 +5028,7 @@ func (portal *Portal) HandleMatrixLeave(brSender bridge.User) {
func (portal *Portal) HandleMatrixKick(brSender bridge.User, brTarget bridge.Ghost) {
sender := brSender.(*User)
target := brTarget.(*Puppet)
_, err := sender.Client.UpdateGroupParticipants(portal.Key.JID, map[types.JID]whatsmeow.ParticipantChange{
target.JID: whatsmeow.ParticipantChangeRemove,
})
_, err := sender.Client.UpdateGroupParticipants(portal.Key.JID, []types.JID{target.JID}, whatsmeow.ParticipantChangeRemove)
if err != nil {
portal.log.Errorfln("Failed to kick %s from group as %s: %v", target.JID, sender.MXID, err)
return
@ -5008,9 +5039,7 @@ func (portal *Portal) HandleMatrixKick(brSender bridge.User, brTarget bridge.Gho
func (portal *Portal) HandleMatrixInvite(brSender bridge.User, brTarget bridge.Ghost) {
sender := brSender.(*User)
target := brTarget.(*Puppet)
_, err := sender.Client.UpdateGroupParticipants(portal.Key.JID, map[types.JID]whatsmeow.ParticipantChange{
target.JID: whatsmeow.ParticipantChangeAdd,
})
_, err := sender.Client.UpdateGroupParticipants(portal.Key.JID, []types.JID{target.JID}, whatsmeow.ParticipantChangeAdd)
if err != nil {
portal.log.Errorfln("Failed to add %s to group as %s: %v", target.JID, sender.MXID, err)
return

View file

@ -24,6 +24,7 @@ import (
"fmt"
"net"
"net/http"
_ "net/http/pprof"
"strings"
"time"
@ -71,6 +72,13 @@ func (prov *ProvisioningAPI) Init() {
prov.bridge.AS.Router.HandleFunc("/_matrix/app/com.beeper.asmux/ping", prov.BridgeStatePing).Methods(http.MethodPost)
prov.bridge.AS.Router.HandleFunc("/_matrix/app/com.beeper.bridge_state", prov.BridgeStatePing).Methods(http.MethodPost)
if prov.bridge.Config.Bridge.Provisioning.DebugEndpoints {
prov.log.Debugln("Enabling debug API at /debug")
r := prov.bridge.AS.Router.PathPrefix("/debug").Subrouter()
r.Use(prov.AuthMiddleware)
r.PathPrefix("/pprof").Handler(http.DefaultServeMux)
}
// Deprecated, just use /disconnect
r.HandleFunc("/v1/delete_connection", prov.Disconnect).Methods(http.MethodPost)
}

54
user.go
View file

@ -635,15 +635,17 @@ func (user *User) handleCallStart(sender types.JID, id, callType string, ts time
if callType != "" {
text = fmt.Sprintf("Incoming %s call. Use the WhatsApp app to answer.", callType)
}
portal.messages <- PortalMessage{
fake: &fakeMessage{
Sender: sender,
Text: text,
ID: id,
Time: ts,
Important: true,
portal.events <- &PortalEvent{
Message: &PortalMessage{
fake: &fakeMessage{
Sender: sender,
Text: text,
ID: id,
Time: ts,
Important: true,
},
source: user,
},
source: user,
}
}
@ -865,11 +867,15 @@ func (user *User) HandleEvent(event interface{}) {
go user.handleChatPresence(v)
case *events.Message:
portal := user.GetPortalByMessageSource(v.Info.MessageSource)
portal.messages <- PortalMessage{evt: v, source: user}
portal.events <- &PortalEvent{
Message: &PortalMessage{evt: v, source: user},
}
case *events.MediaRetry:
user.phoneSeen(v.Timestamp)
portal := user.GetPortalByJID(v.ChatID)
portal.mediaRetries <- PortalMediaRetry{evt: v, source: user}
portal.events <- &PortalEvent{
MediaRetry: &PortalMediaRetry{evt: v, source: user},
}
case *events.CallOffer:
user.handleCallStart(v.CallCreator, v.CallID, "", v.Timestamp)
case *events.CallOfferNotice:
@ -885,22 +891,26 @@ func (user *User) HandleEvent(event interface{}) {
if v.Implicit {
text = fmt.Sprintf("Your security code with %s (device #%d) changed.", puppet.Displayname, v.JID.Device)
}
portal.messages <- PortalMessage{
fake: &fakeMessage{
Sender: v.JID,
Text: text,
ID: strconv.FormatInt(v.Timestamp.Unix(), 10),
Time: v.Timestamp,
Important: false,
portal.events <- &PortalEvent{
Message: &PortalMessage{
fake: &fakeMessage{
Sender: v.JID,
Text: text,
ID: strconv.FormatInt(v.Timestamp.Unix(), 10),
Time: v.Timestamp,
Important: false,
},
source: user,
},
source: user,
}
}
case *events.CallTerminate, *events.CallRelayLatency, *events.CallAccept, *events.UnknownCallEvent:
// ignore
case *events.UndecryptableMessage:
portal := user.GetPortalByMessageSource(v.Info.MessageSource)
portal.messages <- PortalMessage{undecryptable: v, source: user}
portal.events <- &PortalEvent{
Message: &PortalMessage{undecryptable: v, source: user},
}
case *events.HistorySync:
if user.bridge.Config.Bridge.HistorySync.Backfill {
user.historySyncs <- v
@ -1228,14 +1238,16 @@ func (user *User) handleChatPresence(presence *events.ChatPresence) {
}
func (user *User) handleReceipt(receipt *events.Receipt) {
if receipt.Type != events.ReceiptTypeRead && receipt.Type != events.ReceiptTypeReadSelf && receipt.Type != events.ReceiptTypeDelivered {
if receipt.Type != types.ReceiptTypeRead && receipt.Type != types.ReceiptTypeReadSelf && receipt.Type != types.ReceiptTypeDelivered {
return
}
portal := user.GetPortalByMessageSource(receipt.MessageSource)
if portal == nil || len(portal.MXID) == 0 {
return
}
portal.messages <- PortalMessage{receipt: receipt, source: user}
portal.events <- &PortalEvent{
Message: &PortalMessage{receipt: receipt, source: user},
}
}
func (user *User) makeReadMarkerContent(eventID id.EventID, doublePuppet bool) CustomReadMarkers {