mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-07-19 07:44:02 +02:00
Fix input validation for fields in monitor edit form
This commit is contained in:
parent
aaf438a248
commit
21f629e055
2 changed files with 55 additions and 24 deletions
|
@ -290,9 +290,9 @@
|
|||
type="text"
|
||||
class="form-control"
|
||||
:pattern="`${
|
||||
monitor.type === 'mqtt' ? mqttIpOrHostnameRegexPattern :
|
||||
monitor.type === 'dns' ? ipOrDnsNameRegexPattern :
|
||||
ipOrHostnameRegexPattern
|
||||
monitor.type === 'mqtt' ? mqttIpOrHostnameRegexPattern.source :
|
||||
monitor.type === 'dns' ? ipOrDnsNameRegexPattern.source :
|
||||
ipOrHostnameRegexPattern.source
|
||||
}`"
|
||||
required
|
||||
data-testid="hostname-input"
|
||||
|
@ -371,7 +371,7 @@
|
|||
<template v-if="monitor.type === 'dns'">
|
||||
<div class="my-3">
|
||||
<label for="dns_resolve_server" class="form-label">{{ $t("Resolver Server") }}</label>
|
||||
<input id="dns_resolve_server" v-model="monitor.dns_resolve_server" type="text" class="form-control" :pattern="ipOrHostnameRegex" required>
|
||||
<input id="dns_resolve_server" v-model="monitor.dns_resolve_server" type="text" class="form-control" :pattern="dnsResolverRegex" required>
|
||||
<div class="form-text">
|
||||
{{ $t("resolverserverDescription") }}
|
||||
</div>
|
||||
|
@ -384,7 +384,7 @@
|
|||
<input id="doh_query_path" v-model="monitor.doh_query_path" type="text" class="form-control" :pattern="urlQueryRegex" placeholder="dns-query?dns={query}">
|
||||
</div>
|
||||
<div class="form-text">
|
||||
{{ $t("dohQueryPathDescription") }}{{ ' "{query}".' }}
|
||||
{{ $t("dohQueryPathDescription") + " " }}{{ '"{query}".' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1179,7 +1179,8 @@ export default {
|
|||
dnsresolvetypeOptions: [],
|
||||
dnsTransportOptions: [],
|
||||
kafkaSaslMechanismOptions: [],
|
||||
ipRegexPattern: hostNameRegexPattern().split("|")[0],
|
||||
ipRegexPattern: hostNameRegexPattern(false, true, false),
|
||||
hostnameRegexPattern: hostNameRegexPattern(false, false, true),
|
||||
ipOrHostnameRegexPattern: hostNameRegexPattern(),
|
||||
mqttIpOrHostnameRegexPattern: hostNameRegexPattern(true),
|
||||
ipOrDnsNameRegexPattern: dnsNameRegexPattern(),
|
||||
|
@ -1202,7 +1203,7 @@ export default {
|
|||
|
||||
// Allow to test with simple dns server with port (127.0.0.1:5300)
|
||||
if (! isDev) {
|
||||
return this.ipRegexPattern;
|
||||
return this.ipRegexPattern.source;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
@ -1211,16 +1212,24 @@ export default {
|
|||
|
||||
// Permit either IP address or hostname (127.0.0.1, dns.example.com)
|
||||
if (! isDev) {
|
||||
return this.ipOrHostnameRegexPattern;
|
||||
return this.ipOrHostnameRegexPattern.source;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
dnsNameRegex() {
|
||||
dnsResolverRegex() {
|
||||
|
||||
// Permit IP address, hostname, TLD, or root
|
||||
// Permit IP address for TCP/UDP resolvers, hostname for DoH/DoT
|
||||
if (! isDev) {
|
||||
return this.ipOrDnsNameRegexPattern;
|
||||
switch (this.monitor.dns_transport) {
|
||||
case "UDP":
|
||||
case "TCP":
|
||||
return this.ipRegexPattern.source;
|
||||
|
||||
case "DoH":
|
||||
case "DoT":
|
||||
return this.hostnameRegexPattern.source;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
@ -1229,7 +1238,7 @@ export default {
|
|||
|
||||
// Permit only URL paths with a query parameter ( {query} )
|
||||
if (! isDev) {
|
||||
return this.queryRegexPattern;
|
||||
return this.queryRegexPattern.source;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
|
|
@ -112,17 +112,37 @@ export function getDevContainerServerHostname() {
|
|||
* 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
|
||||
* @param {boolean} ip whether the regex should match IP addresses
|
||||
* @param {boolean} hostname whether the regex should match hostnames
|
||||
* @returns {RegExp} The requested regex
|
||||
*/
|
||||
export function hostNameRegexPattern(mqtt = false) {
|
||||
export function hostNameRegexPattern(mqtt = false, ip = true, hostname = true) {
|
||||
// mqtt, mqtts, ws and wss schemes accepted by mqtt.js (https://github.com/mqttjs/MQTT.js/#connect)
|
||||
const mqttSchemeRegexPattern = "((mqtt|ws)s?:\\/\\/)?";
|
||||
const mqttSchemeRegexPattern = /((mqtt|ws)s?:\/\/)?/;
|
||||
// Source: https://digitalfortress.tech/tips/top-15-commonly-used-regex/
|
||||
const ipRegexPattern = `((^${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]))$)|(^((([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}))|:)))(%.+)?$))`;
|
||||
// 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_])(\\.)?$`;
|
||||
const ipv4RegexPattern = /^(([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])$/;
|
||||
const ipv6RegexPattern = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
|
||||
// See this answer for detailed a explanation: https://stackoverflow.com/a/53875771/1854468
|
||||
/* eslint-disable-next-line no-useless-escape */
|
||||
const hostNameRegexPattern = /^[a-zA-Z][a-zA-Z0-9\-]{0,62}\.([a-zA-Z0-9][a-zA-Z0-9\-]{0,62}\.)*([a-zA-Z]{2,63}|[xX][nN]--[a-zA-Z0-9]{0,59})$/;
|
||||
/* eslint-disable-next-line no-useless-escape */
|
||||
const localNameRegexPattern = /^[a-zA-Z0-9][a-zA-Z0-9\-]{0,127}$/;
|
||||
|
||||
return `${ipRegexPattern}|${hostNameRegexPattern}`;
|
||||
let patterns = [];
|
||||
if (ip) {
|
||||
patterns.push(ipv4RegexPattern, ipv6RegexPattern);
|
||||
}
|
||||
if (hostname) {
|
||||
patterns.push(hostNameRegexPattern, localNameRegexPattern);
|
||||
}
|
||||
if (mqtt) {
|
||||
// all modified patterns must start with "^" for this to work
|
||||
patterns = patterns.map(pattern => {
|
||||
return new RegExp(`^${mqttSchemeRegexPattern.source}${pattern.source.slice(1)}`);
|
||||
});
|
||||
}
|
||||
|
||||
return new RegExp(patterns.map(pattern => `(${pattern.source})`).join("|"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -131,12 +151,13 @@ export function hostNameRegexPattern(mqtt = false) {
|
|||
*/
|
||||
export function dnsNameRegexPattern() {
|
||||
// This borrows ipRegexPattern from hostNameRegexPattern above
|
||||
const ipRegexPattern = hostNameRegexPattern().split("|")[0];
|
||||
const ipRegexPattern = hostNameRegexPattern(false, true, false);
|
||||
// Similar to hostNameRegexPattern, except the hostname pattern
|
||||
// can also match root (.) and top-level domains (.com, .org)
|
||||
const dnsNamePattern = "^(\\.|(\\.?[a-zA-Z0-9_]+)+)$";
|
||||
// can also match root (.) and top-level domains (.com, .org),
|
||||
// and may contain underscores (_)
|
||||
const dnsNamePattern = /^(\.|(\.?[a-zA-Z0-9\-_]+)+)$/;
|
||||
|
||||
return `${ipRegexPattern}|${dnsNamePattern}`;
|
||||
return new RegExp(`(${ipRegexPattern.source})|(${dnsNamePattern.source})`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,9 +167,10 @@ export function dnsNameRegexPattern() {
|
|||
*/
|
||||
export function urlPathRegexPattern(qstr = false) {
|
||||
// Ensures a URL path follows query string format
|
||||
const queryStringRegexPattern = "^/?(([a-zA-Z0-9\\-_%])+/)*[a-zA-Z0-9\\-_%]*\\?([a-zA-Z0-9\\-_%]+=[a-zA-Z0-9\\-_%]*&?)+$";
|
||||
const queryStringRegexPattern = /^\/?(([a-zA-Z0-9\-_%])+\/)*[a-zA-Z0-9\-_%]*\?([a-zA-Z0-9\-_%]+=[a-zA-Z0-9\-_%]*&?)+$/;
|
||||
// Only checks for valid URL path containing "{query}"
|
||||
const queryRegexPattern = "^[a-zA-Z0-9\\-._~:\\/?#\\[\\]@!$&'\\(\\)*+,;=]*\\{query\\}[a-zA-Z0-9\\-._~:\\/?#\\[\\]@!$&'\\(\\)*+,;=]*$";
|
||||
/* eslint-disable-next-line no-useless-escape */
|
||||
const queryRegexPattern = /^[a-zA-Z0-9\-._~:\/?#\[\]@!$&'\(\)*+,;=]*\{query\}[a-zA-Z0-9\-._~:\/?#\[\]@!$&'\(\)*+,;=]*$/;
|
||||
|
||||
if (qstr) {
|
||||
return queryStringRegexPattern;
|
||||
|
|
Loading…
Add table
Reference in a new issue