PageRenderTime 24ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/python-packages/django/contrib/auth/forms.py

https://gitlab.com/gregtyka/ka-lite
Python | 358 lines | 294 code | 33 blank | 31 comment | 31 complexity | 3a052d54f7566ed5903bc3e6342097cc MD5 | raw file
  1. from __future__ import unicode_literals
  2. from django import forms
  3. from django.forms.util import flatatt
  4. from django.template import loader
  5. from django.utils.datastructures import SortedDict
  6. from django.utils.html import format_html, format_html_join
  7. from django.utils.http import int_to_base36
  8. from django.utils.safestring import mark_safe
  9. from django.utils.text import capfirst
  10. from django.utils.translation import ugettext, ugettext_lazy as _
  11. from django.contrib.auth import authenticate, get_user_model
  12. from django.contrib.auth.models import User
  13. from django.contrib.auth.hashers import UNUSABLE_PASSWORD, identify_hasher
  14. from django.contrib.auth.tokens import default_token_generator
  15. from django.contrib.sites.models import get_current_site
  16. UNMASKED_DIGITS_TO_SHOW = 6
  17. mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p) - UNMASKED_DIGITS_TO_SHOW, 0))
  18. class ReadOnlyPasswordHashWidget(forms.Widget):
  19. def render(self, name, value, attrs):
  20. encoded = value
  21. final_attrs = self.build_attrs(attrs)
  22. if not encoded or encoded == UNUSABLE_PASSWORD:
  23. summary = mark_safe("<strong>%s</strong>" % ugettext("No password set."))
  24. else:
  25. try:
  26. hasher = identify_hasher(encoded)
  27. except ValueError:
  28. summary = mark_safe("<strong>%s</strong>" % ugettext(
  29. "Invalid password format or unknown hashing algorithm."))
  30. else:
  31. summary = format_html_join('',
  32. "<strong>{0}</strong>: {1} ",
  33. ((ugettext(key), value)
  34. for key, value in hasher.safe_summary(encoded).items())
  35. )
  36. return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary)
  37. class ReadOnlyPasswordHashField(forms.Field):
  38. widget = ReadOnlyPasswordHashWidget
  39. def __init__(self, *args, **kwargs):
  40. kwargs.setdefault("required", False)
  41. super(ReadOnlyPasswordHashField, self).__init__(*args, **kwargs)
  42. def bound_data(self, data, initial):
  43. # Always return initial because the widget doesn't
  44. # render an input field.
  45. return initial
  46. class UserCreationForm(forms.ModelForm):
  47. """
  48. A form that creates a user, with no privileges, from the given username and
  49. password.
  50. """
  51. error_messages = {
  52. 'duplicate_username': _("A user with that username already exists."),
  53. 'password_mismatch': _("The two password fields didn't match."),
  54. }
  55. #Changed to modify username length from 30 to 75 (matching email addresses)
  56. username = forms.RegexField(label=_("Username"), max_length=75, # KA-LITE-MOD (using email addr for username)
  57. regex=r'^[\w.@+-]+$',
  58. help_text=_("Required. 30 characters or fewer. Letters, digits and "
  59. "@/./+/-/_ only."),
  60. error_messages={
  61. 'invalid': _("This value may contain only letters, numbers and "
  62. "@/./+/-/_ characters.")})
  63. password1 = forms.CharField(label=_("Password"),
  64. widget=forms.PasswordInput)
  65. password2 = forms.CharField(label=_("Password confirmation"),
  66. widget=forms.PasswordInput,
  67. help_text=_("Enter the same password as above, for verification."))
  68. class Meta:
  69. model = User
  70. fields = ("username",)
  71. def clean_username(self):
  72. # Since User.username is unique, this check is redundant,
  73. # but it sets a nicer error message than the ORM. See #13147.
  74. username = self.cleaned_data["username"]
  75. try:
  76. User._default_manager.get(username=username)
  77. except User.DoesNotExist:
  78. return username
  79. raise forms.ValidationError(self.error_messages['duplicate_username'])
  80. def clean_password2(self):
  81. password1 = self.cleaned_data.get("password1")
  82. password2 = self.cleaned_data.get("password2")
  83. if password1 and password2 and password1 != password2:
  84. raise forms.ValidationError(
  85. self.error_messages['password_mismatch'])
  86. return password2
  87. def save(self, commit=True):
  88. user = super(UserCreationForm, self).save(commit=False)
  89. user.set_password(self.cleaned_data["password1"])
  90. if commit:
  91. user.save()
  92. return user
  93. class UserChangeForm(forms.ModelForm):
  94. username = forms.RegexField(
  95. label=_("Username"), max_length=30, regex=r"^[\w.@+-]+$",
  96. help_text=_("Required. 30 characters or fewer. Letters, digits and "
  97. "@/./+/-/_ only."),
  98. error_messages={
  99. 'invalid': _("This value may contain only letters, numbers and "
  100. "@/./+/-/_ characters.")})
  101. password = ReadOnlyPasswordHashField(label=_("Password"),
  102. help_text=_("Raw passwords are not stored, so there is no way to see "
  103. "this user's password, but you can change the password "
  104. "using <a href=\"password/\">this form</a>."))
  105. class Meta:
  106. model = User
  107. def __init__(self, *args, **kwargs):
  108. super(UserChangeForm, self).__init__(*args, **kwargs)
  109. f = self.fields.get('user_permissions', None)
  110. if f is not None:
  111. f.queryset = f.queryset.select_related('content_type')
  112. def clean_password(self):
  113. # Regardless of what the user provides, return the initial value.
  114. # This is done here, rather than on the field, because the
  115. # field does not have access to the initial value
  116. return self.initial["password"]
  117. class AuthenticationForm(forms.Form):
  118. """
  119. Base class for authenticating users. Extend this to get a form that accepts
  120. username/password logins.
  121. """
  122. username = forms.CharField(max_length=254)
  123. password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
  124. error_messages = {
  125. 'invalid_login': _("Please enter a correct %(username)s and password. "
  126. "Note that both fields may be case-sensitive."),
  127. 'no_cookies': _("Your Web browser doesn't appear to have cookies "
  128. "enabled. Cookies are required for logging in."),
  129. 'inactive': _("This account is inactive."),
  130. }
  131. def __init__(self, request=None, *args, **kwargs):
  132. """
  133. If request is passed in, the form will validate that cookies are
  134. enabled. Note that the request (a HttpRequest object) must have set a
  135. cookie with the key TEST_COOKIE_NAME and value TEST_COOKIE_VALUE before
  136. running this validation.
  137. """
  138. self.request = request
  139. self.user_cache = None
  140. super(AuthenticationForm, self).__init__(*args, **kwargs)
  141. # Set the label for the "username" field.
  142. UserModel = get_user_model()
  143. self.username_field = UserModel._meta.get_field(UserModel.USERNAME_FIELD)
  144. if not self.fields['username'].label:
  145. self.fields['username'].label = capfirst(self.username_field.verbose_name)
  146. def clean(self):
  147. username = self.cleaned_data.get('username')
  148. password = self.cleaned_data.get('password')
  149. if username and password:
  150. self.user_cache = authenticate(username=username,
  151. password=password)
  152. if self.user_cache is None:
  153. raise forms.ValidationError(
  154. self.error_messages['invalid_login'] % {
  155. 'username': self.username_field.verbose_name
  156. })
  157. elif not self.user_cache.is_active:
  158. raise forms.ValidationError(self.error_messages['inactive'])
  159. self.check_for_test_cookie()
  160. return self.cleaned_data
  161. def check_for_test_cookie(self):
  162. if self.request and not self.request.session.test_cookie_worked():
  163. raise forms.ValidationError(self.error_messages['no_cookies'])
  164. def get_user_id(self):
  165. if self.user_cache:
  166. return self.user_cache.id
  167. return None
  168. def get_user(self):
  169. return self.user_cache
  170. class PasswordResetForm(forms.Form):
  171. error_messages = {
  172. 'unknown': _("That email address doesn't have an associated "
  173. "user account. Are you sure you've registered?"),
  174. 'unusable': _("The user account associated with this email "
  175. "address cannot reset the password."),
  176. }
  177. email = forms.EmailField(label=_("Email"), max_length=254)
  178. def clean_email(self):
  179. """
  180. Validates that an active user exists with the given email address.
  181. """
  182. UserModel = get_user_model()
  183. email = self.cleaned_data["email"]
  184. self.users_cache = UserModel._default_manager.filter(email__iexact=email)
  185. if not len(self.users_cache):
  186. raise forms.ValidationError(self.error_messages['unknown'])
  187. if not any(user.is_active for user in self.users_cache):
  188. # none of the filtered users are active
  189. raise forms.ValidationError(self.error_messages['unknown'])
  190. if any((user.password == UNUSABLE_PASSWORD)
  191. for user in self.users_cache):
  192. raise forms.ValidationError(self.error_messages['unusable'])
  193. return email
  194. def save(self, domain_override=None,
  195. subject_template_name='registration/password_reset_subject.txt',
  196. email_template_name='registration/password_reset_email.html',
  197. use_https=False, token_generator=default_token_generator,
  198. from_email=None, request=None):
  199. """
  200. Generates a one-use only link for resetting password and sends to the
  201. user.
  202. """
  203. from django.core.mail import send_mail
  204. for user in self.users_cache:
  205. if not domain_override:
  206. current_site = get_current_site(request)
  207. site_name = current_site.name
  208. domain = current_site.domain
  209. else:
  210. site_name = domain = domain_override
  211. c = {
  212. 'email': user.email,
  213. 'domain': domain,
  214. 'site_name': site_name,
  215. 'uid': int_to_base36(user.pk),
  216. 'user': user,
  217. 'token': token_generator.make_token(user),
  218. 'protocol': use_https and 'https' or 'http',
  219. }
  220. subject = loader.render_to_string(subject_template_name, c)
  221. # Email subject *must not* contain newlines
  222. subject = ''.join(subject.splitlines())
  223. email = loader.render_to_string(email_template_name, c)
  224. send_mail(subject, email, from_email, [user.email])
  225. class SetPasswordForm(forms.Form):
  226. """
  227. A form that lets a user change set his/her password without entering the
  228. old password
  229. """
  230. error_messages = {
  231. 'password_mismatch': _("The two password fields didn't match."),
  232. }
  233. new_password1 = forms.CharField(label=_("New password"),
  234. widget=forms.PasswordInput)
  235. new_password2 = forms.CharField(label=_("New password confirmation"),
  236. widget=forms.PasswordInput)
  237. def __init__(self, user, *args, **kwargs):
  238. self.user = user
  239. super(SetPasswordForm, self).__init__(*args, **kwargs)
  240. def clean_new_password2(self):
  241. password1 = self.cleaned_data.get('new_password1')
  242. password2 = self.cleaned_data.get('new_password2')
  243. if password1 and password2:
  244. if password1 != password2:
  245. raise forms.ValidationError(
  246. self.error_messages['password_mismatch'])
  247. return password2
  248. def save(self, commit=True):
  249. self.user.set_password(self.cleaned_data['new_password1'])
  250. if commit:
  251. self.user.save()
  252. return self.user
  253. class PasswordChangeForm(SetPasswordForm):
  254. """
  255. A form that lets a user change his/her password by entering
  256. their old password.
  257. """
  258. error_messages = dict(SetPasswordForm.error_messages, **{
  259. 'password_incorrect': _("Your old password was entered incorrectly. "
  260. "Please enter it again."),
  261. })
  262. old_password = forms.CharField(label=_("Old password"),
  263. widget=forms.PasswordInput)
  264. def clean_old_password(self):
  265. """
  266. Validates that the old_password field is correct.
  267. """
  268. old_password = self.cleaned_data["old_password"]
  269. if not self.user.check_password(old_password):
  270. raise forms.ValidationError(
  271. self.error_messages['password_incorrect'])
  272. return old_password
  273. PasswordChangeForm.base_fields = SortedDict([
  274. (k, PasswordChangeForm.base_fields[k])
  275. for k in ['old_password', 'new_password1', 'new_password2']
  276. ])
  277. class AdminPasswordChangeForm(forms.Form):
  278. """
  279. A form used to change the password of a user in the admin interface.
  280. """
  281. error_messages = {
  282. 'password_mismatch': _("The two password fields didn't match."),
  283. }
  284. password1 = forms.CharField(label=_("Password"),
  285. widget=forms.PasswordInput)
  286. password2 = forms.CharField(label=_("Password (again)"),
  287. widget=forms.PasswordInput)
  288. def __init__(self, user, *args, **kwargs):
  289. self.user = user
  290. super(AdminPasswordChangeForm, self).__init__(*args, **kwargs)
  291. def clean_password2(self):
  292. password1 = self.cleaned_data.get('password1')
  293. password2 = self.cleaned_data.get('password2')
  294. if password1 and password2:
  295. if password1 != password2:
  296. raise forms.ValidationError(
  297. self.error_messages['password_mismatch'])
  298. return password2
  299. def save(self, commit=True):
  300. """
  301. Saves the new password.
  302. """
  303. self.user.set_password(self.cleaned_data["password1"])
  304. if commit:
  305. self.user.save()
  306. return self.user