zitinexus-router-script/UI/public/dashboard.php

433 lines
20 KiB
PHP

<?php
/**
* Main dashboard for ZitiNexus Router Enrollment UI
*/
require_once '../includes/auth.php';
require_once '../includes/enrollment.php';
// Require authentication
AuthManager::requireAuth();
// Check if user requires initial setup
if (AuthManager::requiresSetup()) {
header('Location: setup.php');
exit;
}
// Get current user
$currentUser = AuthManager::getCurrentUser();
// Initialize enrollment manager
$enrollmentManager = new EnrollmentManager();
// Handle AJAX requests
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
header('Content-Type: application/json');
if (isset($_GET['action']) && $_GET['action'] === 'get_status') {
// Get system status
$status = $enrollmentManager->getSystemStatus();
echo json_encode($status);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'enroll') {
// Handle enrollment request
AuthManager::requireCSRF();
$hashKey = sanitizeInput($_POST['hashKey'] ?? '');
$apiEndpoint = sanitizeInput($_POST['apiEndpoint'] ?? DEFAULT_API_ENDPOINT);
// Validate inputs
if (!ApiClient::validateHashKey($hashKey)) {
echo json_encode(['success' => false, 'error' => 'Invalid hash key format']);
exit;
}
if (!ApiClient::validateApiEndpoint($apiEndpoint)) {
echo json_encode(['success' => false, 'error' => 'Invalid API endpoint format']);
exit;
}
// Start enrollment
$result = $enrollmentManager->enrollRouter($hashKey, $apiEndpoint);
echo json_encode($result);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'cleanup') {
// Handle cleanup request
AuthManager::requireCSRF();
// Start cleanup
$result = $enrollmentManager->cleanupRouter();
echo json_encode($result);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'change_credentials') {
// Handle credentials change request
AuthManager::requireCSRF();
$currentPassword = $_POST['current_password'] ?? '';
$newUsername = $_POST['new_username'] ?? '';
$newPassword = $_POST['new_password'] ?? '';
$result = AuthManager::changeCredentials($currentPassword, $newUsername, $newPassword);
echo json_encode($result);
exit;
}
}
// Get system status for initial page load
$systemStatus = $enrollmentManager->getSystemStatus();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo APP_NAME; ?> - Dashboard</title>
<link rel="stylesheet" href="assets/css/style.css">
<link rel="icon" type="image/x-icon" href="assets/images/favicon.ico">
</head>
<body>
<div class="dashboard-container">
<!-- Header -->
<header class="header">
<div class="header-content">
<h1 class="header-title"><?php echo APP_NAME; ?></h1>
<div class="header-actions">
<div class="user-info">
Welcome, <strong><?php echo htmlspecialchars($currentUser['username']); ?></strong>
<span class="text-xs">
| Logged in: <?php echo date('M j, Y g:i A', $currentUser['login_time']); ?>
</span>
</div>
<button id="refreshStatus" class="btn btn-secondary" title="Refresh System Status">
🔄 Refresh
</button>
<button id="settingsBtn" class="btn btn-secondary" title="Account Settings">
⚙️ Settings
</button>
<a href="index.php?action=logout" class="btn btn-secondary">
Logout
</a>
</div>
</div>
</header>
<!-- Main Content -->
<main class="main-content">
<!-- System Status Card -->
<div class="card">
<div class="card-header">
<h2 class="card-title">System Status</h2>
</div>
<div class="card-body">
<div class="status-grid">
<div class="status-item">
<div id="zitiStatusIcon" class="status-icon <?php echo $systemStatus['ziti_status'] === 'installed' ? 'success' : 'error'; ?>">
<?php echo $systemStatus['ziti_status'] === 'installed' ? '✓' : '✗'; ?>
</div>
<div class="status-content">
<h4>Ziti CLI Status</h4>
<p id="zitiStatus">
<?php
if ($systemStatus['ziti_status'] === 'installed') {
echo 'Installed (' . htmlspecialchars($systemStatus['ziti_version']) . ')';
} else {
echo 'Not Installed';
}
?>
</p>
</div>
</div>
<div class="status-item">
<div id="serviceStatusIcon" class="status-icon <?php echo $systemStatus['service_active'] ? 'success' : 'error'; ?>">
<?php echo $systemStatus['service_active'] ? '▶' : '⏹'; ?>
</div>
<div class="status-content">
<h4>Router Service</h4>
<p id="serviceStatus">
<?php echo $systemStatus['service_active'] ? 'Running' : 'Stopped'; ?>
</p>
</div>
</div>
<div class="status-item">
<div id="configStatusIcon" class="status-icon <?php
if ($systemStatus['config_exists'] && $systemStatus['certificates_exist']) {
echo 'success';
} elseif ($systemStatus['config_exists']) {
echo 'warning';
} else {
echo 'error';
}
?>">
<?php
if ($systemStatus['config_exists'] && $systemStatus['certificates_exist']) {
echo '⚙';
} elseif ($systemStatus['config_exists']) {
echo '⚠';
} else {
echo '✗';
}
?>
</div>
<div class="status-content">
<h4>Configuration</h4>
<p id="configStatus">
<?php
if ($systemStatus['config_exists'] && $systemStatus['certificates_exist']) {
echo 'Configured';
} elseif ($systemStatus['config_exists']) {
echo 'Partial';
} else {
echo 'Not Configured';
}
?>
</p>
</div>
</div>
<div class="status-item">
<div class="status-icon success">
🖥
</div>
<div class="status-content">
<h4>Hostname</h4>
<p id="hostname"><?php echo htmlspecialchars($systemStatus['hostname']); ?></p>
</div>
</div>
</div>
</div>
</div>
<!-- Enrollment Form Card -->
<div class="card">
<div class="card-header">
<h2 class="card-title">Router Enrollment</h2>
</div>
<div class="card-body">
<form id="enrollmentForm" class="enrollment-form">
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
<div class="form-row">
<div class="form-group">
<label for="apiEndpoint" class="form-label">API Endpoint</label>
<input
type="url"
id="apiEndpoint"
name="apiEndpoint"
class="form-input"
value="<?php echo DEFAULT_API_ENDPOINT; ?>"
placeholder="https://backend.zitinexus.com"
required
>
<small class="text-sm text-secondary">ZitiNexus Portal API endpoint</small>
</div>
<div class="form-group">
<label for="hashKey" class="form-label">Hash Key</label>
<input
type="text"
id="hashKey"
name="hashKey"
class="form-input"
placeholder="32-character hexadecimal hash key"
maxlength="32"
pattern="[a-fA-F0-9]{32}"
required
>
<small class="text-sm text-secondary">Router enrollment hash key from ZitiNexus Portal</small>
</div>
</div>
<div class="form-group-full">
<button type="submit" id="enrollBtn" class="btn btn-primary">
Start Enrollment
</button>
<button type="button" id="cleanupBtn" class="btn btn-danger" style="margin-left: 1rem;">
🗑️ Clean Up Router
</button>
<button type="button" id="clearLogs" class="btn btn-secondary" style="margin-left: 1rem;">
Clear Logs
</button>
</div>
</form>
<!-- Progress Container -->
<div id="progressContainer" class="progress-container">
<div class="progress-bar">
<div id="progressFill" class="progress-fill"></div>
</div>
<div class="progress-steps">
<div class="progress-step">Initialize</div>
<div class="progress-step">Requirements</div>
<div class="progress-step">Install</div>
<div class="progress-step">Directories</div>
<div class="progress-step">Register</div>
<div class="progress-step">Configure</div>
<div class="progress-step">Enroll</div>
<div class="progress-step">Service</div>
<div class="progress-step">Start</div>
<div class="progress-step">Report</div>
<div class="progress-step">Complete</div>
</div>
<div id="logContainer" class="log-container">
<!-- Log entries will be added here dynamically -->
</div>
</div>
</div>
</div>
<!-- Information Card -->
<div class="card">
<div class="card-header">
<h2 class="card-title">Information</h2>
</div>
<div class="card-body">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem;">
<div>
<h4 class="font-medium mb-2">How to Use</h4>
<ol class="text-sm text-secondary" style="padding-left: 1.5rem;">
<li>Obtain a hash key from the ZitiNexus Portal by creating a router enrollment</li>
<li>Enter the API endpoint (default is pre-filled)</li>
<li>Paste the 32-character hash key</li>
<li>Click "Start Enrollment" to begin the process</li>
<li>Monitor the progress and logs for status updates</li>
<li><strong>To re-enroll:</strong> Click "Clean Up Router" to reset configuration, then enter a new hash key</li>
</ol>
</div>
<div>
<h4 class="font-medium mb-2">System Requirements</h4>
<ul class="text-sm text-secondary" style="padding-left: 1.5rem;">
<li>Ubuntu 22.04 or 24.04 LTS</li>
<li>Root/sudo access required</li>
<li>Internet connectivity</li>
<li>systemctl available</li>
<li>curl and jq packages (auto-installed)</li>
</ul>
</div>
<div>
<h4 class="font-medium mb-2">File Locations</h4>
<ul class="text-sm text-secondary" style="padding-left: 1.5rem;">
<li><code>/etc/zitirouter/</code> - Configuration directory</li>
<li><code>/etc/zitirouter/certs/</code> - Certificates</li>
<li><code>/var/log/ziti-router-enrollment.log</code> - Enrollment log</li>
<li><code>/etc/systemd/system/ziti-router.service</code> - Service file</li>
</ul>
</div>
<div>
<h4 class="font-medium mb-2">Service Management</h4>
<ul class="text-sm text-secondary" style="padding-left: 1.5rem;">
<li><code>systemctl status ziti-router</code> - Check status</li>
<li><code>systemctl start ziti-router</code> - Start service</li>
<li><code>systemctl stop ziti-router</code> - Stop service</li>
<li><code>journalctl -u ziti-router -f</code> - View logs</li>
</ul>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Settings Modal -->
<div id="settingsModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2>⚙️ Account Settings</h2>
<button class="modal-close" id="closeSettingsModal">&times;</button>
</div>
<div class="modal-body">
<form id="settingsForm">
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
<div class="form-group">
<label for="settings_current_password" class="form-label">Current Password</label>
<input
type="password"
id="settings_current_password"
name="current_password"
class="form-input"
placeholder="Enter current password"
required
autocomplete="current-password"
>
<small class="text-sm text-secondary">Required to verify your identity</small>
</div>
<div class="form-group">
<label for="settings_new_username" class="form-label">Username</label>
<input
type="text"
id="settings_new_username"
name="new_username"
class="form-input"
placeholder="Enter new username"
value="<?php echo htmlspecialchars($currentUser['username']); ?>"
minlength="3"
maxlength="20"
pattern="[a-zA-Z0-9_]+"
required
autocomplete="username"
>
<small class="text-sm text-secondary">3-20 characters, letters, numbers, and underscores only</small>
</div>
<div class="form-group">
<label for="settings_new_password" class="form-label">New Password</label>
<input
type="password"
id="settings_new_password"
name="new_password"
class="form-input"
placeholder="Enter new password"
minlength="6"
required
autocomplete="new-password"
>
<small class="text-sm text-secondary">Minimum 6 characters</small>
<div id="settingsPasswordStrength" class="password-strength"></div>
</div>
<div class="form-group">
<label for="settings_confirm_password" class="form-label">Confirm New Password</label>
<input
type="password"
id="settings_confirm_password"
name="confirm_password"
class="form-input"
placeholder="Confirm new password"
minlength="6"
required
autocomplete="new-password"
>
<small class="text-sm text-secondary">Re-enter your new password</small>
<div id="settingsPasswordMatch" class="password-match"></div>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" id="cancelSettings">Cancel</button>
<button type="submit" class="btn btn-primary">
💾 Save Changes
</button>
</div>
</form>
</div>
</div>
</div>
<script src="assets/js/app.js"></script>
</body>
</html>