From 8375673d93d5481cc575dcb61825eba9b08c1515 Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Fri, 28 May 2021 17:30:37 +0200 Subject: [PATCH] global-functions: implement notifications via Matrix Matrix is an open network for secure, decentralized communication - and it has a web api. A warning on message type: Using 'm.notice' breaks rendering on Element for Android (no fixed width font) and does not pop up desktop notification. Thus we use 'm.text'. Should be safe as we do not send the messages in response to other messages. https://matrix.org/ --- doc/check-certificates.md | 4 +- doc/check-health.md | 2 +- doc/check-lte-firmware-upgrade.md | 2 +- doc/cloud-backup.md | 2 +- doc/collect-wireless-mac.md | 2 +- doc/daily-psk.md | 2 +- doc/log-forward.md | 2 +- doc/netwatch-notify.md | 2 +- doc/sms-forward.md | 4 +- doc/upload-backup.md | 2 +- global-config | 18 ++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- global-functions.d/notification-matrix | 157 +++++++++++++++++++++++++ 15 files changed, 186 insertions(+), 18 deletions(-) create mode 100644 global-functions.d/notification-matrix diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 5b1e3b2..aa4a258 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -22,8 +22,8 @@ Just install the script: Configuration ------------- -The expiry notifications just require notification settings for e-mail and -telegram. +The expiry notifications just require notification settings for e-mail, +matrix and/or telegram. For automatic download and renewal of certificates you need configuration in `global-config-overlay`, these are the parameters: diff --git a/doc/check-health.md b/doc/check-health.md index f1b9d91..de7f9eb 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -39,7 +39,7 @@ The configuration goes to `global-config-overlay`, These are the parameters: * `CheckHealthTemperature`: an array specifying temperature thresholds for sensors * `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. --- [◀ Go back to main README](../README.md) diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index a145da8..dea6b82 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -31,7 +31,7 @@ Just install the script: Configuration ------------- -Notification setting are required for e-mail and telegram. +Notification setting are required for e-mail, matrix and/or telegram. See also -------- diff --git a/doc/cloud-backup.md b/doc/cloud-backup.md index 60e71c9..21d287f 100644 --- a/doc/cloud-backup.md +++ b/doc/cloud-backup.md @@ -26,7 +26,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. Usage and invocation -------------------- diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 4da06b9..8f3ff6f 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -36,7 +36,7 @@ On first run a disabled access list entry acting as marker (with comment "`--- collected above ---`") is added. Move this entry to define where new entries are to be added. -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. Usage and invocation -------------------- diff --git a/doc/daily-psk.md b/doc/daily-psk.md index ec55c85..28f9afc 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -47,7 +47,7 @@ Then add an access list entry: / interface wireless access-list add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. --- [◀ Go back to main README](../README.md) diff --git a/doc/log-forward.md b/doc/log-forward.md index 0993b52..68a6ca1 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -39,7 +39,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardFilter`: define topics *not* to be forwarded * `LogForwardFilterMessage`: define message text *not* to be forwarded -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. --- [◀ Go back to main README](../README.md) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index ff1eae9..2bba8d9 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -61,7 +61,7 @@ But be warned: Dynamic updates will probably cause issues if the name has more than one record in dns - a high rate of configuration changes (and flash writes) at least. -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. Tips & Tricks ------------- diff --git a/doc/sms-forward.md b/doc/sms-forward.md index d603daa..69ea5d0 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -27,8 +27,8 @@ Just install the script: Configuration ------------- -Notification settings are required for e-mail and telegram. Also you have -to enable receiving of SMS: +Notification settings are required for e-mail, matrix and/or telegram. Also +you have to enable receiving of SMS: / tool sms set receive-enabled=yes; diff --git a/doc/upload-backup.md b/doc/upload-backup.md index 4b656e4..f9a9b4f 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -32,7 +32,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupUploadUser`: username for server authentication * `BackupUploadPass`: password for server authentication -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. ### Issues with SFTP client diff --git a/global-config b/global-config index 6730a45..19d1215 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 52; +:global GlobalConfigVersion 53; # This is used for DNS and backup file. :global Domain "example.com"; @@ -33,9 +33,19 @@ # This is whether or not to send Telegram messages with fixed-width font. :global TelegramFixedWidthFont true; -# It is possible to override e-mail and Telegram setting for every script. -# This is done in arrays EmailGeneralToOverride, EmailGeneralCcOverride, -# TelegramTokenIdOverride and TelegramChatIdOverride like this: +# You can send Matrix notifications. Configure these settings and +# install the module: +# $ScriptInstallUpdate global-functions.d/notification-matrix +:global MatrixHomeServer ""; +:global MatrixAccessToken ""; +:global MatrixRoom ""; +#:global MatrixHomeServer "matrix.org"; +#:global MatrixAccessToken "123456ABCDEFGHI..."; +#:global MatrixRoom "!example:matrix.org"; + +# It is possible to override e-mail, Telegram and Matrix setting for every +# script. This is done in arrays, where 'Override' is appended to the +# variable name, like this: #:global EmailGeneralToOverride { # "check-certificates"="override@example.com"; # "email-backup"="backup@example.com"; diff --git a/global-config-overlay b/global-config-overlay index f90abd6..1cbaedf 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 52; +:global GlobalConfigVersion 53; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index cfaf649..21d4941 100644 --- a/global-config.changes +++ b/global-config.changes @@ -56,6 +56,7 @@ 50="Added support for dynamic address update in 'netwatch-notify'."; 51="Added 'ipsec-to-dns' to add DNS records for IPSec peers from mode-config."; 52="Updated Let's Encrypt trust chain to use root certificate 'ISRG Root X1'. Do not re-import the old chain!"; + 53="Added support to send notifications via Matrix."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 5ceab4f..b3db3dd 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 52; +:global ExpectedConfigVersion 53; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/global-functions.d/notification-matrix b/global-functions.d/notification-matrix new file mode 100644 index 0000000..962924e --- /dev/null +++ b/global-functions.d/notification-matrix @@ -0,0 +1,157 @@ +#!rsc by RouterOS +# RouterOS script: global-functions.d/notification-matrix +# Copyright (c) 2013-2021 Michael Gisbers +# Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global FlushMatrixQueue; +:global NotificationFunctions; +:global SendMatrix; +:global SendMatrix2; + +# flush Matrix queue +:set FlushMatrixQueue do={ + :global MatrixQueue; + + :global LogPrintExit2; + + :local AllDone true; + :local QueueLen [ :len $MatrixQueue ]; + + :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; + } + + :foreach Id,Message in=$MatrixQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ + "/send/m.room.message?access_token=" . $Message->"accesstoken") \ + http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \ + "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ + $Message->"formatted" . "\" }") as-value; + :set ($MatrixQueue->$Id); + } on-error={ + $LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ + / system scheduler remove [ find where name="FlushMatrixQueue" ]; + :set MatrixQueue; + } +} + +# send notification via Matrix - expects one array argument +:set ($NotificationFunctions->"matrix") do={ + :local Notification $1; + + :global Identity; + :global MatrixAccessToken; + :global MatrixAccessTokenOverride; + :global MatrixHomeServer; + :global MatrixHomeServerOverride; + :global MatrixQueue; + :global MatrixRoom; + :global MatrixRoomOverride; + + :global EitherOr; + :global LogPrintExit2; + :global SymbolForNotification; + + :local PrepareText do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return ""; + } + + :local Return ""; + :local Chars { + "plain"={ "\\"; "\""; "\n" }; + "format"={ "\\"; "\""; "\n"; "&"; "<"; ">" }; + } + :local Subs { + "plain"={ "\\\\"; "\\\""; "\\n" }; + "format"={ "\\\\"; """; "
"; "&"; "<"; ">" }; + } + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find ($Chars->$2) $Char ]; + + :if ([ :typeof $Replace ] = "num") do={ + :set Char ($Subs->$2->$Replace); + } + :set Return ($Return . $Char); + } + + :return $Return; + } + + :local AccessToken [ $EitherOr ($MatrixAccessTokenOverride->($Notification->"origin")) $MatrixAccessToken ]; + :local HomeServer [ $EitherOr ($MatrixHomeServerOverride->($Notification->"origin")) $MatrixHomeServer ]; + :local Room [ $EitherOr ($MatrixRoomOverride->($Notification->"origin")) $MatrixRoom ]; + + :if ([ :len $AccessToken ] = 0 || [ :len $HomeServer ] = 0 || [ :len $Room ] = 0) do={ + :return false; + } + + :local Plain [ $PrepareText ("## [" . $Identity . "] " . ($Notification->"subject") . "\n```\n" . \ + ($Notification->"message") . "\n```") "plain" ]; + :local Formatted ("

