from random import shuffle import re from django.core.exceptions import ValidationError from django.forms import Form, CharField, EmailField, Textarea, ChoiceField, BooleanField import sshpubkeys as ssh from .models import SSH_TYPE_CHOICES USERNAME_RE = re.compile(r'[a-z][a-z0-9_]+') USERNAME_MIN_LENGTH = 4 DISPLAY_NAME_RE = re.compile(r"[a-zA-Z0-9_\-']+") DISPLAY_MIN_LENGTH = 2 # >_> CAPTCHA_CHOICES = [('two', 'zorp borp'), ('three', 'quop bop'), ('four', 'NO, I AM NOT A ROBOT'), ('five', 'crackle zop'), ('six', '*rusty screech*'), ('seven', 'mother, give me legs')] shuffle(CAPTCHA_CHOICES) CAPTCHA_CHOICES.insert(0, ('one', 'beep boop'),) NOT_A_ROBOT = 'four' # <_< def validate_username(username): if len(username) < USERNAME_MIN_LENGTH: raise ValidationError('Username too short.') if not USERNAME_RE.match(username): raise ValidationError('Username must be all lowercase, start with a letter, and only use the _ special charcter') def validate_displayname(display_name): if len(display_name) < DISPLAY_MIN_LENGTH: raise ValidationError('Display name too short.') if not DISPLAY_NAME_RE.match(display_name): raise ValidationError("Valid characters: a-z, A-Z, 0-9, -, _, and '.") def validate_pubkey(pubkey): key = ssh.SSHKey(pubkey, strict_mode=False, skip_option_parsing=True) try: key.parse() except ssh.InvalidKeyException as e: raise ValidationError('Could not validate key: {}'.format(e)) except NotImplementedError as e: raise ValidationError('Invalid key type') except Exception as e: raise ValidationError('unknown error: {}'.format(e)) def validate_captcha(captcha): if captcha != NOT_A_ROBOT: raise ValidationError('Are you sure you are not a robot?') class TownieForm(Form): username = CharField( validators=(validate_username,), help_text='lowercase and no spaces. underscore ok', label='username') email = EmailField( help_text='only used to message you about your account and nothing else.', label='e-mail') displayname = CharField( validators=(validate_displayname,), help_text='100% optional. pseudonyms welcome.', label='display name', required=False) reasons = CharField( widget=Textarea, required=False, label='what interests you about tilde.town?', help_text='This is a totally optional place for you to tell us what excites you about getting a ~ account. This is mainly just so we can all feel warm fuzzies.') captcha = ChoiceField( choices=CAPTCHA_CHOICES, label='are you a robot?', help_text='pick the response that indicates whether or not you are a robot.', validators=(validate_captcha,) ) pubkey = CharField( widget=Textarea, validators=(validate_pubkey,), label='SSH public key', help_text='if this is not a thing you are familiar with, that\'s okay! check out our guide to learn how to get one of these.') pubkey_type = ChoiceField( choices=SSH_TYPE_CHOICES, label='SSH public key type', help_text="unless you know what you're doing you can leave this be.") aup = BooleanField( label='i super agree to our acceptable use policy', help_text='please read our code of conduct and click this box if you agree.') def clean(self): result = super().clean() if self.errors: raise ValidationError('oops, looks like there were some problems below.') return result