608ffd9663
Adds basic labels support to the registry code (V2), and the API. Note that this does not yet add any UI related support.
85 lines
2.4 KiB
Python
85 lines
2.4 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.'
|
|
INVALID_USERNAME_CHARACTERS = r'[^a-z0-9_]'
|
|
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])?$'
|
|
|
|
|
|
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):
|
|
return bool(re.match(r'[^@]+@[^@]+\.[^@]+', email_address))
|
|
|
|
|
|
def validate_username(username):
|
|
# Based off the restrictions defined in the Docker Registry API spec
|
|
regex_match = (re.search(INVALID_USERNAME_CHARACTERS, username) is None)
|
|
if not regex_match:
|
|
return (False, 'Username must match expression [a-z0-9_]+')
|
|
|
|
length_match = (len(username) >= MIN_USERNAME_LENGTH and len(username) <= MAX_USERNAME_LENGTH)
|
|
if not length_match:
|
|
return (False, 'Username 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):
|
|
# Docker's regex: [a-z0-9]+(?:[._-][a-z0-9]+)*
|
|
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]
|
|
|
|
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
|
|
|