diff --git a/README.md b/README.md index db57735..151416f 100644 --- a/README.md +++ b/README.md @@ -66,33 +66,35 @@ The binary takes three flags: The config file is a yaml formatted file with the following fields: -| name | requires restart | default | optional | description | -| -------------------------------| ---------------- | ---------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `avatar_url` | No | `https://ui-avatars.com/api/?name=${USERNAME}` | Yes | The URL for the API to use to tell Discord what Avatar to use for a User when the user's avatar cannot be found at Discord already. | -| `discord_token` | Yes | | No | [The bot user token](https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&-getting-a-token) | -| `irc_server` | Yes | | No | IRC server address | -| `irc_server_name` | Yes | | No | Used as a reference when PMing from Discord to IRC. Try to use short, simple one-word names like `freenode` or `swift` | -| `channel_mappings` | No | | No | a dict with irc channel as key (prefixed with `#`) and Discord channel ID as value | -| `guild_id` | No | | No | the Discord guild (server) id | -| `irc_pass` | Yes | | Yes | password for connecting to the IRC server | -| `suffix` | No | `~d` | Yes | appended to each Discord user's nickname when they are connected to IRC. If set to `_d2`, if the name will be `bob_d2` | -| `separator` | No | `_` | Yes | used in fallback situations. If set to `-`, the **fallback name** will be like `bob-7247_d2` (where `7247` is the discord user's discriminator, and `_d2` is the suffix) | -| `irc_listener_name` | Yes | `~d` | The name of the irc listener | | -| `ignored_discord_ids` | Sometimes | | Yes | A list of Discord IDs to not relay to IRC | -| `puppet_username` | No | username of discord account being puppeted | Yes | username to connect to irc with | -| `webirc_pass` | No | | Yes | optional, but recommended for regular (non-simple) usage. this must be obtained by the IRC sysops | -| `irc_listener_prejoin_commands`| Yes | | Yes | list of commands for the listener IRC connection to execute (right before joining channels) | -| `irc_puppet_prejoin_commands` | Yes | | Yes | list of commands for each Puppet IRC connection to execute (right before joining channels) | -| `debug` | Yes | false | Yes | debug mode | -| `insecure`, | Yes | false | Yes | TLS will skip verification (but still uses TLS) | -| `no_tls`, | Yes | false | Yes | turns off TLS | -| `webhook_prefix`, | Yes | | No | a prefix for webhooks, so we know which ones to keep and which ones to delete | -| `nickserv_identify` | No | | Yes | on connect this message will be sent: `PRIVMSG nickserv IDENTIFY `, you can provide both a username and password if your ircd supports it | -| `cooldown_duration` | No | 86400 (24 hours) | Yes | time in seconds for a discord user to be offline before it's puppet disconnects from irc | -| `show_joinquit` | No | false | yes | displays JOIN, PART, QUIT, KICK on discord | -| `max_nick_length` | No | 30 | yes | Maximum allowed nick length | -| `ignored_irc_hostmasks` | No | | Yes | A list of IRC users identified by hostmask to not relay to Discord, uses matching syntax as in [glob](https://github.com/gobwas/glob) | -| `connection_limit` | Yes | 0 | Yes | How many connections to IRC (including our listener) to spawn (limit of 0 or less means unlimited) | +| name | requires restart | default | optional | description | +| ------------------------------- | ---------------- | ---------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `avatar_url` | No | `https://ui-avatars.com/api/?name=${USERNAME}` | Yes | The URL for the API to use to tell Discord what Avatar to use for a User when the user's avatar cannot be found at Discord already. | +| `discord_token` | Yes | | No | [The bot user token](https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&-getting-a-token) | +| `discord_message_filter` | No | | Yes | Filters messages from Discord to IRC when they match. | +| `irc_message_filter` | No | | Yes | Filters messages from IRC to Discord when they match. | +| `irc_server` | Yes | | No | IRC server address | +| `irc_server_name` | Yes | | No | Used as a reference when PMing from Discord to IRC. Try to use short, simple one-word names like `freenode` or `swift` | +| `channel_mappings` | No | | No | a dict with irc channel as key (prefixed with `#`) and Discord channel ID as value | +| `guild_id` | No | | No | the Discord guild (server) id | +| `irc_pass` | Yes | | Yes | password for connecting to the IRC server | +| `suffix` | No | `~d` | Yes | appended to each Discord user's nickname when they are connected to IRC. If set to `_d2`, if the name will be `bob_d2` | +| `separator` | No | `_` | Yes | used in fallback situations. If set to `-`, the **fallback name** will be like `bob-7247_d2` (where `7247` is the discord user's discriminator, and `_d2` is the suffix) | +| `irc_listener_name` | Yes | `~d` | The name of the irc listener | | +| `ignored_discord_ids` | Sometimes | | Yes | A list of Discord IDs to not relay to IRC | +| `puppet_username` | No | username of discord account being puppeted | Yes | username to connect to irc with | +| `webirc_pass` | No | | Yes | optional, but recommended for regular (non-simple) usage. this must be obtained by the IRC sysops | +| `irc_listener_prejoin_commands` | Yes | | Yes | list of commands for the listener IRC connection to execute (right before joining channels) | +| `irc_puppet_prejoin_commands` | Yes | | Yes | list of commands for each Puppet IRC connection to execute (right before joining channels) | +| `debug` | Yes | false | Yes | debug mode | +| `insecure`, | Yes | false | Yes | TLS will skip verification (but still uses TLS) | +| `no_tls`, | Yes | false | Yes | turns off TLS | +| `webhook_prefix`, | Yes | | No | a prefix for webhooks, so we know which ones to keep and which ones to delete | +| `nickserv_identify` | No | | Yes | on connect this message will be sent: `PRIVMSG nickserv IDENTIFY `, you can provide both a username and password if your ircd supports it | +| `cooldown_duration` | No | 86400 (24 hours) | Yes | time in seconds for a discord user to be offline before it's puppet disconnects from irc | +| `show_joinquit` | No | false | yes | displays JOIN, PART, QUIT, KICK on discord | +| `max_nick_length` | No | 30 | yes | Maximum allowed nick length | +| `ignored_irc_hostmasks` | No | | Yes | A list of IRC users identified by hostmask to not relay to Discord, uses matching syntax as in [glob](https://github.com/gobwas/glob) | +| `connection_limit` | Yes | 0 | Yes | How many connections to IRC (including our listener) to spawn (limit of 0 or less means unlimited) | **The filename.yaml file is continuously read from and many changes will automatically update on the bridge. This means you can add or remove channels diff --git a/bridge/bridge.go b/bridge/bridge.go index 28136ba..17373f4 100644 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -37,6 +37,10 @@ type Config struct { IRCPuppetPrejoinCommands []string IRCListenerPrejoinCommands []string + // filters + IRCFilteredMessages []glob.Glob + DiscordFilteredMessages []glob.Glob + // NoTLS constrols whether to use TLS at all when connecting to the IRC server NoTLS bool diff --git a/bridge/irc_listener.go b/bridge/irc_listener.go index 2810e53..7ed7595 100644 --- a/bridge/irc_listener.go +++ b/bridge/irc_listener.go @@ -218,18 +218,10 @@ func (i *ircListener) OnPrivateMessage(e *irc.Event) { return } - // Discord doesn't accept an empty message - if strings.TrimSpace(e.Message()) == "" { - return - } - - // Ignore messages from Discord bots - if i.isPuppetNick(e.Nick) { - return - } - - // Ignored hostmasks - if i.bridge.ircManager.isIgnoredHostmask(e.Source) { + if strings.TrimSpace(e.Message()) == "" || // Discord doesn't accept an empty message + i.isPuppetNick(e.Nick) || // ignore msg's from our puppets + i.bridge.ircManager.isIgnoredHostmask(e.Source) || //ignored hostmasks + i.bridge.ircManager.isFilteredIRCMessage(e.Message()) { // filtered return } diff --git a/bridge/irc_manager.go b/bridge/irc_manager.go index 1a7760b..d948565 100644 --- a/bridge/irc_manager.go +++ b/bridge/irc_manager.go @@ -411,6 +411,10 @@ func (m *IRCManager) SendMessage(channel string, msg *DiscordMessage) { ircMessage.Message = line[4:] } + if m.isFilteredDiscordMessage(line) { + continue + } + select { // Try to send the message immediately case con.messages <- ircMessage: @@ -440,6 +444,24 @@ func (m *IRCManager) isIgnoredHostmask(mask string) bool { return false } +func (m *IRCManager) isFilteredIRCMessage(txt string) bool { + for _, ban := range m.bridge.Config.IRCFilteredMessages { + if ban.Match(txt) { + return true + } + } + return false +} + +func (m *IRCManager) isFilteredDiscordMessage(txt string) bool { + for _, ban := range m.bridge.Config.DiscordFilteredMessages { + if ban.Match(txt) { + return true + } + } + return false +} + func (m *IRCManager) generateUsername(discordUser DiscordUser) string { if len(m.bridge.Config.PuppetUsername) > 0 { return m.bridge.Config.PuppetUsername diff --git a/main.go b/main.go index 52d16f8..1d0d11d 100644 --- a/main.go +++ b/main.go @@ -77,6 +77,8 @@ func main() { identify := viper.GetString("nickserv_identify") // NickServ IDENTIFY for Listener ircIgnores := viper.GetStringSlice("ignored_irc_hostmasks") // IRC hosts to not relay to Discord rawDiscordIgnores := viper.GetStringSlice("ignored_discord_ids") // Ignore these Discord users on IRC + rawIRCFilter := viper.GetStringSlice("irc_message_filter") // Ignore lines containing matched text from IRC + rawDiscordFilter := viper.GetStringSlice("discord_message_filter") // Ignore lines containing matched text from Discord connectionLimit := viper.GetInt("connection_limit") // Limiter on how many IRC Connections we can spawn // if !*debugMode { @@ -129,6 +131,8 @@ func main() { } matchers := setupHostmaskMatchers(ircIgnores) + discordFilter := setupFilter(rawDiscordFilter) + ircFilter := setupFilter(rawIRCFilter) SetLogDebug(*debugMode) discordIgnores := make(map[string]struct{}, len(rawDiscordIgnores)) @@ -148,7 +152,9 @@ func main() { IRCListenerPrejoinCommands: ircListenerPrejoinCommands, ConnectionLimit: connectionLimit, IRCIgnores: matchers, + IRCFilteredMessages: ircFilter, DiscordIgnores: discordIgnores, + DiscordFilteredMessages: discordFilter, PuppetUsername: puppetUsername, NickServIdentify: identify, WebIRCPass: webIRCPass, @@ -202,6 +208,11 @@ func main() { ircIgnores := viper.GetStringSlice("ignored_irc_hostmasks") dib.Config.IRCIgnores = setupHostmaskMatchers(ircIgnores) + rawIRCFilter := viper.GetStringSlice("irc_message_filter") + rawDiscordFilter := viper.GetStringSlice("discord_message_filter") + dib.Config.DiscordFilteredMessages = setupFilter(rawDiscordFilter) + dib.Config.IRCFilteredMessages = setupFilter(rawIRCFilter) + avatarURL := viper.GetString("avatar_url") dib.Config.AvatarURL = avatarURL @@ -259,6 +270,21 @@ func setupHostmaskMatchers(hostmasks []string) []glob.Glob { return matchers } +func setupFilter(filters []string) []glob.Glob { + var matchers []glob.Glob + for _, filter := range filters { + g, err := glob.Compile(filter) + if err != nil { + log.WithField("error", err).WithField("filter", filter).Errorln("Failed to compile message filter!") + continue + } + + matchers = append(matchers, g) + } + + return matchers +} + func SetLogDebug(debug bool) { logger := log.StandardLogger() if debug {