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/
This commit is contained in:
Michael Gisbers 2021-05-28 17:30:37 +02:00 committed by Christian Hesse
parent 7a43bfbc6a
commit 8375673d93
15 changed files with 186 additions and 18 deletions

View file

@ -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:

View file

@ -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)

View file

@ -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
--------

View file

@ -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
--------------------

View file

@ -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
--------------------

View file

@ -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)

View file

@ -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)

View file

@ -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
-------------

View file

@ -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;

View file

@ -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

View file

@ -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";

View file

@ -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.

View file

@ -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

View file

@ -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;

View file

@ -0,0 +1,157 @@
#!rsc by RouterOS
# RouterOS script: global-functions.d/notification-matrix
# Copyright (c) 2013-2021 Michael Gisbers <michael@gisbers.de>
# Christian Hesse <mail@eworm.de>
# 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"={ "\\\\"; "&quot;"; "<br/>"; "&amp;"; "&lt;"; "&gt;" };
}
: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 ("<h2>" . [ $PrepareText ("[" . $Identity . "] " . ($Notification->"subject")) "format" ] . "</h2>" . \
"<pre><code>" . [ $PrepareText ($Notification->"message") "format" ] . "</code></pre>");
:if ([ :len ($Notification->"link") ] > 0) do={
:set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \
[ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]);
:set Formatted ($Formatted . "<br/>" . [ $SymbolForNotification "link" ] . \
"<a href=\\\"" . [ $PrepareText ($Notification->"link") "format" ] . "\\\">" . \
[ $PrepareText ($Notification->"link") "format" ] . "</a>");
}
: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 . "<br/>" . $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;
}