mirror of
https://github.com/tulir/mautrix-whatsapp
synced 2024-06-15 01:18:31 +02:00
Merge branch 'mautrix:master' into master
This commit is contained in:
commit
c7d05f857f
1
.idea/icon.svg
Normal file
1
.idea/icon.svg
Normal 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 |
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM alpine:3.18
|
||||
FROM alpine:3.19
|
||||
|
||||
ENV UID=1337 \
|
||||
GID=1337
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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" {
|
||||
|
|
|
@ -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
12
go.mod
|
@ -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
24
go.sum
|
@ -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=
|
||||
|
|
|
@ -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).
|
||||
|
|
2
main.go
2
main.go
|
@ -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",
|
||||
|
|
81
portal.go
81
portal.go
|
@ -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
|
||||
|
|
|
@ -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
54
user.go
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue