diff options
Diffstat (limited to 'mod')
-rw-r--r-- | mod/bridge-port-to.rsc | 12 | ||||
-rw-r--r-- | mod/bridge-port-vlan.rsc | 12 | ||||
-rw-r--r-- | mod/inspectvar.rsc | 32 | ||||
-rw-r--r-- | mod/ipcalc.rsc | 12 | ||||
-rw-r--r-- | mod/notification-email.rsc | 93 | ||||
-rw-r--r-- | mod/notification-gotify.rsc | 139 | ||||
-rw-r--r-- | mod/notification-matrix.rsc | 61 | ||||
-rw-r--r-- | mod/notification-ntfy.rsc | 32 | ||||
-rw-r--r-- | mod/notification-telegram.rsc | 92 | ||||
-rw-r--r-- | mod/scriptrunonce.rsc | 44 | ||||
-rw-r--r-- | mod/ssh-keys-import.rsc | 35 |
11 files changed, 389 insertions, 175 deletions
diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index ec6f612..93eedce 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -1,16 +1,16 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-to # Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # reset bridge ports to default bridge -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md +# https://rsc.eworm.de/doc/mod/bridge-port-to.md :global BridgePortTo; -:set BridgePortTo do={ :do { +:set BridgePortTo do={ :onerror Err { :local BridgePortTo [ :tostr $1 ]; :global IfThenElse; @@ -65,6 +65,6 @@ $LogPrint info $0 ("Re-enabling interfaces..."); /interface/ethernet/enable $InterfaceReEnable; } -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index 6221646..6deee99 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -1,16 +1,16 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-vlan # Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # manage VLANs on bridge ports -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md +# https://rsc.eworm.de/doc/mod/bridge-port-vlan.md :global BridgePortVlan; -:global BridgePortVlan do={ :do { +:global BridgePortVlan do={ :onerror Err { :local ConfigTo [ :tostr $1 ]; :global IfThenElse; @@ -74,6 +74,6 @@ $LogPrint info $0 ("Re-enabling interfaces..."); /interface/ethernet/enable $InterfaceReEnable; } -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index 01724bb..fc1b366 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -1,23 +1,23 @@ #!rsc by RouterOS # RouterOS script: mod/inspectvar # Copyright (c) 2020-2025 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # inspect variables -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/inspectvar.md +# https://rsc.eworm.de/doc/mod/inspectvar.md :global InspectVar; :global InspectVarReturn; # inspect variable and print on terminal -:set InspectVar do={ :do { +:set InspectVar do={ :onerror Err { :global InspectVarReturn; :put [ :tocrlf [ $InspectVarReturn $1 ] ]; -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # inspect variable and return formatted string @@ -25,6 +25,7 @@ :local Input $1; :local Level (0 + [ :tonum $2 ]); + :global CharacterReplace; :global IfThenElse; :global InspectVarReturn; @@ -33,14 +34,13 @@ :local Value [ :tostr $2 ]; :local Level [ :tonum $3 ]; - :local Indent ""; - :for I from=1 to=$Level step=1 do={ - :set Indent ($Indent . " "); - } - :return ($Indent . "-" . $Prefix . "-> " . $Value); + :global CharacterMultiply; + + :return ([ $CharacterMultiply " " $Level ] . "-" . $Prefix . "-> " . $Value); } :local TypeOf [ :typeof $Input ]; + :local Len [ :len $Input ]; :local Return [ $IndentReturn "type" $TypeOf $Level ]; :if ($TypeOf = "array") do={ @@ -50,6 +50,16 @@ [ $InspectVarReturn $Value ($Level + 2) ]); } } else={ + :if ($TypeOf = "str") do={ + :set $Return ($Return . "\n" . \ + [ $IndentReturn "len" $Len $Level ]); + :if ([ :typeof [ :find $Input ("\r") ] ] = "num") do={ + :set Input [ $CharacterReplace $Input ("\r") "" ]; + } + :if ([ :typeof [ :find $Input ("\n") ] ] = "num") do={ + :set Input [ $CharacterReplace $Input ("\n") " " ]; + } + } :if ($TypeOf != "nothing") do={ :set $Return ($Return . "\n" . \ [ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \ diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index 69dec8b..eacff6d 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -1,18 +1,18 @@ #!rsc by RouterOS # RouterOS script: mod/ipcalc # Copyright (c) 2020-2025 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # ip address calculation -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ipcalc.md +# https://rsc.eworm.de/doc/mod/ipcalc.md :global IPCalc; :global IPCalcReturn; # print netmask, network, min host, max host and broadcast -:set IPCalc do={ :do { +:set IPCalc do={ :onerror Err { :local Input [ :tostr $1 ]; :global FormatLine; @@ -27,8 +27,8 @@ [ $FormatLine "HostMin" ($Values->"hostmin") ] . "\n" . \ [ $FormatLine "HostMax" ($Values->"hostmax") ] . "\n" . \ [ $FormatLine "Broadcast" ($Values->"broadcast") ]) ]; -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # calculate and return netmask, network, min host, max host and broadcast diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 6d700f5..ad9762a 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -1,12 +1,13 @@ #!rsc by RouterOS # RouterOS script: mod/notification-email # Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 +# requires device-mode, email, scheduler # # send notifications via e-mail -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-email.md +# https://rsc.eworm.de/doc/mod/notification-email.md :global EMailGenerateFrom; :global FlushEmailQueue; @@ -34,14 +35,16 @@ } # flush e-mail queue -:set FlushEmailQueue do={ :do { +:set FlushEmailQueue do={ :onerror Err { :global EmailQueue; :global EitherOr; :global EMailGenerateFrom; + :global FileExists; :global IsDNSResolving; :global IsTimeSync; :global LogPrint; + :global RmFile; :local AllDone true; :local QueueLen [ :len $EmailQueue ]; @@ -88,35 +91,40 @@ :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ - :local Attach ({}); :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } - :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={ - :if ([ :len [ /file/find where name=$File ] ] = 1) do={ - :set Attach ($Attach, $File); - } else={ - $LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach."); + :onerror Err { + :local Attach ({}); + :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={ + :if ([ $FileExists $File ] = true) do={ + :set Attach ($Attach, $File); + } else={ + $LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach."); + } } - } - /tool/e-mail/send from=[ $EMailGenerateFrom ] to=($Message->"to") cc=($Message->"cc") \ - subject=($Message->"subject") body=($Message->"body") file=$Attach; - :local Wait true; - :do { - :delay 1s; - :local Status [ /tool/e-mail/get last-status ]; - :if ($Status = "succeeded") do={ - :set ($EmailQueue->$Id); - :set Wait false; - :if (($Message->"remove-attach") = true) do={ - :foreach File in=$Attach do={ - /file/remove $File; + /tool/e-mail/send from=[ $EMailGenerateFrom ] to=($Message->"to") cc=($Message->"cc") \ + subject=($Message->"subject") body=($Message->"body") file=$Attach; + :local Wait true; + :do { + :delay 1s; + :local Status [ /tool/e-mail/get last-status ]; + :if ($Status = "succeeded") do={ + :set ($EmailQueue->$Id); + :set Wait false; + :if (($Message->"remove-attach") = true) do={ + :foreach File in=$Attach do={ + $RmFile $File; + } } } - } - :if ($Status = "failed") do={ - :set AllDone false; - :set Wait false; - } - } while=($Wait = true); + :if ($Status = "failed") do={ + :set AllDone false; + :set Wait false; + } + } while=($Wait = true); + } do={ + $LogPrint warning $0 ("Sending queued mail failed: " . $Err); + :set AllDone false; + } } } @@ -134,8 +142,8 @@ /system/scheduler/set interval=(($SchedVal->"run-count") . "m") \ comment="Waiting for retry..." $Scheduler; -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # generate filter for log-forward @@ -175,6 +183,7 @@ :global IfThenElse; :global NotificationEMailSignature; :global NotificationEMailSubject; + :global SymbolForNotification; :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; @@ -187,13 +196,23 @@ :if ([ :typeof $EmailQueue ] = "nothing") do={ :set EmailQueue ({}); } + :local Truncated false; + :local Body ($Notification->"message"); + :if ([ :len $Body ] > 62000) do={ + :set Body ([ :pick $Body 0 62000 ] . "..."); + :set Truncated true; + } :local Signature [ $EitherOr [ $NotificationEMailSignature ] [ /system/note/get note ] ]; + :set Body ($Body . "\n" . \ + [ $IfThenElse ([ :len ($Notification->"link") ] > 0) \ + ("\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")) ] . \ + [ $IfThenElse ($Truncated = true) ("\n" . [ $SymbolForNotification "scissors" ] . \ + "The message was too long and has been truncated!") ] . \ + [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); :set ($EmailQueue->[ :len $EmailQueue ]) { to=$To; cc=$Cc; subject=[ $NotificationEMailSubject ($Notification->"subject") ]; - body=(($Notification->"message") . \ - [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ - [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ + body=$Body; \ attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; :if ([ :len [ /system/scheduler/find where name="_FlushEmailQueue" ] ] = 0) do={ /system/scheduler/add name="_FlushEmailQueue" interval=1s start-time=startup \ @@ -247,12 +266,12 @@ } # send notification via e-mail - expects at least two string arguments -:set SendEMail do={ :do { +:set SendEMail do={ :onerror Err { :global SendEMail2; $SendEMail2 ({ origin=$0; subject=$1; message=$2; link=$3 }); -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # send notification via e-mail - expects one array argument diff --git a/mod/notification-gotify.rsc b/mod/notification-gotify.rsc new file mode 100644 index 0000000..d8eafbe --- /dev/null +++ b/mod/notification-gotify.rsc @@ -0,0 +1,139 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-gotify +# Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de> +# Leonardo David Monteiro <leo@cub3.xyz> +# https://rsc.eworm.de/COPYING.md +# +# requires RouterOS, version=7.15 +# requires device-mode, fetch, scheduler +# +# send notifications via Gotify (gotify.net) +# https://rsc.eworm.de/doc/mod/notification-gotify.md + +:global FlushGotifyQueue; +:global NotificationFunctions; +:global PurgeGotifyQueue; +:global SendGotify; +:global SendGotify2; + +# flush Gotify queue +:set FlushGotifyQueue do={ :onerror Err { + :global GotifyQueue; + + :global IsFullyConnected; + :global LogPrint; + + :if ([ $IsFullyConnected ] = false) do={ + $LogPrint debug $0 ("System is not fully connected, not flushing."); + :return false; + } + + :local AllDone true; + :local QueueLen [ :len $GotifyQueue ]; + + :if ([ :len [ /system/scheduler/find where name="_FlushGotifyQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrint warning $0 ("Flushing Gotify messages from scheduler, but queue is empty."); + } + + :foreach Id,Message in=$GotifyQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :onerror Err { + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + http-header-field=($Message->"headers") http-data=[ :serialize to=json ($Message->"message") ] \ + ($Message->"url") as-value; + :set ($GotifyQueue->$Id); + } do={ + $LogPrint debug $0 ("Sending queued Gotify message failed: " . $Err); + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $GotifyQueue ]) do={ + /system/scheduler/remove [ find where name="_FlushGotifyQueue" ]; + :set GotifyQueue; + } +} do={ + :global ExitError; $ExitError false $0 $Err; +} } + +# send notification via Gotify - expects one array argument +:set ($NotificationFunctions->"gotify") do={ + :local Notification $1; + + :global Identity; + :global IdentityExtra; + :global GotifyQueue; + :global GotifyServer; + :global GotifyServerOverride; + :global GotifyToken; + :global GotifyTokenOverride; + + :global EitherOr; + :global FetchUserAgentStr; + :global IfThenElse; + :global LogPrint; + :global SymbolForNotification; + + :local Server [ $EitherOr ($GotifyServerOverride->($Notification->"origin")) $GotifyServer ]; + :local Token [ $EitherOr ($GotifyTokenOverride->($Notification->"origin")) $GotifyToken ]; + + :if ([ :len $Token ] = 0) do={ + :return false; + } + + :local Url ("https://" . $Server . "/message"); + :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ]; \ + ("X-Gotify-Key: " . $Token); "Content-Type: application/json" }); + :local Message ({ + "title"=("[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")); \ + "message"=(($Notification->"message") . "\n" . [ $IfThenElse ([ :len ($Notification->"link") ] > 0) \ + ("\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")) ]); \ + "priority"=[ :tonum [ $IfThenElse ($Notification->"silent") 2 5 ] ] }); + + :onerror Err { + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + http-header-field=$Headers http-data=[ :serialize to=json $Message ] $Url as-value; + } do={ + $LogPrint info $0 ("Failed sending Gotify notification: " . $Err . " - Queuing..."); + + :if ([ :typeof $GotifyQueue ] = "nothing") do={ + :set GotifyQueue ({}); + } + :set ($Message->"message") (($Notification->"message") . "\n" . \ + [ $SymbolForNotification "alarm-clock" ] . "This message was queued since " . \ + [ /system/clock/get date ] . " " . [ /system/clock/get time ] . " and may be obsolete."); + :set ($GotifyQueue->[ :len $GotifyQueue ]) \ + { url=$Url; headers=$Headers; message=$Message }; + :if ([ :len [ /system/scheduler/find where name="_FlushGotifyQueue" ] ] = 0) do={ + /system/scheduler/add name="_FlushGotifyQueue" interval=1m start-time=startup \ + on-event=(":global FlushGotifyQueue; \$FlushGotifyQueue;"); + } + } +} + +# purge the Gotify queue +:set PurgeGotifyQueue do={ + :global GotifyQueue; + + /system/scheduler/remove [ find where name="_FlushGotifyQueue" ]; + :set GotifyQueue; +} + +# send notification via Gotify - expects at least two string arguments +:set SendGotify do={ :onerror Err { + :global SendGotify2; + + $SendGotify2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); +} do={ + :global ExitError; $ExitError false $0 $Err; +} } + +# send notification via Gotify - expects one array argument +:set SendGotify2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"gotify") ("\$NotificationFunctions->\"gotify\"") $Notification; +} diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index aad8b42..e9b42a0 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -2,12 +2,13 @@ # RouterOS script: mod/notification-matrix # Copyright (c) 2013-2025 Michael Gisbers <michael@gisbers.de> # Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 +# requires device-mode, fetch, scheduler # # send notifications via Matrix -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-matrix.md +# https://rsc.eworm.de/doc/mod/notification-matrix.md :global FlushMatrixQueue; :global NotificationFunctions; @@ -18,7 +19,7 @@ :global SetupMatrixJoinRoom; # flush Matrix queue -:set FlushMatrixQueue do={ :do { +:set FlushMatrixQueue do={ :onerror Err { :global MatrixQueue; :global IsFullyConnected; @@ -38,7 +39,7 @@ :foreach Id,Message in=$MatrixQueue do={ :if ([ :typeof $Message ] = "array" ) do={ - :do { + :onerror Err { /tool/fetch check-certificate=yes-without-crl output=none \ http-header-field=($Message->"headers") http-method=post \ http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=($Message->"plain"); @@ -46,8 +47,8 @@ ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ "/send/m.room.message?access_token=" . $Message->"accesstoken") as-value; :set ($MatrixQueue->$Id); - } on-error={ - $LogPrint debug $0 ("Sending queued Matrix message failed."); + } do={ + $LogPrint debug $0 ("Sending queued Matrix message failed: " . $Err); :set AllDone false; } } @@ -57,8 +58,8 @@ /system/scheduler/remove [ find where name="_FlushMatrixQueue" ]; :set MatrixQueue; } -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # send notification via Matrix - expects one array argument @@ -128,15 +129,15 @@ [ $PrepareText $Label ] . "</a>"); } - :do { + :onerror Err { /tool/fetch check-certificate=yes-without-crl output=none \ http-header-field=$Headers http-method=post \ http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=$Plain; "format"="org.matrix.custom.html"; "formatted_body"=$Formatted } ] \ ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ "/send/m.room.message?access_token=" . $AccessToken) as-value; - } on-error={ - $LogPrint info $0 ("Failed sending Matrix notification! Queuing..."); + } do={ + $LogPrint info $0 ("Failed sending Matrix notification: " . $Err . " - Queuing..."); :if ([ :typeof $MatrixQueue ] = "nothing") do={ :set MatrixQueue ({}); @@ -166,12 +167,12 @@ } # send notification via Matrix - expects at least two string arguments -:set SendMatrix do={ :do { +:set SendMatrix do={ :onerror Err { :global SendMatrix2; $SendMatrix2 ({ origin=$0; subject=$1; message=$2; link=$3 }); -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # send notification via Matrix - expects one array argument @@ -195,14 +196,14 @@ :global MatrixHomeServer; :local Domain [ :pick $User ([ :find $User ":" ] + 1) [ :len $User] ]; - :do { + :onerror Err { :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ ("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data"); :set MatrixHomeServer ([ :deserialize from=json value=$Data ]->"m.homeserver"->"base_url"); $LogPrint debug $0 ("Home server is: " . $MatrixHomeServer); - } on-error={ - $LogPrint error $0 ("Failed getting home server!"); + } do={ + $LogPrint error $0 ("Failed getting home server: " . $Err); :return false; } @@ -210,27 +211,27 @@ :set MatrixHomeServer [ :pick $MatrixHomeServer 8 [ :len $MatrixHomeServer ] ]; } - :do { + :onerror Err { :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post \ http-data=[ :serialize to=json { "type"="m.login.password"; "user"=$User; "password"=$Pass } ] \ ("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data"); :set MatrixAccessToken ([ :deserialize from=json value=$Data ]->"access_token"); $LogPrint debug $0 ("Access token is: " . $MatrixAccessToken); - } on-error={ - $LogPrint error $0 ("Failed logging in (and getting access token)!"); + } do={ + $LogPrint error $0 ("Failed logging in (and getting access token): " . $Err); :return false; } - :do { + :onerror Err { /system/script/remove [ find where name="global-config-overlay.d/mod/notification-matrix" ]; /system/script/add name="global-config-overlay.d/mod/notification-matrix" source=( \ "# configuration snippet: mod/notification-matrix\n\n" . \ ":global MatrixHomeServer \"" . $MatrixHomeServer . "\";\n" . \ ":global MatrixAccessToken \"" . $MatrixAccessToken . "\";\n"); $LogPrint info $0 ("Added configuration snippet. Now create and join a room, please!"); - } on-error={ - $LogPrint error $0 ("Failed adding configuration snippet!"); + } do={ + $LogPrint error $0 ("Failed adding configuration snippet: " . $Err); :return false; } } @@ -247,24 +248,24 @@ :global MatrixHomeServer; :global MatrixRoom; - :do { + :onerror Err { /tool/fetch check-certificate=yes-without-crl output=none \ http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post http-data="" \ ("https://" . $MatrixHomeServer . "/_matrix/client/r0/rooms/" . [ $UrlEncode $MatrixRoom ] . \ "/join?access_token=" . [ $UrlEncode $MatrixAccessToken ]) as-value; $LogPrint debug $0 ("Joined the room."); - } on-error={ - $LogPrint error $0 ("Failed joining the room!"); + } do={ + $LogPrint error $0 ("Failed joining the room: " . $Err); :return false; } - :do { + :onerror Err { :local Snippet [ /system/script/find where name="global-config-overlay.d/mod/notification-matrix" ]; /system/script/set $Snippet source=([ get $Snippet source ] . \ ":global MatrixRoom \"" . $MatrixRoom . "\";\n"); $LogPrint info $0 ("Appended configuration to configuration snippet. Please review!"); - } on-error={ - $LogPrint error $0 ("Failed appending configuration to snippet!"); + } do={ + $LogPrint error $0 ("Failed appending configuration to snippet: " . $Err); :return false; } } diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 53ba9b4..7114020 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -1,12 +1,13 @@ #!rsc by RouterOS # RouterOS script: mod/notification-ntfy # Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 +# requires device-mode, fetch, scheduler # # send notifications via Ntfy (ntfy.sh) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-ntfy.md +# https://rsc.eworm.de/doc/mod/notification-ntfy.md :global FlushNtfyQueue; :global NotificationFunctions; @@ -15,9 +16,8 @@ :global SendNtfy2; # flush ntfy queue -:set FlushNtfyQueue do={ :do { +:set FlushNtfyQueue do={ :onerror Err { :global NtfyQueue; - :global NtfyMessageIDs; :global IsFullyConnected; :global LogPrint; @@ -36,13 +36,13 @@ :foreach Id,Message in=$NtfyQueue do={ :if ([ :typeof $Message ] = "array" ) do={ - :do { + :onerror Err { /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ http-header-field=($Message->"headers") http-data=($Message->"text") \ ($Message->"url") as-value; :set ($NtfyQueue->$Id); - } on-error={ - $LogPrint debug $0 ("Sending queued Ntfy message failed."); + } do={ + $LogPrint debug $0 ("Sending queued Ntfy message failed: " . $Err); :set AllDone false; } } @@ -52,8 +52,8 @@ /system/scheduler/remove [ find where name="_FlushNtfyQueue" ]; :set NtfyQueue; } -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # send notification via ntfy - expects one array argument @@ -107,7 +107,7 @@ :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")); } - :do { + :onerror Err { :if ($Server = "ntfy.sh") do={ :if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={ $LogPrint warning $0 ("Downloading required certificate failed."); @@ -116,8 +116,8 @@ } /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ http-header-field=$Headers http-data=$Text $Url as-value; - } on-error={ - $LogPrint info $0 ("Failed sending ntfy notification! Queuing..."); + } do={ + $LogPrint info $0 ("Failed sending ntfy notification: " . $Err . " - Queuing..."); :if ([ :typeof $NtfyQueue ] = "nothing") do={ :set NtfyQueue ({}); @@ -143,12 +143,12 @@ } # send notification via ntfy - expects at least two string arguments -:set SendNtfy do={ :do { +:set SendNtfy do={ :onerror Err { :global SendNtfy2; $SendNtfy2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # send notification via ntfy - expects one array argument diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index f9700cf..2eb90e1 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -1,27 +1,28 @@ #!rsc by RouterOS # RouterOS script: mod/notification-telegram # Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 +# requires device-mode, fetch, scheduler # # send notifications via Telegram -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-telegram.md +# https://rsc.eworm.de/doc/mod/notification-telegram.md :global FlushTelegramQueue; +:global GetTelegramChatId; :global NotificationFunctions; :global PurgeTelegramQueue; :global SendTelegram; :global SendTelegram2; # flush telegram queue -:set FlushTelegramQueue do={ :do { +:set FlushTelegramQueue do={ :onerror Err { :global TelegramQueue; :global TelegramMessageIDs; :global IsFullyConnected; :global LogPrint; - :global UrlEncode; :if ([ $IsFullyConnected ] = false) do={ $LogPrint debug $0 ("System is not fully connected, not flushing."); @@ -37,16 +38,14 @@ :foreach Id,Message in=$TelegramQueue do={ :if ([ :typeof $Message ] = "array" ) do={ - :do { + :onerror Err { :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ - http-data=("chat_id=" . ($Message->"chatid") . "&disable_notification=" . ($Message->"silent") . \ - "&reply_to_message_id=" . ($Message->"replyto") . "&disable_web_page_preview=true" . \ - "&parse_mode=MarkdownV2&text=" . [ $UrlEncode ($Message->"text") ]) as-value ]->"data"); + http-data=($Message->"http-data") as-value ]->"data"); :set ($TelegramQueue->$Id); :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; - } on-error={ - $LogPrint debug $0 ("Sending queued Telegram message failed."); + } do={ + $LogPrint debug $0 ("Sending queued Telegram message failed: " . $Err); :set AllDone false; } } @@ -56,10 +55,49 @@ /system/scheduler/remove [ find where name="_FlushTelegramQueue" ]; :set TelegramQueue; } -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } +# get the chat id +:set GetTelegramChatId do={ :onerror Err { + :global TelegramTokenId; + + :global CertificateAvailable; + :global LogPrint; + + :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ + $LogPrint warning $0 ("Downloading required certificate failed."); + :return false; + } + + :local Data; + :onerror Err { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=0" . \ + "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); + } do={ + $LogPrint warning $0 ("Fetching data failed: " . $Err); + :return false; + } + + :local JSON [ :deserialize from=json value=$Data ]; + :local Count [ :len ($JSON->"result") ]; + + :if ($Count = 0) do={ + $LogPrint info $0 ("No message received."); + :return false; + } + + :local Message ($JSON->"result"->($Count - 1)->"message"); + $LogPrint info $0 ("The chat id is: " . ($Message->"chat"->"id")); + :if (($Message->"is_topic_message") = true) do={ + $LogPrint info $0 ("The thread id is: " . ($Message->"message_thread_id")); + } +} do={ + :global ExitError; $ExitError false $0 $Err; +} } + # send notification via telegram - expects one array argument :set ($NotificationFunctions->"telegram") do={ :local Notification $1; @@ -70,6 +108,8 @@ :global TelegramChatIdOverride; :global TelegramMessageIDs; :global TelegramQueue; + :global TelegramThreadId; + :global TelegramThreadIdOverride; :global TelegramTokenId; :global TelegramTokenIdOverride; @@ -110,6 +150,9 @@ :local ChatId [ $EitherOr ($Notification->"chatid") \ [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ]; + :local ThreadId [ $EitherOr ($Notification->"threadid") \ + [ $EitherOr ($TelegramThreadIdOverride->($Notification->"origin")) \ + [ $IfThenElse ([ :len ($TelegramChatIdOverride->($Notification->"origin")) ] = 0) $TelegramThreadId ] ] ]; :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ @@ -144,19 +187,20 @@ (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%_!") "plain" "_" ]); } - :do { + :local HTTPData ("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ + "&reply_to_message_id=" . ($Notification->"replyto") . "&message_thread_id=" . $ThreadId . \ + "&disable_web_page_preview=true&parse_mode=MarkdownV2"); + :onerror Err { :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ $LogPrint warning $0 ("Downloading required certificate failed."); :error false; } :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ - http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ - "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \ - "&parse_mode=MarkdownV2&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); + http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; - } on-error={ - $LogPrint info $0 ("Failed sending Telegram notification! Queuing..."); + } do={ + $LogPrint info $0 ("Failed sending Telegram notification: " . $Err . " - Queuing..."); :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue ({}); @@ -164,8 +208,8 @@ :set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \ [ $EscapeMD ("This message was queued since _" . [ /system/clock/get date ] . \ " " . [ /system/clock/get time ] . "_ and may be obsolete.") "plain" "_" ]); - :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; - text=$Text; silent=($Notification->"silent"); replyto=($Notification->"replyto") }; + :set ($TelegramQueue->[ :len $TelegramQueue ]) { tokenid=$TokenId; + http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) }; :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] = 0) do={ /system/scheduler/add name="_FlushTelegramQueue" interval=1m start-time=startup \ on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); @@ -182,12 +226,12 @@ } # send notification via telegram - expects at least two string arguments -:set SendTelegram do={ :do { +:set SendTelegram do={ :onerror Err { :global SendTelegram2; $SendTelegram2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # send notification via telegram - expects one array argument diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 7e01e72..1d6aaf1 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -1,22 +1,23 @@ #!rsc by RouterOS # RouterOS script: mod/scriptrunonece # Copyright (c) 2020-2025 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # download script and run it once -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/scriptrunonce.md +# https://rsc.eworm.de/doc/mod/scriptrunonce.md :global ScriptRunOnce; # fetch and run script(s) once -:set ScriptRunOnce do={ :do { +:set ScriptRunOnce do={ :onerror Err { :local Scripts [ :toarray $1 ]; :global ScriptRunOnceBaseUrl; :global ScriptRunOnceUrlSuffix; + :global FetchHuge; :global LogPrint; :global ValidateSyntax; @@ -29,26 +30,27 @@ :set Script ($ScriptRunOnceBaseUrl . $Script . ".rsc" . $ScriptRunOnceUrlSuffix); } - :local Source; - :do { - :set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); - } on-error={ + :local Source [ $FetchHuge $0 $Script true ]; + :if ($Source = false) do={ $LogPrint warning $0 ("Failed fetching script '" . $Script . "'!"); + :return false; } - :if ([ :len $Source ] > 0) do={ - :if ([ $ValidateSyntax $Source ] = true) do={ - :do { - $LogPrint info $0 ("Running script '" . $Script . "' now."); - [ :parse $Source ]; - } on-error={ - $LogPrint warning $0 ("The script '" . $Script . "' failed to run!"); - } - } else={ - $LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!"); - } + :if ([ $ValidateSyntax $Source ] = false) do={ + $LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!"); + :return false; + } + + :onerror Err { + $LogPrint info $0 ("Running script '" . $Script . "' now."); + [ :parse $Source ]; + } do={ + $LogPrint warning $0 ("The script '" . $Script . "' failed to run: " . $Err); + :return false; } + + :return true; } -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index ad3a81e..7bdc95d 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -1,24 +1,25 @@ #!rsc by RouterOS # RouterOS script: mod/ssh-keys-import # Copyright (c) 2020-2025 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.16 # # import ssh keys for public key authentication -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md +# https://rsc.eworm.de/doc/mod/ssh-keys-import.md :global SSHKeysImport; :global SSHKeysImportFile; # import single key passed as string -:set SSHKeysImport do={ :do { +:set SSHKeysImport do={ :onerror Err { :local Key [ :tostr $1 ]; :local User [ :tostr $2 ]; :global GetRandom20CharAlNum; :global LogPrint; :global MkDir; + :global RmDir; :global WaitForFile; :if ([ :len $Key ] = 0 || [ :len $User ] = 0) do={ @@ -54,26 +55,27 @@ /file/add name=$FileName contents=($Key . ", md5=" . $FingerPrintMD5); $WaitForFile $FileName; - :do { + :onerror Err { /user/ssh-keys/import public-key-file=$FileName user=$User; $LogPrint info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \ "MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'."); - /file/remove "tmpfs/ssh-keys-import"; - } on-error={ - $LogPrint warning $0 ("Failed importing key."); - /file/remove "tmpfs/ssh-keys-import"; + $RmDir "tmpfs/ssh-keys-import"; + } do={ + $LogPrint warning $0 ("Failed importing key: " . $Err); + $RmDir "tmpfs/ssh-keys-import"; :return false; } -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } # import keys from a file -:set SSHKeysImportFile do={ :do { +:set SSHKeysImportFile do={ :onerror Err { :local FileName [ :tostr $1 ]; :local User [ :tostr $2 ]; :global EitherOr; + :global FileExists; :global LogPrint; :global ParseKeyValueStore; :global SSHKeysImport; @@ -83,8 +85,7 @@ :return false; } - :local File [ /file/find where name=$FileName ]; - :if ([ :len $File ] = 0) do={ + :if ([ $FileExists $FileName ] = true) do={ $LogPrint warning $0 ("File '" . $FileName . "' does not exist."); :return false; } @@ -93,9 +94,7 @@ :foreach KeyVal in=[ :deserialize $Keys delimiter=" " from=dsv options=dsv.plain ] do={ :local Continue false; :if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={ - :do { - $SSHKeysImport ($KeyVal->0 . " " . $KeyVal->1 . " " . $KeyVal->2) $User; - } on-error={ + :if ([ $SSHKeysImport ($KeyVal->0 . " " . $KeyVal->1 . " " . $KeyVal->2) $User ] = false) do={ $LogPrint warning $0 ("Failed importing key for user '" . $User . "'."); } :set Continue true; @@ -108,6 +107,6 @@ $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); } } -} on-error={ - :global ExitError; $ExitError false $0; +} do={ + :global ExitError; $ExitError false $0 $Err; } } |