506 lines
25 KiB
HTML
506 lines
25 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}2FA Device Details - Account Security{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="content">
|
|
<div class="container-fluid">
|
|
<!-- Page Header -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="page-header">
|
|
<div class="page-title">
|
|
<h4>
|
|
<a href="{% url 'accounts:two_factor_device_list' %}" class="me-3">
|
|
<i class="fas fa-arrow-left"></i>
|
|
</a>
|
|
2FA Device Details
|
|
</h4>
|
|
<h6>View and manage two-factor authentication device</h6>
|
|
</div>
|
|
<div class="page-btn">
|
|
<a href="{% url 'accounts:two_factor_device_update' object.pk %}" class="btn btn-secondary me-2">
|
|
<i class="fas fa-edit me-1"></i>Edit Device
|
|
</a>
|
|
<a href="#" class="btn btn-primary" onclick="testDevice()">
|
|
<i class="fas fa-vial me-1"></i>Test Device
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Device Information -->
|
|
<div class="col-lg-8 col-md-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-shield-alt me-2"></i>
|
|
Device Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-2 text-center">
|
|
<div class="device-icon-large mb-3">
|
|
{% if object.device_type == 'authenticator' %}
|
|
<i class="fas fa-mobile-alt fa-4x text-primary"></i>
|
|
{% elif object.device_type == 'hardware_key' %}
|
|
<i class="fas fa-key fa-4x text-success"></i>
|
|
{% elif object.device_type == 'sms' %}
|
|
<i class="fas fa-sms fa-4x text-warning"></i>
|
|
{% else %}
|
|
<i class="fas fa-shield-alt fa-4x text-info"></i>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-10">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Device Name</label>
|
|
<div class="info-value">
|
|
<strong>{{ object.name|default:"Google Authenticator" }}</strong>
|
|
</div>
|
|
</div>
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Device Type</label>
|
|
<div class="info-value">
|
|
{% if object.device_type == 'authenticator' %}
|
|
<span class="badge bg-primary">
|
|
<i class="fas fa-mobile-alt me-1"></i>Mobile App
|
|
</span>
|
|
{% elif object.device_type == 'hardware_key' %}
|
|
<span class="badge bg-success">
|
|
<i class="fas fa-key me-1"></i>Hardware Key
|
|
</span>
|
|
{% elif object.device_type == 'sms' %}
|
|
<span class="badge bg-warning">
|
|
<i class="fas fa-sms me-1"></i>SMS
|
|
</span>
|
|
{% else %}
|
|
<span class="badge bg-info">
|
|
<i class="fas fa-shield-alt me-1"></i>Other
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Status</label>
|
|
<div class="info-value">
|
|
{% if object.is_active %}
|
|
<span class="badges bg-lightgreen">
|
|
<i class="fas fa-check-circle me-1"></i>Active
|
|
</span>
|
|
{% else %}
|
|
<span class="badges bg-lightred">
|
|
<i class="fas fa-times-circle me-1"></i>Inactive
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Added Date</label>
|
|
<div class="info-value">
|
|
<strong>{{ object.created_at|default:"Jan 15, 2024"|date:"M d, Y" }}</strong>
|
|
<small class="d-block text-muted">{{ object.created_at|default:"3 months ago"|timesince }} ago</small>
|
|
</div>
|
|
</div>
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Last Used</label>
|
|
<div class="info-value">
|
|
<strong>{{ object.last_used_at|default:"Today 09:30 AM"|date:"M d, Y g:i A" }}</strong>
|
|
<small class="d-block text-muted">{{ object.last_used_at|default:"2 hours ago"|timesince }} ago</small>
|
|
</div>
|
|
</div>
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Usage Count</label>
|
|
<div class="info-value">
|
|
<strong>{{ object.usage_count|default:247 }} times</strong>
|
|
<small class="d-block text-muted">Total authentications</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if object.description %}
|
|
<div class="row mt-4">
|
|
<div class="col-12">
|
|
<div class="info-group">
|
|
<label class="info-label">Description</label>
|
|
<div class="info-value">
|
|
<p class="mb-0">{{ object.description|default:"Primary mobile device for two-factor authentication. Used for daily login verification." }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Security Information -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-lock me-2"></i>
|
|
Security Details
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Device ID</label>
|
|
<div class="info-value">
|
|
<code>{{ object.device_id|default:"auth_device_12345" }}</code>
|
|
<button class="btn btn-sm btn-outline-secondary ms-2" onclick="copyToClipboard('{{ object.device_id|default:"auth_device_12345" }}')">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Backup Codes</label>
|
|
<div class="info-value">
|
|
{% if object.backup_codes_generated %}
|
|
<span class="text-success">
|
|
<i class="fas fa-check-circle me-1"></i>Generated
|
|
</span>
|
|
<button class="btn btn-sm btn-outline-primary ms-2" onclick="showBackupCodes()">
|
|
<i class="fas fa-eye me-1"></i>View Codes
|
|
</button>
|
|
{% else %}
|
|
<span class="text-warning">
|
|
<i class="fas fa-exclamation-triangle me-1"></i>Not Generated
|
|
</span>
|
|
<button class="btn btn-sm btn-outline-warning ms-2" onclick="generateBackupCodes()">
|
|
<i class="fas fa-plus me-1"></i>Generate
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Security Level</label>
|
|
<div class="info-value">
|
|
{% if object.device_type == 'hardware_key' %}
|
|
<span class="badge bg-success">High Security</span>
|
|
{% elif object.device_type == 'authenticator' %}
|
|
<span class="badge bg-primary">Medium Security</span>
|
|
{% else %}
|
|
<span class="badge bg-warning">Basic Security</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="info-group mb-3">
|
|
<label class="info-label">Verification Method</label>
|
|
<div class="info-value">
|
|
{% if object.device_type == 'authenticator' %}
|
|
<span class="text-info">Time-based One-Time Password (TOTP)</span>
|
|
{% elif object.device_type == 'hardware_key' %}
|
|
<span class="text-success">FIDO2/WebAuthn</span>
|
|
{% elif object.device_type == 'sms' %}
|
|
<span class="text-warning">SMS Code</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Usage History -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-history me-2"></i>
|
|
Recent Usage History
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Date & Time</th>
|
|
<th>IP Address</th>
|
|
<th>Location</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>
|
|
<strong>Today 09:30 AM</strong>
|
|
<small class="d-block text-muted">Apr 15, 2024</small>
|
|
</td>
|
|
<td>192.168.1.100</td>
|
|
<td>
|
|
<i class="fas fa-map-marker-alt text-muted me-1"></i>
|
|
New York, NY
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-success">Success</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<strong>Yesterday 02:15 PM</strong>
|
|
<small class="d-block text-muted">Apr 14, 2024</small>
|
|
</td>
|
|
<td>192.168.1.100</td>
|
|
<td>
|
|
<i class="fas fa-map-marker-alt text-muted me-1"></i>
|
|
New York, NY
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-success">Success</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<strong>Apr 13, 08:45 AM</strong>
|
|
<small class="d-block text-muted">Apr 13, 2024</small>
|
|
</td>
|
|
<td>10.0.0.50</td>
|
|
<td>
|
|
<i class="fas fa-map-marker-alt text-muted me-1"></i>
|
|
Office Network
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-success">Success</span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="text-center mt-3">
|
|
<a href="#" class="btn btn-outline-primary btn-sm">
|
|
<i class="fas fa-history me-1"></i>View Full History
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions Sidebar -->
|
|
<div class="col-lg-4 col-md-12">
|
|
<!-- Quick Actions -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-bolt me-2"></i>
|
|
Quick Actions
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<button type="button" class="btn btn-primary" onclick="testDevice()">
|
|
<i class="fas fa-vial me-2"></i>Test Device
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary" onclick="regenerateSecret()">
|
|
<i class="fas fa-sync me-2"></i>Regenerate Secret
|
|
</button>
|
|
<button type="button" class="btn btn-outline-info" onclick="downloadQRCode()">
|
|
<i class="fas fa-qrcode me-2"></i>Download QR Code
|
|
</button>
|
|
<button type="button" class="btn btn-outline-warning" onclick="generateBackupCodes()">
|
|
<i class="fas fa-key me-2"></i>Generate Backup Codes
|
|
</button>
|
|
<hr>
|
|
<button type="button" class="btn btn-outline-danger" onclick="confirmDeactivate()">
|
|
<i class="fas fa-pause me-2"></i>Deactivate Device
|
|
</button>
|
|
<a href="{% url 'accounts:two_factor_device_delete' object.pk %}" class="btn btn-danger">
|
|
<i class="fas fa-trash me-2"></i>Remove Device
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Security Tips -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-lightbulb me-2"></i>
|
|
Security Tips
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="security-tips">
|
|
<div class="tip-item mb-3">
|
|
<i class="fas fa-check-circle text-success me-2"></i>
|
|
<small>Test your device regularly to ensure it's working</small>
|
|
</div>
|
|
<div class="tip-item mb-3">
|
|
<i class="fas fa-key text-warning me-2"></i>
|
|
<small>Keep backup codes in a secure, offline location</small>
|
|
</div>
|
|
<div class="tip-item mb-3">
|
|
<i class="fas fa-shield-alt text-info me-2"></i>
|
|
<small>Use multiple 2FA methods for redundancy</small>
|
|
</div>
|
|
<div class="tip-item">
|
|
<i class="fas fa-exclamation-triangle text-danger me-2"></i>
|
|
<small>Never share your 2FA codes with anyone</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Device Statistics -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-chart-bar me-2"></i>
|
|
Usage Statistics
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="stat-item mb-3">
|
|
<div class="d-flex justify-content-between">
|
|
<span>Total Uses</span>
|
|
<strong class="text-primary">247</strong>
|
|
</div>
|
|
</div>
|
|
<div class="stat-item mb-3">
|
|
<div class="d-flex justify-content-between">
|
|
<span>This Month</span>
|
|
<strong class="text-success">42</strong>
|
|
</div>
|
|
</div>
|
|
<div class="stat-item mb-3">
|
|
<div class="d-flex justify-content-between">
|
|
<span>Success Rate</span>
|
|
<strong class="text-info">99.6%</strong>
|
|
</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="d-flex justify-content-between">
|
|
<span>Failed Attempts</span>
|
|
<strong class="text-warning">1</strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function testDevice() {
|
|
const button = event.target.closest('button');
|
|
const originalText = button.innerHTML;
|
|
|
|
// Show loading state
|
|
button.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Testing...';
|
|
button.disabled = true;
|
|
|
|
// Simulate test
|
|
setTimeout(() => {
|
|
alert('Test verification code sent to your device. Please check and verify.');
|
|
button.innerHTML = originalText;
|
|
button.disabled = false;
|
|
}, 2000);
|
|
}
|
|
|
|
function regenerateSecret() {
|
|
if (confirm('Are you sure you want to regenerate the secret? You will need to reconfigure your authenticator app.')) {
|
|
alert('Secret regenerated successfully. Please scan the new QR code.');
|
|
}
|
|
}
|
|
|
|
function downloadQRCode() {
|
|
alert('QR code download functionality would be implemented here.');
|
|
}
|
|
|
|
function generateBackupCodes() {
|
|
if (confirm('Generate new backup codes? This will invalidate any existing backup codes.')) {
|
|
alert('New backup codes generated. Please save them in a secure location.');
|
|
}
|
|
}
|
|
|
|
function showBackupCodes() {
|
|
alert('Backup codes display functionality would be implemented here.');
|
|
}
|
|
|
|
function confirmDeactivate() {
|
|
if (confirm('Are you sure you want to deactivate this device? You will not be able to use it for authentication.')) {
|
|
alert('Device deactivated successfully.');
|
|
}
|
|
}
|
|
|
|
function copyToClipboard(text) {
|
|
navigator.clipboard.writeText(text).then(function() {
|
|
// Show success feedback
|
|
const button = event.target.closest('button');
|
|
const originalIcon = button.innerHTML;
|
|
button.innerHTML = '<i class="fas fa-check"></i>';
|
|
|
|
setTimeout(() => {
|
|
button.innerHTML = originalIcon;
|
|
}, 2000);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.info-label {
|
|
font-weight: 600;
|
|
color: #6c757d;
|
|
font-size: 0.875rem;
|
|
margin-bottom: 5px;
|
|
display: block;
|
|
}
|
|
|
|
.info-value {
|
|
color: #495057;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.device-icon-large {
|
|
padding: 20px;
|
|
background: #f8f9fa;
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.security-tips .tip-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.stat-item {
|
|
padding: 8px 0;
|
|
border-bottom: 1px solid #eee;
|
|
}
|
|
|
|
.stat-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.device-icon-large {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.page-btn {
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.page-btn .btn {
|
|
display: block;
|
|
width: 100%;
|
|
margin-bottom: 10px;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|