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 Townie, 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):
# TODO actually check for existence of user on the current system with
# 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')
duplicate = Townie.objects.filter(username=username).count()
if duplicate > 0:
raise ValidationError('Username already in use :(')
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):
# TODO see if I can get the type out
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