Files
novacpx/panel/api/endpoints/backup.php
T
myron 537d52dafa Role isolation, impersonation, account ownership, loading spinners, Docker fixes
- Enforce portal role isolation: admin/reseller/user can only auth on their own port
- Admin/reseller impersonation: Login As with cookie handoff + Return banner in user panel
- Account ownership: admin can reassign accounts to resellers, DNS NS follows
- accounts/update: ownership change cascades package + NS to new owner
- users.php endpoint: admin list/filter by role (reseller dropdown)
- Docker launch fix: uDockerUpdateParams defined before call
- Nova.loading() spinners: login, SSL, PHP switch/save, backup create, docker launch/actions
- Logo consistency: gradient CPX text on all login pages, novacpx_logo_html() in all sidebars
- BackupManager: fix DB class name, table name, column name
- DNSManager: fix settings keys (ns1_hostname/ns2_hostname)
- docker.php: resolve account_id from user uid for all actions
- Auth: impersonate sets cookie + stores return_token for seamless round-trip

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 02:56:45 +00:00

83 lines
3.5 KiB
PHP

<?php
require_once NOVACPX_LIB . '/BackupManager.php';
if (!in_array($currentUser['role'], ['admin','reseller','user'])) Response::error('Forbidden', 403);
$bm = new BackupManager();
$body = json_decode(file_get_contents('php://input'), true) ?? [];
$isAdmin = $currentUser['role'] === 'admin';
$accountId = (int)($body['account_id'] ?? $_GET['account_id'] ?? 0);
if ($currentUser["role"] === "user") { $row = DB::getInstance()->fetchOne("SELECT id FROM accounts WHERE user_id=?", [$currentUser["uid"]]); $accountId = $row ? (int)$row["id"] : 0; }
match ($action) {
'list' => (function() use ($bm, $accountId, $isAdmin) {
$list = $bm->list($isAdmin ? $accountId : $accountId);
Response::success(['backups' => $list, 'disk_used' => $bm->diskUsage($accountId)]);
})(),
'create' => (function() use ($bm, $body, $accountId) {
if (!$accountId) Response::error('account_id required');
$type = in_array($body['type'] ?? 'full', ['full','files','database']) ? $body['type'] : 'full';
$result = $bm->create($accountId, $type);
audit('backup_create', 'backup', ['account_id' => $accountId, 'type' => $type]);
Response::success($result, 'Backup created successfully');
})(),
'restore' => (function() use ($bm, $body, $isAdmin) {
if (!$isAdmin) Response::error('Admin only', 403);
$id = (int)($body['id'] ?? 0);
if (!$id) Response::error('id required');
$bm->restore($id);
audit('backup_restore', 'backup', ['id' => $id]);
Response::success(null, 'Backup restored successfully');
})(),
'download' => (function() use ($bm, $body) {
$id = (int)($body['id'] ?? $_GET['id'] ?? 0);
if (!$id) Response::error('id required');
$path = $bm->getDownloadPath($id);
$name = basename($path);
header('Content-Type: application/gzip');
header("Content-Disposition: attachment; filename=\"{$name}\"");
header('Content-Length: ' . filesize($path));
ob_end_clean();
readfile($path);
exit;
})(),
'delete' => (function() use ($bm, $body, $isAdmin) {
if (!$isAdmin) Response::error('Admin only', 403);
$id = (int)($body['id'] ?? 0);
if (!$id) Response::error('id required');
$bm->delete($id);
audit('backup_delete', 'backup', ['id' => $id]);
Response::success(null, 'Backup deleted');
})(),
'schedule' => (function() use ($bm, $body, $accountId, $isAdmin) {
if (!$isAdmin) Response::error('Admin only', 403);
if (!$accountId) Response::error('account_id required');
$freq = $body['frequency'] ?? 'daily';
$type = $body['type'] ?? 'full';
$retain = (int)($body['retain'] ?? 7);
$bm->setSchedule($accountId, $freq, $type, $retain);
Response::success(null, 'Backup schedule saved');
})(),
'get-schedule' => (function() use ($bm, $accountId) {
if (!$accountId) Response::error('account_id required');
Response::success($bm->getSchedule($accountId));
})(),
'upload-remote' => (function() use ($bm, $body, $isAdmin) {
if (!$isAdmin) Response::error('Admin only', 403);
$id = (int)($body['id'] ?? 0);
$remote = trim($body['remote'] ?? '');
if (!$id || !$remote) Response::error('id and remote required');
$out = $bm->uploadRemote($id, $remote);
Response::success(['output' => $out], 'Upload complete');
})(),
default => Response::error('Unknown action', 404),
};