"""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'') # 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) }