Adds IS_IPADDRESS() to gluon/validators.py
IS_IPADDRESS() is mostly a meta function that will call IS_IPV4()
or IS_IPV6 accordingly based upon both dev-configured logic and
library checking of the address given. For instance:
>>> IS_IPADDRESS()('192.168.1.5')
('192.168.1.5', None)
will run through the IS_IPV4() function since the ipaddr.py lib
recognizes it as an IPv4 address. Specific v4 or v6 validation
can be done by setting is_ipv4=True or is_ipv6=True:
>>> IS_IPADDRESS(is_ipv4=True)('fe80::126c:8ffa:fe22:b3af')
('fe80::126c:8ffa:fe22:b3af', 'enter valid IP address')
>>> IS_IPADDRESS(is_ipv6=True)('192.168.1.1')
('192.168.1.1', 'enter valid IP address')
The same arguments for IS_IPV4() and IS_IPV6() are supported and
no changes have been made to either of these two functions. The
goal of this function is to allow IPv4 or IPv6 addresses in a
textfield:
INPUT(_type='text', _name='name', requires=IS_IPADDRESS())
This commit is contained in:
@@ -3529,6 +3529,216 @@ class IS_IPV6(Validator):
|
|||||||
return (value, translate(self.error_message))
|
return (value, translate(self.error_message))
|
||||||
|
|
||||||
|
|
||||||
|
class IS_IPADDRESS(Validator):
|
||||||
|
"""
|
||||||
|
Checks if field's value is an IP Address (v4 or v6). Can be set to force
|
||||||
|
addresses from within a specific range. Checks are done with the correct
|
||||||
|
IS_IPV4 and IS_IPV6 validators.
|
||||||
|
|
||||||
|
Uses ipaddress library if found, falls back to PEP-3144 ipaddr.py from
|
||||||
|
Google (in contrib).
|
||||||
|
|
||||||
|
Universal arguments:
|
||||||
|
|
||||||
|
minip: lowest allowed address; accepts:
|
||||||
|
str, eg. 192.168.0.1
|
||||||
|
list or tuple of octets, eg. [192, 168, 0, 1]
|
||||||
|
maxip: highest allowed address; same as above
|
||||||
|
invert: True to allow addresses only from outside of given range; note
|
||||||
|
that range boundaries are not matched this way
|
||||||
|
|
||||||
|
IPv4 specific arguments:
|
||||||
|
|
||||||
|
is_localhost: localhost address treatment:
|
||||||
|
None (default): indifferent
|
||||||
|
True (enforce): query address must match localhost address
|
||||||
|
(127.0.0.1)
|
||||||
|
False (forbid): query address must not match localhost
|
||||||
|
address
|
||||||
|
is_private: same as above, except that query address is checked against
|
||||||
|
two address ranges: 172.16.0.0 - 172.31.255.255 and
|
||||||
|
192.168.0.0 - 192.168.255.255
|
||||||
|
is_automatic: same as above, except that query address is checked against
|
||||||
|
one address range: 169.254.0.0 - 169.254.255.255
|
||||||
|
is_ipv4: None (default): indifferent
|
||||||
|
True (enforce): must be an IPv4 address
|
||||||
|
False (forbid): must NOT be an IPv4 address
|
||||||
|
|
||||||
|
IPv6 specific arguments:
|
||||||
|
|
||||||
|
is_link_local: Same as above but uses fe80::/10 range
|
||||||
|
is_reserved: Same as above but uses IETF reserved range
|
||||||
|
is_mulicast: Same as above but uses ff00::/8 range
|
||||||
|
is_routeable: Similar to above but enforces not private, link_local,
|
||||||
|
reserved or multicast
|
||||||
|
is_6to4: Same as above but uses 2002::/16 range
|
||||||
|
is_teredo: Same as above but uses 2001::/32 range
|
||||||
|
subnets: value must be a member of at least one from list of subnets
|
||||||
|
is_ipv6: None (default): indifferent
|
||||||
|
True (enforce): must be an IPv6 address
|
||||||
|
False (forbid): must NOT be an IPv6 address
|
||||||
|
|
||||||
|
Minip and maxip may also be lists or tuples of addresses in all above
|
||||||
|
forms (str, int, list / tuple), allowing setup of multiple address ranges:
|
||||||
|
|
||||||
|
minip = (minip1, minip2, ... minipN)
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
maxip = (maxip1, maxip2, ... maxipN)
|
||||||
|
|
||||||
|
Longer iterable will be truncated to match length of shorter one.
|
||||||
|
|
||||||
|
>>> IS_IPADDRESS()('192.168.1.5')
|
||||||
|
('192.168.1.5', None)
|
||||||
|
>>> IS_IPADDRESS(is_ipv6=False)('192.168.1.5')
|
||||||
|
('192.168.1.5', None)
|
||||||
|
>>> IS_IPADDRESS()('255.255.255.255')
|
||||||
|
('255.255.255.255', None)
|
||||||
|
>>> IS_IPADDRESS()('192.168.1.5 ')
|
||||||
|
('192.168.1.5 ', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS()('192.168.1.1.5')
|
||||||
|
('192.168.1.1.5', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS()('123.123')
|
||||||
|
('123.123', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS()('1111.2.3.4')
|
||||||
|
('1111.2.3.4', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS()('0111.2.3.4')
|
||||||
|
('0111.2.3.4', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS()('256.2.3.4')
|
||||||
|
('256.2.3.4', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS()('300.2.3.4')
|
||||||
|
('300.2.3.4', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(minip='192.168.1.0', maxip='192.168.1.255')('192.168.1.100')
|
||||||
|
('192.168.1.100', None)
|
||||||
|
>>> IS_IPADDRESS(minip='1.2.3.5', maxip='1.2.3.9', error_message='bad ip')('1.2.3.4')
|
||||||
|
('1.2.3.4', 'bad ip')
|
||||||
|
>>> IS_IPADDRESS(maxip='1.2.3.4', invert=True)('127.0.0.1')
|
||||||
|
('127.0.0.1', None)
|
||||||
|
>>> IS_IPADDRESS(maxip='192.168.1.4', invert=True)('192.168.1.4')
|
||||||
|
('192.168.1.4', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(is_localhost=True)('127.0.0.1')
|
||||||
|
('127.0.0.1', None)
|
||||||
|
>>> IS_IPADDRESS(is_localhost=True)('192.168.1.10')
|
||||||
|
('192.168.1.10', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(is_localhost=False)('127.0.0.1')
|
||||||
|
('127.0.0.1', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(maxip='100.0.0.0', is_localhost=True)('127.0.0.1')
|
||||||
|
('127.0.0.1', 'enter valid IP address')
|
||||||
|
|
||||||
|
>>> IS_IPADDRESS()('fe80::126c:8ffa:fe22:b3af')
|
||||||
|
('fe80::126c:8ffa:fe22:b3af', None)
|
||||||
|
>>> IS_IPADDRESS(is_ipv4=False)('fe80::126c:8ffa:fe22:b3af')
|
||||||
|
('fe80::126c:8ffa:fe22:b3af', None)
|
||||||
|
>>> IS_IPADDRESS()('fe80::126c:8ffa:fe22:b3af ')
|
||||||
|
('fe80::126c:8ffa:fe22:b3af ', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(is_ipv4=True)('fe80::126c:8ffa:fe22:b3af')
|
||||||
|
('fe80::126c:8ffa:fe22:b3af', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(is_ipv6=True)('192.168.1.1')
|
||||||
|
('192.168.1.1', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(is_ipv6=True, error_message='bad ip')('192.168.1.1')
|
||||||
|
('192.168.1.1', 'bad ip')
|
||||||
|
>>> IS_IPADDRESS(is_link_local=True)('fe80::126c:8ffa:fe22:b3af')
|
||||||
|
('fe80::126c:8ffa:fe22:b3af', None)
|
||||||
|
>>> IS_IPADDRESS(is_link_local=False)('fe80::126c:8ffa:fe22:b3af')
|
||||||
|
('fe80::126c:8ffa:fe22:b3af', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(is_link_local=True)('2001::126c:8ffa:fe22:b3af')
|
||||||
|
('2001::126c:8ffa:fe22:b3af', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(is_multicast=True)('2001::126c:8ffa:fe22:b3af')
|
||||||
|
('2001::126c:8ffa:fe22:b3af', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(is_multicast=True)('ff00::126c:8ffa:fe22:b3af')
|
||||||
|
('ff00::126c:8ffa:fe22:b3af', None)
|
||||||
|
>>> IS_IPADDRESS(is_routeable=True)('2001::126c:8ffa:fe22:b3af')
|
||||||
|
('2001::126c:8ffa:fe22:b3af', None)
|
||||||
|
>>> IS_IPADDRESS(is_routeable=True)('ff00::126c:8ffa:fe22:b3af')
|
||||||
|
('ff00::126c:8ffa:fe22:b3af', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(subnets='2001::/32')('2001::8ffa:fe22:b3af')
|
||||||
|
('2001::8ffa:fe22:b3af', None)
|
||||||
|
>>> IS_IPADDRESS(subnets='fb00::/8')('2001::8ffa:fe22:b3af')
|
||||||
|
('2001::8ffa:fe22:b3af', 'enter valid IP address')
|
||||||
|
>>> IS_IPADDRESS(subnets=['fc00::/8','2001::/32'])('2001::8ffa:fe22:b3af')
|
||||||
|
('2001::8ffa:fe22:b3af', None)
|
||||||
|
>>> IS_IPADDRESS(subnets='invalidsubnet')('2001::8ffa:fe22:b3af')
|
||||||
|
('2001::8ffa:fe22:b3af', 'invalid subnet provided')
|
||||||
|
"""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
minip='0.0.0.0',
|
||||||
|
maxip='255.255.255.255',
|
||||||
|
invert=False,
|
||||||
|
is_localhost=None,
|
||||||
|
is_private=None,
|
||||||
|
is_automatic=None,
|
||||||
|
is_ipv4=None,
|
||||||
|
is_link_local=None,
|
||||||
|
is_reserved=None,
|
||||||
|
is_multicast=None,
|
||||||
|
is_routeable=None,
|
||||||
|
is_6to4=None,
|
||||||
|
is_teredo=None,
|
||||||
|
subnets=None,
|
||||||
|
is_ipv6=None,
|
||||||
|
error_message='enter valid IP address'):
|
||||||
|
self.minip = minip,
|
||||||
|
self.maxip = maxip,
|
||||||
|
self.invert = invert
|
||||||
|
self.is_localhost = is_localhost
|
||||||
|
self.is_private = is_private
|
||||||
|
self.is_automatic = is_automatic
|
||||||
|
self.is_ipv4 = is_ipv4
|
||||||
|
self.is_private = is_private
|
||||||
|
self.is_link_local = is_link_local
|
||||||
|
self.is_reserved = is_reserved
|
||||||
|
self.is_multicast = is_multicast
|
||||||
|
self.is_routeable = is_routeable
|
||||||
|
self.is_6to4 = is_6to4
|
||||||
|
self.is_teredo = is_teredo
|
||||||
|
self.subnets = subnets
|
||||||
|
self.is_ipv6 = is_ipv6
|
||||||
|
self.error_message = error_message
|
||||||
|
|
||||||
|
def __call__(self, value):
|
||||||
|
try:
|
||||||
|
import ipaddress
|
||||||
|
except ImportError:
|
||||||
|
from contrib import ipaddr as ipaddress
|
||||||
|
|
||||||
|
try:
|
||||||
|
ip = ipaddress.ip_address(value)
|
||||||
|
except ValueError, e:
|
||||||
|
return (value, translate(self.error_message))
|
||||||
|
|
||||||
|
if self.is_ipv4 and isinstance(ip, ipaddress.IPv6Address):
|
||||||
|
retval = (value, translate(self.error_message))
|
||||||
|
elif self.is_ipv6 and isinstance(ip, ipaddress.IPv4Address):
|
||||||
|
retval = (value, translate(self.error_message))
|
||||||
|
elif self.is_ipv4 or isinstance(ip, ipaddress.IPv4Address):
|
||||||
|
retval = IS_IPV4(
|
||||||
|
minip=self.minip,
|
||||||
|
maxip=self.maxip,
|
||||||
|
invert=self.invert,
|
||||||
|
is_localhost=self.is_localhost,
|
||||||
|
is_private=self.is_private,
|
||||||
|
is_automatic=self.is_automatic,
|
||||||
|
error_message=self.error_message
|
||||||
|
)(value)
|
||||||
|
elif self.is_ipv6 or isinstance(ip, ipaddress.IPv6Address):
|
||||||
|
retval = IS_IPV6(
|
||||||
|
is_private=self.is_private,
|
||||||
|
is_link_local=self.is_link_local,
|
||||||
|
is_reserved=self.is_reserved,
|
||||||
|
is_multicast=self.is_multicast,
|
||||||
|
is_routeable=self.is_routeable,
|
||||||
|
is_6to4=self.is_6to4,
|
||||||
|
is_teredo=self.is_teredo,
|
||||||
|
subnets=self.subnets,
|
||||||
|
error_message=self.error_message
|
||||||
|
)(value)
|
||||||
|
else:
|
||||||
|
retval = (value, translate(self.error_message))
|
||||||
|
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod(
|
doctest.testmod(
|
||||||
|
|||||||
Reference in New Issue
Block a user