Add options to improve handling of webhook messages sent by other bridges
This commit is contained in:
@@ -51,6 +51,8 @@ type BridgeConfig struct {
|
|||||||
DeletePortalOnChannelDelete bool `yaml:"delete_portal_on_channel_delete"`
|
DeletePortalOnChannelDelete bool `yaml:"delete_portal_on_channel_delete"`
|
||||||
DeleteGuildOnLeave bool `yaml:"delete_guild_on_leave"`
|
DeleteGuildOnLeave bool `yaml:"delete_guild_on_leave"`
|
||||||
FederateRooms bool `yaml:"federate_rooms"`
|
FederateRooms bool `yaml:"federate_rooms"`
|
||||||
|
PrefixWebhookMessages bool `yaml:"prefix_webhook_messages"`
|
||||||
|
EnableWebhookAvatars bool `yaml:"enable_webhook_avatars"`
|
||||||
UseDiscordCDNUpload bool `yaml:"use_discord_cdn_upload"`
|
UseDiscordCDNUpload bool `yaml:"use_discord_cdn_upload"`
|
||||||
|
|
||||||
CacheMedia string `yaml:"cache_media"`
|
CacheMedia string `yaml:"cache_media"`
|
||||||
@@ -287,9 +289,14 @@ func (bc BridgeConfig) FormatUsername(userID string) string {
|
|||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc BridgeConfig) FormatDisplayname(user *discordgo.User) string {
|
type DisplaynameParams struct {
|
||||||
|
*discordgo.User
|
||||||
|
Webhook bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc BridgeConfig) FormatDisplayname(user *discordgo.User, webhook bool) string {
|
||||||
var buffer strings.Builder
|
var buffer strings.Builder
|
||||||
_ = bc.displaynameTemplate.Execute(&buffer, user)
|
_ = bc.displaynameTemplate.Execute(&buffer, &DisplaynameParams{user, webhook})
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ func DoUpgrade(helper *up.Helper) {
|
|||||||
helper.Copy(up.Bool, "bridge", "delete_portal_on_channel_delete")
|
helper.Copy(up.Bool, "bridge", "delete_portal_on_channel_delete")
|
||||||
helper.Copy(up.Bool, "bridge", "delete_guild_on_leave")
|
helper.Copy(up.Bool, "bridge", "delete_guild_on_leave")
|
||||||
helper.Copy(up.Bool, "bridge", "federate_rooms")
|
helper.Copy(up.Bool, "bridge", "federate_rooms")
|
||||||
|
helper.Copy(up.Bool, "bridge", "prefix_webhook_messages")
|
||||||
|
helper.Copy(up.Bool, "bridge", "enable_webhook_avatars")
|
||||||
helper.Copy(up.Bool, "bridge", "use_discord_cdn_upload")
|
helper.Copy(up.Bool, "bridge", "use_discord_cdn_upload")
|
||||||
helper.Copy(up.Bool, "bridge", "media_patterns", "enabled")
|
helper.Copy(up.Bool, "bridge", "media_patterns", "enabled")
|
||||||
helper.Copy(up.Str, "bridge", "cache_media")
|
helper.Copy(up.Str, "bridge", "cache_media")
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ bridge:
|
|||||||
# .Discriminator - The 4 numbers after the name on Discord
|
# .Discriminator - The 4 numbers after the name on Discord
|
||||||
# .Bot - Whether the user is a bot
|
# .Bot - Whether the user is a bot
|
||||||
# .System - Whether the user is an official system user
|
# .System - Whether the user is an official system user
|
||||||
|
# .Webhook - Whether the user is a webhook
|
||||||
displayname_template: '{{or .GlobalName .Username}}{{if .Bot}} (bot){{end}}'
|
displayname_template: '{{or .GlobalName .Username}}{{if .Bot}} (bot){{end}}'
|
||||||
# Displayname template for Discord channels (bridged as rooms, or spaces when type=4).
|
# Displayname template for Discord channels (bridged as rooms, or spaces when type=4).
|
||||||
# Available variables:
|
# Available variables:
|
||||||
@@ -146,6 +147,11 @@ bridge:
|
|||||||
# Whether or not created rooms should have federation enabled.
|
# Whether or not created rooms should have federation enabled.
|
||||||
# If false, created portal rooms will never be federated.
|
# If false, created portal rooms will never be federated.
|
||||||
federate_rooms: true
|
federate_rooms: true
|
||||||
|
# Prefix messages from webhooks with the profile info? This can be used along with a custom displayname_template
|
||||||
|
# to better handle webhooks that change their name all the time (like ones used by bridges).
|
||||||
|
prefix_webhook_messages: false
|
||||||
|
# Bridge webhook avatars?
|
||||||
|
enable_webhook_avatars: true
|
||||||
# Should the bridge upload media to the Discord CDN directly before sending the message when using a user token,
|
# Should the bridge upload media to the Discord CDN directly before sending the message when using a user token,
|
||||||
# like the official client does? The other option is sending the media in the message send request as a form part
|
# like the official client does? The other option is sending the media in the message send request as a form part
|
||||||
# (which is always used by bots and webhooks).
|
# (which is always used by bots and webhooks).
|
||||||
|
|||||||
@@ -897,6 +897,9 @@ func (portal *Portal) handleDiscordMessageUpdate(user *User, msg *discordgo.Mess
|
|||||||
Msg("Dropping non-text edit")
|
Msg("Dropping non-text edit")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if msg.WebhookID != "" {
|
||||||
|
addWebhookMeta(converted, msg)
|
||||||
|
}
|
||||||
converted.Content.Mentions = portal.convertDiscordMentions(msg, "", false)
|
converted.Content.Mentions = portal.convertDiscordMentions(msg, "", false)
|
||||||
converted.Content.SetEdit(existing[0].MXID)
|
converted.Content.SetEdit(existing[0].MXID)
|
||||||
// Never actually mention new users of edits, only include mentions inside m.new_content
|
// Never actually mention new users of edits, only include mentions inside m.new_content
|
||||||
|
|||||||
@@ -308,9 +308,33 @@ func (portal *Portal) convertDiscordMessage(ctx context.Context, intent *appserv
|
|||||||
parts = append(parts, part)
|
parts = append(parts, part)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if msg.WebhookID != "" {
|
||||||
|
for _, part := range parts {
|
||||||
|
addWebhookMeta(part, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
return parts
|
return parts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addWebhookMeta(part *ConvertedMessage, msg *discordgo.Message) {
|
||||||
|
if msg.WebhookID == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if part.Extra == nil {
|
||||||
|
part.Extra = make(map[string]any)
|
||||||
|
}
|
||||||
|
part.Extra["fi.mau.discord.webhook_metadata"] = map[string]any{
|
||||||
|
"id": msg.WebhookID,
|
||||||
|
"name": msg.Author.Username,
|
||||||
|
"avatar_id": msg.Author.Avatar,
|
||||||
|
"avatar_url": msg.Author.AvatarURL(""),
|
||||||
|
}
|
||||||
|
part.Extra["com.beeper.per_message_profile"] = map[string]any{
|
||||||
|
"avatar_url": msg.Author.AvatarURL(""),
|
||||||
|
"displayname": msg.Author.Username,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
embedHTMLWrapper = `<blockquote class="discord-embed">%s</blockquote>`
|
embedHTMLWrapper = `<blockquote class="discord-embed">%s</blockquote>`
|
||||||
embedHTMLWrapperColor = `<blockquote class="discord-embed" background-color="#%06X">%s</blockquote>`
|
embedHTMLWrapperColor = `<blockquote class="discord-embed" background-color="#%06X">%s</blockquote>`
|
||||||
@@ -628,5 +652,11 @@ func (portal *Portal) convertDiscordTextMessage(ctx context.Context, intent *app
|
|||||||
"com.beeper.linkpreviews": previews,
|
"com.beeper.linkpreviews": previews,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if msg.WebhookID != "" && portal.bridge.Config.Bridge.PrefixWebhookMessages {
|
||||||
|
content.EnsureHasHTML()
|
||||||
|
content.Body = fmt.Sprintf("%s: %s", msg.Author.Username, content.Body)
|
||||||
|
content.FormattedBody = fmt.Sprintf("<strong>%s</strong>: %s", html.EscapeString(msg.Author.Username), content.FormattedBody)
|
||||||
|
}
|
||||||
|
|
||||||
return &ConvertedMessage{Type: event.EventMessage, Content: &content, Extra: extraContent}
|
return &ConvertedMessage{Type: event.EventMessage, Content: &content, Extra: extraContent}
|
||||||
}
|
}
|
||||||
|
|||||||
10
puppet.go
10
puppet.go
@@ -207,7 +207,7 @@ func (puppet *Puppet) updatePortalMeta(meta func(portal *Portal)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (puppet *Puppet) UpdateName(info *discordgo.User) bool {
|
func (puppet *Puppet) UpdateName(info *discordgo.User) bool {
|
||||||
newName := puppet.bridge.Config.Bridge.FormatDisplayname(info)
|
newName := puppet.bridge.Config.Bridge.FormatDisplayname(info, puppet.IsWebhook)
|
||||||
if puppet.Name == newName && puppet.NameSet {
|
if puppet.Name == newName && puppet.NameSet {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -229,6 +229,9 @@ func (puppet *Puppet) UpdateName(info *discordgo.User) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (puppet *Puppet) UpdateAvatar(info *discordgo.User) bool {
|
func (puppet *Puppet) UpdateAvatar(info *discordgo.User) bool {
|
||||||
|
if puppet.IsWebhook && !puppet.bridge.Config.Bridge.EnableWebhookAvatars {
|
||||||
|
info.Avatar = ""
|
||||||
|
}
|
||||||
if puppet.Avatar == info.Avatar && puppet.AvatarSet {
|
if puppet.Avatar == info.Avatar && puppet.AvatarSet {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -324,7 +327,7 @@ func (puppet *Puppet) UpdateContactInfo(info *discordgo.User) bool {
|
|||||||
puppet.IsBot = info.Bot
|
puppet.IsBot = info.Bot
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
if changed {
|
if (changed && !puppet.IsWebhook) || !puppet.ContactInfoSet {
|
||||||
puppet.ContactInfoSet = false
|
puppet.ContactInfoSet = false
|
||||||
puppet.ResendContactInfo()
|
puppet.ResendContactInfo()
|
||||||
return true
|
return true
|
||||||
@@ -345,6 +348,9 @@ func (puppet *Puppet) ResendContactInfo() {
|
|||||||
"com.beeper.bridge.network": puppet.bridge.BeeperNetworkName,
|
"com.beeper.bridge.network": puppet.bridge.BeeperNetworkName,
|
||||||
"com.beeper.bridge.is_network_bot": puppet.IsBot,
|
"com.beeper.bridge.is_network_bot": puppet.IsBot,
|
||||||
}
|
}
|
||||||
|
if puppet.IsWebhook {
|
||||||
|
contactInfo["com.beeper.bridge.identifiers"] = []string{}
|
||||||
|
}
|
||||||
err := puppet.DefaultIntent().BeeperUpdateProfile(contactInfo)
|
err := puppet.DefaultIntent().BeeperUpdateProfile(contactInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
puppet.log.Warn().Err(err).Msg("Failed to store custom contact info in profile")
|
puppet.log.Warn().Err(err).Msg("Failed to store custom contact info in profile")
|
||||||
|
|||||||
Reference in New Issue
Block a user