This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/util/validation.py
Joseph Schorr 462f47924e More detailed namespace validation
Fixes namespace validation to use the proper regex for checking length, as well as showing the proper messaging if the entered namespace is invalid

[Delivers #137830461]
2017-01-17 17:31:59 -05:00

91 lines
2.5 KiB
Python

import string
import re
import json
import anunidecode # Don't listen to pylint's lies. This import is required.
INVALID_PASSWORD_MESSAGE = 'Invalid password, password must be at least ' + \
'8 characters and contain no whitespace.'
VALID_CHARACTERS = string.digits + string.lowercase
MIN_USERNAME_LENGTH = 4
MAX_USERNAME_LENGTH = 30
VALID_LABEL_KEY_REGEX = r'^[a-z0-9](([a-z0-9]|[-.](?![.-]))*[a-z0-9])?$'
VALID_USERNAME_REGEX = r'^([a-z0-9]+(?:[._-][a-z0-9]+)*)$'
INVALID_USERNAME_CHARACTERS = r'[^a-z0-9_]'
def validate_label_key(label_key):
if len(label_key) > 255:
return False
return bool(re.match(VALID_LABEL_KEY_REGEX, label_key))
def validate_email(email_address):
if not email_address:
return False
return bool(re.match(r'[^@]+@[^@]+\.[^@]+', email_address))
def validate_username(username):
# Based off the restrictions defined in the Docker Registry API spec
if not re.match(VALID_USERNAME_REGEX, username):
return (False, 'Namespace must match expression ' + VALID_USERNAME_REGEX)
length_match = (len(username) >= MIN_USERNAME_LENGTH and len(username) <= MAX_USERNAME_LENGTH)
if not length_match:
return (False, 'Namespace must be between %s and %s characters in length' %
(MIN_USERNAME_LENGTH, MAX_USERNAME_LENGTH))
return (True, '')
def validate_password(password):
# No whitespace and minimum length of 8
if re.search(r'\s', password):
return False
return len(password) > 7
def _gen_filler_chars(num_filler_chars):
if num_filler_chars == 0:
yield ''
else:
for char in VALID_CHARACTERS:
for suffix in _gen_filler_chars(num_filler_chars - 1):
yield char + suffix
def generate_valid_usernames(input_username):
normalized = input_username.encode('unidecode', 'ignore').strip().lower()
prefix = re.sub(INVALID_USERNAME_CHARACTERS, '_', normalized)[:30]
prefix = re.sub(r'_{2,}', '_', prefix)
if prefix.endswith('_'):
prefix = prefix[0:len(prefix) - 1]
while prefix.startswith('_'):
prefix = prefix[1:]
num_filler_chars = max(0, MIN_USERNAME_LENGTH - len(prefix))
while num_filler_chars + len(prefix) <= MAX_USERNAME_LENGTH:
for suffix in _gen_filler_chars(num_filler_chars):
yield prefix + suffix
num_filler_chars += 1
def is_json(value):
if ((value.startswith('{') and value.endswith('}')) or
(value.startswith('[') and value.endswith(']'))):
try:
json.loads(value)
return True
except TypeError:
return False