refactor(api): streamline mikrotik-install script and enhance synchronization logic
- Consolidated the `mikrotik-install.rsc` script to utilize a single `evofw-sync` script for improved clarity and efficiency in synchronization processes. - Removed the legacy `evofw-env` script, simplifying the token management and ensuring a more reliable update mechanism. - Updated the token generation logic to enhance security and reliability, while ensuring compatibility with RouterOS 7+. - Adjusted test assertions in `install-links.test.ts` to verify the presence of new script components and ensure accurate testing of the installation logic. These changes improve the overall robustness and maintainability of the agent installation and synchronization process.
This commit is contained in:
@@ -1,11 +1,8 @@
|
|||||||
# EvoFirewall MikroTik install (RouterOS 7.21+)
|
# EvoFirewall MikroTik install (RouterOS 7.21+)
|
||||||
# Short-link sets EvofwCpUrl / EvofwSeed / EvofwName / EvofwInstallLinkId before body.
|
# Short-link sets EvofwCpUrl / EvofwSeed / EvofwName / EvofwInstallLinkId before body.
|
||||||
# Legacy: set globals, then /import file-name=mikrotik-install.rsc
|
|
||||||
#
|
#
|
||||||
# Re-import on an already-enrolled router: skips enroll, refreshes sync + scheduler (token kept).
|
# One script only: evofw-sync (credentials + sync). Legacy evofw-env is removed.
|
||||||
#
|
# Sync: GET /v1/agent/policy (JSON) → rebuild address-lists. LastHash in RAM (full rebuild after reboot).
|
||||||
# Sync uses GET /v1/agent/policy (JSON) + address-list rebuild — not /import of huge .rsc
|
|
||||||
# (large /import often fails silently while apply-report still looks "ok").
|
|
||||||
|
|
||||||
:global EvofwCpUrl
|
:global EvofwCpUrl
|
||||||
:global EvofwSeed
|
:global EvofwSeed
|
||||||
@@ -19,19 +16,40 @@
|
|||||||
:if ([:typeof $EvofwName] = "nothing" || [:len $EvofwName] = 0) do={ :set EvofwName [/system identity get name] }
|
:if ([:typeof $EvofwName] = "nothing" || [:len $EvofwName] = 0) do={ :set EvofwName [/system identity get name] }
|
||||||
|
|
||||||
:local already 0
|
:local already 0
|
||||||
|
|
||||||
|
# Prefer token already baked into evofw-sync
|
||||||
:do {
|
:do {
|
||||||
/system script run evofw-env
|
:local src [/system script get [find name="evofw-sync"] source]
|
||||||
:if ([:typeof $EvofwToken] != "nothing" && [:len $EvofwToken] > 0) do={ :set already 1 }
|
:local key "EvofwToken \""
|
||||||
|
:local i [:find $src $key]
|
||||||
|
:if ([:typeof $i] != "nil") do={
|
||||||
|
:local rest [:pick $src ($i + [:len $key]) [:len $src]]
|
||||||
|
:local j [:find $rest "\""]
|
||||||
|
:if ([:typeof $j] != "nil") do={
|
||||||
|
:local tok [:pick $rest 0 $j]
|
||||||
|
:if ([:len $tok] > 10) do={
|
||||||
|
:set EvofwToken $tok
|
||||||
|
:set already 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} on-error={}
|
} on-error={}
|
||||||
|
|
||||||
|
# Legacy: migrate from evofw-env if present
|
||||||
|
:if ($already = 0) do={
|
||||||
|
:do {
|
||||||
|
/system script run evofw-env
|
||||||
|
:if ([:typeof $EvofwToken] != "nothing" && [:len $EvofwToken] > 0) do={ :set already 1 }
|
||||||
|
} on-error={}
|
||||||
|
}
|
||||||
|
|
||||||
:if ($already = 0) do={
|
:if ($already = 0) do={
|
||||||
# Portable token: :rndstr is RouterOS 7+; avoid /certificate scep-server nonce (often missing).
|
|
||||||
:local token ("evofw_" . [:rndstr length=32 from="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"])
|
:local token ("evofw_" . [:rndstr length=32 from="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"])
|
||||||
:if ([:len $token] < 20) do={
|
:if ([:len $token] < 20) do={
|
||||||
:set token ("evofw_" . [:tostr [/system clock get time]] . [:tostr [/system resource get cpu-load]] . [:tostr [/system resource get free-memory]] . [:tostr [:rndnum from=100000 to=999999]])
|
:set token ("evofw_" . [:tostr [/system clock get time]] . [:tostr [/system resource get cpu-load]] . [:tostr [/system resource get free-memory]] . [:tostr [:rndnum from=100000 to=999999]])
|
||||||
}
|
}
|
||||||
|
|
||||||
:local body ("{\"name\":\"" . $EvofwName . "\",\"hostname\":\"" . [/system identity get name] . "\",\"platform\":\"mikrotik\",\"token\":\"" . $token . "\",\"client_version\":\"rsc/2\"")
|
:local body ("{\"name\":\"" . $EvofwName . "\",\"hostname\":\"" . [/system identity get name] . "\",\"platform\":\"mikrotik\",\"token\":\"" . $token . "\",\"client_version\":\"rsc/3\"")
|
||||||
:if ([:typeof $EvofwInstallLinkId] != "nothing" && [:len $EvofwInstallLinkId] > 0) do={
|
:if ([:typeof $EvofwInstallLinkId] != "nothing" && [:len $EvofwInstallLinkId] > 0) do={
|
||||||
:set body ($body . ",\"install_link_id\":\"" . $EvofwInstallLinkId . "\"")
|
:set body ($body . ",\"install_link_id\":\"" . $EvofwInstallLinkId . "\"")
|
||||||
}
|
}
|
||||||
@@ -42,38 +60,29 @@
|
|||||||
} on-error={
|
} on-error={
|
||||||
:error "evofw: enroll failed — check EvofwCpUrl / EvofwSeed / connectivity"
|
:error "evofw: enroll failed — check EvofwCpUrl / EvofwSeed / connectivity"
|
||||||
}
|
}
|
||||||
|
|
||||||
:do { /system script remove [find name="evofw-env"] } on-error={}
|
|
||||||
/system script add name=evofw-env policy=read,write,policy,test source=(" :global EvofwCpUrl \"" . $EvofwCpUrl . "\"; :global EvofwToken \"" . $token . "\"; :global EvofwLastHash \"\" ")
|
|
||||||
:set EvofwToken $token
|
:set EvofwToken $token
|
||||||
:set EvofwLastHash ""
|
|
||||||
} else={
|
} else={
|
||||||
:put "evofw: already enrolled — updating sync script (token kept); forcing full list rebuild"
|
:put "evofw: already enrolled — updating single sync script (token kept)"
|
||||||
:set EvofwLastHash ""
|
|
||||||
:do { /system script remove [find name="evofw-env"] } on-error={}
|
|
||||||
/system script add name=evofw-env policy=read,write,policy,test source=(" :global EvofwCpUrl \"" . $EvofwCpUrl . "\"; :global EvofwToken \"" . $EvofwToken . "\"; :global EvofwLastHash \"\" ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Filter rules (idempotent by comment) — names must match policy toggles below
|
:set EvofwLastHash ""
|
||||||
:do { /ip firewall filter remove [find comment~"^evofw-"] } on-error={}
|
|
||||||
|
|
||||||
|
# Filter rules (idempotent by comment)
|
||||||
|
:do { /ip firewall filter remove [find comment~"^evofw-"] } on-error={}
|
||||||
/ip firewall filter add chain=input action=drop src-address-list=EVOFW_DENY comment=evofw-deny-drop-input disabled=no
|
/ip firewall filter add chain=input action=drop src-address-list=EVOFW_DENY comment=evofw-deny-drop-input disabled=no
|
||||||
/ip firewall filter add chain=forward action=drop src-address-list=EVOFW_DENY comment=evofw-deny-drop-forward disabled=no
|
/ip firewall filter add chain=forward action=drop src-address-list=EVOFW_DENY comment=evofw-deny-drop-forward disabled=no
|
||||||
/ip firewall filter add chain=forward action=accept src-address-list=EVOFW_ALLOW comment=evofw-allow-accept-forward disabled=no
|
/ip firewall filter add chain=forward action=accept src-address-list=EVOFW_ALLOW comment=evofw-allow-accept-forward disabled=no
|
||||||
/ip firewall filter add chain=forward action=drop comment=evofw-default-drop-forward disabled=yes
|
/ip firewall filter add chain=forward action=drop comment=evofw-default-drop-forward disabled=yes
|
||||||
|
|
||||||
# Sync: JSON policy → rebuild address-lists (reliable for ~1k CIDRs; no nested /import)
|
# Build sync body as a template script, then prepend baked credentials → one script
|
||||||
:do { /system script remove [find name="evofw-sync"] } on-error={}
|
:do { /system script remove [find name="evofw-sync-body"] } on-error={}
|
||||||
/system script add name=evofw-sync policy=read,write,policy,test source={
|
/system script add name=evofw-sync-body policy=read,write,policy,test source={
|
||||||
:global EvofwCpUrl
|
:global EvofwCpUrl
|
||||||
:global EvofwToken
|
:global EvofwToken
|
||||||
:global EvofwLastHash
|
:global EvofwLastHash
|
||||||
:if ([:typeof $EvofwCpUrl] = "nothing" || [:typeof $EvofwToken] = "nothing") do={
|
:if ([:typeof $EvofwCpUrl] = "nothing" || [:len $EvofwCpUrl] = 0 || [:typeof $EvofwToken] = "nothing" || [:len $EvofwToken] = 0) do={
|
||||||
/system script run evofw-env
|
|
||||||
}
|
|
||||||
:if ([:typeof $EvofwCpUrl] = "nothing" || [:typeof $EvofwToken] = "nothing") do={
|
|
||||||
:log error "evofw: missing EvofwCpUrl/EvofwToken"
|
:log error "evofw: missing EvofwCpUrl/EvofwToken"
|
||||||
:error "evofw env missing"
|
:error "evofw missing credentials"
|
||||||
}
|
}
|
||||||
:if ([:typeof $EvofwLastHash] = "nothing") do={ :set EvofwLastHash "" }
|
:if ([:typeof $EvofwLastHash] = "nothing") do={ :set EvofwLastHash "" }
|
||||||
|
|
||||||
@@ -114,8 +123,6 @@
|
|||||||
:do { /ip firewall filter set [find comment=evofw-default-drop-forward] disabled=yes } on-error={}
|
:do { /ip firewall filter set [find comment=evofw-default-drop-forward] disabled=yes } on-error={}
|
||||||
}
|
}
|
||||||
:set EvofwLastHash $hash
|
:set EvofwLastHash $hash
|
||||||
:do { /system script remove [find name="evofw-env"] } on-error={}
|
|
||||||
/system script add name=evofw-env policy=read,write,policy,test source=(" :global EvofwCpUrl \"" . $EvofwCpUrl . "\"; :global EvofwToken \"" . $EvofwToken . "\"; :global EvofwLastHash \"" . $hash . "\" ")
|
|
||||||
:log info ("evofw: applied " . $hash)
|
:log info ("evofw: applied " . $hash)
|
||||||
:set syncOk 1
|
:set syncOk 1
|
||||||
}
|
}
|
||||||
@@ -138,6 +145,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:local bodySrc [/system script get [find name="evofw-sync-body"] source]
|
||||||
|
:local head (":global EvofwCpUrl \"" . $EvofwCpUrl . "\"; :global EvofwToken \"" . $EvofwToken . "\"; ")
|
||||||
|
:do { /system script remove [find name="evofw-sync-body"] } on-error={}
|
||||||
|
:do { /system script remove [find name="evofw-sync"] } on-error={}
|
||||||
|
:do { /system script remove [find name="evofw-env"] } on-error={}
|
||||||
|
/system script add name=evofw-sync policy=read,write,policy,test source=($head . $bodySrc)
|
||||||
|
|
||||||
:do { /system scheduler remove [find name="evofw-sync"] } on-error={}
|
:do { /system scheduler remove [find name="evofw-sync"] } on-error={}
|
||||||
/system scheduler add name=evofw-sync interval=1m on-event=evofw-sync policy=read,write,policy,test
|
/system scheduler add name=evofw-sync interval=1m on-event=evofw-sync policy=read,write,policy,test
|
||||||
|
|
||||||
@@ -146,7 +160,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:if ($already = 1) do={
|
:if ($already = 1) do={
|
||||||
:put ("EvoFirewall updated for " . $EvofwName . " — sync script + scheduler refreshed")
|
:put ("EvoFirewall updated for " . $EvofwName . " — single script evofw-sync")
|
||||||
} else={
|
} else={
|
||||||
:put ("EvoFirewall enrolled as " . $EvofwName . " — approve in UI; scheduler evofw-sync every 1m")
|
:put ("EvoFirewall enrolled as " . $EvofwName . " — approve in UI; script/scheduler evofw-sync every 1m")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,8 @@ describe('install-links', () => {
|
|||||||
expect(byId.body).toContain('evofw-deny-drop-input')
|
expect(byId.body).toContain('evofw-deny-drop-input')
|
||||||
expect(byId.body).toContain('/v1/agent/policy')
|
expect(byId.body).toContain('/v1/agent/policy')
|
||||||
expect(byId.body).toContain(':deserialize')
|
expect(byId.body).toContain(':deserialize')
|
||||||
|
expect(byId.body).toContain('evofw-sync-body')
|
||||||
|
expect(byId.body).toContain('remove [find name="evofw-env"]')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('approved agent can fetch empty policy without rule sets', async () => {
|
it('approved agent can fetch empty policy without rule sets', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user