This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/passbook/factors/otp/forms.py
2019-10-07 16:33:48 +02:00

71 lines
2.5 KiB
Python

"""passbook OTP Forms"""
from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.core.validators import RegexValidator
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django_otp.models import Device
from passbook.factors.forms import GENERAL_FIELDS
from passbook.factors.otp.models import OTPFactor
OTP_CODE_VALIDATOR = RegexValidator(r'^[0-9a-z]{6,8}$',
_('Only alpha-numeric characters are allowed.'))
class PictureWidget(forms.widgets.Widget):
"""Widget to render value as img-tag"""
def render(self, name, value, attrs=None, renderer=None):
return mark_safe(f'<img src="{value}" />') # nosec
class OTPVerifyForm(forms.Form):
"""Simple Form to verify OTP Code"""
order = ['code']
code = forms.CharField(label=_('Code'), validators=[OTP_CODE_VALIDATOR],
widget=forms.TextInput(attrs={
'autocomplete': 'off',
'placeholder': 'Code'
}))
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# This is a little helper so the field is focused by default
# TODO: Tell browser to not suggest any values
self.fields['code'].widget.attrs.update({'autofocus': 'autofocus'})
class OTPSetupForm(forms.Form):
"""OTP Setup form"""
title = _('Set up OTP')
device: Device = None
qr_code = forms.CharField(widget=PictureWidget, disabled=True, required=False,
label=_('Scan this Code with your OTP App.'))
code = forms.CharField(label=_('Code'), validators=[OTP_CODE_VALIDATOR],
widget=forms.TextInput(attrs={'placeholder': _('One-Time Password')}))
tokens = forms.MultipleChoiceField(disabled=True, required=False)
def clean_code(self):
"""Check code with new otp device"""
if self.device is not None:
if not self.device.verify_token(int(self.cleaned_data.get('code'))):
raise forms.ValidationError(_("OTP Code does not match"))
return self.cleaned_data.get('code')
class OTPFactorForm(forms.ModelForm):
"""Form to edit OTPFactor instances"""
class Meta:
model = OTPFactor
fields = GENERAL_FIELDS + ['enforced']
widgets = {
'name': forms.TextInput(),
'order': forms.NumberInput(),
'policies': FilteredSelectMultiple(_('policies'), False)
}