@ -6,6 +6,9 @@ from django.http import HttpResponse, HttpResponseRedirect
from django . core . validators import validate_email , ValidationError
from django . urls import reverse_lazy
from django_nameko import get_pool
from django . contrib . auth . tokens import PasswordResetTokenGenerator
from base64 import b64encode , b64decode
from datetime import datetime
# Check to see if the username is already taken
# Helper function, not to be set up as a view
@ -170,16 +173,96 @@ class ResetPassword(View):
urlname = ' reset_password '
service = ' send a password reset request '
user = request . POST . get ( ' user ' )
if check_user_exists ( user ) :
# TODO: Get a good backend for reset requests
# Sending the reset request
email = self . send_resetrequest ( user )
return render ( request , ' send_resetrequest.html ' , { ' user ' : user , ' email ' : email } )
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' The user does not exist. ' } )
def send_resetrequest ( self , user ) :
#TODO: call nameko to get the associated email and send a confirmation mail
return " test@example.com "
# First, check if the user exists
if not check_user_exists ( user ) :
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' The user does not exist. ' } )
# user exists, so try to get email
with get_pool ( ) . next ( ) as rpc :
( state , tmp1 , tmp2 , email ) = rpc . getuserdata . get_data ( user )
# Either error with the datalookup or no email provided
if state == " error " or email == ' No email given ' or not email :
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : ' Unable to retrieve email address for user. ' } )
# Try to send the email out
emailsend = self . email ( user , email )
# Email got sent out
if emailsend == True :
return render ( request , ' send_resetrequest.html ' , { ' user ' : user } )
# Error while trying to send email
else :
return render ( request , ' error.html ' , { ' urlname ' : urlname , ' service ' : service , ' error ' : emailsend } )
def email ( self , user , email ) :
#TODO figure out how to send email
email_from = ' Userservice at ungleich <userservice@ungleich.ch> '
to = ' %s < %s > ' % ( user , email )
subject = ' Password reset request for %s ' % user
no - reply = True
link = self . build_reset_link ( user )
body = ' This is an automated email which was triggered by a reset request for the user %s . \n ' % user
body + = ' If you received this email in error, please disregard it. If you get multiple emails like this, please contact us to look into potential abuse. \n '
body + = ' To reset your password, please follow the link below: \n '
body + = ' %s \n \n ' % link
body + = ' The link will remain active for 24 hours. \n '
# For debug
return link
def build_reset_link ( self , user ) :
host = ' localhost:8000 '
x = PasswordResetTokenGenerator ( )
token = x . make_token ( user )
buser = bytes ( user , ' utf-8 ' )
userpart = b64encode ( buser )
d = datetime . now ( )
# TODO Make Model und put it into the database
link = ' https:// %s /reset/ %s / %s / ' % ( host , userpart . decode ( ' utf-8 ' ) , token )
return link
# Catch the resetrequest and check it
class ResetRequest ( View ) :
# Gets the URL with user in b64 and the token, and checks it
# Also cleans the database
def get ( self , request , user = None , token = None ) :
# Cleans up outdated tokens
self . clean_db ( )
if user == None or token == None :
return HttpResponse ( ' Invalid URL. ' , status = 404 )
# extract user from b64 format
tmp_user = bytes ( user , ' utf-8 ' )
user = b64decode ( tmp_user )
user_clean = user . decode ( ' utf-8 ' )
d = datetime . now ( )
#TODO write the model and check if token is still active and belongs to the user
# set checks_out = True if yes
if not checks_out :
return HttpResponse ( ' Invalid URL. ' , status = 404 )
else :
return render ( request , ' resetpasswordnew.html ' , { ' user ' : user_clean } )
# Gets the post form with the new password and sets it
def post ( self , request ) :
service = ' reset the password '
password1 = request . POST . get ( " password1 " )
password2 = request . POST . get ( " password2 " )
user = request . POST . get ( " user " )
if password1 == " " or not password1 or password2 == " " or not password2 :
return render ( request , ' error.html ' , { ' service ' : service , ' error ' : ' Please supply a password and confirm it. ' } )
if password1 != password2 :
return render ( request , ' error.html ' , { ' service ' : service , ' error ' : ' The supplied passwords do not match. ' } )
with get_pool ( ) . next ( ) as rpc :
pwd = r ' %s ' % password1
result = rpc . changepassword . change_password ( user , pwd )
if result == True :
return render ( request , ' changedpassword.html ' , { ' user ' : user } )
else :
return render ( request , ' error.html ' , { ' service ' : service , ' error ' : result } )
# Cleans up outdated tokens
def clean_db ( self ) :
# TODO write the model and use this to clean tokens > 24h old
# The logged in user can change the password here