Skip to content

Commit

Permalink
msgconv/from-whatsapp: add option to disable bridging view-once media
Browse files Browse the repository at this point in the history
  • Loading branch information
tulir committed Oct 7, 2024
1 parent 6683754 commit a38ab07
Show file tree
Hide file tree
Showing 9 changed files with 40 additions and 19 deletions.
7 changes: 4 additions & 3 deletions pkg/connector/backfill.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ func (wa *WhatsAppClient) FetchMessages(ctx context.Context, params bridgev2.Fet
return nil, fmt.Errorf("failed to parse info of message %s: %w", msg.GetKey().GetID(), err)
}
var mediaReq *wadb.MediaRequest
convertedMessages[i], mediaReq = wa.convertHistorySyncMessage(ctx, params.Portal, &evt.Info, evt.Message, msg.Reactions)
isViewOnce := evt.IsViewOnce || evt.IsViewOnceV2 || evt.IsViewOnceV2Extension
convertedMessages[i], mediaReq = wa.convertHistorySyncMessage(ctx, params.Portal, &evt.Info, evt.Message, isViewOnce, msg.Reactions)
if mediaReq != nil {
mediaRequests = append(mediaRequests, mediaReq)
}
Expand Down Expand Up @@ -324,12 +325,12 @@ func (wa *WhatsAppClient) FetchMessages(ctx context.Context, params bridgev2.Fet
}

