Skip to content

Commit

Permalink
Initial Support for Ignoring IRC Hosts from Discord
Browse files Browse the repository at this point in the history
This should add a configuration option that allows for using nearly IRC
style hostmasks to "ban" matching users in IRC from sending messages
towards Discord. This would be useful for ignoring bots in channels.
  • Loading branch information
llmII committed Feb 14, 2021
1 parent 8838ded commit 17db5d4
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 28 deletions.
43 changes: 22 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,27 +66,28 @@ 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 |
| `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 |
| `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 |
| `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 <value>`, 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 |
| 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 |
| `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 |
| `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 |
| `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 <value>`, 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) |

**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
Expand Down
2 changes: 2 additions & 0 deletions bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/bwmarrin/discordgo"
"github.com/gobwas/glob"
"github.com/pkg/errors"
irc "github.com/qaisjp/go-ircevent"
log "github.com/sirupsen/logrus"
Expand All @@ -17,6 +18,7 @@ import (
type Config struct {
AvatarURL string
DiscordBotToken, GuildID string
DiscordIgnoresIRC []glob.Glob

// Map from Discord to IRC
ChannelMappings map[string]string
Expand Down
5 changes: 5 additions & 0 deletions bridge/irc_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ func (i *ircConnection) experimentalNotice(nick string) {
}

func (i *ircConnection) OnPrivateMessage(e *irc.Event) {
// Ignored hostmasks
if i.manager.isIgnoredHostmask(e.Source) {
return
}

// Alert private messages
if string(e.Arguments[0][0]) != "#" {
if e.Message() == "help" {
Expand Down
10 changes: 10 additions & 0 deletions bridge/irc_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ func (i *ircListener) OnJoinQuitCallback(event *irc.Event) {
return
}

// Ignored hostmasks
if i.bridge.ircManager.isIgnoredHostmask(event.Source) {
return
}

who := event.Nick
message := event.Nick
id := " (" + event.User + "@" + event.Host + ") "
Expand Down Expand Up @@ -215,6 +220,11 @@ func (i *ircListener) OnPrivateMessage(e *irc.Event) {
return
}

// Ignored hostmasks
if i.bridge.ircManager.isIgnoredHostmask(e.Source) {
return
}

replacements := []string{}
for _, con := range i.bridge.ircManager.ircConnections {
replacements = append(replacements, con.nick, "<@!"+con.discord.ID+">")
Expand Down
9 changes: 9 additions & 0 deletions bridge/irc_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,15 @@ func (m *IRCManager) RequestChannels(userID string) []Mapping {
return m.bridge.mappings
}

func (m *IRCManager) isIgnoredHostmask(mask string) bool {
for _, ban := range m.bridge.Config.DiscordIgnoresIRC {
if ban.Match(mask) {
return true
}
}
return false
}

func (m *IRCManager) generateUsername(discordUser DiscordUser) string {
if len(m.bridge.Config.PuppetUsername) > 0 {
return m.bridge.Config.PuppetUsername
Expand Down
5 changes: 5 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@ no_tls: false
debug: false
webhook_prefix: "(auto-test)"
# simple: true

# Uses matching syntax as in https://github.com/gobwas/glob
# ignored_irc_hostmasks:
# - "bot1!*@*"
# - "*!?bot@*"
36 changes: 29 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/fsnotify/fsnotify"
"github.com/gobwas/glob"
"github.com/pkg/errors"
"github.com/qaisjp/go-discord-irc/bridge"
ircnick "github.com/qaisjp/go-discord-irc/irc/nick"
Expand Down Expand Up @@ -61,13 +62,14 @@ func main() {
log.Fatalln(errors.Wrap(err, "could not read config"))
}

discordBotToken := viper.GetString("discord_token") // Discord Bot User Token
channelMappings := viper.GetStringMapString("channel_mappings") // Discord:IRC mappings in format '#discord1:#irc1,#discord2:#irc2,...'
ircServer := viper.GetString("irc_server") // Server address to use, example `irc.freenode.net:7000`.
ircPassword := viper.GetString("irc_pass") // Optional password for connecting to the IRC server
guildID := viper.GetString("guild_id") // Guild to use
webIRCPass := viper.GetString("webirc_pass") // Password for WEBIRC
identify := viper.GetString("nickserv_identify") // NickServ IDENTIFY for Listener
discordBotToken := viper.GetString("discord_token") // Discord Bot User Token
channelMappings := viper.GetStringMapString("channel_mappings") // Discord:IRC mappings in format '#discord1:#irc1,#discord2:#irc2,...'
ircServer := viper.GetString("irc_server") // Server address to use, example `irc.freenode.net:7000`.
ircPassword := viper.GetString("irc_pass") // Optional password for connecting to the IRC server
guildID := viper.GetString("guild_id") // Guild to use
webIRCPass := viper.GetString("webirc_pass") // Password for WEBIRC
identify := viper.GetString("nickserv_identify") // NickServ IDENTIFY for Listener
discordIgnoresIRC := viper.GetStringSlice("ignored_irc_hostmasks") // IRC hosts to not relay to Discord
//
if !*debugMode {
*debugMode = viper.GetBool("debug")
Expand Down Expand Up @@ -115,11 +117,13 @@ func main() {
log.Warnln("Channel mappings are missing!")
}

matchers := setupHostmaskMatchers(discordIgnoresIRC)
SetLogDebug(*debugMode)

dib, err := bridge.New(&bridge.Config{
AvatarURL: avatarURL,
DiscordBotToken: discordBotToken,
DiscordIgnoresIRC: matchers,
GuildID: guildID,
IRCListenerName: ircUsername,
IRCServer: ircServer,
Expand Down Expand Up @@ -174,6 +178,9 @@ func main() {
dib.SetIRCListenerName(ircUsername)
}

discordIgnoresIRC := viper.GetStringSlice("ignored_irc_hostmasks")
dib.Config.DiscordIgnoresIRC = setupHostmaskMatchers(discordIgnoresIRC)

avatarURL := viper.GetString("avatar_url")
dib.Config.AvatarURL = avatarURL

Expand Down Expand Up @@ -209,6 +216,21 @@ func main() {
dib.Close()
}

func setupHostmaskMatchers(hostmasks []string) []glob.Glob {
var matchers []glob.Glob
for _, mask := range hostmasks {
g, err := glob.Compile(mask)
if err != nil {
log.WithField("error", err).WithField("hostmask", mask).Errorln("Failed to compile hostmask ban!")
continue
}

matchers = append(matchers, g)
}

return matchers
}

func SetLogDebug(debug bool) {
logger := log.StandardLogger()
if debug {
Expand Down

0 comments on commit 17db5d4

Please sign in to comment.