Repository: louislam/uptime-kuma
File: src/pages/EditMonitor.vue (Vue)

Code before:
            if (this.monitor.type === "rabbitmq") {
                if (this.monitor.rabbitmqNodes.length === 0) {
                    toast.error(this.$t("rabbitmqNodesRequired"));
                    return false;
                }
                if (!this.monitor.rabbitmqNodes.every(node => node.startsWith("http://") || node.startsWith("https://"))) {
                    toast.error(this.$t("rabbitmqNodesInvalid"));
                    return false;
                }
            }

            // Validate MQTT WebSocket Path pattern if present
            if (this.monitor.type === "mqtt" && this.monitor.mqttWebsocketPath) {
                const pattern = /^\/[A-Za-z0-9-_&()*+]*$/;
                if (!pattern.test(this.monitor.mqttWebsocketPath)) {
                    toast.error(this.$t("mqttWebsocketPathInvalid"));
                    return false;
                }
            }

            // 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,

Review comment (suggestion):
```suggestion
                    toast.error("DNS hostname cannot be an IP. Did you mean to use the resolver field?");
```

Code after:
                    return false;
                }
                if (!this.monitor.rabbitmqNodes.every(node => node.startsWith("http://") || node.startsWith("https://"))) {
                    toast.error(this.$t("rabbitmqNodesInvalid"));
                    return false;
                }
            }

            // Validate MQTT WebSocket Path pattern if present
            if (this.monitor.type === "mqtt" && this.monitor.mqttWebsocketPath) {
                const pattern = /^\/[A-Za-z0-9-_&()*+]*$/;
                if (!pattern.test(this.monitor.mqttWebsocketPath)) {
                    toast.error(this.$t("mqttWebsocketPathInvalid"));
                    return false;
                }
            }

            // Validate hostname field input for various monitors
            if ([ "mqtt", "dns", "port", "ping", "steam", "gamedig", "radius", "tailscale-ping", "smtp", "snmp" ].includes(this.monitor.type) && this.monitor.hostname) {
                let hostname = this.monitor.hostname.trim();

                if (this.monitor.type === "mqtt") {
                    hostname = hostname.replace(/^(mqtt|ws)s?:\/\//, "");
                }

                if (this.monitor.type === "dns" && isIP(hostname)) {
                    toast.error(this.$t("hostnameCannotBeIP"));
                    return false;
                }

                // Wildcard is allowed only for DNS
                if (!isFQDN(hostname, {
                    allow_wildcard: this.monitor.type === "dns",
                    require_tld: false,
                    allow_underscores: true,
                    allow_trailing_dot: true,
                }) && !isIP(hostname)) {
                    if (this.monitor.type === "dns") {
                        toast.error(this.$t("invalidDNSHostname"));
                    } else {
                        toast.error(this.$t("invalidHostnameOrIP"));
                    }
                    return false;
                }
            }

            // Validate URL field input for various monitors
            if ([ "http", "keyword", "json-query", "websocket-upgrade", "real-browser" ].includes(this.monitor.type) && this.monitor.url) {
                try {
                    const url = new URL(this.monitor.url);
                    // Browser can encode *.hostname.com to %2A.hostname.com