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

88 lines
2.6 KiB
Python
Raw Normal View History

"""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 gettext_lazy as _
2019-10-07 14:33:48 +00:00
from django_otp.models import Device
2019-10-07 14:33:48 +00:00
from passbook.factors.otp.models import OTPFactor
from passbook.flows.forms import GENERAL_FIELDS
2019-12-31 11:51:16 +00:00
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):
2019-12-31 11:51:16 +00:00
return mark_safe(f'<img src="{value}" />') # nosec
class OTPVerifyForm(forms.Form):
"""Simple Form to verify OTP Code"""
2019-12-31 11:51:16 +00:00
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
2019-12-31 11:51:16 +00:00
self.fields["code"].widget.attrs.update(
{"autofocus": "autofocus", "autocomplete": "off"}
)
class OTPSetupForm(forms.Form):
"""OTP Setup form"""
2019-12-31 11:51:16 +00:00
title = _("Set up OTP")
2019-10-07 14:33:48 +00:00
device: Device = None
2019-12-31 11:51:16 +00:00
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:
2019-12-31 11:51:16 +00:00
if not self.device.verify_token(int(self.cleaned_data.get("code"))):
raise forms.ValidationError(_("OTP Code does not match"))
2019-12-31 11:51:16 +00:00
return self.cleaned_data.get("code")
class OTPFactorForm(forms.ModelForm):
"""Form to edit OTPFactor instances"""
class Meta:
model = OTPFactor
2019-12-31 11:51:16 +00:00
fields = GENERAL_FIELDS + ["enforced"]
widgets = {
2019-12-31 11:51:16 +00:00
"name": forms.TextInput(),
"order": forms.NumberInput(),
"policies": FilteredSelectMultiple(_("policies"), False),
}
help_texts = {
"policies": _(
"Policies which determine if this factor applies to the current user."
)
}