mirror of
https://github.com/mautrix/whatsapp.git
synced 2026-11-09 15:49:18 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
945474343f |
||
|
|
5c8c1fc835 |
||
|
|
d9b0daca89 |
||
|
|
ac29fa5272 |
||
|
|
d574a67a2d |
||
|
|
5640ef311b |
||
|
|
81f64557ea | ||
|
|
03859bb3db |
11 changed files with 54 additions and 16 deletions
1
.github/workflows/go.yml
vendored
1
.github/workflows/go.yml
vendored
|
|
@ -30,6 +30,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
go install golang.org/x/tools/cmd/goimports@latest
|
go install golang.org/x/tools/cmd/goimports@latest
|
||||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||||
|
go install github.com/beeper/pre-commit-go/bridgelint@latest
|
||||||
export PATH="$HOME/go/bin:$PATH"
|
export PATH="$HOME/go/bin:$PATH"
|
||||||
|
|
||||||
- name: Run pre-commit
|
- name: Run pre-commit
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,5 @@ repos:
|
||||||
- id: prevent-literal-http-methods
|
- id: prevent-literal-http-methods
|
||||||
- id: zerolog-ban-global-log
|
- id: zerolog-ban-global-log
|
||||||
- id: bridgelint
|
- id: bridgelint
|
||||||
|
language: system
|
||||||
verbose: true
|
verbose: true
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -20,7 +20,7 @@ require (
|
||||||
golang.org/x/sync v0.24.0
|
golang.org/x/sync v0.24.0
|
||||||
google.golang.org/protobuf v1.36.12
|
google.golang.org/protobuf v1.36.12
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
maunium.net/go/mautrix v0.32.1-0.20261031224934-b69deb427bd7
|
maunium.net/go/mautrix v0.32.1-0.20261105141340-842796acf445
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -103,5 +103,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
||||||
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
||||||
maunium.net/go/mautrix v0.32.1-0.20261031224934-b69deb427bd7 h1:GpLIqeJTpG0/ti7XA370HgjnSWd/pQxXVGb/FRkayOA=
|
maunium.net/go/mautrix v0.32.1-0.20261105141340-842796acf445 h1:ZI9Y2YEmjqQDloOCiciHeynTRYjUwK0ZZbNcRH/5NOc=
|
||||||
maunium.net/go/mautrix v0.32.1-0.20261031224934-b69deb427bd7/go.mod h1:tZSwPzw+/0pa0dxGufkh0uJqM84BNxB6e2I0+S0UyjU=
|
maunium.net/go/mautrix v0.32.1-0.20261105141340-842796acf445/go.mod h1:tZSwPzw+/0pa0dxGufkh0uJqM84BNxB6e2I0+S0UyjU=
|
||||||
|
|
|
||||||
|
|
@ -298,6 +298,9 @@ func (wa *WhatsAppClient) handleWAHistorySync(
|
||||||
Int("msg_index", i).
|
Int("msg_index", i).
|
||||||
Str("msg_id", rawMsg.GetMessage().GetKey().GetID()).
|
Str("msg_id", rawMsg.GetMessage().GetKey().GetID()).
|
||||||
Uint64("msg_time_seconds", rawMsg.GetMessage().GetMessageTimestamp()).
|
Uint64("msg_time_seconds", rawMsg.GetMessage().GetMessageTimestamp()).
|
||||||
|
Stringer("stub_type", rawMsg.GetMessage().GetMessageStubType()).
|
||||||
|
Str("message_type", getMessageType(rawMsg.GetMessage().GetMessage())).
|
||||||
|
Bool("from_me", rawMsg.GetMessage().GetKey().GetFromMe()).
|
||||||
Msg("Dropping historical message due to parse error")
|
Msg("Dropping historical message due to parse error")
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Any("web_message_info", rawMsg.GetMessage()).
|
Any("web_message_info", rawMsg.GetMessage()).
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,7 @@ func (wa *WhatsAppClient) HandleMatrixMessageRemove(ctx context.Context, msg *br
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wa *WhatsAppClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bridgev2.MatrixReadReceipt) (retErr error) {
|
func (wa *WhatsAppClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bridgev2.MatrixReadReceipt) (retErr error) {
|
||||||
if !receipt.ReadUpTo.After(receipt.LastRead) {
|
if receipt.Receipt.IsThread() || !receipt.ReadUpTo.After(receipt.LastRead) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if receipt.LastRead.IsZero() {
|
if receipt.LastRead.IsZero() {
|
||||||
|
|
|
||||||
|
|
@ -374,6 +374,14 @@ func (wa *WhatsAppClient) handleWAMessage(ctx context.Context, evt *events.Messa
|
||||||
if assocType := messageAssoc.GetAssociationType(); assocType == waE2E.MessageAssociation_HD_IMAGE_DUAL_UPLOAD || assocType == waE2E.MessageAssociation_HD_VIDEO_DUAL_UPLOAD {
|
if assocType := messageAssoc.GetAssociationType(); assocType == waE2E.MessageAssociation_HD_IMAGE_DUAL_UPLOAD || assocType == waE2E.MessageAssociation_HD_VIDEO_DUAL_UPLOAD {
|
||||||
parentKey := messageAssoc.GetParentMessageKey()
|
parentKey := messageAssoc.GetParentMessageKey()
|
||||||
protocolMsg, shouldHideEdit := makeHDMediaReplacementEdit(evt.Message, parentKey)
|
protocolMsg, shouldHideEdit := makeHDMediaReplacementEdit(evt.Message, parentKey)
|
||||||
|
if protocolMsg.GetEditedMessage() == nil {
|
||||||
|
wa.UserLogin.Log.Debug().
|
||||||
|
Str("message_id", evt.Info.ID).
|
||||||
|
Str("parent_id", parentKey.GetID()).
|
||||||
|
Stringer("assoc_type", assocType).
|
||||||
|
Msg("Ignoring HD replacement message without replacement content")
|
||||||
|
return
|
||||||
|
}
|
||||||
dontRenderEdited = shouldHideEdit
|
dontRenderEdited = shouldHideEdit
|
||||||
wa.UserLogin.Log.Debug().
|
wa.UserLogin.Log.Debug().
|
||||||
Str("message_id", evt.Info.ID).
|
Str("message_id", evt.Info.ID).
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,11 @@ func (wa *WhatsAppConnector) syncMismatchingGhosts(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wa *WhatsAppConnector) removeRejoinedPNGhosts(ctx context.Context) error {
|
func (wa *WhatsAppConnector) removeRejoinedPNGhosts(ctx context.Context) error {
|
||||||
if wa.Bridge.Background || wa.Bridge.DB.KV.Get(ctx, "whatsapp_lid_dm_pn_ghosts_removed") == "true" {
|
if wa.Bridge.Background || wa.Bridge.DB.KV.Get(ctx, "whatsapp_lid_dm_pn_ghosts_removed_v2") == "true" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
stateGetter, ok := wa.Bridge.Matrix.(bridgev2.MatrixConnectorWithArbitraryRoomState)
|
||||||
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log := zerolog.Ctx(ctx).With().Str("action", "remove rejoined pn ghosts").Logger()
|
log := zerolog.Ctx(ctx).With().Str("action", "remove rejoined pn ghosts").Logger()
|
||||||
|
|
@ -322,12 +326,14 @@ func (wa *WhatsAppConnector) removeRejoinedPNGhosts(ctx context.Context) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pnUserID := waid.MakeUserID(pn)
|
pnUserID := waid.MakeUserID(pn)
|
||||||
member, err := wa.Bridge.Matrix.GetMemberInfo(ctx, portal.MXID, wa.Bridge.Matrix.FormatGhostMXID(pnUserID))
|
memberEvt, err := stateGetter.GetStateEvent(ctx, portal.MXID, event.StateMember, wa.Bridge.Matrix.FormatGhostMXID(pnUserID).String())
|
||||||
if err != nil {
|
if errors.Is(err, mautrix.MNotFound) || errors.Is(err, mautrix.MForbidden) {
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
log.Warn().Err(err).Stringer("room_id", portal.MXID).Msg("Failed to get PN ghost membership")
|
log.Warn().Err(err).Stringer("room_id", portal.MXID).Msg("Failed to get PN ghost membership")
|
||||||
failed++
|
failed++
|
||||||
continue
|
continue
|
||||||
} else if member == nil || member.Membership != event.MembershipJoin {
|
} else if memberEvt == nil || memberEvt.Content.AsMember().Membership != event.MembershipJoin {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pnGhost, err := wa.Bridge.GetGhostByID(ctx, pnUserID)
|
pnGhost, err := wa.Bridge.GetGhostByID(ctx, pnUserID)
|
||||||
|
|
@ -345,6 +351,12 @@ func (wa *WhatsAppConnector) removeRejoinedPNGhosts(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
log.Debug().
|
||||||
|
Stringer("room_id", portal.MXID).
|
||||||
|
Stringer("pn", pn).
|
||||||
|
Stringer("join_sender", memberEvt.Sender).
|
||||||
|
Time("join_ts", time.UnixMilli(memberEvt.Timestamp)).
|
||||||
|
Msg("Removed PN ghost from LID DM")
|
||||||
removed++
|
removed++
|
||||||
}
|
}
|
||||||
log.Info().
|
log.Info().
|
||||||
|
|
@ -353,7 +365,7 @@ func (wa *WhatsAppConnector) removeRejoinedPNGhosts(ctx context.Context) error {
|
||||||
Int("total_lid_portals", len(lidPortals)).
|
Int("total_lid_portals", len(lidPortals)).
|
||||||
Msg("Finished removing rejoined PN ghosts from LID DMs")
|
Msg("Finished removing rejoined PN ghosts from LID DMs")
|
||||||
if failed == 0 && ctx.Err() == nil {
|
if failed == 0 && ctx.Err() == nil {
|
||||||
wa.Bridge.DB.KV.Set(ctx, "whatsapp_lid_dm_pn_ghosts_removed", "true")
|
wa.Bridge.DB.KV.Set(ctx, "whatsapp_lid_dm_pn_ghosts_removed_v2", "true")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -57,9 +56,9 @@ func (wa *WhatsAppClient) resyncWASARootSecrets(ctx context.Context) {
|
||||||
success := true
|
success := true
|
||||||
if err := wa.Client.FetchAppState(ctx, appstate.WAPatchRegularHigh, true, false); err != nil {
|
if err := wa.Client.FetchAppState(ctx, appstate.WAPatchRegularHigh, true, false); err != nil {
|
||||||
log.Err(err).Msg("Failed to resync WASA root secrets")
|
log.Err(err).Msg("Failed to resync WASA root secrets")
|
||||||
// Mark the sync as completed on mismatching LTHash errors, because those can get permanently stuck
|
// Mark the sync as completed on errors too, because some get permanently stuck (mismatching LTHash,
|
||||||
// (retrying won't help). In case it's not stuck, a single call should be enough to request a resync.
|
// expired patch blobs), and a failed full sync already requests app state recovery from the phone.
|
||||||
if !errors.Is(err, appstate.ErrMismatchingLTHash) || ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
success = false
|
success = false
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@ func (wa *WhatsAppClient) doGhostResync(ctx context.Context, queue map[types.JID
|
||||||
var ghostJIDs []types.JID
|
var ghostJIDs []types.JID
|
||||||
var ghosts []*bridgev2.Ghost
|
var ghosts []*bridgev2.Ghost
|
||||||
var portals []*bridgev2.Portal
|
var portals []*bridgev2.Portal
|
||||||
|
selectedGhosts := make(map[types.JID]*bridgev2.Ghost)
|
||||||
for jid, item := range queue {
|
for jid, item := range queue {
|
||||||
var lastSync time.Time
|
var lastSync time.Time
|
||||||
unknownAvatar := false
|
unknownAvatar := false
|
||||||
|
|
@ -136,12 +137,23 @@ func (wa *WhatsAppClient) doGhostResync(ctx context.Context, queue map[types.JID
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if item.ghost != nil {
|
if item.ghost != nil {
|
||||||
ghosts = append(ghosts, item.ghost)
|
selectedGhosts[jid] = item.ghost
|
||||||
ghostJIDs = append(ghostJIDs, jid)
|
|
||||||
} else if item.portal != nil {
|
} else if item.portal != nil {
|
||||||
portals = append(portals, item.portal)
|
portals = append(portals, item.portal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for jid, ghost := range selectedGhosts {
|
||||||
|
if jid.Server == types.DefaultUserServer {
|
||||||
|
lid, err := wa.GetStore().LIDs.GetLIDForPN(ctx, jid)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Stringer("jid", jid).Msg("Failed to get LID for background sync")
|
||||||
|
} else if _, lidSelected := selectedGhosts[lid]; lidSelected {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ghosts = append(ghosts, ghost)
|
||||||
|
ghostJIDs = append(ghostJIDs, jid)
|
||||||
|
}
|
||||||
for _, portal := range portals {
|
for _, portal := range portals {
|
||||||
wa.UserLogin.QueueRemoteEvent(&simplevent.ChatResync{
|
wa.UserLogin.QueueRemoteEvent(&simplevent.ChatResync{
|
||||||
EventMeta: simplevent.EventMeta{
|
EventMeta: simplevent.EventMeta{
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/yuin/goldmark/extension"
|
"github.com/yuin/goldmark/extension"
|
||||||
"go.mau.fi/whatsmeow/types/richresponse"
|
"go.mau.fi/whatsmeow/types/richresponse"
|
||||||
"maunium.net/go/mautrix/bridgev2"
|
"maunium.net/go/mautrix/bridgev2"
|
||||||
|
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||||
"maunium.net/go/mautrix/event"
|
"maunium.net/go/mautrix/event"
|
||||||
"maunium.net/go/mautrix/format"
|
"maunium.net/go/mautrix/format"
|
||||||
"maunium.net/go/mautrix/format/mdext"
|
"maunium.net/go/mautrix/format/mdext"
|
||||||
|
|
@ -36,7 +37,8 @@ import (
|
||||||
|
|
||||||
func (mc *MessageConverter) convertUnifiedRichResponseMessage(ctx context.Context, data []byte) *bridgev2.ConvertedMessagePart {
|
func (mc *MessageConverter) convertUnifiedRichResponseMessage(ctx context.Context, data []byte) *bridgev2.ConvertedMessagePart {
|
||||||
extra := map[string]any{}
|
extra := map[string]any{}
|
||||||
if json.Valid(data) && len(data) < 24*1024 {
|
_, canonicalErr := canonicaljson.Marshal(json.RawMessage(data))
|
||||||
|
if canonicalErr == nil && len(data) < 24*1024 {
|
||||||
extra["fi.mau.whatsapp.rich_message"] = json.RawMessage(data)
|
extra["fi.mau.whatsapp.rich_message"] = json.RawMessage(data)
|
||||||
} else if len(data) < 16*1024 {
|
} else if len(data) < 16*1024 {
|
||||||
extra["fi.mau.whatsapp.non_json_rich_message"] = base64.StdEncoding.EncodeToString(data)
|
extra["fi.mau.whatsapp.non_json_rich_message"] = base64.StdEncoding.EncodeToString(data)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue