From c02e66fe04336c4ff0cd52afbce5fc33f1b5f2d1 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Mon, 16 Mar 2026 08:55:20 +0100 Subject: [PATCH] Fix xo errors Signed-off-by: yubiuser --- scripts/js/footer.js | 7 +++-- scripts/js/gravity.js | 4 +-- scripts/js/groups-clients.js | 2 +- scripts/js/groups-domains.js | 2 +- scripts/js/groups-lists.js | 2 +- scripts/js/groups.js | 4 +-- scripts/js/index.js | 4 +-- scripts/js/interfaces.js | 2 +- scripts/js/network.js | 2 +- scripts/js/settings-dns-records.js | 4 +-- scripts/js/settings-system.js | 5 ++-- scripts/js/settings-teleporter.js | 2 +- scripts/js/taillog.js | 2 +- scripts/js/utils.js | 47 +++++++++++++++++++++++++----- 14 files changed, 61 insertions(+), 28 deletions(-) diff --git a/scripts/js/footer.js b/scripts/js/footer.js index 44bd22ca..6c734d61 100644 --- a/scripts/js/footer.js +++ b/scripts/js/footer.js @@ -5,7 +5,7 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ -/* global utils:false, moment:false */ +/* global utils:false, moment:false, base64ToString:false */ "use strict"; @@ -544,7 +544,7 @@ function updateVersionInfo() { // Display update information for the docker tag updateComponentAvailable = true; dockerUpdate = true; - } else if (/^\d{4}\.\d{2}\.\d+/.test(v.local)) { + } else if (/^\d{4}\.\d{2}\.\d+/v.test(v.local)) { // Display the link if the current tag is a normal date-based tag localVersion = ' el !== ""); const ipStr = JSON.stringify(ips); diff --git a/scripts/js/groups-domains.js b/scripts/js/groups-domains.js index 0f4929f4..23adc919 100644 --- a/scripts/js/groups-domains.js +++ b/scripts/js/groups-domains.js @@ -486,7 +486,7 @@ function addDomain() { // Check if the user wants to add multiple domains (space or newline separated) // If so, split the input and store it in an array - let domains = domainEl.val().split(/\s+/); + let domains = domainEl.val().split(/\s+/v); // Remove empty elements domains = domains.filter(el => el !== ""); const domainStr = JSON.stringify(domains); diff --git a/scripts/js/groups-lists.js b/scripts/js/groups-lists.js index 47c3db92..970e75a7 100644 --- a/scripts/js/groups-lists.js +++ b/scripts/js/groups-lists.js @@ -499,7 +499,7 @@ function addList(event) { // If so, split the input and store it in an array let addresses = $("#new_address") .val() - .split(/[\s,]+/); + .split(/[\s,]+/v); // Remove empty elements addresses = addresses.filter(el => el !== ""); const addressestr = JSON.stringify(addresses); diff --git a/scripts/js/groups.js b/scripts/js/groups.js index 581902f6..fbad0364 100644 --- a/scripts/js/groups.js +++ b/scripts/js/groups.js @@ -243,8 +243,8 @@ function addGroup() { let names = utils .escapeHtml($("#new_name")) .val() - .match(/(?:[^\s"]+|"[^"]*")+/g) - .map(name => name.replaceAll(/(^"|"$)/g, "")); + .match(/(?:[^\s"]+|"[^"]*")+/gv) + .map(name => name.replaceAll(/(^"|"$)/gv, "")); // Remove empty elements names = names.filter(el => el !== ""); const groupStr = JSON.stringify(names); diff --git a/scripts/js/index.js b/scripts/js/index.js index f79aa0df..84b61b34 100644 --- a/scripts/js/index.js +++ b/scripts/js/index.js @@ -647,7 +647,7 @@ $(() => { callbacks: { title(tooltipTitle) { const label = tooltipTitle[0].label; - const time = label.match(/(\d?\d):?(\d?\d?)/); + const time = label.match(/(\d?\d):?(\d?\d?)/v); const h = Number.parseInt(time[1], 10); const m = Number.parseInt(time[2], 10) || 0; const from = utils.padNumber(h) + ":" + utils.padNumber(m - 5) + ":00"; @@ -751,7 +751,7 @@ $(() => { callbacks: { title(tooltipTitle) { const label = tooltipTitle[0].label; - const time = label.match(/(\d?\d):?(\d?\d?)/); + const time = label.match(/(\d?\d):?(\d?\d?)/v); const h = Number.parseInt(time[1], 10); const m = Number.parseInt(time[2], 10) || 0; const from = utils.padNumber(h) + ":" + utils.padNumber(m - 5) + ":00"; diff --git a/scripts/js/interfaces.js b/scripts/js/interfaces.js index d09da152..67518642 100644 --- a/scripts/js/interfaces.js +++ b/scripts/js/interfaces.js @@ -484,7 +484,7 @@ function sortInterfaces(interfaces, masterInterfaces) { } // Add interfaces that are not slaves at the top of the list (in reverse order) - for (const iface of ifaces.reverse()) { + for (const iface of ifaces.toReversed()) { if (!interfaceList.includes(iface)) { interfaceList.unshift(iface); } diff --git a/scripts/js/network.js b/scripts/js/network.js index e6116e8f..4dafb082 100644 --- a/scripts/js/network.js +++ b/scripts/js/network.js @@ -51,7 +51,7 @@ function mixColors(ratio, rgb1, rgb2) { } function parseColor(input) { - const match = input.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i); + const match = input.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/iv); if (match) { return [match[1], match[2], match[3]]; diff --git a/scripts/js/settings-dns-records.js b/scripts/js/settings-dns-records.js index f29be667..90617ffe 100644 --- a/scripts/js/settings-dns-records.js +++ b/scripts/js/settings-dns-records.js @@ -14,7 +14,7 @@ function hostsDomain(data) { // We split both on spaces and tabs to support both formats // Also, we remove any comments after the name(s) const name = data - .split(/[\t ]+/) + .split(/[\t ]+/v) .slice(1) .join(" ") .split("#")[0] @@ -25,7 +25,7 @@ function hostsDomain(data) { function hostsIP(data) { // Split record in format IP NAME1 [NAME2 [NAME3 [NAME...]]] // We split both on spaces and tabs to support both formats - const ip = data.split(/[\t ]+/)[0].trim(); + const ip = data.split(/[\t ]+/v)[0].trim(); return ip; } diff --git a/scripts/js/settings-system.js b/scripts/js/settings-system.js index ae5ebb73..aab9d200 100644 --- a/scripts/js/settings-system.js +++ b/scripts/js/settings-system.js @@ -35,7 +35,7 @@ function updateCachePie(data) { } // Sort data by value, put OTHER always as last - const sorted = Object.keys(data).sort((a, b) => { + const sorted = Object.keys(data).toSorted((a, b) => { if (a === "OTHER") { return 1; } @@ -292,8 +292,7 @@ $("#loggingButton").confirm({ "Furthermore, you will be logged out of the web interface.", title: "Confirmation required", confirm() { - const data = {}; - data.config = {}; + const data = { config: {} }; data.config.dns = {}; data.config.dns.queryLogging = $("#loggingButton").data("state") !== "enabled"; $.ajax({ diff --git a/scripts/js/settings-teleporter.js b/scripts/js/settings-teleporter.js index 623e5858..c54618a9 100644 --- a/scripts/js/settings-teleporter.js +++ b/scripts/js/settings-teleporter.js @@ -90,7 +90,7 @@ $("#GETTeleporter").on("click", () => { const url = globalThis.URL.createObjectURL(data); a.href = url; - a.download = xhr.getResponseHeader("Content-Disposition").match(/filename="([^"]*)"/)[1]; + a.download = xhr.getResponseHeader("Content-Disposition").match(/filename="([^"]*)"/v)[1]; document.body.append(a); a.click(); a.remove(); diff --git a/scripts/js/taillog.js b/scripts/js/taillog.js index 0f9a9e45..283514e2 100644 --- a/scripts/js/taillog.js +++ b/scripts/js/taillog.js @@ -24,7 +24,7 @@ const markUpdates = true; // Format a line of the dnsmasq log function formatDnsmasq(line) { // Remove dnsmasq + PID - let txt = line.replaceAll(/ dnsmasq\[\d*]/g, ""); + let txt = line.replaceAll(/ dnsmasq\[\d*\]/gv, ""); if (line.includes("denied") || line.includes("gravity blocked")) { // Red bold text for blocked domains diff --git a/scripts/js/utils.js b/scripts/js/utils.js index dfd5cf9a..2d86396f 100644 --- a/scripts/js/utils.js +++ b/scripts/js/utils.js @@ -19,6 +19,37 @@ $(() => { }); }); +/** + * Decode a base64 string to UTF-8 text using native browser APIs + * This is the replacement for the deprecated atob() function + * @param {string} base64 - Base64 encoded string + * @returns {string} Decoded UTF-8 string + */ +// eslint-disable-next-line no-unused-vars -- Used by other scripts (e.g., footer.js) +function base64ToString(base64) { + // Remove padding and whitespace + const cleanBase64 = base64.replaceAll(/[=\s]/gv, ""); + const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + // Decode base64 to bytes + const bytes = []; + for (let i = 0; i < cleanBase64.length; i += 4) { + const encoded1 = base64Chars.indexOf(cleanBase64[i]); + const encoded2 = base64Chars.indexOf(cleanBase64[i + 1]); + const encoded3 = base64Chars.indexOf(cleanBase64[i + 2]); + const encoded4 = base64Chars.indexOf(cleanBase64[i + 3]); + + /* eslint-disable no-bitwise -- Bitwise operations required for base64 decoding */ + bytes.push((encoded1 << 2) | (encoded2 >> 4)); + if (encoded3 !== -1) bytes.push(((encoded2 & 15) << 4) | (encoded3 >> 2)); + if (encoded4 !== -1) bytes.push(((encoded3 & 3) << 6) | encoded4); + /* eslint-enable no-bitwise */ + } + + // Decode bytes as UTF-8 + return new TextDecoder().decode(new Uint8Array(bytes)); +} + // Credit: https://stackoverflow.com/a/4835406 function escapeHtml(text) { const map = { @@ -32,7 +63,7 @@ function escapeHtml(text) { // Return early when text is not a string if (typeof text !== "string") return text; - return text.replaceAll(/[&<>"']/g, m => map[m]); + return text.replaceAll(/[&<>"']/gv, m => map[m]); } function unescapeHtml(text) { @@ -54,7 +85,7 @@ function unescapeHtml(text) { if (text === null) return null; return text.replaceAll( - /&(?:amp|lt|gt|quot|#039|Uuml|uuml|Auml|auml|Ouml|ouml|szlig);/g, + /&(?:amp|lt|gt|quot|#039|Uuml|uuml|Auml|auml|Ouml|ouml|szlig);/gv, m => map[m] ); } @@ -195,7 +226,8 @@ function validateIPv4CIDR(ip) { // Build the complete IPv4/CIDR validator // Format: xxx.xxx.xxx.xxx[/yy] where each xxx is 0-255 and optional yy is 1-32 const ipv4validator = new RegExp( - `^${ipv4elem}\\.${ipv4elem}\\.${ipv4elem}\\.${ipv4elem}${v4cidr}$` + `^${ipv4elem}\\.${ipv4elem}\\.${ipv4elem}\\.${ipv4elem}${v4cidr}$`, + "v" ); return ipv4validator.test(ip); @@ -210,19 +242,20 @@ function validateIPv6CIDR(ip) { const v6cidr = "(\\/([1-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])){0,1}"; const ipv6validator = new RegExp( - `^(((?:${ipv6elem}))*((?::${ipv6elem}))*::((?:${ipv6elem}))*((?::${ipv6elem}))*|((?:${ipv6elem}))((?::${ipv6elem})){7})${v6cidr}$` + `^(((?:${ipv6elem}))*((?::${ipv6elem}))*::((?:${ipv6elem}))*((?::${ipv6elem}))*|((?:${ipv6elem}))((?::${ipv6elem})){7})${v6cidr}$`, + "v" ); return ipv6validator.test(ip); } function validateMAC(mac) { - const macvalidator = /^([\da-fA-F]{2}:){5}([\da-fA-F]{2})$/; + const macvalidator = /^([\da-fA-F]{2}:){5}([\da-fA-F]{2})$/v; return macvalidator.test(mac); } function validateHostname(name) { - const namevalidator = /[^<>;"]/; + const namevalidator = /[^<>;"]/v; return namevalidator.test(name); } @@ -494,7 +527,7 @@ function hexEncode(text) { function hexDecode(text) { if (typeof text !== "string" || text.length === 0) return ""; - const hexes = text.match(/.{1,4}/g); + const hexes = text.match(/.{1,4}/gv); if (!hexes || hexes.length === 0) return ""; return hexes.map(hex => String.fromCodePoint(Number.parseInt(hex, 16))).join("");