131 Zeilen
5.1 KiB
HTML
131 Zeilen
5.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>2FA Verifizierung - Admin Panel</title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<style>
|
|
body {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.login-container {
|
|
background: white;
|
|
padding: 2rem;
|
|
border-radius: 10px;
|
|
box-shadow: 0 0 20px rgba(0,0,0,0.1);
|
|
width: 100%;
|
|
max-width: 400px;
|
|
}
|
|
.logo {
|
|
text-align: center;
|
|
font-size: 3rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.code-input {
|
|
text-align: center;
|
|
font-size: 1.5rem;
|
|
letter-spacing: 0.5rem;
|
|
font-family: monospace;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="login-container">
|
|
<div class="logo">🔐</div>
|
|
<h2 class="text-center mb-4">Zwei-Faktor-Authentifizierung</h2>
|
|
|
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
{% if messages %}
|
|
{% for category, message in messages %}
|
|
<div class="alert alert-{{ 'danger' if category == 'error' else category }} alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% endwith %}
|
|
|
|
<form method="POST">
|
|
<div class="mb-3">
|
|
<label for="token" class="form-label">Authentifizierungscode eingeben</label>
|
|
<input type="text"
|
|
class="form-control code-input"
|
|
id="token"
|
|
name="token"
|
|
placeholder="000000"
|
|
maxlength="6"
|
|
pattern="[0-9]{6}"
|
|
autocomplete="off"
|
|
autofocus
|
|
required>
|
|
<div class="form-text text-center mt-2">
|
|
Geben Sie den 6-stelligen Code aus Ihrer Authenticator-App ein
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-grid gap-2">
|
|
<button type="submit" class="btn btn-primary btn-lg">Verifizieren</button>
|
|
</div>
|
|
|
|
<div class="text-center mt-3">
|
|
<details>
|
|
<summary class="text-muted" style="cursor: pointer;">Backup-Code verwenden</summary>
|
|
<div class="mt-2">
|
|
<p class="small text-muted">
|
|
Falls Sie keinen Zugriff auf Ihre Authenticator-App haben,
|
|
können Sie einen 8-stelligen Backup-Code eingeben.
|
|
</p>
|
|
<input type="text"
|
|
class="form-control code-input mt-2"
|
|
id="backup-token"
|
|
placeholder="ABCD1234"
|
|
maxlength="8"
|
|
pattern="[A-Z0-9]{8}"
|
|
style="letter-spacing: 0.25rem;">
|
|
</div>
|
|
</details>
|
|
</div>
|
|
|
|
<hr class="my-4">
|
|
|
|
<div class="text-center">
|
|
<a href="{{ url_for('auth.logout') }}" class="text-muted">Abbrechen und zur Anmeldung zurück</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script>
|
|
// Auto-format the code input
|
|
document.getElementById('token').addEventListener('input', function(e) {
|
|
// Remove non-digits
|
|
e.target.value = e.target.value.replace(/\D/g, '');
|
|
});
|
|
|
|
// Handle backup code input
|
|
document.getElementById('backup-token').addEventListener('input', function(e) {
|
|
// Convert to uppercase and remove non-alphanumeric
|
|
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
|
|
|
|
// If backup code is being used, copy to main token field
|
|
if (e.target.value.length > 0) {
|
|
document.getElementById('token').value = e.target.value;
|
|
document.getElementById('token').removeAttribute('pattern');
|
|
document.getElementById('token').setAttribute('maxlength', '8');
|
|
}
|
|
});
|
|
|
|
// Reset main field when typing in it
|
|
document.getElementById('token').addEventListener('focus', function(e) {
|
|
document.getElementById('backup-token').value = '';
|
|
e.target.setAttribute('pattern', '[0-9]{6}');
|
|
e.target.setAttribute('maxlength', '6');
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |