You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
7.3 KiB
HTML
243 lines
7.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<meta name="referrer" content="no-referrer">
|
|
|
|
<!-- Security headers -->
|
|
<meta http-equiv="Content-Security-Policy"
|
|
content="default-src 'self';
|
|
img-src 'self' data:;
|
|
style-src 'self' 'unsafe-inline';
|
|
script-src 'self' 'unsafe-inline';
|
|
font-src 'self' data:;
|
|
connect-src 'self';">
|
|
|
|
<meta http-equiv="X-Content-Type-Options" content="nosniff">
|
|
<meta http-equiv="X-Frame-Options" content="DENY">
|
|
|
|
<title>TorGuard WireGuard Manager</title>
|
|
|
|
<!-- Bootstrap CSS and Icons (Local) -->
|
|
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
|
|
<link href="{{ url_for('static', filename='css/bootstrap-icons.css') }}" rel="stylesheet">
|
|
|
|
<!-- Custom Styles -->
|
|
<style>
|
|
:root {
|
|
--primary-color: #0d6efd;
|
|
--danger-color: #dc3545;
|
|
--success-color: #198754;
|
|
}
|
|
|
|
body {
|
|
background-color: #f8f9fa;
|
|
min-height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.container {
|
|
max-width: 800px;
|
|
flex: 1;
|
|
}
|
|
|
|
.logo {
|
|
max-width: 300px;
|
|
margin: 2rem 0;
|
|
height: auto;
|
|
}
|
|
|
|
.status-badge {
|
|
font-size: 1.1rem;
|
|
padding: 0.5rem 1rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.form-container {
|
|
background: #ffffff;
|
|
padding: 2rem;
|
|
border-radius: 10px;
|
|
box-shadow: 0 0 20px rgba(0,0,0,0.1);
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.btn {
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.btn:hover {
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.alert {
|
|
border-radius: 8px;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.alert-info {
|
|
background-color: #cff4fc;
|
|
border-color: #b6effb;
|
|
}
|
|
|
|
.alert-danger {
|
|
background-color: #f8d7da;
|
|
border-color: #f5c2c7;
|
|
}
|
|
|
|
.alert-success {
|
|
background-color: #d1e7dd;
|
|
border-color: #badbcc;
|
|
}
|
|
|
|
/* Loading spinner */
|
|
.spinner-overlay {
|
|
display: none;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
z-index: 9999;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.spinner-container {
|
|
background: white;
|
|
padding: 2rem;
|
|
border-radius: 10px;
|
|
text-align: center;
|
|
}
|
|
|
|
/* Responsive adjustments */
|
|
@media (max-width: 768px) {
|
|
.form-container {
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.logo {
|
|
max-width: 250px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 576px) {
|
|
.form-container {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.logo {
|
|
max-width: 200px;
|
|
}
|
|
}
|
|
|
|
/* Footer */
|
|
.footer {
|
|
margin-top: auto;
|
|
padding: 1rem 0;
|
|
text-align: center;
|
|
font-size: 0.875rem;
|
|
color: #6c757d;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<!-- Loading Spinner -->
|
|
<div class="spinner-overlay" id="loadingSpinner">
|
|
<div class="spinner-container">
|
|
<div class="spinner-border text-primary mb-2" role="status">
|
|
<span class="visually-hidden">Loading...</span>
|
|
</div>
|
|
<div>Please wait...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container py-4">
|
|
<!-- Header Section -->
|
|
{% if session.authenticated %}
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div>
|
|
<span class="text-muted">Welcome, {{ session.username }}</span>
|
|
</div>
|
|
<div>
|
|
<a href="{{ url_for('logout') }}" class="btn btn-outline-danger">
|
|
<i class="bi bi-box-arrow-right"></i> Logout
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Logo Section -->
|
|
<div class="text-center">
|
|
<img src="{{ url_for('static', filename='logo.png') }}"
|
|
alt="TorGuard Logo"
|
|
class="logo"
|
|
onerror="this.onerror=null; this.src='data:image/svg+xml,<svg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 100 40\'><rect width=\'100\' height=\'40\' fill=\'%23f8f9fa\'/><text x=\'50\' y=\'20\' text-anchor=\'middle\' alignment-baseline=\'middle\' font-family=\'Arial\' font-size=\'16\'>TorGuard</text></svg>';">
|
|
</div>
|
|
|
|
<!-- Flash Messages -->
|
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
{% if messages %}
|
|
{% for category, message in messages %}
|
|
<div class="alert alert-{{ category if category != 'message' else 'info' }} alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% endwith %}
|
|
|
|
<!-- Main Content -->
|
|
{% block content %}{% endblock %}
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<footer class="footer">
|
|
<div class="container">
|
|
<p class="mb-0">TorGuard WireGuard Manager</p>
|
|
{% if session.authenticated %}
|
|
<small>Connected to: {{ request.host }}</small>
|
|
{% endif %}
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- JavaScript Dependencies (Local) -->
|
|
<script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
|
|
|
|
<!-- Common JavaScript -->
|
|
<script>
|
|
// Show loading spinner on form submissions
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const forms = document.querySelectorAll('form');
|
|
const spinner = document.getElementById('loadingSpinner');
|
|
|
|
forms.forEach(form => {
|
|
form.addEventListener('submit', function() {
|
|
if (this.checkValidity()) {
|
|
spinner.style.display = 'flex';
|
|
}
|
|
});
|
|
});
|
|
|
|
// Hide alerts after 5 seconds
|
|
const alerts = document.querySelectorAll('.alert');
|
|
alerts.forEach(alert => {
|
|
setTimeout(() => {
|
|
const bsAlert = new bootstrap.Alert(alert);
|
|
bsAlert.close();
|
|
}, 5000);
|
|
});
|
|
});
|
|
|
|
// Prevent form resubmission on refresh
|
|
if (window.history.replaceState) {
|
|
window.history.replaceState(null, null, window.location.href);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |