mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-07-19 23:44:04 +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"
|
type="text"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:pattern="`${
|
:pattern="`${
|
||||||
monitor.type === 'mqtt' ? mqttIpOrHostnameRegexPattern :
|
monitor.type === 'mqtt' ? mqttIpOrHostnameRegexPattern.source :
|
||||||
monitor.type === 'dns' ? ipOrDnsNameRegexPattern :
|
monitor.type === 'dns' ? ipOrDnsNameRegexPattern.source :
|
||||||
ipOrHostnameRegexPattern
|
ipOrHostnameRegexPattern.source
|
||||||
}`"
|
}`"
|
||||||
required
|
required
|
||||||
data-testid="hostname-input"
|
data-testid="hostname-input"
|
||||||
|
@ -371,7 +371,7 @@
|
||||||
<template v-if="monitor.type === 'dns'">
|
<template v-if="monitor.type === 'dns'">
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<label for="dns_resolve_server" class="form-label">{{ $t("Resolver Server") }}</label>
|
<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">
|
<div class="form-text">
|
||||||
{{ $t("resolverserverDescription") }}
|
{{ $t("resolverserverDescription") }}
|
||||||
</div>
|
</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}">
|
<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>
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
{{ $t("dohQueryPathDescription") }}{{ ' "{query}".' }}
|
{{ $t("dohQueryPathDescription") + " " }}{{ '"{query}".' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1179,7 +1179,8 @@ export default {
|
||||||
dnsresolvetypeOptions: [],
|
dnsresolvetypeOptions: [],
|
||||||
dnsTransportOptions: [],
|
dnsTransportOptions: [],
|
||||||
kafkaSaslMechanismOptions: [],
|
kafkaSaslMechanismOptions: [],
|
||||||
ipRegexPattern: hostNameRegexPattern().split("|")[0],
|
ipRegexPattern: hostNameRegexPattern(false, true, false),
|
||||||
|
hostnameRegexPattern: hostNameRegexPattern(false, false, true),
|
||||||
ipOrHostnameRegexPattern: hostNameRegexPattern(),
|
ipOrHostnameRegexPattern: hostNameRegexPattern(),
|
||||||
mqttIpOrHostnameRegexPattern: hostNameRegexPattern(true),
|
mqttIpOrHostnameRegexPattern: hostNameRegexPattern(true),
|
||||||
ipOrDnsNameRegexPattern: dnsNameRegexPattern(),
|
ipOrDnsNameRegexPattern: dnsNameRegexPattern(),
|
||||||
|
@ -1202,7 +1203,7 @@ export default {
|
||||||
|
|
||||||
// Allow to test with simple dns server with port (127.0.0.1:5300)
|
// Allow to test with simple dns server with port (127.0.0.1:5300)
|
||||||
if (! isDev) {
|
if (! isDev) {
|
||||||
return this.ipRegexPattern;
|
return this.ipRegexPattern.source;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -1211,16 +1212,24 @@ export default {
|
||||||
|
|
||||||
// Permit either IP address or hostname (127.0.0.1, dns.example.com)
|
// Permit either IP address or hostname (127.0.0.1, dns.example.com)
|
||||||
if (! isDev) {
|
if (! isDev) {
|
||||||
return this.ipOrHostnameRegexPattern;
|
return this.ipOrHostnameRegexPattern.source;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
dnsNameRegex() {
|
dnsResolverRegex() {
|
||||||
|
|
||||||
// Permit IP address, hostname, TLD, or root
|
// Permit IP address for TCP/UDP resolvers, hostname for DoH/DoT
|
||||||
if (! isDev) {
|
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;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -1229,7 +1238,7 @@ export default {
|
||||||
|
|
||||||
// Permit only URL paths with a query parameter ( {query} )
|
// Permit only URL paths with a query parameter ( {query} )
|
||||||
if (! isDev) {
|
if (! isDev) {
|
||||||
return this.queryRegexPattern;
|
return this.queryRegexPattern.source;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
|
@ -112,17 +112,37 @@ export function getDevContainerServerHostname() {
|
||||||
* Regex pattern for identifying hostnames and IP addresses
|
* Regex pattern for identifying hostnames and IP addresses
|
||||||
* @param {boolean} mqtt whether or not the regex should take into
|
* @param {boolean} mqtt whether or not the regex should take into
|
||||||
* account the fact that it is an mqtt uri
|
* 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
|
* @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)
|
// 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/
|
// 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}))|:)))(%.+)?$))`;
|
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])$/;
|
||||||
// Source: https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
|
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]))$/;
|
||||||
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_])(\\.)?$`;
|
// 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() {
|
export function dnsNameRegexPattern() {
|
||||||
// This borrows ipRegexPattern from hostNameRegexPattern above
|
// This borrows ipRegexPattern from hostNameRegexPattern above
|
||||||
const ipRegexPattern = hostNameRegexPattern().split("|")[0];
|
const ipRegexPattern = hostNameRegexPattern(false, true, false);
|
||||||
// Similar to hostNameRegexPattern, except the hostname pattern
|
// Similar to hostNameRegexPattern, except the hostname pattern
|
||||||
// can also match root (.) and top-level domains (.com, .org)
|
// can also match root (.) and top-level domains (.com, .org),
|
||||||
const dnsNamePattern = "^(\\.|(\\.?[a-zA-Z0-9_]+)+)$";
|
// 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) {
|
export function urlPathRegexPattern(qstr = false) {
|
||||||
// Ensures a URL path follows query string format
|
// 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}"
|
// 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) {
|
if (qstr) {
|
||||||
return queryStringRegexPattern;
|
return queryStringRegexPattern;
|
||||||
|
|
Loading…
Add table
Reference in a new issue