Commit 6f455e79 authored by Jan Čermák's avatar Jan Čermák

added server-side IP validation, validators converted to new-style classes,...

added server-side IP validation, validators converted to new-style classes, rewrite of JS IP validation - refs #2986 & refs #2995
parent 12fac06c
...@@ -201,7 +201,8 @@ def config_page_post(page_name): ...@@ -201,7 +201,8 @@ def config_page_post(page_name):
bottle.redirect(request.fullpath) bottle.redirect(request.fullpath)
except TypeError: except TypeError:
# raised by Validator - could happen when the form is posted with wrong fields # raised by Validator - could happen when the form is posted with wrong fields
pass logger.exception("Error when saving form.")
logger.warning("Form not saved.")
return config_page.render(config_pages=config_page_map.display_names(), return config_page.render(config_pages=config_page_map.display_names(),
active_handler_key=page_name) active_handler_key=page_name)
......
...@@ -178,14 +178,17 @@ class WanHandler(BaseConfigHandler): ...@@ -178,14 +178,17 @@ class WanHandler(BaseConfigHandler):
.requires("proto", WAN_STATIC) .requires("proto", WAN_STATIC)
wan_main.add_field(Textbox, name="ip6addr", label=_("IPv6 address"), wan_main.add_field(Textbox, name="ip6addr", label=_("IPv6 address"),
nuci_path="uci.network.wan.ip6addr", nuci_path="uci.network.wan.ip6addr",
validators=validators.IPv6(),
required=True)\ required=True)\
.requires("proto", WAN_STATIC)\ .requires("proto", WAN_STATIC)\
.requires("static_ipv6", True) .requires("static_ipv6", True)
wan_main.add_field(Textbox, name="ip6gw", label=_("IPv6 gateway"), wan_main.add_field(Textbox, name="ip6gw", label=_("IPv6 gateway"),
validators=validators.IPv6(),
nuci_path="uci.network.wan.ip6gw")\ nuci_path="uci.network.wan.ip6gw")\
.requires("proto", WAN_STATIC)\ .requires("proto", WAN_STATIC)\
.requires("static_ipv6", True) .requires("static_ipv6", True)
wan_main.add_field(Textbox, name="ip6prefix", label=_("IPv6 prefix"), wan_main.add_field(Textbox, name="ip6prefix", label=_("IPv6 prefix"),
validators=validators.IPv6Prefix(),
nuci_path="uci.network.wan.ip6prefix")\ nuci_path="uci.network.wan.ip6prefix")\
.requires("proto", WAN_STATIC)\ .requires("proto", WAN_STATIC)\
.requires("static_ipv6", True) .requires("static_ipv6", True)
......
...@@ -19,8 +19,24 @@ var ForisWizard = {}; ...@@ -19,8 +19,24 @@ var ForisWizard = {};
ForisWizard.validators = { ForisWizard.validators = {
ipv4: function(value) { ipv4: function(value) {
var re_ipv4 = /^(\d{1,3}\.){3}\d{1,3}$/; var bytes = value.split(".");
return value.search(re_ipv4) != -1; if (bytes.length != 4)
return false;
var intRE = /^[0-9]+$/;
for (var i = 0; i < bytes.length; i++) {
// check it's an integer number, not exponential format, hex number etc...
if (!intRE.test(bytes[i]))
return false;
if (bytes[i] < 0 || bytes[i] > 255)
return false;
}
return true;
},
ipv6: function(value) {
return true; // TODO: at least basic IPv6 check
},
ipv6prefix: function(value) {
return true; // TODO: at least basic IPv6 check
}, },
integer: function(value) { integer: function(value) {
var re_integer = /^\d+$/; var re_integer = /^\d+$/;
......
...@@ -21,7 +21,7 @@ import re ...@@ -21,7 +21,7 @@ import re
PARAM_DELIMITER = "|" PARAM_DELIMITER = "|"
class Validator: class Validator(object):
js_validator = None js_validator = None
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
...@@ -42,7 +42,7 @@ class Validator: ...@@ -42,7 +42,7 @@ class Validator:
class RegExp(Validator): class RegExp(Validator):
def __init__(self, msg, reg_exp): def __init__(self, msg, reg_exp):
self.reg_exp = re.compile(reg_exp) self.reg_exp = re.compile(reg_exp)
Validator.__init__(self, msg, lambda val: bool(self.reg_exp.match(val))) super(RegExp, self).__init__(msg, lambda val: bool(self.reg_exp.match(val)))
def valid(self, value): def valid(self, value):
return bool(self.reg_exp.match(value)) return bool(self.reg_exp.match(value))
...@@ -52,28 +52,73 @@ class NotEmpty(Validator): ...@@ -52,28 +52,73 @@ class NotEmpty(Validator):
js_validator = "notempty" js_validator = "notempty"
def __init__(self): def __init__(self):
Validator.__init__(self, "This field is required.", bool) super(NotEmpty, self).__init__("This field is required.", bool)
class IPv4(RegExp): class IPv4(Validator):
js_validator = "ipv4" js_validator = "ipv4"
def __init__(self): def __init__(self):
RegExp.__init__(self, "Not a valid IPv4 address.", r"(\d{1,3}\.){3}\d{1,3}") super(IPv4, self).__init__("Not a valid IPv4 address.", None)
def valid(self, value):
import socket
try:
socket.inet_pton(socket.AF_INET, value)
return True
except socket.error:
pass
return False
class IPv6(Validator):
js_validator = "ipv6"
def __init__(self):
super(IPv6, self).__init__("Not a valid IPv6 address.", None)
def valid(self, value):
import socket
try:
socket.inet_pton(socket.AF_INET6, value)
return True
except Exception:
pass
return False
class IPv6Prefix(Validator):
js_validator = "ipv6prefix"
def __init__(self):
super(IPv6Prefix, self).__init__("Not a valid IPv6 prefix.", None)
def valid(self, value):
import socket
try:
address, length = value.split("/")
length = int(length)
socket.inet_pton(socket.AF_INET6, address)
if length < 0 or length > 128:
return False
return True
except Exception:
pass
return False
class Integer(RegExp): class Integer(RegExp):
js_validator = "integer" js_validator = "integer"
def __init__(self): def __init__(self):
RegExp.__init__(self, "Is not a number.", r"\d+") super(Integer, self).__init__("Is not a number.", r"\d+")
class MacAddress(RegExp): class MacAddress(RegExp):
js_validator = "macaddress" js_validator = "macaddress"
def __init__(self): def __init__(self):
RegExp.__init__(self, "MAC address is not valid.", r"([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}") super(MacAddress, self).__init__("MAC address is not valid.", r"([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}")
class InRange(Validator): class InRange(Validator):
...@@ -90,7 +135,7 @@ class LenRange(Validator): ...@@ -90,7 +135,7 @@ class LenRange(Validator):
def __init__(self, low, high): def __init__(self, low, high):
test = lambda val: low <= len(val) <= high test = lambda val: low <= len(val) <= high
Validator.__init__(self, "Length must be from %s to %s characters." % (low, high), test) super(LenRange, self).__init__("Length must be from %s to %s characters." % (low, high), test)
self.js_validator_params = "%s%s%s" % (low, PARAM_DELIMITER, high) self.js_validator_params = "%s%s%s" % (low, PARAM_DELIMITER, high)
...@@ -98,7 +143,7 @@ class FieldsEqual(Validator): ...@@ -98,7 +143,7 @@ class FieldsEqual(Validator):
js_validator = "eqfields" js_validator = "eqfields"
def __init__(self, field1, field2, message): def __init__(self, field1, field2, message):
Validator.__init__(self, message, lambda data: data[field1] == data[field2]) super(FieldsEqual, self).__init__(message, lambda data: data[field1] == data[field2])
self.js_validator_params = PARAM_DELIMITER.join([field1, field2, message]) self.js_validator_params = PARAM_DELIMITER.join([field1, field2, message])
......
...@@ -332,7 +332,8 @@ def step_post(number=1): ...@@ -332,7 +332,8 @@ def step_post(number=1):
bottle.redirect(reverse("wizard_step", number=int(number) + 1)) bottle.redirect(reverse("wizard_step", number=int(number) + 1))
except TypeError: except TypeError:
# raised by Validator - could happen when the form is posted with wrong fields # raised by Validator - could happen when the form is posted with wrong fields
pass logger.exception("Error when saving form.")
logger.warning("Form not saved.")
return wiz.render(stepnumber=number) return wiz.render(stepnumber=number)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment