Skip to content

Commit c17784f

Browse files
authored
v1.8
1 parent 1dc5f60 commit c17784f

File tree

1 file changed

+70
-5
lines changed

1 file changed

+70
-5
lines changed

data/common.js

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,17 @@
275275
$$('input[type=range]').forEach(el => {rangeSlider(el, false, el.getAttribute('value'));}); // initialise range sliders
276276
}
277277

278-
async function sendUpdates(doAction) {
278+
async function sendUpdates(doAction) {
279+
// Validate AP_Pass before sending
280+
const apPassInput = $('#AP_Pass');
281+
if (apPassInput) {
282+
const errorMessage = validateApPassword(apPassInput.value.trim());
283+
if (errorMessage) {
284+
showInputError(apPassInput, errorMessage);
285+
showAlert('Cannot save settings: Invalid AP password.');
286+
return;
287+
}
288+
}
279289
// send bulk updates to app as json
280290
statusData['action'] = doAction;
281291
const response = await fetch(webServer + '/update', {
@@ -288,6 +298,41 @@
288298

289299
/*********** utility functions ***********/
290300

301+
// Function to validate AP password
302+
function validateApPassword(password) {
303+
const minLength = 8;
304+
const maxLength = 63;
305+
const validAscii = /^[\x20-\x7E]*$/; // Printable ASCII characters only
306+
const strongPassword = /^(?=.*[A-Za-z])(?=.*\d).+$/; // At least one letter and one number
307+
308+
if (password.length < minLength) {
309+
return 'Password must be at least 8 characters long.';
310+
}
311+
if (password.length > maxLength) {
312+
return 'Password cannot exceed 63 characters.';
313+
}
314+
if (!validAscii.test(password)) {
315+
return 'Password must contain only printable ASCII characters.';
316+
}
317+
if (!strongPassword.test(password)) {
318+
return 'Password must include at least one letter and one number.';
319+
}
320+
return ''; // Valid password
321+
}
322+
323+
// Display error messages below input fields
324+
function showInputError(inputEl, errorMessage) {
325+
let errorEl = inputEl.nextElementSibling;
326+
if (!errorEl || !errorEl.classList.contains('error-message')) {
327+
errorEl = document.createElement('div');
328+
errorEl.classList.add('error-message');
329+
errorEl.style.color = 'red';
330+
errorEl.style.fontSize = '0.8em';
331+
inputEl.parentElement.appendChild(errorEl);
332+
}
333+
errorEl.textContent = errorMessage;
334+
}
335+
291336
function debounce(func, timeout = 500){
292337
// debounce rapid clicks to prevent unnecessary fetches
293338
let timer;
@@ -372,6 +417,16 @@
372417
}
373418

374419
async function saveChanges() {
420+
// Validate AP_Pass before saving
421+
const apPassInput = $('#AP_Pass');
422+
if (apPassInput) {
423+
const errorMessage = validateApPassword(apPassInput.value.trim());
424+
if (errorMessage) {
425+
showInputError(apPassInput, errorMessage);
426+
showAlert('Cannot save settings: Invalid AP password.');
427+
return;
428+
}
429+
}
375430
// save change and reboot
376431
await sleep(100);
377432
sendControl('save', 1);
@@ -468,7 +523,16 @@
468523
const et = event.target.type;
469524
// input fields of given class
470525
if (e.nodeName == 'INPUT') {
471-
if (e.type === 'checkbox') processStatus(ID, e.id, e.checked ? 1 : 0);
526+
if (e.id === 'AP_Pass') {
527+
// Validate AP password
528+
const errorMessage = validateApPassword(value);
529+
showInputError(e, errorMessage);
530+
// Only send valid passwords
531+
if (!errorMessage) {
532+
processStatus(ID, e.id, value);
533+
}
534+
}
535+
else if (e.type === 'checkbox') processStatus(ID, e.id, e.checked ? 1 : 0);
472536
else if (et === 'button' || et === 'file') processStatus(ID, e.id, 1);
473537
else if (et === 'radio') { if (e.checked) processStatus(ID, e.name, value); }
474538
else if (et === 'range') processStatus(ID, e.id, e.parentElement.children.rangeVal.innerHTML);
@@ -782,12 +846,13 @@
782846
}
783847
}
784848

785-
function refreshAllContainers() {
849+
function refreshAllContainers(uniq = false) {
786850
const containers = document.querySelectorAll('.ipContainer');
787851
containers.forEach((container) => {
788852
const ip = container.querySelector('.ipUrl').textContent;
789853
const hubImg = container.querySelector('img');
790854
hubImg.src = `http://${ip}`;
855+
if (uniq) hubImg.src += Date.now();
791856
});
792857
}
793858

@@ -796,9 +861,9 @@
796861
const ipInput = document.getElementById('ipInput');
797862
const ipAddresses = localStorage.getItem('enteredIPs') ? JSON.parse(localStorage.getItem('enteredIPs')) : [];
798863

799-
// Add the entered IP to the array
864+
// Add the entered IP to the array if not already present
800865
let newIP = ipInput.value.trim();
801-
if (newIP !== '' && !ipAddresses.includes(newIP)) {
866+
if (newIP !== '' && !ipAddresses.some(item => item.includes(newIP))) {
802867
// if only ip address, add app specific URI
803868
// for any other app, enter full URL
804869
if (newIP.indexOf('/') == -1) newIP += appHub;

0 commit comments

Comments
 (0)