feat: items #9-13 — password change, webmail SSO, DKIM live, file manager security, cache busting

#9  auth.php: add self-service change-password action (current+new+confirm)
    accounts.php: fix admin change-password — accept account_id, fetch username
    for chpasswd (was using int ID), add Auth::require('admin') guard
    user.js: add Change Password page + navItem + submitChangePassword()

#10 EmailManager: store AES-256-CBC enc_password alongside SHA512-CRYPT hash
    webmail.php: rewrite login-url to use webmail_sso_tokens table
    novacpx-sso.php: Roundcube SSO bridge (validate token, decrypt, autosubmit)
    Migration 005: add enc_password column + webmail_sso_tokens table

#11 opendkim: installed, configured (/etc/opendkim.conf, signing.table,
    key.table, trusted.hosts), socket at /var/spool/postfix/opendkim/,
    Postfix milter wired, service enabled+running, key generation verified

#12 files.php: fix safe_path() for non-existent paths (write/mkdir),
    add safe_path_new() helper using parent-dir realpath check,
    fix delete guard (block deleting account root dirs),
    fix rename destination, clamp chmod to 0777

#13 nova.js: api() handles network errors, 429 rate-limit with retry-after,
    non-JSON responses (PHP fatal pages) — graceful error instead of throw
    admin/user/reseller index.php: filemtime-based cache-busting on all assets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 01:19:33 +00:00
parent 62707d62ce
commit 6fdccc6dbd
27 changed files with 1736 additions and 79 deletions
+4 -3
View File
@@ -1,5 +1,6 @@
<?php
// NovaCPX Reseller Panel — port 8881
$_v = fn($f) => '?v=' . @filemtime(dirname(__DIR__) . $f);
?>
<!DOCTYPE html>
<html lang="en">
@@ -8,7 +9,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>NovaCPX Reseller</title>
<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg">
<link rel="stylesheet" href="/assets/css/nova.css">
<link rel="stylesheet" href="/assets/css/nova.css<?= $_v('/assets/css/nova.css') ?>">
</head>
<body>
@@ -75,8 +76,8 @@
</div>
</div>
<script src="/assets/js/nova.js"></script>
<script src="/assets/js/reseller.js"></script>
<script src="/assets/js/nova.js<?= $_v('/assets/js/nova.js') ?>"></script>
<script src="/assets/js/reseller.js<?= $_v('/assets/js/reseller.js') ?>"></script>
</body>
</html>