def password_change_request(self, email): if EnkiModelUser.exist_by_email(email): # create an email verify token, send it to the email address token = security.generate_random_string(entropy=256) emailToken = EnkiModelTokenVerify(token=token, email=email, type='passwordchange') emailToken.put() link = enki.libutil.get_local_url( 'passwordrecoverconfirm', {'verifytoken': emailToken.token}) self.send_email(email, MSG.SEND_EMAIL_PASSWORD_RESET_SUBJECT(), MSG.SEND_EMAIL_PASSWORD_RESET_BODY(link)) result = enki.libutil.ENKILIB_OK else: result = self.ERROR_EMAIL_NOT_EXIST return result
def email_set_request(self, email): # request the creation of a new account based on an email address result = enki.libutil.ENKILIB_OK if EnkiModelUser.exist_by_email(email): result = self.ERROR_EMAIL_IN_USE else: # create an email verify token, send it to the email address token = security.generate_random_string(entropy=256) emailToken = EnkiModelTokenVerify(token=token, email=email, type='register') emailToken.put() link = enki.libutil.get_local_url( 'registerconfirm', {'verifytoken': emailToken.token}) self.send_email(email, MSG.SEND_EMAIL_REGISTER_CONFIRM_SUBJECT(), MSG.SEND_EMAIL_REGISTER_CONFIRM_BODY(link)) return result
def provider_authenticated_callback(self, loginInfo): # We expect the fields of the dictionary to be: # - 'provider_name' unique 'pretty' provider name (e.g. google, facebook,...) # - 'provider_uid' provider specific (a.k.a "locally unique") user Id, i.e unique to the provider (e.g. the google user id number) # - 'email' # - 'email_verified' # We IGNORE: username, gender (facebook), avatar link, etc. # get the verified email from the auth provider email = None if loginInfo['email'] and loginInfo['email_verified'] == True: email = loginInfo['email'] # get the authId from the auth provider auth_id = loginInfo['provider_name'] + ':' + loginInfo['provider_uid'] if auth_id: # Modify existing or create user # check if it's an add login method request LoginAddToken = EnkiModelTokenVerify.get_by_user_id_state_type( self.user_id, loginInfo['provider_name'], 'loginaddconfirm_1') if LoginAddToken: # Add a login method if not EnkiModelUser.exist_by_auth_id(auth_id): # store the new auth prov + id in the session LoginAddToken.state = auth_id LoginAddToken.type = 'loginaddconfirm_2' LoginAddToken.put() self.redirect( enki.libutil.get_local_url('loginaddconfirm')) else: self.add_infomessage( MSG.INFORMATION(), MSG.AUTH_PROVIDER_CANNOT_BE_ADDED(str(auth_id))) self.redirect(enki.libutil.get_local_url('accountconnect')) return else: user = self.get_user_from_authid(auth_id, email) if user: # Existing authentication method / user if self.is_logged_in() and self.user_id == user.key.id(): # Refresh the reauthenticated status self.session['reauth_time'] = datetime.datetime.now() self.add_infomessage(MSG.SUCCESS(), MSG.REAUTHENTICATED()) self.redirect_to_relevant_page() return # Login self.log_in_session_token_create(user) self.add_infomessage(MSG.SUCCESS(), MSG.LOGGED_IN()) self.redirect_to_relevant_page() else: # New authentication method register_token = EnkiModelTokenVerify.get_by_state_type( auth_id, 'register') if register_token: # If a token already exists, get the token value and update the email token = register_token.token register_token.email = email # update in case the user changed their email or modified their email access permission else: # Create a new token token = security.generate_random_string(entropy=256) register_token = EnkiModelTokenVerify(token=token, email=email, state=auth_id, type='register') register_token.put() self.session['tokenregisterauth'] = token if EnkiModelUser.exist_by_email(email): self.redirect( enki.libutil.get_local_url( 'registeroauthwithexistingemail')) else: self.redirect( enki.libutil.get_local_url('registeroauthconfirm')) else: self.redirect_to_relevant_page()
def email_change_request(self, email): # request an email address to be modified. Create a rollback option. result = 'cannot_remove' emailCurrent = self.enki_user.email userId = self.enki_user.key.id() if email != '' and EnkiModelUser.exist_by_email(email): # if the new email matches an existing verified user email, reject it if emailCurrent == email: result = 'same' else: result = self.ERROR_EMAIL_IN_USE # Note: send an email to emailcurrent regardless to prevent email checking (see below) else: if email == '': # if the user erased the email, and they can log in through auth, store "removed" in the email field, so it isn't overwritten by an auth login with a verified email if self.enki_user.auth_ids_provider: self.enki_user.email = 'removed' self.enki_user.put() result = 'removed' else: return result else: # email the new, unverified address with a link to allow the user to verify the email tokenEntity = EnkiModelTokenVerify.get_by_user_id_email_type( userId, email, 'emailchange') if tokenEntity: # if a verify token for the same new email address and user already exists, use its token token = tokenEntity.token else: # otherwise create a new token token = security.generate_random_string(entropy=256) emailToken = EnkiModelTokenVerify(token=token, email=email, user_id=userId, type='emailchange') emailToken.put() link = enki.libutil.get_local_url('emailchangeconfirm', {'verifytoken': token}) self.send_email( email, MSG.SEND_EMAIL_EMAIL_CHANGE_CONFIRM_SUBJECT(), MSG.SEND_EMAIL_EMAIL_CHANGE_CONFIRM_BODY(link, email)) result = 'change' if emailCurrent and emailCurrent != 'removed' and result != 'same': # email the current, verified address in case they want to undo the change (useful if account has been hacked) # skip this step if the current email is empty (case if user logged in with auth id without email with e.g. Steam) or "removed". # If the email is already in use, mask the fact to prevent email checking. tokenEntity = EnkiModelTokenEmailRollback.get_by_user_id_email( userId, emailCurrent) if tokenEntity: # if the old email is already in the archive, use its token token = tokenEntity.token else: # otherwise create a new token token = security.generate_random_string(entropy=256) emailOldToken = EnkiModelTokenEmailRollback(token=token, email=emailCurrent, user_id=userId) emailOldToken.put() if result == self.ERROR_EMAIL_IN_USE: self.add_debugmessage( '''Comment - whether the email is available or not, the feedback through both the UI AND EMAIL is identical to prevent email checking.''' ) link = enki.libutil.get_local_url('emailrollback', {'rollbacktoken': token}) self.send_email( emailCurrent, MSG.SEND_EMAIL_EMAIL_CHANGE_UNDO_SUBJECT(), MSG.SEND_EMAIL_EMAIL_CHANGE_UNDO_BODY(link, emailCurrent)) return result