parent
42dce7bde9
commit
812f91202f
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Livewire\Ui\Security;
|
namespace App\Livewire\Ui\Security;
|
||||||
|
|
||||||
|
|
@ -11,35 +12,193 @@ class RblCard extends Component
|
||||||
public int $hits = 0;
|
public int $hits = 0;
|
||||||
public array $lists = [];
|
public array $lists = [];
|
||||||
|
|
||||||
public function mount(): void { $this->load(); }
|
public ?string $ipv4 = null;
|
||||||
public function render() { return view('livewire.ui.security.rbl-card'); }
|
public ?string $ipv6 = null;
|
||||||
public function refresh(): void { $this->load(true); }
|
|
||||||
|
|
||||||
protected function load(bool $force=false): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
|
$this->load();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.ui.security.rbl-card');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refresh(): void
|
||||||
|
{
|
||||||
|
Cache::forget('dash.rbl');
|
||||||
|
$this->load(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function load(bool $force = false): void
|
||||||
|
{
|
||||||
|
// 1) IPv4/IPv6 bevorzugt aus /etc/mailwolt/installer.env
|
||||||
|
[$ip4, $ip6] = $this->resolvePublicIpsFromInstallerEnv();
|
||||||
|
|
||||||
|
// 2) Fallback auf .env
|
||||||
|
$this->ipv4 = $ip4 ?: trim((string) env('SERVER_PUBLIC_IPV4', '')) ?: '–';
|
||||||
|
$this->ipv6 = $ip6 ?: trim((string) env('SERVER_PUBLIC_IPV6', '')) ?: '–';
|
||||||
|
|
||||||
|
// 3) RBL-Ermittlung (cached)
|
||||||
$data = Cache::remember('dash.rbl', $force ? 1 : 21600, function () {
|
$data = Cache::remember('dash.rbl', $force ? 1 : 21600, function () {
|
||||||
$ip = trim(@file_get_contents('/etc/mailwolt/public_ip') ?: '');
|
// bevorzugt eine valide IPv4 für den RBL-Check
|
||||||
if ($ip === '') $ip = trim(@shell_exec("curl -fsS --max-time 2 ifconfig.me 2>/dev/null") ?? '');
|
$candidate = $this->validIPv4($this->ipv4 ?? '') ? $this->ipv4 : null;
|
||||||
if (!preg_match('/^\d+\.\d+\.\d+\.\d+$/', $ip)) $ip = '0.0.0.0';
|
|
||||||
|
|
||||||
$rev = implode('.', array_reverse(explode('.', $ip)));
|
if (!$candidate) {
|
||||||
$sources = [
|
$fromFile = @file_get_contents('/etc/mailwolt/public_ip') ?: '';
|
||||||
'zen.spamhaus.org',
|
$fromFile = trim($fromFile);
|
||||||
'bl.spamcop.net',
|
if ($this->validIPv4($fromFile)) {
|
||||||
'dnsbl.sorbs.net',
|
$candidate = $fromFile;
|
||||||
'b.barracudacentral.org',
|
}
|
||||||
];
|
|
||||||
|
|
||||||
$lists = [];
|
|
||||||
foreach ($sources as $s) {
|
|
||||||
$q = "$rev.$s";
|
|
||||||
$res = trim(@shell_exec("dig +short ".escapeshellarg($q)." A 2>/dev/null") ?? '');
|
|
||||||
if ($res !== '') $lists[] = $s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['ip'=>$ip, 'hits'=>count($lists), 'lists'=>$lists];
|
if (!$candidate) {
|
||||||
|
// letzter Fallback – kann auf Hardened-Systemen geblockt sein
|
||||||
|
$curl = @shell_exec("curl -fsS --max-time 2 ifconfig.me 2>/dev/null") ?: '';
|
||||||
|
$curl = trim($curl);
|
||||||
|
if ($this->validIPv4($curl)) {
|
||||||
|
$candidate = $curl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ip = $candidate ?: '0.0.0.0';
|
||||||
|
$lists = $this->queryRblLists($ip);
|
||||||
|
|
||||||
|
return ['ip' => $ip, 'hits' => count($lists), 'lists' => $lists];
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach ($data as $k=>$v) $this->$k = $v;
|
// 4) Werte ins Component-State
|
||||||
|
foreach ($data as $k => $v) {
|
||||||
|
$this->$k = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Bevorzugt Installer-ENV; gibt [ipv4, ipv6] zurück oder [null, null]. */
|
||||||
|
private function resolvePublicIpsFromInstallerEnv(): array
|
||||||
|
{
|
||||||
|
$file = '/etc/mailwolt/installer.env';
|
||||||
|
if (!is_readable($file)) {
|
||||||
|
return [null, null];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ipv4 = null;
|
||||||
|
$ipv6 = null;
|
||||||
|
|
||||||
|
$lines = @file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
// Kommentare überspringen
|
||||||
|
if (preg_match('/^\s*#/', $line)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// KEY=VALUE (VALUE evtl. in "..." oder '...')
|
||||||
|
if (!str_contains($line, '=')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
[$k, $v] = array_map('trim', explode('=', $line, 2));
|
||||||
|
$v = trim($v, " \t\n\r\0\x0B\"'");
|
||||||
|
|
||||||
|
if ($k === 'SERVER_PUBLIC_IPV4' && $this->validIPv4($v)) {
|
||||||
|
$ipv4 = $v;
|
||||||
|
} elseif ($k === 'SERVER_PUBLIC_IPV6' && $this->validIPv6($v)) {
|
||||||
|
$ipv6 = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$ipv4, $ipv6];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validIPv4(?string $ip): bool
|
||||||
|
{
|
||||||
|
return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validIPv6(?string $ip): bool
|
||||||
|
{
|
||||||
|
return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prüft die IP gegen ein paar gängige RBLs.
|
||||||
|
* Nutzt PHP-DNS (checkdnsrr), keine externen Tools.
|
||||||
|
*
|
||||||
|
* @return array<string> gelistete RBL-Zonen
|
||||||
|
*/
|
||||||
|
private function queryRblLists(string $ip): array
|
||||||
|
{
|
||||||
|
// Nur IPv4 prüfen (die meisten Listen hier sind v4)
|
||||||
|
if (!$this->validIPv4($ip)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$rev = implode('.', array_reverse(explode('.', $ip)));
|
||||||
|
$sources = [
|
||||||
|
'zen.spamhaus.org',
|
||||||
|
'bl.spamcop.net',
|
||||||
|
'dnsbl.sorbs.net',
|
||||||
|
'b.barracudacentral.org',
|
||||||
|
];
|
||||||
|
|
||||||
|
$listed = [];
|
||||||
|
foreach ($sources as $zone) {
|
||||||
|
$qname = "{$rev}.{$zone}";
|
||||||
|
// A-Record oder TXT deuten auf Listing hin
|
||||||
|
if (@checkdnsrr($qname . '.', 'A') || @checkdnsrr($qname . '.', 'TXT')) {
|
||||||
|
$listed[] = $zone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $listed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
//namespace App\Livewire\Ui\Security;
|
||||||
|
//
|
||||||
|
//use Livewire\Component;
|
||||||
|
//use Illuminate\Support\Facades\Cache;
|
||||||
|
//
|
||||||
|
//class RblCard extends Component
|
||||||
|
//{
|
||||||
|
// public string $ip = '–';
|
||||||
|
// public int $hits = 0;
|
||||||
|
// public array $lists = [];
|
||||||
|
//
|
||||||
|
// public ?string $ipv4 = null;
|
||||||
|
// public ?string $ipv6 = null;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// public function mount(): void { $this->load(); }
|
||||||
|
// public function render() { return view('livewire.ui.security.rbl-card'); }
|
||||||
|
// public function refresh(): void { $this->load(true); }
|
||||||
|
//
|
||||||
|
// protected function load(bool $force=false): void
|
||||||
|
// {
|
||||||
|
// $this->ipv4 = trim(env('SERVER_PUBLIC_IPV4')) ?: '–';
|
||||||
|
// $this->ipv6 = trim(env('SERVER_PUBLIC_IPV6')) ?: '–';
|
||||||
|
//
|
||||||
|
// $data = Cache::remember('dash.rbl', $force ? 1 : 21600, function () {
|
||||||
|
// $ip = trim(@file_get_contents('/etc/mailwolt/public_ip') ?: '');
|
||||||
|
// if ($ip === '') $ip = trim(@shell_exec("curl -fsS --max-time 2 ifconfig.me 2>/dev/null") ?? '');
|
||||||
|
// if (!preg_match('/^\d+\.\d+\.\d+\.\d+$/', $ip)) $ip = '0.0.0.0';
|
||||||
|
//
|
||||||
|
// $rev = implode('.', array_reverse(explode('.', $ip)));
|
||||||
|
// $sources = [
|
||||||
|
// 'zen.spamhaus.org',
|
||||||
|
// 'bl.spamcop.net',
|
||||||
|
// 'dnsbl.sorbs.net',
|
||||||
|
// 'b.barracudacentral.org',
|
||||||
|
// ];
|
||||||
|
//
|
||||||
|
// $lists = [];
|
||||||
|
// foreach ($sources as $s) {
|
||||||
|
// $q = "$rev.$s";
|
||||||
|
// $res = trim(@shell_exec("dig +short ".escapeshellarg($q)." A 2>/dev/null") ?? '');
|
||||||
|
// if ($res !== '') $lists[] = $s;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return ['ip'=>$ip, 'hits'=>count($lists), 'lists'=>$lists];
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// foreach ($data as $k=>$v) $this->$k = $v;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,98 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
namespace App\Livewire\Ui\System;
|
namespace App\Livewire\Ui\System;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class ServicesCard extends Component
|
class ServicesCard extends Component
|
||||||
{
|
{
|
||||||
public array $services = [];
|
|
||||||
public array $servicesCompact = [];
|
public array $servicesCompact = [];
|
||||||
|
|
||||||
// Mapping für schöne Labels/Hints
|
/** Pro Karte mehrere Quellen – grün sobald eine Quelle OK ist */
|
||||||
protected array $nameMap = [
|
protected array $cards = [
|
||||||
// Mail
|
// Mail
|
||||||
'postfix' => ['label' => 'Postfix', 'hint' => 'MTA / Versand'],
|
'postfix' => [
|
||||||
'dovecot' => ['label' => 'Dovecot', 'hint' => 'IMAP / POP3'],
|
'label' => 'Postfix', 'hint' => 'MTA / Versand',
|
||||||
'rspamd' => ['label' => 'Rspamd', 'hint' => 'Spamfilter'],
|
'sources' => ['systemd:postfix'],
|
||||||
'clamav' => ['label' => 'ClamAV', 'hint' => 'Virenscanner'],
|
],
|
||||||
|
'dovecot' => [
|
||||||
|
'label' => 'Dovecot', 'hint' => 'IMAP / POP3',
|
||||||
|
'sources' => ['systemd:dovecot', 'tcp:127.0.0.1:993'],
|
||||||
|
],
|
||||||
|
'rspamd' => [
|
||||||
|
'label' => 'Rspamd', 'hint' => 'Spamfilter',
|
||||||
|
'sources' => ['systemd:rspamd', 'tcp:127.0.0.1:11333', 'tcp:127.0.0.1:11334'],
|
||||||
|
],
|
||||||
|
'clamav' => [
|
||||||
|
'label' => 'ClamAV', 'hint' => 'Virenscanner',
|
||||||
|
// mehrere mögliche Units + Socket/PID + TCP
|
||||||
|
'sources' => [
|
||||||
|
'systemd:clamav-daemon',
|
||||||
|
'systemd:clamav-daemon@scan',
|
||||||
|
'systemd:clamd',
|
||||||
|
'socket:/run/clamav/clamd.ctl',
|
||||||
|
'pid:/run/clamav/clamd.pid',
|
||||||
|
'tcp:127.0.0.1:3310',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
// Daten & Cache
|
// Daten & Cache
|
||||||
'db' => ['label' => 'Datenbank', 'hint' => 'MySQL / MariaDB'],
|
'db' => [
|
||||||
'127.0.0.1:6379' => ['label' => 'Redis', 'hint' => 'Cache / Queue'],
|
'label' => 'Datenbank', 'hint' => 'MySQL / MariaDB',
|
||||||
|
'sources' => ['db'],
|
||||||
|
],
|
||||||
|
'redis' => [
|
||||||
|
'label' => 'Redis', 'hint' => 'Cache / Queue',
|
||||||
|
'sources' => ['tcp:127.0.0.1:6379', 'systemd:redis-server', 'systemd:redis'],
|
||||||
|
],
|
||||||
|
|
||||||
// Web / PHP
|
// Web / PHP
|
||||||
'php8.2-fpm' => ['label' => 'PHP-FPM', 'hint' => 'PHP Runtime'],
|
'php-fpm' => [
|
||||||
'nginx' => ['label' => 'Nginx', 'hint' => 'Webserver'],
|
'label' => 'PHP-FPM', 'hint' => 'PHP Runtime',
|
||||||
|
'sources' => [
|
||||||
|
'systemd:php8.3-fpm', 'systemd:php8.2-fpm', 'systemd:php8.1-fpm', 'systemd:php-fpm',
|
||||||
|
'socket:/run/php/php8.3-fpm.sock', 'socket:/run/php/php8.2-fpm.sock',
|
||||||
|
'socket:/run/php/php8.1-fpm.sock', 'socket:/run/php/php-fpm.sock',
|
||||||
|
'tcp:127.0.0.1:9000',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'nginx' => [
|
||||||
|
'label' => 'Nginx', 'hint' => 'Webserver',
|
||||||
|
'sources' => ['systemd:nginx', 'tcp:127.0.0.1:80'],
|
||||||
|
],
|
||||||
|
|
||||||
// MailWolt
|
// MailWolt (Units ODER laufende artisan-Prozesse)
|
||||||
'mailwolt-queue' => ['label' => 'MailWolt Queue', 'hint' => 'Job Worker'],
|
'mw-queue' => [
|
||||||
'mailwolt-schedule'=> ['label' => 'MailWolt Schedule', 'hint' => 'Task Scheduler'],
|
'label' => 'MailWolt Queue', 'hint' => 'Job Worker',
|
||||||
'mailwolt-ws' => ['label' => 'MailWolt WebSocket','hint' => 'Echtzeit Updates'],
|
'sources' => [
|
||||||
|
'systemd:mailwolt-queue',
|
||||||
|
'proc:/php.*artisan(\.php)?\s+queue:work',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'mw-schedule' => [
|
||||||
|
'label' => 'MailWolt Schedule', 'hint' => 'Task Scheduler',
|
||||||
|
'sources' => [
|
||||||
|
'systemd:mailwolt-schedule',
|
||||||
|
'proc:/php.*artisan(\.php)?\s+schedule:work',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'mw-ws' => [
|
||||||
|
'label' => 'MailWolt WebSocket', 'hint' => 'Echtzeit Updates',
|
||||||
|
'sources' => ['systemd:mailwolt-ws', 'tcp:127.0.0.1:8080'],
|
||||||
|
],
|
||||||
|
|
||||||
// Sonstiges
|
// Sonstiges
|
||||||
'fail2ban' => ['label' => 'Fail2Ban', 'hint' => 'SSH / Mail Protection'],
|
'fail2ban' => [
|
||||||
'systemd-journald'=> ['label' => 'System Logs', 'hint' => 'Journal'],
|
'label' => 'Fail2Ban', 'hint' => 'SSH / Mail Protection',
|
||||||
'rsyslog' => ['label' => 'Rsyslog', 'hint' => 'Logging'],
|
'sources' => ['systemd:fail2ban'],
|
||||||
|
],
|
||||||
// WebSocket/TCP
|
'journal' => [
|
||||||
'127.0.0.1:8080' => ['label' => 'Reverb', 'hint' => 'WebSocket Server'],
|
'label' => 'System Logs', 'hint' => 'Journal',
|
||||||
|
'sources' => ['systemd:systemd-journald', 'systemd:rsyslog'],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
|
|
@ -46,36 +100,205 @@ class ServicesCard extends Component
|
||||||
$this->load();
|
$this->load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function refresh(): void
|
||||||
|
{
|
||||||
|
Cache::forget('health:services.v2');
|
||||||
|
$this->load();
|
||||||
|
}
|
||||||
|
|
||||||
public function load(): void
|
public function load(): void
|
||||||
{
|
{
|
||||||
$this->services = Cache::get('health:services', []);
|
$data = Cache::remember('health:services.v2', 15, function () {
|
||||||
$meta = Cache::get('health:meta', []);
|
$out = [];
|
||||||
$updated = $meta['updated_at'] ?? null;
|
foreach ($this->cards as $key => $card) {
|
||||||
|
$ok = false;
|
||||||
|
foreach ($card['sources'] as $src) {
|
||||||
|
if ($this->check($src)) {
|
||||||
|
$ok = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$out[$key] = ['label' => $card['label'], 'hint' => $card['hint'], 'ok' => $ok];
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
});
|
||||||
|
|
||||||
$existing = collect($this->services)->keyBy('name');
|
$this->servicesCompact = collect($data)->map(function ($row) {
|
||||||
|
$ok = (bool)$row['ok'];
|
||||||
$this->servicesCompact = collect($this->nameMap)
|
return [
|
||||||
->map(function ($meta, $key) use ($existing) {
|
'label' => $row['label'],
|
||||||
$srv = $existing->get($key, []);
|
'hint' => $row['hint'],
|
||||||
$ok = (bool)($srv['ok'] ?? false);
|
'ok' => $ok,
|
||||||
|
'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
|
||||||
return [
|
'pillText' => $ok ? 'Online' : 'Offline',
|
||||||
'label' => $meta['label'],
|
'pillClass' => $ok
|
||||||
'hint' => $meta['hint'],
|
? 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'
|
||||||
'ok' => $ok,
|
: 'text-rose-300 border-rose-400/30 bg-rose-500/10',
|
||||||
'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
|
];
|
||||||
'pillText' => $ok ? 'Aktiv' : 'Offline',
|
})->values()->all();
|
||||||
'pillClass' => $ok
|
|
||||||
? 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'
|
|
||||||
: 'text-rose-300 border-rose-400/30 bg-rose-500/10',
|
|
||||||
];
|
|
||||||
})
|
|
||||||
->values()
|
|
||||||
->all();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.ui.system.services-card');
|
return view('livewire.ui.system.services-card');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ───────────── Probes ─────────────
|
||||||
|
|
||||||
|
protected function check(string $source): bool
|
||||||
|
{
|
||||||
|
if (str_starts_with($source, 'systemd:')) {
|
||||||
|
return $this->probeSystemd(substr($source, 8));
|
||||||
|
}
|
||||||
|
if (str_starts_with($source, 'tcp:')) {
|
||||||
|
[$host, $port] = explode(':', substr($source, 4), 2);
|
||||||
|
return $this->probeTcp($host, (int)$port);
|
||||||
|
}
|
||||||
|
if (str_starts_with($source, 'socket:')) {
|
||||||
|
$path = substr($source, 7);
|
||||||
|
return is_string($path) && @file_exists($path);
|
||||||
|
}
|
||||||
|
if (str_starts_with($source, 'pid:')) {
|
||||||
|
$path = substr($source, 4);
|
||||||
|
if (!@is_file($path)) return false;
|
||||||
|
$pid = (int)trim(@file_get_contents($path) ?: '');
|
||||||
|
return $pid > 1 && @posix_kill($pid, 0);
|
||||||
|
}
|
||||||
|
if (str_starts_with($source, 'proc:')) {
|
||||||
|
$regex = substr($source, 5);
|
||||||
|
return $this->probeProcessRegex($regex);
|
||||||
|
}
|
||||||
|
if ($source === 'db') {
|
||||||
|
return $this->probeDatabase();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function probeSystemd(string $unit): bool
|
||||||
|
{
|
||||||
|
// versuche /bin und /usr/bin
|
||||||
|
$bin = file_exists('/bin/systemctl') ? '/bin/systemctl'
|
||||||
|
: (file_exists('/usr/bin/systemctl') ? '/usr/bin/systemctl' : 'systemctl');
|
||||||
|
|
||||||
|
$cmd = sprintf('%s is-active --quiet %s 2>/dev/null', escapeshellcmd($bin), escapeshellarg($unit));
|
||||||
|
$exit = null;
|
||||||
|
@exec($cmd, $_, $exit);
|
||||||
|
return $exit === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function probeTcp(string $host, int $port, int $timeout = 1): bool
|
||||||
|
{
|
||||||
|
$fp = @fsockopen($host, $port, $e1, $e2, $timeout);
|
||||||
|
if (is_resource($fp)) {
|
||||||
|
fclose($fp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
// Alternative: stream_socket_client("tcp://$host:$port", …)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function probeProcessRegex(string $regex): bool
|
||||||
|
{
|
||||||
|
// /proc durchsuchen – leichtgewichtig und ohne ps-Depend
|
||||||
|
$regex = '#' . $regex . '#i';
|
||||||
|
foreach (@scandir('/proc') ?: [] as $d) {
|
||||||
|
if (!ctype_digit($d)) continue;
|
||||||
|
$cmd = @file_get_contents("/proc/$d/cmdline");
|
||||||
|
if ($cmd === false || $cmd === '') continue;
|
||||||
|
$cmd = str_replace("\0", ' ', $cmd);
|
||||||
|
if (preg_match($regex, $cmd)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function probeDatabase(): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
DB::connection()->getPdo();
|
||||||
|
return true;
|
||||||
|
} catch (\Throwable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//namespace App\Livewire\Ui\System;
|
||||||
|
//
|
||||||
|
//use Carbon\Carbon;
|
||||||
|
//use Illuminate\Support\Facades\Cache;
|
||||||
|
//use Livewire\Component;
|
||||||
|
//
|
||||||
|
//class ServicesCard extends Component
|
||||||
|
//{
|
||||||
|
// public array $services = [];
|
||||||
|
// public array $servicesCompact = [];
|
||||||
|
//
|
||||||
|
// // Mapping für schöne Labels/Hints
|
||||||
|
// protected array $nameMap = [
|
||||||
|
// // Mail
|
||||||
|
// 'postfix' => ['label' => 'Postfix', 'hint' => 'MTA / Versand'],
|
||||||
|
// 'dovecot' => ['label' => 'Dovecot', 'hint' => 'IMAP / POP3'],
|
||||||
|
// 'rspamd' => ['label' => 'Rspamd', 'hint' => 'Spamfilter'],
|
||||||
|
// 'clamav' => ['label' => 'ClamAV', 'hint' => 'Virenscanner'],
|
||||||
|
//
|
||||||
|
// // Daten & Cache
|
||||||
|
// 'db' => ['label' => 'Datenbank', 'hint' => 'MySQL / MariaDB'],
|
||||||
|
// '127.0.0.1:6379' => ['label' => 'Redis', 'hint' => 'Cache / Queue'],
|
||||||
|
//
|
||||||
|
// // Web / PHP
|
||||||
|
// 'php8.2-fpm' => ['label' => 'PHP-FPM', 'hint' => 'PHP Runtime'],
|
||||||
|
// 'nginx' => ['label' => 'Nginx', 'hint' => 'Webserver'],
|
||||||
|
//
|
||||||
|
// // MailWolt
|
||||||
|
// 'mailwolt-queue' => ['label' => 'MailWolt Queue', 'hint' => 'Job Worker'],
|
||||||
|
// 'mailwolt-schedule'=> ['label' => 'MailWolt Schedule', 'hint' => 'Task Scheduler'],
|
||||||
|
// 'mailwolt-ws' => ['label' => 'MailWolt WebSocket','hint' => 'Echtzeit Updates'],
|
||||||
|
//
|
||||||
|
// // Sonstiges
|
||||||
|
// 'fail2ban' => ['label' => 'Fail2Ban', 'hint' => 'SSH / Mail Protection'],
|
||||||
|
// 'systemd-journald'=> ['label' => 'System Logs', 'hint' => 'Journal'],
|
||||||
|
// 'rsyslog' => ['label' => 'Rsyslog', 'hint' => 'Logging'],
|
||||||
|
//
|
||||||
|
// // WebSocket/TCP
|
||||||
|
// '127.0.0.1:8080' => ['label' => 'Reverb', 'hint' => 'WebSocket Server'],
|
||||||
|
// ];
|
||||||
|
//
|
||||||
|
// public function mount(): void
|
||||||
|
// {
|
||||||
|
// $this->load();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function load(): void
|
||||||
|
// {
|
||||||
|
// $this->services = Cache::get('health:services', []);
|
||||||
|
// $meta = Cache::get('health:meta', []);
|
||||||
|
// $updated = $meta['updated_at'] ?? null;
|
||||||
|
//
|
||||||
|
// $existing = collect($this->services)->keyBy('name');
|
||||||
|
//
|
||||||
|
// $this->servicesCompact = collect($this->nameMap)
|
||||||
|
// ->map(function ($meta, $key) use ($existing) {
|
||||||
|
// $srv = $existing->get($key, []);
|
||||||
|
// $ok = (bool)($srv['ok'] ?? false);
|
||||||
|
//
|
||||||
|
// return [
|
||||||
|
// 'label' => $meta['label'],
|
||||||
|
// 'hint' => $meta['hint'],
|
||||||
|
// 'ok' => $ok,
|
||||||
|
// 'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
|
||||||
|
// 'pillText' => $ok ? 'Aktiv' : 'Offline',
|
||||||
|
// 'pillClass' => $ok
|
||||||
|
// ? 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'
|
||||||
|
// : 'text-rose-300 border-rose-400/30 bg-rose-500/10',
|
||||||
|
// ];
|
||||||
|
// })
|
||||||
|
// ->values()
|
||||||
|
// ->all();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function render()
|
||||||
|
// {
|
||||||
|
// return view('livewire.ui.system.services-card');
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue