|
326 | 326 | v-model="monitor.hostname" |
327 | 327 | type="text" |
328 | 328 | class="form-control" |
329 | | - :pattern="`${monitor.type === 'mqtt' ? mqttIpOrHostnameRegexPattern : ipOrHostnameRegexPattern}`" |
330 | 329 | required |
331 | 330 | data-testid="hostname-input" |
332 | 331 | > |
@@ -1329,7 +1328,9 @@ import { |
1329 | 1328 | MIN_INTERVAL_SECOND, |
1330 | 1329 | sleep, |
1331 | 1330 | } from "../util.ts"; |
1332 | | -import { hostNameRegexPattern, timeDurationFormatter } from "../util-frontend"; |
| 1331 | +import { timeDurationFormatter } from "../util-frontend"; |
| 1332 | +import isFQDN from "validator/lib/isFQDN"; |
| 1333 | +import isIP from "validator/lib/isIP"; |
1333 | 1334 | import HiddenInput from "../components/HiddenInput.vue"; |
1334 | 1335 | import EditMonitorConditions from "../components/EditMonitorConditions.vue"; |
1335 | 1336 |
|
@@ -1417,8 +1418,6 @@ export default { |
1417 | 1418 | acceptedWebsocketCodeOptions: [], |
1418 | 1419 | dnsresolvetypeOptions: [], |
1419 | 1420 | kafkaSaslMechanismOptions: [], |
1420 | | - ipOrHostnameRegexPattern: hostNameRegexPattern(), |
1421 | | - mqttIpOrHostnameRegexPattern: hostNameRegexPattern(true), |
1422 | 1421 | gameList: null, |
1423 | 1422 | connectionStringTemplates: { |
1424 | 1423 | "sqlserver": "Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>", |
@@ -2083,6 +2082,58 @@ message HealthCheckResponse { |
2083 | 2082 | } |
2084 | 2083 | } |
2085 | 2084 |
|
| 2085 | + // Validate hostname field input for various monitors |
| 2086 | + if ([ "mqtt", "dns", "port", "ping", "steam", "gamedig", "radius", "tailscale-ping", "smtp", "snmp" ].includes(this.monitor.type) && this.monitor.hostname) { |
| 2087 | + let hostname = this.monitor.hostname.trim(); |
| 2088 | +
|
| 2089 | + if (this.monitor.type === "mqtt") { |
| 2090 | + hostname = hostname.replace(/^(mqtt|ws)s?:\/\//, ""); |
| 2091 | + } |
| 2092 | +
|
| 2093 | + if (this.monitor.type === "dns" && isIP(hostname)) { |
| 2094 | + toast.error(this.$t("hostnameCannotBeIP")); |
| 2095 | + return false; |
| 2096 | + } |
| 2097 | +
|
| 2098 | + // Wildcard is allowed only for DNS |
| 2099 | + if (!isFQDN(hostname, { |
| 2100 | + allow_wildcard: this.monitor.type === "dns", |
| 2101 | + require_tld: false, |
| 2102 | + allow_underscores: true, |
| 2103 | + allow_trailing_dot: true, |
| 2104 | + }) && !isIP(hostname)) { |
| 2105 | + if (this.monitor.type === "dns") { |
| 2106 | + toast.error(this.$t("invalidDNSHostname")); |
| 2107 | + } else { |
| 2108 | + toast.error(this.$t("invalidHostnameOrIP")); |
| 2109 | + } |
| 2110 | + return false; |
| 2111 | + } |
| 2112 | + } |
| 2113 | +
|
| 2114 | + // Validate URL field input for various monitors |
| 2115 | + if ([ "http", "keyword", "json-query", "websocket-upgrade", "real-browser" ].includes(this.monitor.type) && this.monitor.url) { |
| 2116 | + try { |
| 2117 | + const url = new URL(this.monitor.url); |
| 2118 | + // Browser can encode *.hostname.com to %2A.hostname.com |
| 2119 | + if (url.hostname.includes("*") || url.hostname.includes("%2A")) { |
| 2120 | + toast.error(this.$t("wildcardOnlyForDNS")); |
| 2121 | + return false; |
| 2122 | + } |
| 2123 | + if (!isFQDN(url.hostname, { |
| 2124 | + require_tld: false, |
| 2125 | + allow_underscores: true, |
| 2126 | + allow_trailing_dot: true, |
| 2127 | + }) && !isIP(url.hostname)) { |
| 2128 | + toast.error(this.$t("invalidHostnameOrIP")); |
| 2129 | + return false; |
| 2130 | + } |
| 2131 | + } catch (err) { |
| 2132 | + toast.error(this.$t("invalidURL")); |
| 2133 | + return false; |
| 2134 | + } |
| 2135 | + } |
| 2136 | +
|
2086 | 2137 | return true; |
2087 | 2138 | }, |
2088 | 2139 |
|
|
0 commit comments