Files
stiftung-management-system/app/templates/stiftung/auth/backup_tokens.html
Jan Remmer Siebels ed6a02232e feat: Implement TOTP-based Two-Factor Authentication
- Add django-otp and qrcode dependencies
- Create comprehensive 2FA views and templates in German
- Add 2FA setup, verification, and management interfaces
- Implement backup token system with 10 recovery codes
- Add TwoFactorMiddleware for session enforcement
- Integrate 2FA controls into user navigation menu
- Support QR code generation for authenticator apps
- Add forms for secure 2FA operations with validation
- Configure OTP settings and admin site integration

Features:
- Optional 2FA (users can enable/disable)
- TOTP compatible with Google Authenticator, Authy, etc.
- Backup codes for emergency access
- German language interface
- Session-based 2FA enforcement
- Password confirmation for sensitive operations
- Production-ready with HTTPS support
2025-09-30 00:10:02 +02:00

157 lines
7.0 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h4 class="mb-0">
<i class="fas fa-key text-success"></i>
Backup-Codes für Zwei-Faktor-Authentifizierung
</h4>
</div>
<div class="card-body">
<div class="alert alert-success">
<h5><i class="fas fa-check-circle"></i> Zwei-Faktor-Authentifizierung aktiviert!</h5>
<p class="mb-0">
Ihr Konto ist jetzt mit Zwei-Faktor-Authentifizierung geschützt.
</p>
</div>
<div class="alert alert-warning">
<h6><i class="fas fa-exclamation-triangle"></i> Wichtig: Backup-Codes sicher speichern</h6>
<p class="mb-0">
Diese Backup-Codes können Sie verwenden, falls Sie keinen Zugriff auf Ihre
Authenticator-App haben. <strong>Speichern Sie diese Codes an einem sicheren Ort!</strong>
</p>
</div>
<div class="row">
<div class="col-md-6">
<h5>Ihre Backup-Codes:</h5>
<div class="bg-light p-3 rounded mb-3" id="backup-codes">
{% for token in backup_tokens %}
<div class="font-monospace fw-bold mb-2">{{ token }}</div>
{% endfor %}
</div>
<div class="d-grid gap-2">
<button type="button" class="btn btn-outline-primary" onclick="copyBackupCodes()">
<i class="fas fa-copy"></i>
Codes kopieren
</button>
<button type="button" class="btn btn-outline-secondary" onclick="printBackupCodes()">
<i class="fas fa-print"></i>
Codes drucken
</button>
</div>
</div>
<div class="col-md-6">
<h5>Verwendung der Backup-Codes:</h5>
<ul class="text-muted">
<li>Jeder Code kann nur <strong>einmal</strong> verwendet werden</li>
<li>Geben Sie den Code anstelle des Authenticator-Codes ein</li>
<li>Codes sind 8 Zeichen lang (Buchstaben und Zahlen)</li>
<li>Bewahren Sie die Codes sicher und vertraulich auf</li>
</ul>
<div class="alert alert-info small">
<h6><i class="fas fa-lightbulb"></i> Empfohlene Aufbewahrung:</h6>
<ul class="mb-0 small">
<li>In einem Passwort-Manager</li>
<li>Ausgedruckt in einem Tresor</li>
<li>Verschlüsselt auf einem sicheren Gerät</li>
</ul>
</div>
</div>
</div>
<div class="text-center mt-4">
<a href="{% url 'stiftung:dashboard' %}" class="btn btn-primary btn-lg">
<i class="fas fa-home"></i>
Weiter zum Dashboard
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
function copyBackupCodes() {
const codes = [
{% for token in backup_tokens %}'{{ token }}'{% if not forloop.last %},{% endif %}{% endfor %}
];
const text = codes.join('\n');
navigator.clipboard.writeText(text).then(function() {
// Show success message
const btn = event.target.closest('button');
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-check text-success"></i> Kopiert!';
btn.classList.add('btn-success');
btn.classList.remove('btn-outline-primary');
setTimeout(function() {
btn.innerHTML = originalText;
btn.classList.remove('btn-success');
btn.classList.add('btn-outline-primary');
}, 2000);
}).catch(function(err) {
alert('Fehler beim Kopieren: ' + err);
});
}
function printBackupCodes() {
const codes = [
{% for token in backup_tokens %}'{{ token }}'{% if not forloop.last %},{% endif %}{% endfor %}
];
const printWindow = window.open('', '_blank');
printWindow.document.write(`
<html>
<head>
<title>Backup-Codes - Stiftung Management System</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
h1 { color: #333; }
.codes { background: #f8f9fa; padding: 20px; border-radius: 5px; }
.code { font-family: monospace; font-size: 14px; margin: 10px 0; font-weight: bold; }
.warning { color: #d63384; font-weight: bold; margin: 20px 0; }
.date { color: #666; font-size: 12px; }
</style>
</head>
<body>
<h1>Backup-Codes für Zwei-Faktor-Authentifizierung</h1>
<p><strong>Konto:</strong> ${window.location.hostname}</p>
<p class="date"><strong>Generiert am:</strong> ${new Date().toLocaleString('de-DE')}</p>
<div class="warning">
⚠️ WICHTIG: Diese Codes sind vertraulich und können nur einmal verwendet werden!
</div>
<div class="codes">
${codes.map(code => '<div class="code">' + code + '</div>').join('')}
</div>
<p><strong>Verwendung:</strong></p>
<ul>
<li>Verwenden Sie diese Codes, falls Sie keinen Zugriff auf Ihre Authenticator-App haben</li>
<li>Geben Sie einen Code anstelle des Authenticator-Codes ein</li>
<li>Jeder Code kann nur einmal verwendet werden</li>
<li>Bewahren Sie diese Codes sicher auf</li>
</ul>
</body>
</html>
`);
printWindow.document.close();
printWindow.print();
}
</script>
{% endblock %}