Commit Graph

7 Commits (bc2f2b527f7686c528ef028b4e7484be05fc3420)

Author SHA1 Message Date
boban bc2f2b527f fix(security): close file-read RBAC gap + fail2ban arg-injection + update/HMAC hardening
Confirmed-security quick-wins from a full re-audit (6-agent subsystem fan-out,
Codex-reviewed). Each item ships with a regression test proven to fail pre-fix.

- files: gate file CONTENT reads (download / edit / FileEditor::load) behind the
  `operate` ability so a read-only viewer keeps LISTING/browse access but can no
  longer pull file bytes over the server credential (root -> /etc/shadow, keys,
  .env). Hide the download/edit/delete controls from viewers in the blade, and
  basename() Files::open() for parity with the other path builders.
- fail2ban: reject a leading dash/dot in validJail(). A jail name like "-h" or
  "--help" was parsed by fail2ban-client as an OPTION (argument-injection) rather
  than a positional jail; internal dashes ("nginx-http-auth") still pass.
- bruteforce: release the atomically-claimed ban-audit dedup slot when the
  AuditEvent write throws, so a transient DB failure no longer suppresses the
  auth.ip_banned audit for the whole 60s window (the ban itself is unaffected).
- update path: verify_update_request now FAILS CLOSED when UPDATE_HMAC_KEY is
  unset (was fail-open -> any ./run marker could drive a root update). Pin the
  self-update `git pull` to the recorded CLUSEV_BUILD_BRANCH and refuse a diverged
  checkout, so a `git checkout` in the tree cannot redirect the next root update.
- wireguard: normalise the DNS input to a single comma list and QUOTE the WG_DNS
  assignment in wg.env; an unquoted space previously split the assignment and
  broke the next `. "$WG_ENV"`.

13 new regression tests. 614 tests, Pint, shellcheck, Codex review all green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 16:05:16 +02:00
boban b529201186 feat(rbac): gate service + file mutations behind operate (viewer read-only)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 01:06:06 +02:00
boban 359aa86aea fix(files): binary file content no longer breaks the Livewire snapshot (v0.9.54)
Opening a binary / non-UTF-8 file in the file manager threw "undefined is not
valid JSON". The editor bound the raw file bytes to its public $content
property; Livewire JSON-encodes the component snapshot, and invalid UTF-8 makes
PHP's json_encode return false, so the client received an empty response and
JSON.parse("undefined") failed (the trace in mergeNewSnapshot/deepClone).

Fixed at both layers: FleetService::readFile blanks the content when it detects
binary/non-UTF-8 (returns the binary flag instead), and FileEditor::load only
binds content for non-binary, non-oversize files. Binary/oversize files show
their existing notice; the snapshot is always valid UTF-8.

Tests: load blanks binary content (keeps the snapshot valid) and keeps valid
text content. 374 pass, Pint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 05:49:05 +02:00
boban 8cf8c771c8 feat(files): image preview in the file manager; modal polish
Opening an image now renders it (SFTP base64 data-URI, 5 MB cap, save disabled for
images) instead of the text editor. Recovery-codes modal buttons realigned + the
close button relabeled 'Schließen' (it only closes). All modal textareas resize-none.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 23:10:37 +02:00
boban ec1516184e i18n: complete DE/EN localization (modals, shell, backend) + v0.3.0
- modals: wire 5 hard-coded views + 10 components to lang/{de,en}/modals.php
- shell: command-palette (incl. app.js cmdk(nav,actions) refactor), server-item,
  toaster fallback
- backend: new lang/{de,en}/backend.php; localize Hardening/Firewall/Fail2ban/
  Maintenance services, OsProfile, plus FleetService + CredentialVault errors
- fix: localized page <title> on Dashboard/Servers index+show (->title(), the
  Livewire-3 way; the stray title() methods were never auto-called)
- fix: topbar inline @php() was swallowed by Blade's raw-block precompiler up to a
  later @endphp -> 500 on every authed page; converted to block @php ... @endphp
- versions: localize changelog section labels via a canonical heading map
- translation-quality pass: Unlock, Add credentials, clearer auth/notify copy

Bump 0.2.1 -> 0.3.0; CHANGELOG.

Verified: Pint clean; npm build OK; R12 all routes HTTP 200 + 0 console errors in
BOTH locales (titles/nav/labels switch language); 589 used keys resolve in de+en
with full group parity; Codex review clean; adversarial DE/EN audit (0 high).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 23:27:42 +02:00
boban 0f57074e6f chore(audit): full code sweep — fix open-redirect, drop dead code, clean docs
Full-codebase audit + automatic cleanup (no behavioural change for users).

Security
- ServerSwitcher: post-switch redirect is now reduced to a SAME-ORIGIN
  relative path. Rejects off-host referers, non-http(s) schemes
  (javascript:/data:), different ports (https://host:444/x -> /x), and
  protocol-relative tricks (//host, /\host). Closes a Referer open-redirect
  (Codex P2).
- EditCredential: a key passphrase is stored only for key auth, never for
  password auth.

Removed dead code
- FirewallService::status/allow/deny (+ orphaned clampPort)
- Server::auditEvents(), SshCredential::scopeActive(), unused 'bell' icon

Cleanups / improvements
- Files list + editor use a dedicated 'file' icon (was the audit icon)
- Import RuntimeException/Throwable instead of FQN; fix stale docblocks
  (FirewallService, HardeningService) and the Files delete comment
- Quote base64 in the sudo command path (defensive, consistent)
- Null-safe Auth::user()?->email in Settings; single domain() read in hasTls()

Release
- Bump 0.1.0 -> 0.1.1 + CHANGELOG entry

Verified: Pint clean, Codex review clean (no actionable regressions),
R12 browser check — 9 routes HTTP 200, 0 console errors, lazy pages loaded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 12:54:26 +02:00
boban f418ab35ab feat(ux): real metrics+context, working file manager, settings redesign, EN routes
Full feedback round — all browser-verified (R12: 7 routes 200, zero console errors)
and functionally tested live against the target host.

- Metrics are real AND honest: poller now stores cpu/mem/DISK/LOAD history (all
  four sparklines real, not synthetic); KPIs show absolute context (Memory
  "1,9 / 7,8 GB", Disk "13 / 80 GB", Load "4 Kerne"); tiles are status-coloured
  and Load is rated against core count (so "yellow" actually means load≈0.7-1.0×
  cores), not a fixed warning tint.
- File manager is functional: Hochladen (Livewire upload -> SFTP put), Download
  (SFTP get -> streamed), and view/edit (new FileEditor modal: SFTP get, binary/
  size guards, SFTP put on save + audit). File names + Bearbeiten open the editor.
- Settings redesigned (/frontend-design): account identity header + section nav
  (Profil / Sicherheit) instead of flat stacked panels.
- Routes are English (R13): /einstellungen -> /settings; rule added to rules.md +
  CLAUDE.md. Dummy data removed: the topbar "Flotte online / Uptime 42d" + dead
  bell button are gone, replaced by a real "<online>/<total> online" pill.

New: app/Livewire/Modals/FileEditor + view; FleetService get/read/write/upload +
Sftp putFromFile/size.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 00:32:05 +02:00