Spaces:
Runtime error
Runtime error
File size: 11,739 Bytes
6a5b8d8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
{% extends "base.html" %}
{% block title %}User Profile - Outline VPN{% endblock %}
{% block content %}
<div class="dashboard-container">
{% include 'sidebar.html' %}
<main class="main-content">
<div class="container">
<h1 class="h3 mb-4">User Profile</h1>
<div class="row">
<!-- Profile Information -->
<div class="col-lg-8">
<div class="dashboard-card">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="h5 mb-0">Profile Information</h2>
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#editProfileModal">
<i class="bi bi-pencil me-2"></i>Edit Profile
</button>
</div>
<div class="row">
<div class="col-md-6">
<p class="text-muted mb-1">Username</p>
<p class="h6">{{ current_user.username }}</p>
</div>
<div class="col-md-6">
<p class="text-muted mb-1">Role</p>
<p class="h6">{{ current_user.role.value|title }}</p>
</div>
<div class="col-md-6 mt-3">
<p class="text-muted mb-1">Account Status</p>
<p class="h6">
<span class="status-indicator status-{{ current_user.status.value }}"></span>
{{ current_user.status.value|title }}
</p>
</div>
<div class="col-md-6 mt-3">
<p class="text-muted mb-1">Member Since</p>
<p class="h6">{{ current_user.created_at.strftime('%B %d, %Y') }}</p>
</div>
</div>
</div>
<!-- Security Settings -->
<div class="dashboard-card mt-4">
<h2 class="h5 mb-4">Security Settings</h2>
<!-- Change Password -->
<div class="mb-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
<h3 class="h6 mb-1">Password</h3>
<p class="text-muted small mb-0">Last changed {{ current_user.password_changed_at.strftime('%B %d, %Y') if current_user.password_changed_at else 'Never' }}</p>
</div>
<button class="btn btn-outline-primary btn-sm" data-bs-toggle="modal" data-bs-target="#changePasswordModal">
Change Password
</button>
</div>
</div>
<!-- Two-Factor Authentication -->
<div class="mb-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
<h3 class="h6 mb-1">Two-Factor Authentication</h3>
<p class="text-muted small mb-0">Add an extra layer of security to your account</p>
</div>
<button class="btn btn-outline-primary btn-sm" data-bs-toggle="modal" data-bs-target="#setup2FAModal">
{% if current_user.two_factor_enabled %}Manage 2FA{% else %}Enable 2FA{% endif %}
</button>
</div>
</div>
</div>
</div>
<!-- Active Sessions -->
<div class="col-lg-4">
<div class="dashboard-card">
<h2 class="h5 mb-4">Active Sessions</h2>
<div class="active-sessions">
{% for session in user_sessions %}
<div class="session-item mb-3 p-3 border rounded">
<div class="d-flex justify-content-between align-items-start mb-2">
<div>
<h6 class="mb-1">{{ session.device_info }}</h6>
<small class="text-muted">{{ session.ip_address }}</small>
</div>
{% if session.is_current %}
<span class="badge bg-success">Current</span>
{% endif %}
</div>
<div class="small text-muted mb-2">
Last active: {{ session.last_active.strftime('%B %d, %Y %H:%M') }}
</div>
{% if not session.is_current %}
<button class="btn btn-danger btn-sm" onclick="terminateSession('{{ session.id }}')">
<i class="bi bi-x-circle me-1"></i>Terminate
</button>
{% endif %}
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Edit Profile Modal -->
<div class="modal fade" id="editProfileModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit Profile</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form action="{{ url_for('update_profile') }}" method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Username</label>
<input type="text" class="form-control" name="username" value="{{ current_user.username }}" required>
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" class="form-control" name="email" value="{{ current_user.email }}" required>
</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">Save Changes</button>
</div>
</form>
</div>
</div>
</div>
<!-- Change Password Modal -->
<div class="modal fade" id="changePasswordModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Change Password</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form action="{{ url_for('change_password') }}" method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Current Password</label>
<input type="password" class="form-control" name="current_password" required>
</div>
<div class="mb-3">
<label class="form-label">New Password</label>
<input type="password" class="form-control" name="new_password" required minlength="8">
</div>
<div class="mb-3">
<label class="form-label">Confirm New Password</label>
<input type="password" class="form-control" name="confirm_password" required minlength="8">
</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">Change Password</button>
</div>
</form>
</div>
</div>
</div>
<!-- Setup 2FA Modal -->
<div class="modal fade" id="setup2FAModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Two-Factor Authentication</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
{% if not current_user.two_factor_enabled %}
<div class="text-center mb-4">
<img src="{{ qr_code_url }}" alt="2FA QR Code" class="img-fluid mb-3">
<p class="mb-1">Scan this QR code with your authenticator app</p>
<p class="text-muted small">or enter this code manually: <code>{{ setup_code }}</code></p>
</div>
<form action="{{ url_for('enable_2fa') }}" method="POST">
<div class="mb-3">
<label class="form-label">Verification Code</label>
<input type="text" class="form-control" name="verification_code" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary">Enable 2FA</button>
</div>
</form>
{% else %}
<div class="text-center mb-4">
<i class="bi bi-shield-check text-success" style="font-size: 3rem;"></i>
<h6 class="mt-3">Two-Factor Authentication is Enabled</h6>
</div>
<form action="{{ url_for('disable_2fa') }}" method="POST">
<div class="mb-3">
<label class="form-label">Enter your password to disable 2FA</label>
<input type="password" class="form-control" name="password" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-danger">Disable 2FA</button>
</div>
</form>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
function terminateSession(sessionId) {
if (confirm('Are you sure you want to terminate this session?')) {
fetch(`/api/sessions/${sessionId}/terminate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
}).then(response => {
if (response.ok) {
location.reload();
}
});
}
}
</script>
{% endblock %}
|