From f9596caf7091f46c904b966bbebe9db66d545597 Mon Sep 17 00:00:00 2001 From: Crivion Date: Wed, 22 Oct 2025 14:11:16 +0300 Subject: [PATCH] firewall: remove laranode-ufw.sh - we do that through Process::run() instead --- app/Actions/Firewall/AddUfwDenyRuleAction.php | 3 +- app/Actions/Firewall/AddUfwRuleAction.php | 3 +- .../Firewall/BuildUfwRuleSpecAction.php | 31 ++++++++ app/Actions/Firewall/DeleteUfwRuleAction.php | 8 +- app/Actions/Firewall/GetUfwRulesAction.php | 3 +- app/Actions/Firewall/GetUfwStatusAction.php | 7 +- app/Actions/Firewall/ToggleUfwAction.php | 9 ++- app/Http/Controllers/FirewallController.php | 76 ++++--------------- .../Firewall/CreateFirewallRuleRequest.php | 44 +++++++++++ .../Firewall/ToggleFirewallRequest.php | 20 +++++ laranode-scripts/bin/laranode-installer.sh | 11 +++ laranode-scripts/bin/laranode-ufw.sh | 64 ---------------- 12 files changed, 138 insertions(+), 141 deletions(-) create mode 100644 app/Actions/Firewall/BuildUfwRuleSpecAction.php create mode 100644 app/Http/Requests/Firewall/CreateFirewallRuleRequest.php create mode 100644 app/Http/Requests/Firewall/ToggleFirewallRequest.php delete mode 100644 laranode-scripts/bin/laranode-ufw.sh diff --git a/app/Actions/Firewall/AddUfwDenyRuleAction.php b/app/Actions/Firewall/AddUfwDenyRuleAction.php index 2d71caa..3aaf61d 100644 --- a/app/Actions/Firewall/AddUfwDenyRuleAction.php +++ b/app/Actions/Firewall/AddUfwDenyRuleAction.php @@ -13,8 +13,7 @@ class AddUfwDenyRuleAction if ($ruleSpec === '') { throw new RuntimeException('Empty rule spec'); } - $bin = config('laranode.laranode_bin_path') . '/laranode-ufw.sh'; - $proc = Process::run(['sudo', $bin, 'deny', $ruleSpec]); + $proc = Process::run(['bash', '-lc', 'sudo ufw deny ' . escapeshellarg($ruleSpec)]); if ($proc->failed()) { throw new RuntimeException('UFW deny failed: ' . $proc->errorOutput()); } diff --git a/app/Actions/Firewall/AddUfwRuleAction.php b/app/Actions/Firewall/AddUfwRuleAction.php index 972eb71..8da66c2 100644 --- a/app/Actions/Firewall/AddUfwRuleAction.php +++ b/app/Actions/Firewall/AddUfwRuleAction.php @@ -13,8 +13,7 @@ class AddUfwRuleAction if ($ruleSpec === '') { throw new RuntimeException('Empty rule spec'); } - $bin = config('laranode.laranode_bin_path') . '/laranode-ufw.sh'; - $proc = Process::run(['sudo', $bin, 'allow', $ruleSpec]); + $proc = Process::run(['bash', '-lc', 'sudo ufw allow ' . escapeshellarg($ruleSpec)]); if ($proc->failed()) { throw new RuntimeException('UFW allow failed: ' . $proc->errorOutput()); } diff --git a/app/Actions/Firewall/BuildUfwRuleSpecAction.php b/app/Actions/Firewall/BuildUfwRuleSpecAction.php new file mode 100644 index 0000000..2c5833f --- /dev/null +++ b/app/Actions/Firewall/BuildUfwRuleSpecAction.php @@ -0,0 +1,31 @@ +failed()) { throw new RuntimeException('UFW delete failed: ' . $proc->errorOutput()); } diff --git a/app/Actions/Firewall/GetUfwRulesAction.php b/app/Actions/Firewall/GetUfwRulesAction.php index 1ba7b17..1d3ed31 100644 --- a/app/Actions/Firewall/GetUfwRulesAction.php +++ b/app/Actions/Firewall/GetUfwRulesAction.php @@ -8,8 +8,7 @@ class GetUfwRulesAction { public function execute(): array { - $bin = config('laranode.laranode_bin_path') . '/laranode-ufw.sh'; - $proc = Process::run(['sudo', $bin, 'list']); + $proc = Process::run(['sudo', 'ufw', 'status', 'numbered']); if ($proc->failed()) { return []; } diff --git a/app/Actions/Firewall/GetUfwStatusAction.php b/app/Actions/Firewall/GetUfwStatusAction.php index 91cd6fe..b418588 100644 --- a/app/Actions/Firewall/GetUfwStatusAction.php +++ b/app/Actions/Firewall/GetUfwStatusAction.php @@ -8,11 +8,12 @@ class GetUfwStatusAction { public function execute(): string { - $bin = config('laranode.laranode_bin_path') . '/laranode-ufw.sh'; - $proc = Process::run(['sudo', $bin, 'status']); + $proc = Process::run(['sudo', 'ufw', 'status']); if ($proc->failed()) { return 'unknown'; } - return trim($proc->output()); + $out = trim($proc->output()); + $lines = preg_split("/\r?\n/", $out); + return trim($lines[0] ?? $out); } } diff --git a/app/Actions/Firewall/ToggleUfwAction.php b/app/Actions/Firewall/ToggleUfwAction.php index 4931a08..a45c3c9 100644 --- a/app/Actions/Firewall/ToggleUfwAction.php +++ b/app/Actions/Firewall/ToggleUfwAction.php @@ -9,9 +9,12 @@ class ToggleUfwAction { public function execute(bool $enable): string { - $bin = config('laranode.laranode_bin_path') . '/laranode-ufw.sh'; - $cmd = $enable ? 'enable' : 'disable'; - $proc = Process::run(['sudo', $bin, $cmd]); + if ($enable) { + $proc = Process::run(['sudo', 'ufw', '--force', 'enable']); + } else { + // disable may prompt; confirm automatically + $proc = Process::run(['bash', '-lc', 'yes | sudo ufw disable']); + } if ($proc->failed()) { throw new RuntimeException('UFW toggle failed: ' . $proc->errorOutput()); } diff --git a/app/Http/Controllers/FirewallController.php b/app/Http/Controllers/FirewallController.php index 51b046d..b8a89f7 100644 --- a/app/Http/Controllers/FirewallController.php +++ b/app/Http/Controllers/FirewallController.php @@ -8,6 +8,9 @@ use App\Actions\Firewall\DeleteUfwRuleAction; use App\Actions\Firewall\GetUfwRulesAction; use App\Actions\Firewall\GetUfwStatusAction; use App\Actions\Firewall\ToggleUfwAction; +use App\Http\Requests\Firewall\ToggleFirewallRequest; +use App\Http\Requests\Firewall\CreateFirewallRuleRequest; +use App\Actions\Firewall\BuildUfwRuleSpecAction; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Inertia\Inertia; @@ -21,79 +24,26 @@ class FirewallController extends Controller return Inertia::render('Firewall/Index', compact('status', 'rules')); } - public function toggle(Request $request): RedirectResponse + public function toggle(ToggleFirewallRequest $request): RedirectResponse { - $validated = $request->validate([ - 'enabled' => 'required|boolean', - ]); - - $enable = (bool) $validated['enabled']; + $enable = (bool) $request->validated('enabled'); (new ToggleUfwAction())->execute($enable); session()->flash('success', 'Firewall ' . ($enable ? 'enabled' : 'disabled') . ' successfully.'); return redirect()->route('firewall.index'); } - public function store(Request $request): RedirectResponse + public function store(CreateFirewallRuleRequest $request): RedirectResponse { - $validated = $request->validate([ - 'type' => 'required|string|in:allow,deny', - 'protocol' => 'required|string|in:tcp,udp', - 'port' => 'required|integer|min:1|max:65535', - 'ip' => 'required|string', // validated below for any|ip|cidr - 'to' => 'required|string', - 'comment' => 'nullable|string|max:150', - ]); - - $from = trim($validated['ip']); - $to = trim($validated['to']); - - - $isAny = fn(string $v) => strtolower($v) === 'any'; - $isIp = fn(string $v) => filter_var($v, FILTER_VALIDATE_IP) !== false; - $isCidr = fn(string $v) => (bool) preg_match( - '/^((25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3})\/(3[0-2]|[12]?\d)$/', - $v + $validated = $request->validated(); + $spec = (new BuildUfwRuleSpecAction())->execute( + strtolower($validated['protocol']), + trim($validated['ip']), + trim($validated['to']), + (int) $validated['port'], + $validated['comment'] ?? '' ); - if (!($isAny($from) || $isIp($from) || $isCidr($from))) { - return back() - ->withErrors(['ip' => 'IP must be "any", a valid IP address, or CIDR range.']) - ->withInput(); - } - - if (!($isAny($to) || $isIp($to))) { - return back() - ->withErrors(['to' => 'To must be "any" or a valid IP address.']) - ->withInput(); - } - - $proto = strtolower($validated['protocol']); - $port = (int) $validated['port']; - $comment = trim($validated['comment'] ?? ''); - - // Escape comment safely for shell passing - $commentEscaped = str_replace("'", "\\'", $comment); - - - $ruleSpecParts = [ - 'proto ' . $proto, - 'from ' . $from, - 'to ' . $to, - 'port ' . $port, - ]; - - $spec = implode(' ', $ruleSpecParts); - - if ($commentEscaped !== '') { - $spec .= " comment '" . $commentEscaped . "'"; - } - - if (empty(trim($spec))) { - throw new \RuntimeException('Empty rule spec — cannot execute UFW.'); - } - - if ($validated['type'] === 'allow') { (new AddUfwRuleAction())->execute($spec); } else { diff --git a/app/Http/Requests/Firewall/CreateFirewallRuleRequest.php b/app/Http/Requests/Firewall/CreateFirewallRuleRequest.php new file mode 100644 index 0000000..005cc0d --- /dev/null +++ b/app/Http/Requests/Firewall/CreateFirewallRuleRequest.php @@ -0,0 +1,44 @@ + ['required', 'string', 'in:allow,deny'], + 'protocol' => ['required', 'string', 'in:tcp,udp'], + 'port' => ['required', 'integer', 'min:1', 'max:65535'], + 'ip' => ['required', 'string'], + 'to' => ['required', 'string'], + 'comment' => ['nullable', 'string', 'max:150'], + ]; + } + + public function withValidator($validator) + { + $validator->after(function ($validator) { + $ip = strtolower(trim($this->input('ip'))); + $to = strtolower(trim($this->input('to'))); + + $isAny = fn(string $v) => $v === 'any'; + $isIp = fn(string $v) => filter_var($v, FILTER_VALIDATE_IP) !== false; + $isCidr = fn(string $v) => (bool) preg_match('/^((25[0-5]|2[0-4]\\d|1?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|1?\\d?\\d)){3})\\/(3[0-2]|[12]?\\d)$/', $v); + + if (!($isAny($ip) || $isIp($ip) || $isCidr($ip))) { + $validator->errors()->add('ip', 'IP must be "any", a valid IP address, or CIDR range.'); + } + if (!($isAny($to) || $isIp($to))) { + $validator->errors()->add('to', 'To must be "any" or a valid IP address.'); + } + }); + } +} diff --git a/app/Http/Requests/Firewall/ToggleFirewallRequest.php b/app/Http/Requests/Firewall/ToggleFirewallRequest.php new file mode 100644 index 0000000..721caa2 --- /dev/null +++ b/app/Http/Requests/Firewall/ToggleFirewallRequest.php @@ -0,0 +1,20 @@ + ['required', 'boolean'], + ]; + } +} diff --git a/laranode-scripts/bin/laranode-installer.sh b/laranode-scripts/bin/laranode-installer.sh index c74cd8f..ac086d6 100755 --- a/laranode-scripts/bin/laranode-installer.sh +++ b/laranode-scripts/bin/laranode-installer.sh @@ -248,6 +248,17 @@ cp /home/laranode_ln/panel/laranode-scripts/templates/laranode-queue-worker.serv cp /home/laranode_ln/panel/laranode-scripts/templates/laranode-reverb.service /etc/systemd/system/laranode-reverb.service +echo -e"\033[34m" +echo "--------------------------------------------------------------------------------" +echo "Adding default UFW rules for SSH | HTTP | HTTPS | REVERB WEBSOCKETS" +echo "--------------------------------------------------------------------------------" +echo -e "\033[0m" +ufw allow 22 +ufw allow 80 +ufw allow 443 +ufw allow 8080 + + echo -e "\033[34m" echo "--------------------------------------------------------------------------------" echo "Setting permissions" diff --git a/laranode-scripts/bin/laranode-ufw.sh b/laranode-scripts/bin/laranode-ufw.sh deleted file mode 100644 index 93d1507..0000000 --- a/laranode-scripts/bin/laranode-ufw.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -cmd=${1:-} -arg=${2:-} - -run() { - if command -v ufw >/dev/null 2>&1; then - ufw "$@" - else - echo "ufw command not found" >&2 - exit 127 - fi -} - -case "$cmd" in - status) - run status | head -n1 - ;; - enable) - yes | run enable >/dev/null - echo "enabled" - ;; - disable) - yes | run disable >/dev/null - echo "disabled" - ;; - list) - run status numbered - ;; - allow) - if [ -z "${arg:-}" ]; then - echo "rule spec required" >&2 - exit 2 - fi - run allow "$arg" >/dev/null - echo "allowed: $arg" - ;; - deny) - if [ -z "${arg:-}" ]; then - echo "rule spec required" >&2 - exit 2 - fi - run deny "$arg" >/dev/null - echo "denied: $arg" - ;; - delete) - if [ -z "${arg:-}" ]; then - echo "rule id/spec required" >&2 - exit 2 - fi - if [[ "$arg" =~ ^[0-9]+$ ]]; then - yes | run delete "$arg" >/dev/null - else - yes | run delete "$arg" >/dev/null - fi - echo "deleted: $arg" - ;; - *) - echo "unknown command" >&2 - exit 2 - ;; -esac