diff --git a/server/util-server.js b/server/util-server.js
index f66b10399..9ec3a3103 100644
--- a/server/util-server.js
+++ b/server/util-server.js
@@ -135,7 +135,7 @@ exports.mqttAsync = function (hostname, topic, okMessage, options = {}) {
const { port, username, password, interval = 20 } = options;
// Adds MQTT protocol to the hostname if not already present
- if (!/^(?:http|mqtt)s?:\/\//.test(hostname)) {
+ if (!/^(?:http|mqtt|ws)s?:\/\//.test(hostname)) {
hostname = "mqtt://" + hostname;
}
@@ -145,10 +145,11 @@ exports.mqttAsync = function (hostname, topic, okMessage, options = {}) {
reject(new Error("Timeout"));
}, interval * 1000 * 0.8);
- log.debug("mqtt", "MQTT connecting");
+ const mqttUrl = `${hostname}:${port}`;
- let client = mqtt.connect(hostname, {
- port,
+ log.debug("mqtt", `MQTT connecting to ${mqttUrl}`);
+
+ let client = mqtt.connect(mqttUrl, {
username,
password
});
diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue
index c9d5ad2f1..2ab9acc7e 100644
--- a/src/pages/EditMonitor.vue
+++ b/src/pages/EditMonitor.vue
@@ -105,7 +105,7 @@
-
+
@@ -576,6 +576,7 @@ import DockerHostDialog from "../components/DockerHostDialog.vue";
import ProxyDialog from "../components/ProxyDialog.vue";
import TagsManager from "../components/TagsManager.vue";
import { genSecret, isDev, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND } from "../util.ts";
+import { hostNameRegexPattern } from "../util-frontend";
const toast = useToast();
@@ -600,11 +601,8 @@ export default {
},
acceptedStatusCodeOptions: [],
dnsresolvetypeOptions: [],
-
- // Source: https://digitalfortress.tech/tips/top-15-commonly-used-regex/
- ipRegexPattern: "((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))",
- // Source: https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
- hostnameRegexPattern: "^(([a-zA-Z0-9_]|[a-zA-Z0-9_][a-zA-Z0-9\\-_]*[a-zA-Z0-9_])\\.)*([A-Za-z0-9_]|[A-Za-z0-9_][A-Za-z0-9\\-_]*[A-Za-z0-9_])$"
+ ipOrHostnameRegexPattern: hostNameRegexPattern(),
+ mqttIpOrHostnameRegexPattern: hostNameRegexPattern(true)
};
},
diff --git a/src/util-frontend.js b/src/util-frontend.js
index 3323f3279..23b4ec95f 100644
--- a/src/util-frontend.js
+++ b/src/util-frontend.js
@@ -78,3 +78,19 @@ export function getResBaseURL() {
return "";
}
}
+
+/**
+ *
+ * @param {} mqtt wheather or not the regex should take into account the fact that it is an mqtt uri
+ * @returns RegExp The requested regex
+ */
+export function hostNameRegexPattern(mqtt = false) {
+ // mqtt, mqtts, ws and wss schemes accepted by mqtt.js (https://github.com/mqttjs/MQTT.js/#connect)
+ const mqttSchemeRegexPattern = "((mqtt|ws)s?:\\/\\/)?";
+ // Source: https://digitalfortress.tech/tips/top-15-commonly-used-regex/
+ const ipRegexPattern = `((^\\s*${mqtt ? mqttSchemeRegexPattern : ""}((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))`;
+ // Source: https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
+ const hostNameRegexPattern = `^${mqtt ? mqttSchemeRegexPattern : ""}([a-zA-Z0-9])?(([a-zA-Z0-9_]|[a-zA-Z0-9_][a-zA-Z0-9\\-_]*[a-zA-Z0-9_])\\.)*([A-Za-z0-9_]|[A-Za-z0-9_][A-Za-z0-9\\-_]*[A-Za-z0-9_])$`;
+
+ return `${ipRegexPattern}|${hostNameRegexPattern}`;
+}
diff --git a/test/cypress/unit/util-frontend.spec.js b/test/cypress/unit/util-frontend.spec.js
new file mode 100644
index 000000000..6abedf821
--- /dev/null
+++ b/test/cypress/unit/util-frontend.spec.js
@@ -0,0 +1,33 @@
+import { hostNameRegexPattern } from "../../../src/util-frontend";
+
+describe("Test util-frontend.js", () => {
+
+ describe("hostNameRegexPattern()", () => {
+ it('should return a valid regex for non mqtt hostnames', () => {
+ const regex = new RegExp(hostNameRegexPattern(false));
+
+ expect(regex.test("www.test.com")).to.be.true;
+ expect(regex.test("127.0.0.1")).to.be.true;
+ expect(regex.test("192.168.1.156")).to.be.true;
+
+ ["mqtt", "mqtts", "ws", "wss"].forEach(schema => {
+ expect(regex.test(`${schema}://www.test.com`)).to.be.false;
+ expect(regex.test(`${schema}://127.0.0.1`)).to.be.false;
+ });
+ });
+ it('should return a valid regex for mqtt hostnames', () => {
+ const hostnameString = hostNameRegexPattern(false);
+ console.log('*********', hostnameString, '***********');
+ const regex = new RegExp(hostNameRegexPattern(true));
+
+ expect(regex.test("www.test.com")).to.be.true;
+ expect(regex.test("127.0.0.1")).to.be.true;
+ expect(regex.test("192.168.1.156")).to.be.true;
+
+ ["mqtt", "mqtts", "ws", "wss"].forEach(schema => {
+ expect(regex.test(`${schema}://www.test.com`)).to.be.true;
+ expect(regex.test(`${schema}://127.0.0.1`)).to.be.true;
+ });
+ });
+ });
+});
\ No newline at end of file