jumpserver/apps/users/views/profile/reset.py

145 lines
5.1 KiB
Python

# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
from django.views.generic import RedirectView
from django.shortcuts import reverse, redirect
from django.utils.translation import ugettext as _
from django.conf import settings
from django.urls import reverse_lazy
from django.views.generic import FormView
from users.notifications import ResetPasswordSuccessMsg
from common.utils import get_object_or_none, FlashMessageUtil
from common.utils.verify_code import SendAndVerifyCodeUtil
from ...models import User
from ...utils import (
get_password_check_rules, check_password_rules,
)
from ... import forms
__all__ = [
'UserLoginView', 'UserResetPasswordView', 'UserForgotPasswordView',
]
class UserLoginView(RedirectView):
url = reverse_lazy('authentication:login')
query_string = True
class UserForgotPasswordView(FormView):
template_name = 'users/forgot_password.html'
form_class = forms.UserForgotPasswordForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
form = context['form']
if getattr(form, 'errors', None):
e = getattr(form, 'errors')
context['errors'] = e
context['form_type'] = 'email'
context['XPACK_ENABLED'] = settings.XPACK_ENABLED
cleaned_data = getattr(form, 'cleaned_data', {})
for k, v in cleaned_data.items():
if v:
context[k] = v
return context
@staticmethod
def get_redirect_url(user):
query_params = '?token=%s' % user.generate_reset_token()
reset_password_url = reverse('authentication:reset-password')
return reset_password_url + query_params
def form_valid(self, form):
form_type = form.cleaned_data['form_type']
code = form.cleaned_data['code']
username = form.cleaned_data['username']
if settings.XPACK_ENABLED and form_type == 'phone':
backend = 'sms'
target = form.cleaned_data['phone']
else:
backend = 'email'
target = form.cleaned_data['email']
try:
sender_util = SendAndVerifyCodeUtil(target, backend=backend)
sender_util.verify(code)
except Exception as e:
form.add_error('code', str(e))
return super().form_invalid(form)
user = get_object_or_none(User, **{'username': username, form_type: target})
if not user:
form.add_error('username', _('User does not exist: {}').format(username))
return super().form_invalid(form)
return redirect(self.get_redirect_url(user))
class UserResetPasswordView(FormView):
template_name = 'users/reset_password.html'
form_class = forms.UserTokenResetPasswordForm
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
errors = kwargs.get('errors')
if errors:
context['errors'] = errors
return self.render_to_response(context)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
token = self.request.GET.get('token', '')
user = User.validate_reset_password_token(token)
if not user:
context['errors'] = _('Token invalid or expired')
context['token_invalid'] = True
else:
check_rules = get_password_check_rules(user)
context['password_check_rules'] = check_rules
return context
def form_valid(self, form):
token = self.request.GET.get('token')
user = User.validate_reset_password_token(token)
if not user:
error = _('Token invalid or expired')
form.add_error('new_password', error)
return self.form_invalid(form)
if not user.can_update_password():
error = _('User auth from {}, go there change password')
form.add_error('new_password', error.format(user.get_source_display()))
return self.form_invalid(form)
password = form.cleaned_data['new_password']
is_ok = check_password_rules(password, is_org_admin=user.is_org_admin)
if not is_ok:
error = _('* Your password does not meet the requirements')
form.add_error('new_password', error)
return self.form_invalid(form)
if user.is_history_password(password):
limit_count = settings.OLD_PASSWORD_HISTORY_LIMIT_COUNT
error = _('* The new password cannot be the last {} passwords').format(limit_count)
form.add_error('new_password', error)
return self.form_invalid(form)
user.reset_password(password)
User.expired_reset_password_token(token)
ResetPasswordSuccessMsg(user, self.request).publish_async()
url = self.get_redirect_url()
return redirect(url)
@staticmethod
def get_redirect_url():
message_data = {
'title': _('Reset password success'),
'message': _('Reset password success, return to login page'),
'redirect_url': reverse('authentication:login'),
'auto_redirect': True,
}
return FlashMessageUtil.gen_message_url(message_data)