" . [ $PrepareText ("[" . $Identity . "] " . ($Notification->"subject")) "format" ] . "

" . \ + "
" . [ $PrepareText ($Notification->"message") "format" ] . "
"); + :if ([ :len ($Notification->"link") ] > 0) do={ + :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ + [ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]); + :set Formatted ($Formatted . "
" . [ $SymbolForNotification "link" ] . \ + ""link") "format" ] . "\\\">" . \ + [ $PrepareText ($Notification->"link") "format" ] . ""); + } + + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ + "/send/m.room.message?access_token=" . $AccessToken) \ + http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \ + "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ + $Formatted . "\" }") as-value; + } on-error={ + $LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false; + + :if ([ :typeof $MatrixQueue ] = "nothing") do={ + :set MatrixQueue [ :toarray "" ]; + } + :local Text ([ $SymbolForNotification "alarm-clock" ] . \ + "This message was queued since " . [ / system clock get date ] . \ + " " . [ / system clock get time ] . " and may be obsolete."); + :set Plain ($Plain . "\\n" . $Text); + :set Formatted ($Formatted . "
" . $Text); + :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ + accesstoken=$AccessToken; homeserver=$HomeServer; \ + plain=$Plain; formatted=$Formatted }; + :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] = 0) do={ + / system scheduler add name=FlushMatrixQueue interval=1m start-time=startup \ + on-event=":global FlushMatrixQueue; \$FlushMatrixQueue;"; + } + } +} + +# send notification via Matrix - expects at lease two string arguments +:set SendMatrix do={ + :global SendMatrix2; + + $SendMatrix2 ({ subject=$1; message=$2; link=$3 }); +} + +# send notification via Matrix - expects one array argument +:set SendMatrix2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification; +}