mirror of
				https://github.com/louislam/uptime-kuma.git
				synced 2025-10-31 19:39:20 +08:00 
			
		
		
		
	Merge pull request #2540 from twiggotronix/add-mqtt-schemes
Add mqtt, mqtts, ws and wss protocols to the mqtt monitor
This commit is contained in:
		| @@ -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 | ||||
|         }); | ||||
|   | ||||
| @@ -105,7 +105,7 @@ | ||||
|                             <!-- TCP Port / Ping / DNS / Steam / MQTT / Radius only --> | ||||
|                             <div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'mqtt' || monitor.type === 'radius'" class="my-3"> | ||||
|                                 <label for="hostname" class="form-label">{{ $t("Hostname") }}</label> | ||||
|                                 <input id="hostname" v-model="monitor.hostname" type="text" class="form-control" :pattern="`${ipRegexPattern}|${hostnameRegexPattern}`" required> | ||||
|                                 <input id="hostname" v-model="monitor.hostname" type="text" class="form-control" :pattern="`${monitor.type === 'mqtt' ? mqttIpOrHostnameRegexPattern : ipOrHostnameRegexPattern}`" required> | ||||
|                             </div> | ||||
|  | ||||
|                             <!-- Port --> | ||||
| @@ -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) | ||||
|         }; | ||||
|     }, | ||||
|  | ||||
|   | ||||
| @@ -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}`; | ||||
| } | ||||
|   | ||||
							
								
								
									
										33
									
								
								test/cypress/unit/util-frontend.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								test/cypress/unit/util-frontend.spec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user