From f3d280f1b0147ec6e4295732f228e01d9cafe265 Mon Sep 17 00:00:00 2001 From: Anurag Ekkati Date: Fri, 2 Jan 2026 14:59:39 -0800 Subject: [PATCH] fix(monitor): DNS monitor hostname and other monitors URL validations Fixes Issue #6444 Summary: * DNS monitor hostname input will accept wildcard and rejects IP (Valid : *.testdns.co, Invalid : 8.8.8.8) * http, keyword, json-query, websocket, real-browser monitors will not accept wildcard hostnames in URL (Invalid : https://*.testdns.co/status) --- package-lock.json | 10 +++++++++ package.json | 3 ++- src/pages/EditMonitor.vue | 46 ++++++++++++++++++++++++++++++++++++++- src/util-frontend.js | 4 ++-- 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index ab56e410d..5d1e8fe98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -88,6 +88,7 @@ "thirty-two": "~1.0.2", "tldts": "^7.0.19", "tough-cookie": "~4.1.3", + "validator": "^13.15.26", "web-push": "^3.6.7", "ws": "^8.13.0" }, @@ -18742,6 +18743,15 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/validator": { + "version": "13.15.26", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", + "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/varint": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", diff --git a/package.json b/package.json index 987b5af52..4d4173217 100644 --- a/package.json +++ b/package.json @@ -122,8 +122,8 @@ "net-snmp": "^3.11.2", "node-cloudflared-tunnel": "~1.0.9", "node-fetch-cache": "^5.1.0", - "nodemailer": "~7.0.12", "node-radius-utils": "~1.2.0", + "nodemailer": "~7.0.12", "nostr-tools": "^2.10.4", "notp": "~2.0.3", "openid-client": "^5.4.2", @@ -149,6 +149,7 @@ "thirty-two": "~1.0.2", "tldts": "^7.0.19", "tough-cookie": "~4.1.3", + "validator": "^13.15.26", "web-push": "^3.6.7", "ws": "^8.13.0" }, diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index f72e68423..d5fb6d1a5 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -326,7 +326,7 @@ v-model="monitor.hostname" type="text" class="form-control" - :pattern="`${monitor.type === 'mqtt' ? mqttIpOrHostnameRegexPattern : ipOrHostnameRegexPattern}`" + :pattern="monitor.type === 'mqtt' ? mqttIpOrHostnameRegexPattern : (monitor.type === 'dns' ? null : ipOrHostnameRegexPattern)" required data-testid="hostname-input" > @@ -1330,6 +1330,8 @@ import { sleep, } from "../util.ts"; import { hostNameRegexPattern, timeDurationFormatter } from "../util-frontend"; +import isFQDN from "validator/lib/isFQDN"; +import isIP from "validator/lib/isIP"; import HiddenInput from "../components/HiddenInput.vue"; import EditMonitorConditions from "../components/EditMonitorConditions.vue"; @@ -2083,6 +2085,48 @@ message HealthCheckResponse { } } + // Validate the DNS Monitor hostname input + if (this.monitor.type === "dns" && this.monitor.hostname) { + let hostname = this.monitor.hostname.trim(); + + if (isIP(hostname)) { + toast.error("Hostname cannot be an IP address"); + return false; + } + + if (!isFQDN(hostname, { + allow_wildcard: true, + require_tld: false, + allow_underscores: true, + allow_trailing_dot: true, + })) { + toast.error("Invalid hostname"); + return false; + } + } + + // Validate URL field input + if ((this.monitor.type === "http" || this.monitor.type === "keyword" || this.monitor.type === "json-query" || this.monitor.type === "websocket-upgrade" || this.monitor.type === "real-browser") && this.monitor.url) { + try { + const url = new URL(this.monitor.url); + if (url.hostname.includes("*")) { + toast.error("Wildcard hostnames are only supported for DNS monitors."); + return false; + } + if (!isFQDN(url.hostname, { + require_tld: false, + allow_underscores: true, + allow_trailing_dot: true, + }) && !isIP(url.hostname)) { + toast.error("Invalid hostname"); + return false; + } + } catch (err) { + toast.error("Invalid URL"); + return false; + } + } + return true; }, diff --git a/src/util-frontend.js b/src/util-frontend.js index fdb2a8157..66aabd75b 100644 --- a/src/util-frontend.js +++ b/src/util-frontend.js @@ -109,10 +109,10 @@ export function getDevContainerServerHostname() { } /** - * Regex pattern fr identifying hostnames and IP addresses + * Regex pattern for identifying hostnames and IP addresses * @param {boolean} mqtt whether or not the regex should take into * account the fact that it is an mqtt uri - * @returns {RegExp} The requested regex + * @returns {string} The requested regex string */ export function hostNameRegexPattern(mqtt = false) { // mqtt, mqtts, ws and wss schemes accepted by mqtt.js (https://github.com/mqttjs/MQTT.js/#connect)