Add password protection for critical transmission settings

- Add unlock/lock button for protected settings in admin panel
- Protect AirCarto, uSpot, and miotiq transmission checkboxes
- Require password '123plouf' to enable editing protected checkboxes
- Visual feedback with lock/unlock icons and toast notifications
- Add CLAUDE.md documentation file for development guidance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
AirLab
2025-10-07 14:59:38 +02:00
parent 9de903f2db
commit 79f3ede17f
2 changed files with 360 additions and 15 deletions

View File

@@ -118,23 +118,33 @@
</label>
</div>
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="fw-bold">Protected Settings</span>
<button type="button" class="btn btn-sm btn-outline-primary" onclick="toggleProtectedSettings()" id="unlockBtn">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-lock-fill" viewBox="0 0 16 16">
<path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z"/>
</svg>
Unlock
</button>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" value="" id="check_aircarto" onchange="update_config_sqlite('send_aircarto', this.checked)" disabled>
<input class="form-check-input protected-checkbox" type="checkbox" value="" id="check_aircarto" onchange="update_config_sqlite('send_aircarto', this.checked)" disabled>
<label class="form-check-label" for="check_aircarto">
Send to AirCarto (HTTP)
</label>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" value="" id="check_uSpot" onchange="update_config_sqlite('send_uSpot', this.checked)" disabled>
<input class="form-check-input protected-checkbox" type="checkbox" value="" id="check_uSpot" onchange="update_config_sqlite('send_uSpot', this.checked)" disabled>
<label class="form-check-label" for="check_uSpot">
Send to uSpot (HTTPS)
</label>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" value="" id="check_miotiq" onchange="update_config_sqlite('send_miotiq', this.checked)" disabled>
<input class="form-check-input protected-checkbox" type="checkbox" value="" id="check_miotiq" onchange="update_config_sqlite('send_miotiq', this.checked)" disabled>
<label class="form-check-label" for="check_miotiq">
Send to miotiq (UDP)
</label>
@@ -1396,23 +1406,23 @@ function startEnveaDetection() {
function displayDetectionResults(results) {
console.log("Displaying detection results:", results);
// Hide progress spinner
document.getElementById('detectionProgress').style.display = 'none';
let htmlContent = '<h6>Detection Results:</h6>';
// Create cards for each port result
results.forEach(function(result, index) {
const statusBadge = result.detected ?
'<span class="badge bg-success">Device Detected</span>' :
result.success ?
'<span class="badge bg-warning">No Device</span>' :
const statusBadge = result.detected ?
'<span class="badge bg-success">Device Detected</span>' :
result.success ?
'<span class="badge bg-warning">No Device</span>' :
'<span class="badge bg-danger">Error</span>';
const deviceInfo = result.device_info || (result.detected ? 'Envea Device' : 'None');
const rawData = result.data || 'No data';
htmlContent += `
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
@@ -1442,18 +1452,83 @@ function displayDetectionResults(results) {
</div>
`;
});
// Add summary
const detectedCount = results.filter(r => r.detected).length;
htmlContent += `<div class="alert alert-info mt-3">
<i class="bi bi-info-circle"></i> <strong>Summary:</strong> ${detectedCount} device(s) detected out of ${results.length} ports tested.
</div>`;
document.getElementById('detectionResults').innerHTML = htmlContent;
document.getElementById('startDetectionBtn').style.display = 'inline-block';
document.getElementById('startDetectionBtn').textContent = 'Scan Again';
}
/*
____ _ _ _ ____ _ _ _
| _ \ _ __ ___ | |_ ___ ___| |_ ___ __| | / ___| ___| |_| |_(_)_ __ __ _ ___
| |_) | '__/ _ \| __/ _ \/ __| __/ _ \/ _` | \___ \ / _ \ __| __| | '_ \ / _` / __|
| __/| | | (_) | || __/ (__| || __/ (_| | ___) | __/ |_| |_| | | | | (_| \__ \
|_| |_| \___/ \__\___|\___|\__\___|\__,_| |____/ \___|\__|\__|_|_| |_|\__, |___/
|___/
*/
// Track if protected settings are unlocked
let protectedSettingsUnlocked = false;
function toggleProtectedSettings() {
const unlockBtn = document.getElementById('unlockBtn');
const protectedCheckboxes = document.querySelectorAll('.protected-checkbox');
if (protectedSettingsUnlocked) {
// Lock the settings
protectedSettingsUnlocked = false;
protectedCheckboxes.forEach(checkbox => {
checkbox.disabled = true;
});
// Update button appearance
unlockBtn.classList.remove('btn-success');
unlockBtn.classList.add('btn-outline-primary');
unlockBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-lock-fill" viewBox="0 0 16 16">
<path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z"/>
</svg>
Unlock
`;
// Show toast notification
showToast('Protected settings locked', 'info');
} else {
// Prompt for password
const password = prompt('Enter admin password to unlock protected settings:');
if (password === '123plouf') {
// Correct password - unlock the settings
protectedSettingsUnlocked = true;
protectedCheckboxes.forEach(checkbox => {
checkbox.disabled = false;
});
// Update button appearance
unlockBtn.classList.remove('btn-outline-primary');
unlockBtn.classList.add('btn-success');
unlockBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-unlock-fill" viewBox="0 0 16 16">
<path d="M11 1a2 2 0 0 0-2 2v4a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h5V3a3 3 0 0 1 6 0v4a.5.5 0 0 1-1 0V3a2 2 0 0 0-2-2z"/>
</svg>
Lock
`;
// Show success toast
showToast('Protected settings unlocked! You can now edit the checkboxes.', 'success');
} else if (password !== null) {
// Wrong password (null means user cancelled)
showToast('Incorrect password!', 'error');
}
}
}
</script>