Files
mautrix-discord/config/bridge.go
Gary Kramlich c5f58afe71 End to bridge encryption implementation
So far this is passing my basic tests, but could use some testing from people
that are much more familiar with how this is supposed to work.

Refs #27
2022-04-27 12:43:12 -05:00

190 lines
4.5 KiB
Go

package config
import (
"fmt"
"strings"
"text/template"
"maunium.net/go/mautrix/id"
"github.com/bwmarrin/discordgo"
)
type bridge struct {
UsernameTemplate string `yaml:"username_template"`
DisplaynameTemplate string `yaml:"displayname_template"`
ChannelnameTemplate string `yaml:"channelname_template"`
CommandPrefix string `yaml:"command_prefix"`
ManagementRoomText managementRoomText `yaml:"management_root_text"`
PortalMessageBuffer int `yaml:"portal_message_buffer"`
SyncWithCustomPuppets bool `yaml:"sync_with_custom_puppets"`
SyncDirectChatList bool `yaml:"sync_direct_chat_list"`
DefaultBridgeReceipts bool `yaml:"default_bridge_receipts"`
DefaultBridgePresence bool `yaml:"default_bridge_presence"`
DoublePuppetServerMap map[string]string `yaml:"double_puppet_server_map"`
DoublePuppetAllowDiscovery bool `yaml:"double_puppet_allow_discovery"`
LoginSharedSecretMap map[string]string `yaml:"login_shared_secret_map"`
Encryption encryption `yaml:"encryption"`
usernameTemplate *template.Template `yaml:"-"`
displaynameTemplate *template.Template `yaml:"-"`
channelnameTemplate *template.Template `yaml:"-"`
}
func (config *Config) CanAutoDoublePuppet(userID id.UserID) bool {
_, homeserver, _ := userID.Parse()
_, hasSecret := config.Bridge.LoginSharedSecretMap[homeserver]
return hasSecret
}
func (b *bridge) validate() error {
var err error
if b.UsernameTemplate == "" {
b.UsernameTemplate = "discord_{{.}}"
}
b.usernameTemplate, err = template.New("username").Parse(b.UsernameTemplate)
if err != nil {
return err
}
if b.DisplaynameTemplate == "" {
b.DisplaynameTemplate = "{{.Username}}#{{.Discriminator}} (D){{if .Bot}} (bot){{end}}"
}
b.displaynameTemplate, err = template.New("displayname").Parse(b.DisplaynameTemplate)
if err != nil {
return err
}
if b.ChannelnameTemplate == "" {
b.ChannelnameTemplate = "{{if .Guild}}{{.Guild}} - {{end}}{{if .Folder}}{{.Folder}} - {{end}}{{.Name}} (D)"
}
b.channelnameTemplate, err = template.New("channelname").Parse(b.ChannelnameTemplate)
if err != nil {
return err
}
if b.PortalMessageBuffer <= 0 {
b.PortalMessageBuffer = 128
}
if b.CommandPrefix == "" {
b.CommandPrefix = "!dis"
}
if err := b.ManagementRoomText.validate(); err != nil {
return err
}
return nil
}
func (b *bridge) UnmarshalYAML(unmarshal func(interface{}) error) error {
type rawBridge bridge
// Set our defaults that aren't zero values.
raw := rawBridge{
SyncWithCustomPuppets: true,
DefaultBridgeReceipts: true,
DefaultBridgePresence: true,
}
err := unmarshal(&raw)
if err != nil {
return err
}
*b = bridge(raw)
return b.validate()
}
func (b bridge) FormatUsername(userid string) string {
var buffer strings.Builder
b.usernameTemplate.Execute(&buffer, userid)
return buffer.String()
}
type simplfiedUser struct {
Username string
Discriminator string
Locale string
Verified bool
MFAEnabled bool
Bot bool
System bool
}
func (b bridge) FormatDisplayname(user *discordgo.User) string {
var buffer strings.Builder
b.displaynameTemplate.Execute(&buffer, simplfiedUser{
Username: user.Username,
Discriminator: user.Discriminator,
Locale: user.Locale,
Verified: user.Verified,
MFAEnabled: user.MFAEnabled,
Bot: user.Bot,
System: user.System,
})
return buffer.String()
}
type simplfiedChannel struct {
Guild string
Folder string
Name string
NSFW bool
}
func (b bridge) FormatChannelname(channel *discordgo.Channel, session *discordgo.Session) (string, error) {
var buffer strings.Builder
var guildName, folderName string
if channel.Type != discordgo.ChannelTypeDM && channel.Type != discordgo.ChannelTypeGroupDM {
guild, err := session.Guild(channel.GuildID)
if err != nil {
return "", fmt.Errorf("find guild: %w", err)
}
guildName = guild.Name
folder, err := session.Channel(channel.ParentID)
if err == nil {
folderName = folder.Name
}
} else {
// Group DM's can have a name, but DM's can't, so if we didn't get a
// name return a comma separated list of the formatted user names.
if channel.Name == "" {
recipients := make([]string, len(channel.Recipients))
for idx, user := range channel.Recipients {
recipients[idx] = b.FormatDisplayname(user)
}
return strings.Join(recipients, ", "), nil
}
}
b.channelnameTemplate.Execute(&buffer, simplfiedChannel{
Guild: guildName,
Folder: folderName,
Name: channel.Name,
NSFW: channel.NSFW,
})
return buffer.String(), nil
}