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:
105
html/admin.html
105
html/admin.html
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user