func (wa *WhatsAppClient) convertHistorySyncMessage(
ctx context.Context, portal *bridgev2.Portal, info *types.MessageInfo, msg *waE2E.Message, reactions []*waWeb.Reaction,
ctx context.Context, portal *bridgev2.Portal, info *types.MessageInfo, msg *waE2E.Message, isViewOnce bool, reactions []*waWeb.Reaction,
) (*bridgev2.BackfillMessage, *wadb.MediaRequest) {
// TODO use proper intent
intent := wa.Main.Bridge.Bot
wrapped := &bridgev2.BackfillMessage{
ConvertedMessage: wa.Main.MsgConv.ToMatrix(ctx, portal, wa.Client, intent, msg, info),
ConvertedMessage: wa.Main.MsgConv.ToMatrix(ctx, portal, wa.Client, intent, msg, info, isViewOnce),
Sender: wa.makeEventSender(info.Sender),
ID: waid.MakeMessageID(info.Chat, info.Sender, info.ID),
TxnID: networkid.TransactionID(waid.MakeMessageID(info.Chat, info.Sender, info.ID)),
Expand Down
2 changes: 2 additions & 0 deletions pkg/connector/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Config struct {
WhatsappThumbnail bool `yaml:"whatsapp_thumbnail"`
URLPreviews bool `yaml:"url_previews"`
ExtEvPolls bool `yaml:"extev_polls"`
DisableViewOnce bool `yaml:"disable_view_once"`
ForceActiveDeliveryReceipts bool `yaml:"force_active_delivery_receipts"`

AnimatedSticker msgconv.AnimatedStickerConfig `yaml:"animated_sticker"`
Expand Down Expand Up @@ -102,6 +103,7 @@ func upgradeConfig(helper up.Helper) {
helper.Copy(up.Bool, "whatsapp_thumbnail")
helper.Copy(up.Bool, "url_previews")
helper.Copy(up.Bool, "extev_polls")
helper.Copy(up.Bool, "disable_view_once")
helper.Copy(up.Bool, "force_active_delivery_receipts")

helper.Copy(up.Str, "animated_sticker", "target")
Expand Down
1 change: 1 addition & 0 deletions pkg/connector/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func (wa *WhatsAppConnector) Init(bridge *bridgev2.Bridge) {
wa.MsgConv = msgconv.New(bridge)
wa.MsgConv.AnimatedStickerConfig = wa.Config.AnimatedSticker
wa.MsgConv.ExtEvPolls = wa.Config.ExtEvPolls
wa.MsgConv.DisableViewOnce = wa.Config.DisableViewOnce
wa.MsgConv.OldMediaSuffix = "Requesting old media is not enabled on this bridge."
wa.MsgConv.FetchURLPreviews = wa.Config.URLPreviews
if wa.Config.HistorySync.MediaRequests.AutoRequestMedia {
Expand Down
16 changes: 10 additions & 6 deletions pkg/connector/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ type WAMessageEvent struct {
postHandle func()
}

func (evt *WAMessageEvent) GetStreamOrder() int64 {
return evt.Info.Timestamp.Unix()
}

var (
_ bridgev2.RemoteMessage = (*WAMessageEvent)(nil)
_ bridgev2.RemoteMessageUpsert = (*WAMessageEvent)(nil)
Expand All @@ -112,6 +108,14 @@ var (
_ bridgev2.RemotePostHandler = (*WAMessageEvent)(nil)
)

func (evt *WAMessageEvent) GetStreamOrder() int64 {
return evt.Info.Timestamp.Unix()
}

func (evt *WAMessageEvent) isViewOnce() bool {
return evt.MsgEvent.IsViewOnce || evt.MsgEvent.IsViewOnceV2 || evt.MsgEvent.IsViewOnceV2Extension
}

func (evt *WAMessageEvent) AddLogContext(c zerolog.Context) zerolog.Context {
return evt.MessageInfoWrapper.AddLogContext(c).Str("parsed_message_type", evt.parsedMessageType)
}
Expand All @@ -136,7 +140,7 @@ func (evt *WAMessageEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Por
}

// TODO edits to media captions may not contain the media
cm := evt.wa.Main.MsgConv.ToMatrix(ctx, portal, evt.wa.Client, intent, editedMsg, &evt.Info)
cm := evt.wa.Main.MsgConv.ToMatrix(ctx, portal, evt.wa.Client, intent, editedMsg, &evt.Info, evt.isViewOnce())
if evt.isUndecryptableUpsertSubEvent && isFailedMedia(cm) {
evt.postHandle = func() {
evt.wa.processFailedMedia(ctx, portal.PortalKey, evt.GetID(), cm, false)
Expand Down Expand Up @@ -224,7 +228,7 @@ func (evt *WAMessageEvent) HandleExisting(ctx context.Context, portal *bridgev2.

func (evt *WAMessageEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI) (*bridgev2.ConvertedMessage, error) {
evt.wa.EnqueuePortalResync(portal)
converted := evt.wa.Main.MsgConv.ToMatrix(ctx, portal, evt.wa.Client, intent, evt.Message, &evt.Info)
converted := evt.wa.Main.MsgConv.ToMatrix(ctx, portal, evt.wa.Client, intent, evt.Message, &evt.Info, evt.isViewOnce())
if isFailedMedia(converted) {
evt.postHandle = func() {
evt.wa.processFailedMedia(ctx, portal.PortalKey, evt.GetID(), converted, false)
Expand Down
2 changes: 2 additions & 0 deletions pkg/connector/example-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ whatsapp_thumbnail: false
url_previews: false
# Should polls be sent using unstable MSC3381 event types?
extev_polls: false
# Should view-once messages be disabled entirely?
disable_view_once: false
# Should the bridge always send "active" delivery receipts (two gray ticks on WhatsApp)
# even if the user isn't marked as online (e.g. when presence bridging isn't enabled)?
#
Expand Down
13 changes: 7 additions & 6 deletions pkg/msgconv/from-whatsapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func (mc *MessageConverter) ToMatrix(
intent bridgev2.MatrixAPI,
waMsg *waE2E.Message,
info *types.MessageInfo,
isViewOnce bool,
) *bridgev2.ConvertedMessage {
ctx = context.WithValue(ctx, contextKeyClient, client)
ctx = context.WithValue(ctx, contextKeyIntent, intent)
Expand Down Expand Up @@ -132,21 +133,21 @@ func (mc *MessageConverter) ToMatrix(
case waMsg.EventMessage != nil:
part, contextInfo = mc.convertEventMessage(ctx, waMsg.EventMessage)
case waMsg.ImageMessage != nil:
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.ImageMessage, "photo")
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.ImageMessage, "photo", isViewOnce)
case waMsg.StickerMessage != nil:
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.StickerMessage, "sticker")
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.StickerMessage, "sticker", isViewOnce)
case waMsg.VideoMessage != nil:
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.VideoMessage, "video attachment")
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.VideoMessage, "video attachment", isViewOnce)
case waMsg.PtvMessage != nil:
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.PtvMessage, "video message")
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.PtvMessage, "video message", isViewOnce)
case waMsg.AudioMessage != nil:
typeName := "audio attachment"
if waMsg.AudioMessage.GetPTT() {
typeName = "voice message"
}
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.AudioMessage, typeName)
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.AudioMessage, typeName, isViewOnce)
case waMsg.DocumentMessage != nil:
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.DocumentMessage, "file attachment")
part, contextInfo = mc.convertMediaMessage(ctx, waMsg.DocumentMessage, "file attachment", isViewOnce)
case waMsg.LocationMessage != nil:
part, contextInfo = mc.convertLocationMessage(ctx, waMsg.LocationMessage)
case waMsg.LiveLocationMessage != nil:
Expand Down
1 change: 1 addition & 0 deletions pkg/msgconv/msgconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type MessageConverter struct {
AnimatedStickerConfig AnimatedStickerConfig
FetchURLPreviews bool
ExtEvPolls bool
DisableViewOnce bool
OldMediaSuffix string
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/msgconv/wa-business.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ func (mc *MessageConverter) convertTemplateMessage(ctx context.Context, info *ty
var convertedTitle *bridgev2.ConvertedMessagePart
switch title := tpl.GetTitle().(type) {
case *waE2E.TemplateMessage_HydratedFourRowTemplate_DocumentMessage:
convertedTitle, _ = mc.convertMediaMessage(ctx, title.DocumentMessage, "file attachment")
convertedTitle, _ = mc.convertMediaMessage(ctx, title.DocumentMessage, "file attachment", false)
case *waE2E.TemplateMessage_HydratedFourRowTemplate_ImageMessage:
convertedTitle, _ = mc.convertMediaMessage(ctx, title.ImageMessage, "photo")
convertedTitle, _ = mc.convertMediaMessage(ctx, title.ImageMessage, "photo", false)
case *waE2E.TemplateMessage_HydratedFourRowTemplate_VideoMessage:
convertedTitle, _ = mc.convertMediaMessage(ctx, title.VideoMessage, "video attachment")
convertedTitle, _ = mc.convertMediaMessage(ctx, title.VideoMessage, "video attachment", false)
case *waE2E.TemplateMessage_HydratedFourRowTemplate_LocationMessage:
content = fmt.Sprintf("Unsupported location message\n\n%s", content)
case *waE2E.TemplateMessage_HydratedFourRowTemplate_HydratedTitleText:
Expand Down
11 changes: 10 additions & 1 deletion pkg/msgconv/wa-media.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,16 @@ import (
"maunium.net/go/mautrix-whatsapp/pkg/waid"
)

func (mc *MessageConverter) convertMediaMessage(ctx context.Context, msg MediaMessage, typeName string) (part *bridgev2.ConvertedMessagePart, contextInfo *waE2E.ContextInfo) {
func (mc *MessageConverter) convertMediaMessage(ctx context.Context, msg MediaMessage, typeName string, isViewOnce bool) (part *bridgev2.ConvertedMessagePart, contextInfo *waE2E.ContextInfo) {
if mc.DisableViewOnce && isViewOnce {
return &bridgev2.ConvertedMessagePart{
Type: event.EventMessage,
Content: &event.MessageEventContent{
MsgType: event.MsgNotice,
Body: fmt.Sprintf("You received a view once %s. For added privacy, you can only open it on the WhatsApp app.", typeName),
},
}, nil
}
preparedMedia := prepareMediaMessage(msg)
preparedMedia.TypeDescription = typeName
if preparedMedia.FileName != "" && preparedMedia.Body != preparedMedia.FileName {
Expand Down

0 comments on commit a38ab07

Please sign in to comment.