From ae6594c6061e2bcf5a394f70f40eb092247728b8 Mon Sep 17 00:00:00 2001 From: Luca Bigliardi Date: Sat, 25 Jan 2020 18:03:13 +0000 Subject: [PATCH] Add config option to deliver alerts with PRIVMSG Add `use_privmsg` config option to deliver alerts with PRIVMSG instead of the default NOTICE. This addresses a use case described in https://github.com/google/alertmanager-irc-relay/pull/1 . Signed-off-by: Luca Bigliardi --- README.md | 5 +++++ config.go | 2 ++ config_test.go | 1 + irc.go | 10 ++++++++- irc_test.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a8c2ed1..be474b1 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,11 @@ irc_channels: # Send only one message when webhook data is received. # Note: By default a message is sent for each alert in the webhook data. msg_once_per_alert_group: no +# +# Use PRIVMSG instead of NOTICE (default) to send messages. +# Note: Sending PRIVMSG from bots is bad practice, do not enable this unless +# necessary (e.g. unless NOTICEs would weaken your channel moderation policies) +use_privmsg: yes # Define how IRC messages should be formatted. # diff --git a/config.go b/config.go index 5fde1ed..41f7cf2 100644 --- a/config.go +++ b/config.go @@ -41,6 +41,7 @@ type Config struct { IRCChannels []IRCChannel `yaml:"irc_channels"` MsgTemplate string `yaml:"msg_template"` MsgOnce bool `yaml:"msg_once_per_alert_group"` + UsePrivmsg bool `yaml:"use_privmsg"` } func LoadConfig(configFile string) (*Config, error) { @@ -55,6 +56,7 @@ func LoadConfig(configFile string) (*Config, error) { IRCUseSSL: true, IRCChannels: []IRCChannel{IRCChannel{Name: "#airtest"}}, MsgOnce: false, + UsePrivmsg: false, } if configFile != "" { diff --git a/config_test.go b/config_test.go index ceb190b..3ca5cdd 100644 --- a/config_test.go +++ b/config_test.go @@ -43,6 +43,7 @@ func TestLoadGoodConfig(t *testing.T) { IRCChannels: []IRCChannel{IRCChannel{Name: "#foobar"}}, MsgTemplate: defaultMsgTemplate, MsgOnce: false, + UsePrivmsg: false, } expectedData, err := yaml.Marshal(expectedConfig) if err != nil { diff --git a/irc.go b/irc.go index 08b7011..e897dc2 100644 --- a/irc.go +++ b/irc.go @@ -62,6 +62,8 @@ type IRCNotifier struct { PreJoinChannels []IRCChannel JoinedChannels map[string]ChannelState + UsePrivmsg bool + NickservDelayWait time.Duration BackoffCounter Delayer } @@ -94,6 +96,7 @@ func NewIRCNotifier(config *Config, alertMsgs chan AlertMsg) (*IRCNotifier, erro sessionDownSignal: make(chan bool), PreJoinChannels: config.IRCChannels, JoinedChannels: make(map[string]ChannelState), + UsePrivmsg: config.UsePrivmsg, NickservDelayWait: nickservWaitSecs * time.Second, BackoffCounter: backoffCounter, } @@ -196,7 +199,12 @@ func (notifier *IRCNotifier) MaybeSendAlertMsg(alertMsg *AlertMsg) { return } notifier.JoinChannel(&IRCChannel{Name: alertMsg.Channel}) - notifier.Client.Notice(alertMsg.Channel, alertMsg.Alert) + + if notifier.UsePrivmsg { + notifier.Client.Privmsg(alertMsg.Channel, alertMsg.Alert) + } else { + notifier.Client.Notice(alertMsg.Channel, alertMsg.Alert) + } } func (notifier *IRCNotifier) Run() { diff --git a/irc_test.go b/irc_test.go index a4f3f91..9c8dfa4 100644 --- a/irc_test.go +++ b/irc_test.go @@ -212,6 +212,7 @@ func makeTestIRCConfig(IRCPort int) *Config { IRCChannel{Name: "#bar"}, IRCChannel{Name: "#baz"}, }, + UsePrivmsg: false, } } @@ -321,6 +322,63 @@ func TestSendAlertOnPreJoinedChannel(t *testing.T) { } } +func TestUsePrivmsgToSendAlertOnPreJoinedChannel(t *testing.T) { + server, port := makeTestServer(t) + config := makeTestIRCConfig(port) + config.UsePrivmsg = true + notifier, alertMsgs := makeTestNotifier(t, config) + + var testStep sync.WaitGroup + + testChannel := "#foo" + testMessage := "test message" + + // Send the alert after configured channels have joined, to ensure we + // check for no re-join attempt. + joinedHandler := func(conn *bufio.ReadWriter, line *irc.Line) error { + if line.Args[0] == testChannel { + testStep.Done() + } + return nil + } + server.SetHandler("JOIN", joinedHandler) + + testStep.Add(1) + go notifier.Run() + + testStep.Wait() + + server.SetHandler("JOIN", nil) + + privmsgHandler := func(conn *bufio.ReadWriter, line *irc.Line) error { + testStep.Done() + return nil + } + server.SetHandler("PRIVMSG", privmsgHandler) + + testStep.Add(1) + alertMsgs <- AlertMsg{Channel: testChannel, Alert: testMessage} + + testStep.Wait() + + notifier.StopRunning <- true + server.Stop() + + expectedCommands := []string{ + "NICK foo", + "USER foo 12 * :", + "JOIN #foo", + "JOIN #bar", + "JOIN #baz", + "PRIVMSG #foo :test message", + "QUIT :see ya", + } + + if !reflect.DeepEqual(expectedCommands, server.Log) { + t.Error("Alert not sent correctly. Received commands:\n", strings.Join(server.Log, "\n")) + } +} + func TestSendAlertAndJoinChannel(t *testing.T) { server, port := makeTestServer(t) config := makeTestIRCConfig(port)