feat: TOTP 2FA + diverse Verbesserungen

2FA (TOTP):
- backend/api/auth.go: zweistufiger Login-Flow mit Pending-Token (5min),
  Endpunkte /2fa/validate, /2fa/setup, /2fa/confirm, /2fa/disable
- backend/db/users.go: GetUserByID, SetTOTPSecret, EnableTOTP, DisableTOTP
- backend/db/postgres.go: Migration totp_secret + totp_enabled Spalten
- backend/models/user.go: TOTPEnabled/TOTPSecret Felder, neue Request-Typen
- backend/main.go: neue Routen registriert (/2fa/validate ohne Auth, rest geschuetzt)
- backend/go.mod+sum: github.com/pquerna/otp hinzugefuegt
- frontend/src/pages/Login.jsx: zweistufiger Login (Passwort -> TOTP)
- frontend/src/pages/SettingsPage.jsx: TwoFactorSection mit Setup/Deaktivieren
- frontend/src/stores/auth.js: validateTOTP Action
- frontend/src/api/client.js: setupTOTP, confirmTOTP, disableTOTP, validateTOTP

Weitere Aenderungen (unstaged -> jetzt committed):
- frontend/src/components/ScriptModal.jsx: neu
- frontend/src/components/AgentPanel.jsx: Erweiterungen
- frontend/src/components/ProxmoxPanel.jsx: Erweiterungen
- agent-linux/ws/handler.go: Erweiterungen
- backend/api/scheduler.go + tasks.go: Erweiterungen
- backend/db/tasks.go + models/task.go: Erweiterungen
This commit is contained in:
cynfo3000
2026-03-08 19:17:43 +01:00
parent c76868e806
commit 10684dfc0a
19 changed files with 926 additions and 98 deletions
+55
View File
@@ -45,6 +45,8 @@ func (h *Handler) HandleCommand(msg Message) {
response = h.handleUpdateCheck(msg)
case "update":
response = h.handleUpdate(msg)
case "zpoolscrub":
response = h.handleZpoolScrub(msg)
case "pty_start":
response = h.handlePTYStart(msg)
case "pty_stop":
@@ -426,3 +428,56 @@ func (h *Handler) handleUpdate(msg Message) Message {
return response
}
// handleZpoolScrub: alle ZFS-Pools scrubben
func (h *Handler) handleZpoolScrub(msg Message) Message {
response := Message{Type: "response", ID: msg.ID}
log.Println("ZFS Scrub gestartet (alle Pools)...")
// Alle Pools ermitteln
poolOutput, err := h.runCommand("zpool list -H -o name 2>&1", 30)
if err != nil || strings.TrimSpace(poolOutput) == "" {
response.Status = "error"
response.Error = "Keine ZFS-Pools gefunden oder zpool nicht verfügbar"
return response
}
pools := []string{}
for _, line := range strings.Split(strings.TrimSpace(poolOutput), "\n") {
name := strings.TrimSpace(line)
if name != "" {
pools = append(pools, name)
}
}
results := map[string]string{}
scrubErrors := 0
// Jeden Pool scrubben (nicht-blockierend: scrub startet sofort und läuft im Hintergrund)
for _, pool := range pools {
log.Printf("ZFS Scrub starte: %s", pool)
out, err := h.runCommand(fmt.Sprintf("zpool scrub %s 2>&1", pool), 60)
if err != nil {
results[pool] = fmt.Sprintf("Fehler: %v — %s", err, strings.TrimSpace(out))
scrubErrors++
} else {
results[pool] = "Scrub gestartet"
}
}
if scrubErrors > 0 {
response.Status = "error"
response.Error = fmt.Sprintf("%d Pool(s) konnten nicht gestartet werden", scrubErrors)
} else {
response.Status = "ok"
}
log.Printf("ZFS Scrub: %d Pool(s) gestartet, %d Fehler", len(pools), scrubErrors)
response.Data = map[string]interface{}{
"pools": pools,
"results": results,
"message": fmt.Sprintf("Scrub auf %d Pool(s) gestartet", len(pools)-scrubErrors),
}
return response
}