JRNET / templates /admin.html
Factor Studios
Upload 96 files
6a5b8d8 verified
{% extends "base.html" %}
{% block title %}Server Administration - Outline VPN{% endblock %}
{% block content %}
<div class="dashboard-container">
{% include 'sidebar.html' %}
<main class="main-content">
<div class="container">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3">Server Administration</h1>
<div class="btn-group">
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#backupModal">
<i class="bi bi-download me-2"></i>Backup Configuration
</button>
<button class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#restoreModal">
<i class="bi bi-upload me-2"></i>Restore
</button>
</div>
</div>
<div class="row">
<!-- Server Configuration -->
<div class="col-lg-8">
<div class="dashboard-card">
<h2 class="h5 mb-4">Server Configuration</h2>
<form id="serverConfigForm" action="{{ url_for('update_server_config') }}" method="POST">
<!-- Network Settings -->
<div class="mb-4">
<h3 class="h6 mb-3">Network Settings</h3>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Server Port</label>
<input type="number" class="form-control" name="port" value="{{ config.port }}" required>
</div>
<div class="col-md-6">
<label class="form-label">Access Method</label>
<select class="form-select" name="access_method">
<option value="direct" {% if config.access_method == 'direct' %}selected{% endif %}>Direct</option>
<option value="proxy" {% if config.access_method == 'proxy' %}selected{% endif %}>Proxy</option>
</select>
</div>
</div>
</div>
<!-- Protocol Settings -->
<div class="mb-4">
<h3 class="h6 mb-3">Protocol Settings</h3>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Default Protocol</label>
<select class="form-select" name="default_protocol">
<option value="shadowsocks" {% if config.default_protocol == 'shadowsocks' %}selected{% endif %}>Shadowsocks</option>
<option value="wireguard" {% if config.default_protocol == 'wireguard' %}selected{% endif %}>WireGuard</option>
<option value="openvpn" {% if config.default_protocol == 'openvpn' %}selected{% endif %}>OpenVPN</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Encryption Method</label>
<select class="form-select" name="encryption_method">
<option value="aes-256-gcm" {% if config.encryption_method == 'aes-256-gcm' %}selected{% endif %}>AES-256-GCM</option>
<option value="chacha20-poly1305" {% if config.encryption_method == 'chacha20-poly1305' %}selected{% endif %}>ChaCha20-Poly1305</option>
</select>
</div>
</div>
</div>
<!-- Security Settings -->
<div class="mb-4">
<h3 class="h6 mb-3">Security Settings</h3>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Session Timeout (minutes)</label>
<input type="number" class="form-control" name="session_timeout" value="{{ config.session_timeout }}" required>
</div>
<div class="col-md-6">
<label class="form-label">Max Failed Attempts</label>
<input type="number" class="form-control" name="max_failed_attempts" value="{{ config.max_failed_attempts }}" required>
</div>
</div>
</div>
<div class="text-end">
<button type="submit" class="btn btn-primary">Save Configuration</button>
</div>
</form>
</div>
<!-- Audit Log -->
<div class="dashboard-card mt-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="h5 mb-0">Audit Log</h2>
<div class="btn-group">
<button class="btn btn-outline-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown">
Export
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{{ url_for('export_audit_log', format='csv') }}">CSV</a></li>
<li><a class="dropdown-item" href="{{ url_for('export_audit_log', format='json') }}">JSON</a></li>
</ul>
</div>
</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Timestamp</th>
<th>User</th>
<th>Action</th>
<th>Details</th>
</tr>
</thead>
<tbody>
{% for log in audit_logs %}
<tr>
<td>{{ log.timestamp.strftime('%Y-%m-%d %H:%M:%S') }}</td>
<td>{{ log.username }}</td>
<td>{{ log.action }}</td>
<td>{{ log.details }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- Active Alerts -->
<div class="dashboard-card mt-4">
<h2 class="h5 mb-4">Active Alerts</h2>
<div class="alerts-list">
{% for alert in active_alerts %}
<div class="alert alert-{{ alert.severity }} d-flex align-items-center">
<i class="bi bi-exclamation-triangle me-2"></i>
<div>
<strong>{{ alert.title }}</strong>
<p class="mb-0 small">{{ alert.message }}</p>
<small class="text-muted">{{ alert.timestamp.strftime('%Y-%m-%d %H:%M:%S') }}</small>
</div>
</div>
{% endfor %}
{% if not active_alerts %}
<p class="text-muted text-center mb-0">No active alerts</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Backup Modal -->
<div class="modal fade" id="backupModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Backup Configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>This will create a backup of your entire server configuration, including:</p>
<ul>
<li>Server settings</li>
<li>User configurations</li>
<li>Security settings</li>
<li>Protocol configurations</li>
</ul>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="includeUserData">
<label class="form-check-label" for="includeUserData">
Include user data and statistics
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="createBackup()">Create Backup</button>
</div>
</div>
</div>
</div>
<!-- Restore Modal -->
<div class="modal fade" id="restoreModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Restore Configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form action="{{ url_for('restore_config') }}" method="POST" enctype="multipart/form-data">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Select Backup File</label>
<input type="file" class="form-control" name="backup_file" accept=".zip,.json" required>
</div>
<div class="alert alert-warning">
<i class="bi bi-exclamation-triangle me-2"></i>
Restoring a backup will overwrite your current configuration. This action cannot be undone.
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Restore Configuration</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
// Real-time system health updates
function updateSystemHealth() {
fetch('/api/system-health')
.then(response => response.json())
.then(data => {
updateProgressBar('cpu-usage', data.cpu_usage);
updateProgressBar('memory-usage', data.memory_usage);
updateProgressBar('disk-usage', data.disk_usage);
});
}
function updateProgressBar(id, value) {
const bar = document.getElementById(id);
const label = bar.previousElementSibling;
bar.style.width = value + '%';
label.textContent = value + '%';
const colorClass = value < 70 ? 'success' : value < 90 ? 'warning' : 'danger';
bar.className = `progress-bar bg-${colorClass}`;
}
// Create backup
function createBackup() {
const includeUserData = document.getElementById('includeUserData').checked;
window.location.href = `{{ url_for('create_backup') }}?include_user_data=${includeUserData}`;
}
// Initialize real-time updates
setInterval(updateSystemHealth, 5000);
</script>
{% endblock %}