forked from MirrorHub/mautrix-whatsapp
Move most double puppet source key adding to mautrix-go
This commit is contained in:
parent
e9f01b81d5
commit
bf4c01648f
6 changed files with 51 additions and 120 deletions
2
go.mod
2
go.mod
|
@ -15,7 +15,7 @@ require (
|
|||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
||||
google.golang.org/protobuf v1.28.0
|
||||
maunium.net/go/maulogger/v2 v2.3.2
|
||||
maunium.net/go/mautrix v0.11.1-0.20220630105134-e8349f977b35
|
||||
maunium.net/go/mautrix v0.11.1-0.20220630174618-e98784f2fe26
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
4
go.sum
4
go.sum
|
@ -108,5 +108,5 @@ 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/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0=
|
||||
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||
maunium.net/go/mautrix v0.11.1-0.20220630105134-e8349f977b35 h1:aPiY7xtcRsP7o7u0TvkKY7JiyjVa0bUnsqCEMJQ3vU4=
|
||||
maunium.net/go/mautrix v0.11.1-0.20220630105134-e8349f977b35/go.mod h1:Lj4pBam5P0zIvieIFHnGsuaj+xfFtI3y/sC8yGlyna8=
|
||||
maunium.net/go/mautrix v0.11.1-0.20220630174618-e98784f2fe26 h1:wkfsp2ozyAQ9Vr9oAXbS9caWLhIffQ/Lxa04t7iUY54=
|
||||
maunium.net/go/mautrix v0.11.1-0.20220630174618-e98784f2fe26/go.mod h1:Lj4pBam5P0zIvieIFHnGsuaj+xfFtI3y/sC8yGlyna8=
|
||||
|
|
|
@ -656,33 +656,16 @@ func (portal *Portal) appendBatchEvents(converted *ConvertedMessage, info *types
|
|||
return nil
|
||||
}
|
||||
|
||||
const backfillIDField = "fi.mau.whatsapp.backfill_msg_id"
|
||||
|
||||
func (portal *Portal) wrapBatchEvent(info *types.MessageInfo, intent *appservice.IntentAPI, eventType event.Type, content *event.MessageEventContent, extraContent map[string]interface{}) (*event.Event, error) {
|
||||
if extraContent == nil {
|
||||
extraContent = map[string]interface{}{}
|
||||
}
|
||||
extraContent[backfillIDField] = info.ID
|
||||
if intent.IsCustomPuppet {
|
||||
extraContent[doublePuppetKey] = doublePuppetValue
|
||||
}
|
||||
wrappedContent := event.Content{
|
||||
Parsed: content,
|
||||
Raw: extraContent,
|
||||
}
|
||||
newEventType, err := portal.encrypt(&wrappedContent, eventType)
|
||||
newEventType, err := portal.encrypt(intent, &wrappedContent, eventType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if newEventType == event.EventEncrypted {
|
||||
// Clear other custom keys if the event was encrypted, but keep the double puppet identifier
|
||||
wrappedContent.Raw = map[string]interface{}{backfillIDField: info.ID}
|
||||
if intent.IsCustomPuppet {
|
||||
wrappedContent.Raw[doublePuppetKey] = doublePuppetValue
|
||||
}
|
||||
}
|
||||
|
||||
return &event.Event{
|
||||
Sender: intent.UserID,
|
||||
Type: newEventType,
|
||||
|
|
113
portal.go
113
portal.go
|
@ -331,7 +331,7 @@ func (portal *Portal) handleReceipt(receipt *events.Receipt, source *User) {
|
|||
}
|
||||
intent := portal.bridge.GetPuppetByJID(receipt.Sender).IntentFor(portal)
|
||||
for _, msg := range markAsRead {
|
||||
err := intent.SetReadMarkers(portal.MXID, makeReadMarkerContent(msg.MXID, intent.IsCustomPuppet))
|
||||
err := intent.SetReadMarkers(portal.MXID, source.makeReadMarkerContent(msg.MXID, intent.IsCustomPuppet))
|
||||
if err != nil {
|
||||
portal.log.Warnfln("Failed to mark message %s as read by %s: %v", msg.MXID, intent.UserID, err)
|
||||
} else {
|
||||
|
@ -740,7 +740,7 @@ func (portal *Portal) handleMessage(source *User, evt *events.Message) {
|
|||
if source.MXID == intent.UserID {
|
||||
// There are some edge cases (like call notices) where previous messages aren't marked as read
|
||||
// when the user sends a message from another device, so just mark the new message as read to be safe.
|
||||
err = intent.SetReadMarkers(portal.MXID, makeReadMarkerContent(lastEventID, true))
|
||||
err = intent.SetReadMarkers(portal.MXID, source.makeReadMarkerContent(lastEventID, true))
|
||||
if err != nil {
|
||||
portal.log.Warnfln("Failed to mark own message %s as read by %s: %v", lastEventID, source.MXID, err)
|
||||
}
|
||||
|
@ -1588,11 +1588,6 @@ func (portal *Portal) SetReply(content *event.MessageEventContent, replyToID typ
|
|||
return true
|
||||
}
|
||||
|
||||
type sendReactionContent struct {
|
||||
event.ReactionEventContent
|
||||
DoublePuppet string `json:"fi.mau.double_puppet_source,omitempty"`
|
||||
}
|
||||
|
||||
func (portal *Portal) HandleMessageReaction(intent *appservice.IntentAPI, user *User, info *types.MessageInfo, reaction *waProto.ReactionMessage, existingMsg *database.Message) {
|
||||
if existingMsg != nil {
|
||||
_, _ = portal.MainIntent().RedactEvent(portal.MXID, existingMsg.MXID, mautrix.ReqRedact{
|
||||
|
@ -1608,11 +1603,7 @@ func (portal *Portal) HandleMessageReaction(intent *appservice.IntentAPI, user *
|
|||
return
|
||||
}
|
||||
|
||||
extra := make(map[string]interface{})
|
||||
if intent.IsCustomPuppet {
|
||||
extra[doublePuppetKey] = doublePuppetValue
|
||||
}
|
||||
resp, err := intent.RedactEvent(portal.MXID, existing.MXID, mautrix.ReqRedact{Extra: extra})
|
||||
resp, err := intent.RedactEvent(portal.MXID, existing.MXID)
|
||||
if err != nil {
|
||||
portal.log.Errorfln("Failed to redact reaction %s/%s from %s to %s: %v", existing.MXID, existing.JID, info.Sender, targetJID, err)
|
||||
}
|
||||
|
@ -1625,15 +1616,12 @@ func (portal *Portal) HandleMessageReaction(intent *appservice.IntentAPI, user *
|
|||
return
|
||||
}
|
||||
|
||||
var content sendReactionContent
|
||||
var content event.ReactionEventContent
|
||||
content.RelatesTo = event.RelatesTo{
|
||||
Type: event.RelAnnotation,
|
||||
EventID: target.MXID,
|
||||
Key: variationselector.Add(reaction.GetText()),
|
||||
}
|
||||
if intent.IsCustomPuppet {
|
||||
content.DoublePuppet = doublePuppetValue
|
||||
}
|
||||
resp, err := intent.SendMassagedMessageEvent(portal.MXID, event.EventReaction, &content, info.Timestamp.UnixMilli())
|
||||
if err != nil {
|
||||
portal.log.Errorfln("Failed to bridge reaction %s from %s to %s: %v", info.ID, info.Sender, target.JID, err)
|
||||
|
@ -1651,14 +1639,10 @@ func (portal *Portal) HandleMessageRevoke(user *User, info *types.MessageInfo, k
|
|||
return false
|
||||
}
|
||||
intent := portal.bridge.GetPuppetByJID(info.Sender).IntentFor(portal)
|
||||
redactionReq := mautrix.ReqRedact{Extra: map[string]interface{}{}}
|
||||
if intent.IsCustomPuppet {
|
||||
redactionReq.Extra[doublePuppetKey] = doublePuppetValue
|
||||
}
|
||||
_, err := intent.RedactEvent(portal.MXID, msg.MXID, redactionReq)
|
||||
_, err := intent.RedactEvent(portal.MXID, msg.MXID)
|
||||
if err != nil {
|
||||
if errors.Is(err, mautrix.MForbidden) {
|
||||
_, err = portal.MainIntent().RedactEvent(portal.MXID, msg.MXID, redactionReq)
|
||||
_, err = portal.MainIntent().RedactEvent(portal.MXID, msg.MXID)
|
||||
if err != nil {
|
||||
portal.log.Errorln("Failed to redact %s: %v", msg.JID, err)
|
||||
}
|
||||
|
@ -1673,49 +1657,29 @@ func (portal *Portal) sendMainIntentMessage(content *event.MessageEventContent)
|
|||
return portal.sendMessage(portal.MainIntent(), event.EventMessage, content, nil, 0)
|
||||
}
|
||||
|
||||
func (portal *Portal) encrypt(content *event.Content, eventType event.Type) (event.Type, error) {
|
||||
if portal.Encrypted && portal.bridge.Crypto != nil {
|
||||
// TODO maybe the locking should be inside mautrix-go?
|
||||
portal.encryptLock.Lock()
|
||||
encrypted, err := portal.bridge.Crypto.Encrypt(portal.MXID, eventType, *content)
|
||||
portal.encryptLock.Unlock()
|
||||
if err != nil {
|
||||
return eventType, fmt.Errorf("failed to encrypt event: %w", err)
|
||||
}
|
||||
eventType = event.EventEncrypted
|
||||
content.Parsed = encrypted
|
||||
func (portal *Portal) encrypt(intent *appservice.IntentAPI, content *event.Content, eventType event.Type) (event.Type, error) {
|
||||
if !portal.Encrypted || portal.bridge.Crypto == nil {
|
||||
return eventType, nil
|
||||
}
|
||||
return eventType, nil
|
||||
intent.AddDoublePuppetValue(content)
|
||||
// TODO maybe the locking should be inside mautrix-go?
|
||||
portal.encryptLock.Lock()
|
||||
defer portal.encryptLock.Unlock()
|
||||
err := portal.bridge.Crypto.Encrypt(portal.MXID, eventType, content)
|
||||
if err != nil {
|
||||
return eventType, fmt.Errorf("failed to encrypt event: %w", err)
|
||||
}
|
||||
return event.EventEncrypted, nil
|
||||
}
|
||||
|
||||
const doublePuppetKey = "fi.mau.double_puppet_source"
|
||||
const doublePuppetValue = "mautrix-whatsapp"
|
||||
|
||||
func (portal *Portal) sendMessage(intent *appservice.IntentAPI, eventType event.Type, content *event.MessageEventContent, extraContent map[string]interface{}, timestamp int64) (*mautrix.RespSendEvent, error) {
|
||||
wrappedContent := event.Content{Parsed: content, Raw: extraContent}
|
||||
if timestamp != 0 && intent.IsCustomPuppet {
|
||||
if wrappedContent.Raw == nil {
|
||||
wrappedContent.Raw = map[string]interface{}{}
|
||||
}
|
||||
if intent.IsCustomPuppet {
|
||||
wrappedContent.Raw[doublePuppetKey] = doublePuppetValue
|
||||
}
|
||||
}
|
||||
var err error
|
||||
eventType, err = portal.encrypt(&wrappedContent, eventType)
|
||||
eventType, err = portal.encrypt(intent, &wrappedContent, eventType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if eventType == event.EventEncrypted {
|
||||
// Clear other custom keys if the event was encrypted, but keep the double puppet identifier
|
||||
if intent.IsCustomPuppet {
|
||||
wrappedContent.Raw = map[string]interface{}{doublePuppetKey: doublePuppetValue}
|
||||
} else {
|
||||
wrappedContent.Raw = nil
|
||||
}
|
||||
}
|
||||
|
||||
_, _ = intent.UserTyping(portal.MXID, false, 0)
|
||||
if timestamp == 0 {
|
||||
return intent.SendMessageEvent(portal.MXID, eventType, &wrappedContent)
|
||||
|
@ -2142,11 +2106,11 @@ func (portal *Portal) removeUser(isSameUser bool, kicker *appservice.IntentAPI,
|
|||
if err != nil {
|
||||
portal.log.Warnfln("Failed to kick %s from %s: %v", target, portal.MXID, err)
|
||||
if targetIntent != nil {
|
||||
_, _ = portal.leaveWithPuppetMeta(targetIntent)
|
||||
_, _ = targetIntent.LeaveRoom(portal.MXID)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_, err := portal.leaveWithPuppetMeta(targetIntent)
|
||||
_, err := targetIntent.LeaveRoom(portal.MXID)
|
||||
if err != nil {
|
||||
portal.log.Warnfln("Failed to leave portal as %s: %v", target, err)
|
||||
_, _ = portal.MainIntent().KickUser(portal.MXID, &mautrix.ReqKickUser{UserID: target})
|
||||
|
@ -2178,19 +2142,6 @@ func (portal *Portal) HandleWhatsAppKick(source *User, senderJID types.JID, jids
|
|||
}
|
||||
}
|
||||
|
||||
func (portal *Portal) leaveWithPuppetMeta(intent *appservice.IntentAPI) (*mautrix.RespSendEvent, error) {
|
||||
content := event.Content{
|
||||
Parsed: event.MemberEventContent{
|
||||
Membership: event.MembershipLeave,
|
||||
},
|
||||
Raw: map[string]interface{}{
|
||||
doublePuppetKey: doublePuppetValue,
|
||||
},
|
||||
}
|
||||
// Bypass IntentAPI, we don't want to EnsureJoined here
|
||||
return intent.Client.SendStateEvent(portal.MXID, event.StateMember, intent.UserID.String(), &content)
|
||||
}
|
||||
|
||||
func (portal *Portal) HandleWhatsAppInvite(source *User, senderJID *types.JID, jids []types.JID) (evtID id.EventID) {
|
||||
intent := portal.MainIntent()
|
||||
if senderJID != nil && !senderJID.IsEmpty() {
|
||||
|
@ -2200,17 +2151,11 @@ func (portal *Portal) HandleWhatsAppInvite(source *User, senderJID *types.JID, j
|
|||
for _, jid := range jids {
|
||||
puppet := portal.bridge.GetPuppetByJID(jid)
|
||||
puppet.SyncContact(source, true, false, "handling whatsapp invite")
|
||||
content := event.Content{
|
||||
Parsed: event.MemberEventContent{
|
||||
Membership: "invite",
|
||||
Displayname: puppet.Displayname,
|
||||
AvatarURL: puppet.AvatarURL.CUString(),
|
||||
},
|
||||
Raw: map[string]interface{}{
|
||||
doublePuppetKey: doublePuppetValue,
|
||||
},
|
||||
}
|
||||
resp, err := intent.SendStateEvent(portal.MXID, event.StateMember, puppet.MXID.String(), &content)
|
||||
resp, err := intent.SendStateEvent(portal.MXID, event.StateMember, puppet.MXID.String(), &event.MemberEventContent{
|
||||
Membership: event.MembershipInvite,
|
||||
Displayname: puppet.Displayname,
|
||||
AvatarURL: puppet.AvatarURL.CUString(),
|
||||
})
|
||||
if err != nil {
|
||||
portal.log.Warnfln("Failed to invite %s as %s: %v", puppet.MXID, intent.UserID, err)
|
||||
_ = portal.MainIntent().EnsureInvited(portal.MXID, puppet.MXID)
|
||||
|
@ -3270,11 +3215,7 @@ func (portal *Portal) upsertReaction(intent *appservice.IntentAPI, targetJID typ
|
|||
portal.log.Debugfln("Redacting old Matrix reaction %s after new one (%s) was sent", dbReaction.MXID, mxid)
|
||||
var err error
|
||||
if intent != nil {
|
||||
extra := make(map[string]interface{})
|
||||
if intent.IsCustomPuppet {
|
||||
extra[doublePuppetKey] = doublePuppetValue
|
||||
}
|
||||
_, err = intent.RedactEvent(portal.MXID, dbReaction.MXID, mautrix.ReqRedact{Extra: extra})
|
||||
_, err = intent.RedactEvent(portal.MXID, dbReaction.MXID)
|
||||
}
|
||||
if intent == nil || errors.Is(err, mautrix.MForbidden) {
|
||||
_, err = portal.MainIntent().RedactEvent(portal.MXID, dbReaction.MXID)
|
||||
|
|
10
puppet.go
10
puppet.go
|
@ -201,6 +201,16 @@ type Puppet struct {
|
|||
syncLock sync.Mutex
|
||||
}
|
||||
|
||||
var _ bridge.GhostWithProfile = (*Puppet)(nil)
|
||||
|
||||
func (puppet *Puppet) GetDisplayname() string {
|
||||
return puppet.Displayname
|
||||
}
|
||||
|
||||
func (puppet *Puppet) GetAvatarURL() id.ContentURI {
|
||||
return puppet.AvatarURL
|
||||
}
|
||||
|
||||
func (puppet *Puppet) IntentFor(portal *Portal) *appservice.IntentAPI {
|
||||
if puppet.customIntent == nil || portal.Key.JID == puppet.JID || (portal.Key.JID.Server == types.BroadcastServer && portal.Key.Receiver != puppet.JID) {
|
||||
return puppet.DefaultIntent()
|
||||
|
|
23
user.go
23
user.go
|
@ -344,18 +344,15 @@ func (user *User) doPuppetResync() {
|
|||
}
|
||||
|
||||
func (user *User) ensureInvited(intent *appservice.IntentAPI, roomID id.RoomID, isDirect bool) (ok bool) {
|
||||
inviteContent := event.Content{
|
||||
Parsed: &event.MemberEventContent{
|
||||
Membership: event.MembershipInvite,
|
||||
IsDirect: isDirect,
|
||||
},
|
||||
Raw: map[string]interface{}{},
|
||||
extraContent := make(map[string]interface{})
|
||||
if isDirect {
|
||||
extraContent["is_direct"] = true
|
||||
}
|
||||
customPuppet := user.bridge.GetPuppetByCustomMXID(user.MXID)
|
||||
if customPuppet != nil && customPuppet.CustomIntent() != nil {
|
||||
inviteContent.Raw["fi.mau.will_auto_accept"] = true
|
||||
extraContent["fi.mau.will_auto_accept"] = true
|
||||
}
|
||||
_, err := intent.SendStateEvent(roomID, event.StateMember, user.MXID.String(), &inviteContent)
|
||||
_, err := intent.InviteUser(roomID, &mautrix.ReqInviteUser{UserID: user.MXID}, extraContent)
|
||||
var httpErr mautrix.HTTPError
|
||||
if err != nil && errors.As(err, &httpErr) && httpErr.RespError != nil && strings.Contains(httpErr.RespError.Err, "is already in the room") {
|
||||
user.bridge.StateStore.SetMembership(roomID, user.MXID, event.MembershipJoin)
|
||||
|
@ -981,9 +978,9 @@ func (user *User) updateChatTag(intent *appservice.IntentAPI, portal *Portal, ta
|
|||
currentTag, ok := existingTags.Tags[tag]
|
||||
if active && !ok {
|
||||
user.log.Debugln("Adding tag", tag, "to", portal.MXID)
|
||||
data := CustomTagData{"0.5", doublePuppetValue}
|
||||
data := CustomTagData{Order: "0.5", DoublePuppet: user.bridge.Name}
|
||||
err = intent.AddTagWithCustomData(portal.MXID, tag, &data)
|
||||
} else if !active && ok && currentTag.DoublePuppet == doublePuppetValue {
|
||||
} else if !active && ok && currentTag.DoublePuppet == user.bridge.Name {
|
||||
user.log.Debugln("Removing tag", tag, "from", portal.MXID)
|
||||
err = intent.RemoveTag(portal.MXID, tag)
|
||||
} else {
|
||||
|
@ -1210,10 +1207,10 @@ func (user *User) handleReceipt(receipt *events.Receipt) {
|
|||
portal.messages <- PortalMessage{receipt: receipt, source: user}
|
||||
}
|
||||
|
||||
func makeReadMarkerContent(eventID id.EventID, doublePuppet bool) CustomReadMarkers {
|
||||
func (user *User) makeReadMarkerContent(eventID id.EventID, doublePuppet bool) CustomReadMarkers {
|
||||
var extra CustomReadReceipt
|
||||
if doublePuppet {
|
||||
extra.DoublePuppetSource = doublePuppetValue
|
||||
extra.DoublePuppetSource = user.bridge.Name
|
||||
}
|
||||
return CustomReadMarkers{
|
||||
ReqSetReadMarkers: mautrix.ReqSetReadMarkers{
|
||||
|
@ -1235,7 +1232,7 @@ func (user *User) markSelfReadFull(portal *Portal) {
|
|||
return
|
||||
}
|
||||
user.SetLastReadTS(portal.Key, lastMessage.Timestamp)
|
||||
err := puppet.CustomIntent().SetReadMarkers(portal.MXID, makeReadMarkerContent(lastMessage.MXID, true))
|
||||
err := puppet.CustomIntent().SetReadMarkers(portal.MXID, user.makeReadMarkerContent(lastMessage.MXID, true))
|
||||
if err != nil {
|
||||
user.log.Warnfln("Failed to mark %s (last message) in %s as read: %v", lastMessage.MXID, portal.MXID, err)
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue