Added domain validation
Modify Pydantic Models
This commit is contained in:
@ -1,11 +1,24 @@
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel, field_validator, ValidationInfo
|
||||||
from ipaddress import IPv4Address, IPv6Address
|
from ipaddress import IPv4Address, IPv6Address, ip_address
|
||||||
|
import socket
|
||||||
|
|
||||||
class StatusResponse(BaseModel):
|
class StatusResponse(BaseModel):
|
||||||
ipv4: IPv4Address | None = None
|
ipv4: str | None = None
|
||||||
ipv6: IPv6Address | None = None
|
ipv6: str | None = None
|
||||||
|
|
||||||
|
@field_validator('ipv4', 'ipv6', mode='before')
|
||||||
|
def check_ip_or_domain(cls, v: str, info: ValidationInfo):
|
||||||
|
if v is None:
|
||||||
|
return v
|
||||||
|
try:
|
||||||
|
ip_address(v)
|
||||||
|
return v
|
||||||
|
except ValueError:
|
||||||
|
try:
|
||||||
|
socket.getaddrinfo(v, None)
|
||||||
|
return v
|
||||||
|
except socket.gaierror:
|
||||||
|
raise ValueError(f"'{v}' is not a valid IPv4 or IPv6 address or domain name")
|
||||||
|
|
||||||
class EditInputBody(StatusResponse):
|
class EditInputBody(StatusResponse):
|
||||||
pass
|
pass
|
||||||
@ -264,14 +264,18 @@
|
|||||||
if (!port) return false;
|
if (!port) return false;
|
||||||
return /^[0-9]+$/.test(port) && parseInt(port) > 0 && parseInt(port) <= 65535;
|
return /^[0-9]+$/.test(port) && parseInt(port) > 0 && parseInt(port) <= 65535;
|
||||||
}
|
}
|
||||||
function isValidIP(ip, version) {
|
function isValidIPorDomain(input) {
|
||||||
if (!ip) return true;
|
if (!input) return true;
|
||||||
|
|
||||||
|
const ipV4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
||||||
|
const ipV6Regex = /^(([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}|:))$/;
|
||||||
|
const domainRegex = /^(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}$/;
|
||||||
|
const lowerInput = input.toLowerCase();
|
||||||
|
|
||||||
|
if (ipV4Regex.test(input)) return true;
|
||||||
|
if (ipV6Regex.test(input)) return true;
|
||||||
|
if (domainRegex.test(lowerInput) && !lowerInput.startsWith("http://") && !lowerInput.startsWith("https://")) return true;
|
||||||
|
|
||||||
if (version === 4) {
|
|
||||||
return /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ip);
|
|
||||||
} else if (version === 6) {
|
|
||||||
return /^(([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}|:))$/.test(ip);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,15 +356,8 @@
|
|||||||
} else {
|
} else {
|
||||||
input.removeClass('is-invalid');
|
input.removeClass('is-invalid');
|
||||||
}
|
}
|
||||||
} else if (id === 'ipv4') {
|
} else if (id === 'ipv4' || id === 'ipv6') { // Apply isValidIPorDomain for both IPv4 and IPv6
|
||||||
if (!isValidIP(input.val(), 4)) {
|
if (!isValidIPorDomain(input.val())) {
|
||||||
input.addClass('is-invalid');
|
|
||||||
isValid = false;
|
|
||||||
} else {
|
|
||||||
input.removeClass('is-invalid');
|
|
||||||
}
|
|
||||||
} else if (id === 'ipv6') {
|
|
||||||
if (!isValidIP(input.val(), 6)) {
|
|
||||||
input.addClass('is-invalid');
|
input.addClass('is-invalid');
|
||||||
isValid = false;
|
isValid = false;
|
||||||
} else {
|
} else {
|
||||||
@ -447,15 +444,15 @@
|
|||||||
$("#ipv4").val(data.ipv4 || "");
|
$("#ipv4").val(data.ipv4 || "");
|
||||||
$("#ipv6").val(data.ipv6 || "");
|
$("#ipv6").val(data.ipv6 || "");
|
||||||
|
|
||||||
$("#ipv4").attr("placeholder", "Enter IPv4");
|
$("#ipv4").attr("placeholder", "Enter IPv4 or Domain");
|
||||||
$("#ipv6").attr("placeholder", "Enter IPv6");
|
$("#ipv6").attr("placeholder", "Enter IPv6 or Domain");
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function () {
|
||||||
console.error("Failed to fetch IP addresses.");
|
console.error("Failed to fetch IP addresses.");
|
||||||
$("#ipv4").attr("placeholder", "Enter IPv4");
|
$("#ipv4").attr("placeholder", "Enter IPv4 or Domain");
|
||||||
$("#ipv6").attr("placeholder", "Enter IPv6");
|
$("#ipv6").attr("placeholder", "Enter IPv6 or Domain");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -695,21 +692,14 @@
|
|||||||
$(this).addClass('is-invalid');
|
$(this).addClass('is-invalid');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$('#ipv4').on('input', function () {
|
$('#ipv4, #ipv6').on('input', function () { // Apply to both ipv4 and ipv6
|
||||||
if (isValidIP($(this).val(), 4)) {
|
if (isValidIPorDomain($(this).val())) {
|
||||||
$(this).removeClass('is-invalid');
|
$(this).removeClass('is-invalid');
|
||||||
} else {
|
} else {
|
||||||
$(this).addClass('is-invalid');
|
$(this).addClass('is-invalid');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#ipv6').on('input', function () {
|
|
||||||
if (isValidIP($(this).val(), 6)) {
|
|
||||||
$(this).removeClass('is-invalid');
|
|
||||||
} else {
|
|
||||||
$(this).addClass('is-invalid');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$('#telegram_api_token, #telegram_admin_id').on('input', function () {
|
$('#telegram_api_token, #telegram_admin_id').on('input', function () {
|
||||||
if ($(this).val().trim() !== "") {
|
if ($(this).val().trim() !== "") {
|
||||||
$(this).removeClass('is-invalid');
|
$(this).removeClass('is-invalid');
|
||||||
|
|||||||
Reference in New Issue
Block a user