207 lines
7.6 KiB
HTML
207 lines
7.6 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Device Fingerprinting Demo{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row justify-content-center">
|
|
<div class="col-md-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h1 class="h3 mb-0">Device Fingerprinting Demo</h1>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="device-status" class="alert alert-info">
|
|
{{ device_status }}
|
|
</div>
|
|
|
|
<div id="fingerprint-info" class="mt-4">
|
|
<h5>Device Information:</h5>
|
|
<p><strong>Fingerprint:</strong> <span id="fingerprint-hash">{{ fingerprint_hash }}</span></p>
|
|
|
|
{% if device %}
|
|
<div class="mt-3">
|
|
<p><strong>Device Name:</strong> {{ device.device_name }}</p>
|
|
<p><strong>First Seen:</strong> {{ device.first_seen }}</p>
|
|
<p><strong>Last Seen:</strong> {{ device.last_seen }}</p>
|
|
{% if device.user_agent %}
|
|
<p><strong>User Agent:</strong>
|
|
<small class="text-muted">{{ device.user_agent }}</small>
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<button id="update-name-btn" class="btn btn-primary" onclick="showNameModal()">
|
|
{% if device %}
|
|
Update Device Name
|
|
{% else %}
|
|
Name This Device
|
|
{% endif %}
|
|
</button>
|
|
|
|
{% if fingerprint_hash %}
|
|
<button class="btn btn-outline-secondary ms-2" onclick="refreshFingerprint()">
|
|
Refresh Fingerprint
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if fingerprint_hash %}
|
|
<div class="card mt-4">
|
|
<div class="card-body text-center">
|
|
<div class="spinner-border text-primary" role="status">
|
|
<span class="visually-hidden">Loading...</span>
|
|
</div>
|
|
<p class="mt-2">Generating device fingerprint...</p>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal for updating device name -->
|
|
<div class="modal fade" id="nameModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">
|
|
{% if device %}
|
|
Update Device Name
|
|
{% else %}
|
|
Name This Device
|
|
{% endif %}
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label for="device-name-input" class="form-label">Device Name</label>
|
|
<input type="text"
|
|
id="device-name-input"
|
|
class="form-control"
|
|
placeholder="Enter a name for this device"
|
|
{% if device and device.device_name %}value="{{ device.device_name }}"{% endif %}>
|
|
</div>
|
|
<small class="text-muted">
|
|
This name will be displayed when you visit from this device.
|
|
</small>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-primary" onclick="updateDeviceName()">Save</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
let currentFingerprint = '{{ fingerprint_hash }}';
|
|
|
|
// Generate fingerprint
|
|
async function generateFingerprint() {
|
|
const canvas = document.createElement('canvas');
|
|
const ctx = canvas.getContext('2d');
|
|
ctx.textBaseline = 'top';
|
|
ctx.font = '14px Arial';
|
|
ctx.textBaseline = 'alphabetic';
|
|
ctx.fillStyle = '#f60';
|
|
ctx.fillRect(125, 1, 62, 20);
|
|
ctx.fillStyle = '#069';
|
|
ctx.fillText('Device fingerprint', 2, 15);
|
|
const canvasFingerprint = canvas.toDataURL();
|
|
|
|
// Get available fonts (simplified)
|
|
const fonts = ['Arial', 'Helvetica', 'Times New Roman', 'Courier', 'Verdana', 'Georgia', 'Palatino', 'Garamond', 'Bookman', 'Tahoma'];
|
|
|
|
const fingerprintData = {
|
|
user_agent: navigator.userAgent,
|
|
screen_width: screen.width,
|
|
screen_height: screen.height,
|
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
language: navigator.language,
|
|
platform: navigator.platform,
|
|
canvas_fingerprint: canvasFingerprint,
|
|
fonts: fonts
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/fingerprint', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(fingerprintData)
|
|
});
|
|
|
|
if (response.ok) {
|
|
const result = await response.json();
|
|
currentFingerprint = result.fingerprint_hash;
|
|
|
|
// Reload page to show updated info
|
|
window.location.reload();
|
|
} else {
|
|
console.error('Failed to generate fingerprint:', response.statusText);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error generating fingerprint:', error);
|
|
}
|
|
}
|
|
|
|
function showNameModal() {
|
|
const modal = new bootstrap.Modal(document.getElementById('nameModal'));
|
|
modal.show();
|
|
}
|
|
|
|
async function updateDeviceName() {
|
|
const nameInput = document.getElementById('device-name-input');
|
|
const name = nameInput.value.trim();
|
|
|
|
if (!name) {
|
|
nameInput.classList.add('is-invalid');
|
|
return;
|
|
}
|
|
|
|
nameInput.classList.remove('is-invalid');
|
|
|
|
try {
|
|
const response = await fetch('/api/device/name', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'x-fingerprint': currentFingerprint
|
|
},
|
|
body: JSON.stringify({ device_name: name })
|
|
});
|
|
|
|
if (response.ok) {
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('nameModal'));
|
|
modal.hide();
|
|
window.location.reload();
|
|
} else {
|
|
console.error('Failed to update device name:', response.statusText);
|
|
alert('Failed to update device name. Please try again.');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error updating device name:', error);
|
|
alert('Error updating device name. Please try again.');
|
|
}
|
|
}
|
|
|
|
function refreshFingerprint() {
|
|
if (confirm('This will generate a new fingerprint for your device. Continue?')) {
|
|
generateFingerprint();
|
|
}
|
|
}
|
|
|
|
// Generate fingerprint on page load if not already done
|
|
if (!currentFingerprint) {
|
|
generateFingerprint();
|
|
}
|
|
</script>
|
|
{% endblock %} |