added an XMPP URL validator
- Legacy-Id: 17872
This commit is contained in:
parent
8a0578040e
commit
324be05151
|
@ -5,14 +5,15 @@
|
|||
import os
|
||||
import re
|
||||
from pyquery import PyQuery
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urlparse, urlsplit
|
||||
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import RegexValidator, URLValidator, EmailValidator
|
||||
from django.core.validators import RegexValidator, URLValidator, EmailValidator, _lazy_re_compile
|
||||
from django.template.defaultfilters import filesizeformat
|
||||
from django.utils.deconstruct import deconstructible
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
|
@ -92,6 +93,75 @@ validate_url = URLValidator()
|
|||
validate_http_url = URLValidator(schemes=['http','https'])
|
||||
validate_email = EmailValidator()
|
||||
|
||||
@deconstructible
|
||||
class XMPPURLValidator(RegexValidator):
|
||||
ul = '\u00a1-\uffff' # unicode letters range (must not be a raw string)
|
||||
|
||||
# IP patterns
|
||||
ipv4_re = r'(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}'
|
||||
ipv6_re = r'\[[0-9a-f:\.]+\]' # (simple regex, validated later)
|
||||
|
||||
# Host patterns
|
||||
hostname_re = r'[a-z' + ul + r'0-9](?:[a-z' + ul + r'0-9-]{0,61}[a-z' + ul + r'0-9])?'
|
||||
# Max length for domain name labels is 63 characters per RFC 1034 sec. 3.1
|
||||
domain_re = r'(?:\.(?!-)[a-z' + ul + r'0-9-]{1,63}(?<!-))*'
|
||||
tld_re = (
|
||||
r'\.' # dot
|
||||
r'(?!-)' # can't start with a dash
|
||||
r'(?:[a-z' + ul + '-]{2,63}' # domain label
|
||||
r'|xn--[a-z0-9]{1,59})' # or punycode label
|
||||
r'(?<!-)' # can't end with a dash
|
||||
r'\.?' # may have a trailing dot
|
||||
)
|
||||
host_re = '(' + hostname_re + domain_re + tld_re + '|localhost)'
|
||||
|
||||
regex = _lazy_re_compile(
|
||||
r'^(?:xmpp:)' # Note there is no '//'
|
||||
r'(?:[^\s:@/]+(?::[^\s:@/]*)?@)?' # user:pass authentication
|
||||
r'(?:' + ipv4_re + '|' + ipv6_re + '|' + host_re + ')'
|
||||
r'(?::\d{2,5})?' # port
|
||||
r'(?:[/?#][^\s]*)?' # resource path
|
||||
r'\Z', re.IGNORECASE)
|
||||
message = _('Enter a valid URL.')
|
||||
schemes = ['http', 'https', 'ftp', 'ftps']
|
||||
|
||||
def __call__(self, value):
|
||||
try:
|
||||
super().__call__(value)
|
||||
except ValidationError as e:
|
||||
# Trivial case failed. Try for possible IDN domain
|
||||
if value:
|
||||
try:
|
||||
scheme, netloc, path, query, fragment = urlsplit(value)
|
||||
except ValueError: # for example, "Invalid IPv6 URL"
|
||||
raise ValidationError(self.message, code=self.code)
|
||||
try:
|
||||
netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
|
||||
except UnicodeError: # invalid domain part
|
||||
raise e
|
||||
url = urlunsplit((scheme, netloc, path, query, fragment))
|
||||
super().__call__(url)
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
# Now verify IPv6 in the netloc part
|
||||
host_match = re.search(r'^\[(.+)\](?::\d{2,5})?$', urlsplit(value).netloc)
|
||||
if host_match:
|
||||
potential_ip = host_match.groups()[0]
|
||||
try:
|
||||
validate_ipv6_address(potential_ip)
|
||||
except ValidationError:
|
||||
raise ValidationError(self.message, code=self.code)
|
||||
|
||||
# The maximum length of a full host name is 253 characters per RFC 1034
|
||||
# section 3.1. It's defined to be 255 bytes or less, but this includes
|
||||
# one byte for the length of the name and one byte for the trailing dot
|
||||
# that's used to indicate absolute names in DNS.
|
||||
if len(urlsplit(value).netloc) > 253:
|
||||
raise ValidationError(self.message, code=self.code)
|
||||
|
||||
validate_xmpp = XMPPURLValidator()
|
||||
|
||||
def validate_external_resource_value(name, value):
|
||||
""" validate a resource value using its name's properties """
|
||||
|
||||
|
@ -102,11 +172,7 @@ def validate_external_resource_value(name, value):
|
|||
if urlparse(value).netloc.lower() != 'github.com':
|
||||
raise ValidationError('URL must be a github url')
|
||||
elif name.slug == 'jabber_room':
|
||||
pass
|
||||
# TODO - build a xmpp URL validator. See XEP-0032.
|
||||
# It should be easy to build one by copyhacking URLValidator,
|
||||
# but reading source says it would be better to wait to do that
|
||||
# until after we make the Django 2 transition
|
||||
validate_xmpp(value)
|
||||
else:
|
||||
validate_url(value)
|
||||
|
||||
|
|
Loading…
Reference in a new issue