forked from MirrorHub/mautrix-whatsapp
Fix accepting group invites in encrypted rooms
This commit is contained in:
parent
e31788541a
commit
973f80d7a7
2 changed files with 56 additions and 45 deletions
79
commands.go
79
commands.go
|
@ -18,6 +18,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
|
@ -27,6 +28,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/skip2/go-qrcode"
|
"github.com/skip2/go-qrcode"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
"maunium.net/go/maulogger/v2"
|
"maunium.net/go/maulogger/v2"
|
||||||
|
|
||||||
|
@ -310,19 +312,51 @@ func (handler *CommandHandler) CommandJoin(ce *CommandEvent) {
|
||||||
ce.Reply("Successfully joined group `%s`, the portal should be created momentarily", jid)
|
ce.Reply("Successfully joined group `%s`, the portal should be created momentarily", jid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tryDecryptEvent(crypto Crypto, evt *event.Event) (json.RawMessage, error) {
|
||||||
|
var data json.RawMessage
|
||||||
|
if evt.Type != event.EventEncrypted {
|
||||||
|
data = evt.Content.VeryRaw
|
||||||
|
} else {
|
||||||
|
err := evt.Content.ParseRaw(evt.Type)
|
||||||
|
if err != nil && !errors.Is(err, event.ErrContentAlreadyParsed) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
decrypted, err := crypto.Decrypt(evt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data = decrypted.Content.VeryRaw
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInviteMeta(data json.RawMessage) (*InviteMeta, error) {
|
||||||
|
result := gjson.GetBytes(data, escapedInviteMetaField)
|
||||||
|
if !result.Exists() || !result.IsObject() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
var meta InviteMeta
|
||||||
|
err := json.Unmarshal([]byte(result.Raw), &meta)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &meta, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (handler *CommandHandler) CommandAccept(ce *CommandEvent) {
|
func (handler *CommandHandler) CommandAccept(ce *CommandEvent) {
|
||||||
if ce.Portal == nil || len(ce.ReplyTo) == 0 {
|
if ce.Portal == nil || len(ce.ReplyTo) == 0 {
|
||||||
ce.Reply("You must reply to a group invite message when using this command.")
|
ce.Reply("You must reply to a group invite message when using this command.")
|
||||||
} else if evt, err := ce.Portal.MainIntent().GetEvent(ce.RoomID, ce.ReplyTo); err != nil {
|
} else if evt, err := ce.Portal.MainIntent().GetEvent(ce.RoomID, ce.ReplyTo); err != nil {
|
||||||
handler.log.Errorln("Failed to get event %s to handle !wa accept command: %v", ce.ReplyTo, err)
|
handler.log.Errorln("Failed to get event %s to handle !wa accept command: %v", ce.ReplyTo, err)
|
||||||
ce.Reply("Failed to get reply event")
|
ce.Reply("Failed to get reply event")
|
||||||
} else if meta, ok := evt.Content.Raw[inviteMetaField].(map[string]interface{}); !ok {
|
} else if rawContent, err := tryDecryptEvent(ce.Bridge.Crypto, evt); err != nil {
|
||||||
|
handler.log.Errorln("Failed to decrypt event %s to handle !wa accept command: %v", ce.ReplyTo, err)
|
||||||
|
ce.Reply("Failed to decrypt reply event")
|
||||||
|
} else if meta, err := parseInviteMeta(rawContent); err != nil || meta == nil {
|
||||||
ce.Reply("That doesn't look like a group invite message.")
|
ce.Reply("That doesn't look like a group invite message.")
|
||||||
} else if jid, inviter, code, expiration, ok := parseInviteMeta(meta); !ok {
|
} else if meta.Inviter.User == ce.User.JID.User {
|
||||||
ce.Reply("That doesn't look like a group invite message.")
|
|
||||||
} else if inviter.User == ce.User.JID.User {
|
|
||||||
ce.Reply("You can't accept your own invites")
|
ce.Reply("You can't accept your own invites")
|
||||||
} else if err = ce.User.Client.JoinGroupWithInvite(jid, inviter, code, expiration); err != nil {
|
} else if err = ce.User.Client.JoinGroupWithInvite(meta.JID, meta.Inviter, meta.Code, meta.Expiration); err != nil {
|
||||||
ce.Reply("Failed to accept group invite: %v", err)
|
ce.Reply("Failed to accept group invite: %v", err)
|
||||||
} else {
|
} else {
|
||||||
ce.Reply("Successfully accepted the invite, the portal should be created momentarily")
|
ce.Reply("Successfully accepted the invite, the portal should be created momentarily")
|
||||||
|
@ -414,41 +448,6 @@ func (handler *CommandHandler) CommandCreate(ce *CommandEvent) {
|
||||||
ce.Reply("Successfully created WhatsApp group %s", portal.Key.JID)
|
ce.Reply("Successfully created WhatsApp group %s", portal.Key.JID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseInviteMeta(meta map[string]interface{}) (jid, inviter types.JID, code string, expiration int64, ok bool) {
|
|
||||||
var fieldFound bool
|
|
||||||
code, fieldFound = meta["code"].(string)
|
|
||||||
if !fieldFound {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
expirationStr, fieldFound := meta["expiration"].(string)
|
|
||||||
if !fieldFound {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
inviterStr, fieldFound := meta["inviter"].(string)
|
|
||||||
if !fieldFound {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jidStr, fieldFound := meta["jid"].(string)
|
|
||||||
if !fieldFound {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
expiration, err = strconv.ParseInt(expirationStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
inviter, err = types.ParseJID(inviterStr)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jid, err = types.ParseJID(jidStr)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const cmdSetPowerLevelHelp = `set-pl [user ID] <power level> - Change the power level in a portal room. Only for bridge admins.`
|
const cmdSetPowerLevelHelp = `set-pl [user ID] <power level> - Change the power level in a portal room. Only for bridge admins.`
|
||||||
|
|
||||||
func (handler *CommandHandler) CommandSetPowerLevel(ce *CommandEvent) {
|
func (handler *CommandHandler) CommandSetPowerLevel(ce *CommandEvent) {
|
||||||
|
|
22
portal.go
22
portal.go
|
@ -1667,6 +1667,14 @@ func (portal *Portal) convertLocationMessage(intent *appservice.IntentAPI, msg *
|
||||||
|
|
||||||
const inviteMsg = `%s<hr/>This invitation to join "%s" expires at %s. Reply to this message with <code>!wa accept</code> to accept the invite.`
|
const inviteMsg = `%s<hr/>This invitation to join "%s" expires at %s. Reply to this message with <code>!wa accept</code> to accept the invite.`
|
||||||
const inviteMetaField = "fi.mau.whatsapp.invite"
|
const inviteMetaField = "fi.mau.whatsapp.invite"
|
||||||
|
const escapedInviteMetaField = `fi\.mau\.whatsapp\.invite`
|
||||||
|
|
||||||
|
type InviteMeta struct {
|
||||||
|
JID types.JID `json:"jid"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
Expiration int64 `json:"expiration,string"`
|
||||||
|
Inviter types.JID `json:"inviter"`
|
||||||
|
}
|
||||||
|
|
||||||
func (portal *Portal) convertGroupInviteMessage(intent *appservice.IntentAPI, info *types.MessageInfo, msg *waProto.GroupInviteMessage) *ConvertedMessage {
|
func (portal *Portal) convertGroupInviteMessage(intent *appservice.IntentAPI, info *types.MessageInfo, msg *waProto.GroupInviteMessage) *ConvertedMessage {
|
||||||
expiry := time.Unix(msg.GetInviteExpiration(), 0)
|
expiry := time.Unix(msg.GetInviteExpiration(), 0)
|
||||||
|
@ -1677,12 +1685,16 @@ func (portal *Portal) convertGroupInviteMessage(intent *appservice.IntentAPI, in
|
||||||
Format: event.FormatHTML,
|
Format: event.FormatHTML,
|
||||||
FormattedBody: htmlMessage,
|
FormattedBody: htmlMessage,
|
||||||
}
|
}
|
||||||
|
groupJID, err := types.ParseJID(msg.GetGroupJid())
|
||||||
|
if err != nil {
|
||||||
|
portal.log.Errorfln("Failed to parse invite group JID: %v", err)
|
||||||
|
}
|
||||||
extraAttrs := map[string]interface{}{
|
extraAttrs := map[string]interface{}{
|
||||||
inviteMetaField: map[string]interface{}{
|
inviteMetaField: InviteMeta{
|
||||||
"jid": msg.GetGroupJid(),
|
JID: groupJID,
|
||||||
"code": msg.GetInviteCode(),
|
Code: msg.GetInviteCode(),
|
||||||
"expiration": strconv.FormatInt(msg.GetInviteExpiration(), 10),
|
Expiration: msg.GetInviteExpiration(),
|
||||||
"inviter": info.Sender.ToNonAD().String(),
|
Inviter: info.Sender.ToNonAD(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return &ConvertedMessage{
|
return &ConvertedMessage{
|
||||||
|
|
Loading…
Reference in a new issue