def account_deletion_request(self, delete_posts=False): token_type = 'accountdelete' if delete_posts: token_type = 'accountandpostsdelete' # if the user has an email, create an email verify token, send it to the email address tokenEntity = EnkiModelTokenVerify.get_by_user_id_email_type( self.enki_user.key.id(), self.enki_user.email, token_type) 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) delete_account_token = EnkiModelTokenVerify( token=token, user_id=self.enki_user.key.id(), email=self.enki_user.email, type=token_type) delete_account_token.put() link = enki.libutil.get_local_url( 'accountdeleteconfirm', {'verifytoken': delete_account_token.token}) delete_posts_message = '' if delete_posts: self.send_email(self.enki_user.email, MSG.SEND_EMAIL_ACCOUT_POSTS_DELETE_SUBJECT(), MSG.SEND_EMAIL_ACCOUT_POSTS_DELETE_BODY(link)) else: self.send_email(self.enki_user.email, MSG.SEND_EMAIL_ACCOUT_DELETE_SUBJECT(), MSG.SEND_EMAIL_ACCOUT_DELETE_BODY(link))
def delete_account(self, delete_posts=False, token=''): token_to_save = 'accountdelete' if not token: # there is no token if the user has no email address: they are deleted immediately. They must be logged in. user_to_delete = self.enki_user else: # a user has followed a accountdelete token link. The user account associated with the token will be deleted tokenEntity = EnkiModelTokenVerify.get_by_token(token) user_to_delete = EnkiModelUser.get_by_id(tokenEntity.user_id) # delete all user related tokens except any verify token related to account deletion that's not yet been used if tokenEntity.type == token_to_save: token_to_save = 'accountandpostsdelete' verify_tokens_to_delete = EnkiModelTokenVerify.fetch_keys_by_user_id_except_type( user_to_delete.key.id(), token_to_save) if verify_tokens_to_delete: ndb.delete_multi(verify_tokens_to_delete) email_rollback_tokens_to_delete = EnkiModelTokenEmailRollback.fetch_keys_by_user_id( user_to_delete.key.id()) if email_rollback_tokens_to_delete: ndb.delete_multi(email_rollback_tokens_to_delete) # Delete the user account and log them out. if not HandlerBase.account_is_active(user_to_delete.key.id()): # delete user if the account is inactive display_names = EnkiModelDisplayName.fetch_keys_by_user_id( user_to_delete.key.id()) if display_names: ndb.delete_multi(display_names) user_to_delete.key.delete() else: # anonymise the user if user_to_delete.email: # delete email subscriptions EnkiModelEmailSubscriptions.remove_by_email( user_to_delete.email) user_to_delete.email = None if user_to_delete.password: user_to_delete.password = None if user_to_delete.auth_ids_provider: user_to_delete.auth_ids_provider = [] user_to_delete.put() # keep all historical display_names. Add a new current display_name '[deleted]' (unless it's already been deleted) display_name = EnkiModelDisplayName.get_by_user_id_current( user_to_delete.key.id()) if display_name: if display_name.prefix != EnkiModelDisplayName.DELETED_PREFIX or display_name.suffix != EnkiModelDisplayName.DELETED_SUFFIX: EnkiModelDisplayName.set_display_name( user_to_delete.key.id(), EnkiModelDisplayName.DELETED_PREFIX, EnkiModelDisplayName.DELETED_SUFFIX) # delete user's sent and received messages EnkiModelMessage.delete_user_messages(user_to_delete.key.id()) # delete user's posts if required if delete_posts: EnkiModelPost.delete_user_posts(user_to_delete.key.id()) # log the deleted user out if self.enki_user == user_to_delete.key.id(): self.log_out() EnkiModelTokenAuth.revoke_user_authentications(user_to_delete.key.id())
def post( self ): url = settings.URL_PURCHASE_FASTSPRING if not settings.SECRET_FASTSPRING or enki.libutil.is_debug( ) or settings.ENKI_EMULATE_STORE: url = enki.libutil.get_local_url( 'storeemulatefastspring' ) if self.is_logged_in(): purchaser_user_id = self.enki_user.key.id() token = security.generate_random_string( entropy = 256 ) token_purchase = EnkiModelTokenVerify( token = token, user_id = purchaser_user_id, type = 'purchasebyuser' ) token_purchase.put() url = enki.libutil.get_local_url( 'storeemulatefastspring', { 'referrer': token_purchase.token }) self.redirect( url )
def password_change_request( self, email ): if enki.libuser.exist_EnkiUser( 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 = ERROR_EMAIL_NOT_EXIST return result
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 enki.libuser.exist_EnkiUser( email ): # if the new email matches an existing verified user email, reject it if emailCurrent == email: result = 'same' else: result = 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 = enki.libuser.get_EmailRollbackToken_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 == 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
def create_user_from_email_pw(self, email, password): result = enki.libutil.ENKILIB_OK # create a user with the email provided user = self.set_email(email) if user: # set the user's password result = self.set_password(user, password) if result == enki.libutil.ENKILIB_OK: # cleanup: delete all verify tokens created when registering the email EnkiModelTokenVerify.delete_by_email_type(email, 'register') else: result = self.ERROR_USER_NOT_CREATED return result
def post(self): url = settings.URL_PURCHASE_FASTSPRING # ------ # Requires enkiDL if self.request.get('download'): ref_url = enki.libutil.get_local_url('store') self.session['sessionrefpath'] = ref_url url_fetcher = '' if settings.URLS_ENKIDL: # shuffle then try to download from locations in sequence random.shuffle(settings.URLS_ENKIDL) for i in range(len(settings.URLS_ENKIDL)): url_enkiDL = settings.URLS_ENKIDL[i] item_to_download = 'product_a' url_fetcher = enki.libenkiDL.URLFetcher() url_fetcher.get_download_URL(url_enkiDL, settings.SECRET_ENKIDL, item_to_download, self.request.remote_addr) if not url_fetcher.error: enki.modelcounter.increment('downloads_product_a') break if url_fetcher and url_fetcher.error: self.response.status_int = 500 self.add_infomessage(MSG.WARNING(), MSG.DOWNLOAD_ERROR()) self.redirect('info') return url = url_fetcher.download_url else: self.add_infomessage(MSG.WARNING(), MSG.DOWNLOAD_ERROR()) self.redirect('info') return # ------- else: if not settings.SECRET_FASTSPRING or enki.libutil.is_debug( ) or settings.ENKI_EMULATE_STORE: url = enki.libutil.get_local_url('storeemulatefastspring') else: enki.modelcounter.increment('purchases_product_a') if self.is_logged_in(): purchaser_user_id = self.enki_user.key.id() token = security.generate_random_string(entropy=256) token_purchase = EnkiModelTokenVerify( token=token, user_id=purchaser_user_id, type='purchasebyuser') token_purchase.put() url += '?referrer=' + token_purchase.token.encode('utf-8') self.redirect(url)
def post(self): url = settings.URL_PURCHASE_FASTSPRING if not settings.SECRET_FASTSPRING or enki.libutil.is_debug( ) or settings.ENKI_EMULATE_STORE: url = enki.libutil.get_local_url('storeemulatefastspring') if self.is_logged_in(): purchaser_user_id = self.enki_user.key.id() token = security.generate_random_string(entropy=256) token_purchase = EnkiModelTokenVerify(token=token, user_id=purchaser_user_id, type='purchasebyuser') token_purchase.put() url = enki.libutil.get_local_url( 'storeemulatefastspring', {'referrer': token_purchase.token}) self.redirect(url)
def post_reauthenticated( self, params ): register = params.get( 'register' ) deregister = params.get( 'deregister' ) if register: # initiate adding a new authentication method to the account for authhandler in settings.HANDLERS: if register == authhandler.get_provider_name(): token = security.generate_random_string( entropy = 256 ) LoginAddToken = EnkiModelTokenVerify( token = token, user_id = self.user_id, auth_ids_provider = register, type = 'loginaddconfirm_1' ) LoginAddToken.put() self.redirect( authhandler.get_button().href ) break elif deregister: self.remove_auth_id( deregister) self.add_infomessage( 'success', MSG.SUCCESS(), MSG.AUTH_PROVIDER_REMOVED( deregister )) self.redirect( enki.libutil.get_local_url( 'accountconnect' ))
def email_set_request( self, email ): # request the creation of a new account based on an email address result = enki.libuser.validate_email( email ) if result == enki.libutil.ENKILIB_OK : if enki.libuser.exist_EnkiUser( email ): result = 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 )) result = enki.libutil.ENKILIB_OK return result
def delete_account( self, delete_posts = False, token = '' ): token_to_save = 'accountdelete' if not token: # there is no token if the user has no email address: they are deleted immediately. They must be logged in. user_to_delete = self.enki_user else: # a user has followed a accountdelete token link. The user account associated with the token will be deleted tokenEntity = EnkiModelTokenVerify.get_by_token( token ) user_to_delete = EnkiModelUser.get_by_id( tokenEntity.user_id ) # delete all user related tokens except any verify token related to account deletion that's not yet been used if tokenEntity.type == token_to_save: token_to_save = 'accountandpostsdelete' verify_tokens_to_delete = EnkiModelTokenVerify.fetch_keys_by_user_id_except_type( user_to_delete.key.id(), token_to_save ) if verify_tokens_to_delete: ndb.delete_multi( verify_tokens_to_delete ) email_rollback_tokens_to_delete = enki.libuser.fetch_keys_RollbackToken( user_to_delete.key.id()) if email_rollback_tokens_to_delete: ndb.delete_multi( email_rollback_tokens_to_delete ) # Delete the user account and log them out. if not HandlerBase.account_is_active( user_to_delete.key.id()): # delete user if the account is inactive display_names = enki.libdisplayname.fetch_EnkiUserDisplayName_by_user_id( user_to_delete.key.id()) if display_names: ndb.delete_multi( display_names ) user_to_delete.key.delete() else: # anonymise the user if user_to_delete.email: user_to_delete.email = None if user_to_delete.password: user_to_delete.password = None if user_to_delete.auth_ids_provider: user_to_delete.auth_ids_provider = [] user_to_delete.put() # keep all historical display_names. Add a new current display_name '[deleted]' (unless it's already been deleted) display_name = enki.libdisplayname.get_EnkiUserDisplayName_by_user_id_current( user_to_delete.key.id()) if display_name: if display_name.prefix != enki.libdisplayname.DELETED_PREFIX or display_name.suffix != enki.libdisplayname.DELETED_SUFFIX: enki.libdisplayname.set_display_name( user_to_delete.key.id(), enki.libdisplayname.DELETED_PREFIX, enki.libdisplayname.DELETED_SUFFIX ) # delete user's sent and received messages ndb.delete_multi( enki.libmessage.fetch_keys_sent_or_received_message( user_to_delete.key.id())) # delete user's posts if required if delete_posts: enki.libforum.delete_user_posts( user_to_delete.key.id()) # log the deleted user out if self.enki_user == user_to_delete.key.id(): self.log_out() enki.libuser.revoke_user_authentications( user_to_delete.key.id())
def post( self, **kwargs ): self.check_CSRF() token = kwargs[ 'verifytoken' ] tokenEntity = EnkiModelTokenVerify.get_by_token_type( token, 'passwordchange' ) if tokenEntity: email = tokenEntity.email user = enki.libuser.get_EnkiUser( email ) if user: password = self.request.get( 'password' ) result = enki.libuser.set_password( user, password ) if result == enki.libutil.ENKILIB_OK: enki.libuser.delete_verifytoken_by_email( email, 'passwordchange' ) self.log_in_with_id( user.key.id(), password ) self.add_infomessage( 'success', MSG.SUCCESS( ), MSG.PASSWORD_SET()) self.redirect( enki.libutil.get_local_url( 'profile' ) ) return else: error_message = '' if result == enki.libuser.ERROR_PASSWORD_BLANK : error_message = MSG.MISSING_PW() elif result == enki.libuser.ERROR_PASSWORD_TOO_SHORT : length = len( password ) error_message = " ".join( [ MSG.PW_TOO_SHORT( length ), MSG.PW_ENSURE_MIN_LENGTH( self.app.config.get( 'enki' ).get( 'user' ).get( 'PASSWORD_LENGTH_MIN' ) ) ] ) self.render_tmpl( 'passwordrecoverconfirm.html', error = error_message ) else: self.abort( 401 ) else: self.abort( 404 )
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 get(self, verifytoken): tokenEntity = EnkiModelTokenVerify.get_by_token_type( xstr(verifytoken), 'emailsubscriptionconfirm') if tokenEntity: newsletter = tokenEntity.state unsubscribe_token = EnkiModelEmailSubscriptions.add_newsletter( tokenEntity.email, newsletter) self.add_infomessage(MSG.SUCCESS(), MSG.EMAIL_SUBSCRIBED(newsletter)) # send welcome email with unsubscribe link link = enki.libutil.get_local_url('emailunsubscribe', { 'unsubscribetoken': unsubscribe_token, 'newsletter': newsletter }) self.send_email( tokenEntity.email, MSG.SEND_EMAIL_EMAIL_NEWSLETTER_WELCOME_SUBJECT(newsletter), MSG.SEND_EMAIL_EMAIL_NEWSLETTER_WELCOME_BODY(newsletter, link)) self.add_infomessage( MSG.INFORMATION(), MSG.EMAIL_NEWSLETTER_WELCOME_EMAIL_SENT(newsletter)) self.redirect(enki.libutil.get_local_url('home')) tokenEntity.key.delete() else: self.add_infomessage(MSG.INFORMATION(), MSG.EMAIL_SUBSCRIPTION_FAILED()) self.redirect(enki.libutil.get_local_url('emailsubscriptions'))
def get( self ): token = self.session.get( 'tokenregisterauth' ) tokenEntity = EnkiModelTokenVerify.get_by_token_type( token, 'register' ) if tokenEntity: provider_name, provider_uid = tokenEntity.auth_ids_provider.partition( ':' )[ ::2 ] provider_email = tokenEntity.email provider_authhandler = '' for handler in settings.HANDLERS: if handler.get_provider_name() == provider_name: provider_authhandler = handler # only display the email/pw login if the user has a password email_user_has_pw = enki.libuser.user_has_password_by_email( provider_email ) # list of email user's auth providers authhandlers = [] user = enki.libuser.get_EnkiUser( provider_email ) for user_provider_uid in user.auth_ids_provider: for handler in settings.HANDLERS: if ( handler.get_provider_name() in user_provider_uid ) and ( handler not in authhandlers ): authhandlers.append( handler ) break self.render_tmpl( 'registeroauthwithexistingemail.html', active_menu = 'login', token = tokenEntity, email = provider_email, email_user_has_pw = email_user_has_pw, provider_name = provider_name, provider_uid = str( provider_uid ), provider_authhandler = provider_authhandler, authhandlers = authhandlers, ) else: self.abort( 404 )
def post( self, **kwargs ): self.check_CSRF(), token = kwargs[ 'verifytoken' ] tokenEntity = EnkiModelTokenVerify.get_by_token_type( token, 'register' ) if tokenEntity: email = tokenEntity.email password = self.request.get( 'password' ) result = enki.libuser.validate_password( password ) link = enki.libutil.get_local_url( 'registerconfirm', { 'verifytoken': token } ) if result == enki.libutil.ENKILIB_OK: result = self.create_user_from_email_pw( email, password ) if result == enki.libutil.ENKILIB_OK: self.add_infomessage( 'success', MSG.SUCCESS( ), MSG.ACCOUNT_CREATED()) self.log_in_with_email( email, password ) self.redirect_to_relevant_page() elif result == enki.handlerbase.ERROR_USER_NOT_CREATED: error_message = MSG.FAIL_REGISTRATION() self.render_tmpl( 'register.html', active_menu = 'register', email = email, error = error_message ) else: error_message = '' if result == enki.libuser.ERROR_PASSWORD_BLANK: error_message = MSG.MISSING_PW() elif result == enki.libuser.ERROR_PASSWORD_TOO_SHORT : length = len( password ) error_message = " ".join( [ MSG.PW_TOO_SHORT( length ), MSG.PW_ENSURE_MIN_LENGTH( self.app.config.get( 'enki' ).get( 'user' ).get( 'PASSWORD_LENGTH_MIN' ))]) self.render_tmpl( 'registerconfirm.html', active_menu = 'register', email = email, url = link, error = error_message ) else: self.abort( 404 )
def exist_VerifyToken(token, type): count = EnkiModelTokenVerify.query( ndb.AND(EnkiModelTokenVerify.token == token, EnkiModelTokenVerify.type == type) ).count(1) if count: return True else: return False
def fetch_keys_VerifyToken_by_email_type(email, type): keys = EnkiModelTokenVerify.query( ndb.AND(EnkiModelTokenVerify.email == email, EnkiModelTokenVerify.type == type) ).fetch(keys_only=True) if keys: return keys else: return None
def get_VerifyToken_by_token_type(token, type): entity = EnkiModelTokenVerify.query( ndb.AND(EnkiModelTokenVerify.token == token, EnkiModelTokenVerify.type == type) ).get() if entity: return entity else: return None
def get_VerifyToken_by_authid_type(authId, type): entity = EnkiModelTokenVerify.query( ndb.AND(EnkiModelTokenVerify.auth_ids_provider == authId, EnkiModelTokenVerify.type == type) ).get() if entity: return entity else: return None
def fetch_keys_VerifyToken_by_user_id_except_type(user_id, type): keys = EnkiModelTokenVerify.query( ndb.AND(EnkiModelTokenVerify.user_id == user_id, EnkiModelTokenVerify.type != type) ).fetch(keys_only=True) if keys: return keys else: return None
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 check_and_delete_preventmultipost_token( token ): # prevent accidental multiple posting result = False verify_token = EnkiModelTokenVerify.get_by_token_type( token, 'preventmultipost' ) if verify_token: verify_token.key.delete() result = True return result
def get( self, **kwargs ): token = kwargs[ 'verifytoken' ] delete_posts = False tokenExists = EnkiModelTokenVerify.exist_by_token_type( token, 'accountdelete' ) if not tokenExists: tokenExists = EnkiModelTokenVerify.exist_by_token_type( token, 'accountandpostsdelete' ) if tokenExists: delete_posts = True if tokenExists: result = self.delete_account( delete_posts, token ) if delete_posts: self.add_infomessage( 'success', MSG.SUCCESS(), MSG.ACCOUNT_AND_POSTS_DELETED()) else: self.add_infomessage( 'success', MSG.SUCCESS(), MSG.ACCOUNT_DELETED()) self.redirect( enki.libutil.get_local_url()) else: self.abort( 404 )
def get( self, **kwargs): token = kwargs[ 'verifytoken' ] if EnkiModelTokenVerify.exist_by_token_type( token, 'passwordchange' ): link = enki.libutil.get_local_url( 'passwordrecoverconfirm', { 'verifytoken': token } ) self.render_tmpl( 'passwordrecoverconfirm.html', active_menu = 'profile', url = link ) else: self.abort( 404 )
def get( self, **kwargs ): token = kwargs[ 'verifytoken' ] tokenEntity = EnkiModelTokenVerify.get_by_token_type( token, 'emailchange' ) if tokenEntity: self.email_change( tokenEntity ) self.add_infomessage( 'success', MSG.SUCCESS( ), MSG.EMAIL_SET()) self.redirect( enki.libutil.get_local_url( 'profile' ) ) else: self.abort( 404 )
def post_reauthenticated( self, params ): choice = params.get( 'choice' ) if choice != 'cancel': tokenEntity = EnkiModelTokenVerify.get_by_user_id_auth_id_type( user_id = self.user_id, auth_id = choice, type = 'loginaddconfirm_3' ) if tokenEntity: self.set_auth_id( tokenEntity.auth_ids_provider, self.user_id ) self.add_infomessage( 'success', MSG.SUCCESS(), MSG.AUTH_PROVIDER_ADDED( str( tokenEntity.auth_ids_provider ))) tokenEntity.key.delete() self.redirect( enki.libutil.get_local_url( 'accountconnect' ))
def check_and_delete_preventmultipost_token(token): # prevent accidental multiple posting result = False verify_token = EnkiModelTokenVerify.get_by_token_type( token, 'preventmultipost') if verify_token: verify_token.key.delete() result = True return result
def get(self, **kwargs): token = kwargs['verifytoken'] if EnkiModelTokenVerify.exist_by_token_type(token, 'passwordchange'): link = enki.libutil.get_local_url('passwordrecoverconfirm', {'verifytoken': token}) self.render_tmpl('passwordrecoverconfirm.html', active_menu='profile', url=link) else: self.abort(404)
def get(self, **kwargs): token = kwargs['verifytoken'] tokenEntity = EnkiModelTokenVerify.get_by_token_type( token, 'emailchange') if tokenEntity: self.email_change(tokenEntity) self.add_infomessage('success', MSG.SUCCESS(), MSG.EMAIL_SET()) self.redirect(enki.libutil.get_local_url('profile')) else: self.abort(404)
def account_deletion_request( self, delete_posts = False ): token_type = 'accountdelete' if delete_posts: token_type = 'accountandpostsdelete' # if the user has an email, create an email verify token, send it to the email address tokenEntity = EnkiModelTokenVerify.get_by_user_id_email_type( self.enki_user.key.id( ), self.enki_user.email, token_type ) 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 ) delete_account_token = EnkiModelTokenVerify( token = token, user_id = self.enki_user.key.id(), email = self.enki_user.email, type = token_type ) delete_account_token.put() link = enki.libutil.get_local_url( 'accountdeleteconfirm', { 'verifytoken': delete_account_token.token } ) delete_posts_message = '' if delete_posts: self.send_email( self.enki_user.email, MSG.SEND_EMAIL_ACCOUT_POSTS_DELETE_SUBJECT(), MSG.SEND_EMAIL_ACCOUT_POSTS_DELETE_BODY( link )) else: self.send_email( self.enki_user.email, MSG.SEND_EMAIL_ACCOUT_DELETE_SUBJECT(), MSG.SEND_EMAIL_ACCOUT_DELETE_BODY( link ))
def cleanup_item( self ): likelyhood = 10 # occurs with a probability of 1% number = random.randint( 1, 1000 ) if number < likelyhood: ndb.delete_multi_async( self.fetch_old_backoff_timers( 3 )) ndb.delete_multi_async( self.fetch_old_auth_tokens( 3 )) ndb.delete_multi_async( self.fetch_old_sessions( 3 )) ndb.delete_multi_async( enki.librestapi.fetch_EnkiModelRestAPIConnectToken_expired()) ndb.delete_multi_async( enki.librestapi.fetch_EnkiModelRestAPIDataStore_expired()) ndb.delete_multi_async( EnkiModelTokenVerify.fetch_old_tokens_by_types( 0.007, [ 'loginaddconfirm_1', 'loginaddconfirm_2', 'loginaddconfirm_3' ])) enki.librestapi.refresh_EnkiModelRestAPIConnectToken_non_expiring()
def post_reauthenticated(self, params): register = params.get('register') deregister = params.get('deregister') if register: # initiate adding a new authentication method to the account for authhandler in settings.HANDLERS: if register == authhandler.get_provider_name(): token = security.generate_random_string(entropy=256) LoginAddToken = EnkiModelTokenVerify( token=token, user_id=self.user_id, auth_ids_provider=register, type='loginaddconfirm_1') LoginAddToken.put() self.redirect(authhandler.get_button().href) break elif deregister: self.remove_auth_id(deregister) self.add_infomessage('success', MSG.SUCCESS(), MSG.AUTH_PROVIDER_REMOVED(deregister)) self.redirect(enki.libutil.get_local_url('accountconnect'))
def get( self ): token = self.session.get( 'tokenregisterauth' ) tokenEntity = EnkiModelTokenVerify.get_by_token_type( token, 'register' ) if tokenEntity: provider_name, provider_uid = tokenEntity.auth_ids_provider.partition( ':' )[ ::2 ] self.render_tmpl( 'registeroauthconfirm.html', active_menu = 'register', token = tokenEntity, provider_name = provider_name, provider_uid = str( provider_uid )) else: self.abort( 404 )
def get(self, **kwargs): token = kwargs['verifytoken'] delete_posts = False tokenExists = EnkiModelTokenVerify.exist_by_token_type( token, 'accountdelete') if not tokenExists: tokenExists = EnkiModelTokenVerify.exist_by_token_type( token, 'accountandpostsdelete') if tokenExists: delete_posts = True if tokenExists: result = self.delete_account(delete_posts, token) if delete_posts: self.add_infomessage('success', MSG.SUCCESS(), MSG.ACCOUNT_AND_POSTS_DELETED()) else: self.add_infomessage('success', MSG.SUCCESS(), MSG.ACCOUNT_DELETED()) self.redirect(enki.libutil.get_local_url()) else: self.abort(404)
def get_VerifyToken_by_user_id_email_type(user_id, email, type): entity = EnkiModelTokenVerify.query( ndb.AND( EnkiModelTokenVerify.user_id == user_id, EnkiModelTokenVerify.email == email, EnkiModelTokenVerify.type == type, ) ).get() if entity: return entity else: return None
def get( self, **kwargs ): token = kwargs[ 'verifytoken' ] tokenEntity = EnkiModelTokenVerify.get_by_token_type( token, 'register' ) if tokenEntity: email = tokenEntity.email link = enki.libutil.get_local_url( 'registerconfirm', { 'verifytoken': token } ) self.render_tmpl( 'registerconfirm.html', active_menu = 'register', email = email, url = link ) else: self.abort( 404 )
def cleanup_item(self): number = random.randint(1, 1000) likelihood = 10 # occurs with a probability of 1% if number < likelihood: ndb.delete_multi_async(self.fetch_keys_old_sessions(3)) ndb.delete_multi_async(EnkiModelBackoffTimer.fetch_keys_old(3)) ndb.delete_multi_async(EnkiModelTokenAuth.fetch_keys_expired()) ndb.delete_multi_async( EnkiModelRestAPIConnectToken.fetch_expired()) ndb.delete_multi_async(EnkiModelRestAPIDataStore.fetch_expired()) ndb.delete_multi_async( EnkiModelTokenVerify.fetch_keys_old_tokens_by_types( 0.007, [ 'loginaddconfirm_1', 'loginaddconfirm_2', 'loginaddconfirm_3' ])) EnkiModelRestAPIDataStore.refresh_non_expiring() ndb.delete_multi_async( EnkiModelTokenVerify.fetch_keys_old_tokens_by_types( 1, ['emailsubscriptionconfirm'])) ndb.delete_multi_async(EnkiModelBackoffTimer.fetch_keys_old(1))
def get_logged_in( self ): tokenEntity = EnkiModelTokenVerify.get_by_user_id_type( self.user_id, 'loginaddconfirm_2' ) if tokenEntity: provider_name, provider_uid = tokenEntity.auth_ids_provider.partition( ':' )[ ::2 ] tokenEntity.type = 'loginaddconfirm_3' tokenEntity.put() self.render_tmpl( 'loginaddconfirm.html', active_menu = 'profile', provider_name = provider_name, provider_uid = provider_uid, token = tokenEntity.token ) else: self.redirect( enki.libutil.get_local_url( 'accountconnect' ))
def get(self): token = self.session.get('tokenregisterauth') tokenEntity = EnkiModelTokenVerify.get_by_token_type(token, 'register') if tokenEntity: provider_name, provider_uid = tokenEntity.auth_ids_provider.partition( ':')[::2] self.render_tmpl('registeroauthconfirm.html', active_menu='register', token=tokenEntity, provider_name=provider_name, provider_uid=str(provider_uid)) else: self.abort(404)
def get(self, **kwargs): token = kwargs['verifytoken'] tokenEntity = EnkiModelTokenVerify.get_by_token_type(token, 'register') if tokenEntity: email = tokenEntity.email link = enki.libutil.get_local_url('registerconfirm', {'verifytoken': token}) self.render_tmpl('registerconfirm.html', active_menu='register', email=email, url=link) else: self.abort(404)
def post_reauthenticated(self, params): choice = params.get('choice') if choice != 'cancel': tokenEntity = EnkiModelTokenVerify.get_by_user_id_auth_id_type( user_id=self.user_id, auth_id=choice, type='loginaddconfirm_3') if tokenEntity: self.set_auth_id(tokenEntity.auth_ids_provider, self.user_id) self.add_infomessage( 'success', MSG.SUCCESS(), MSG.AUTH_PROVIDER_ADDED(str( tokenEntity.auth_ids_provider))) tokenEntity.key.delete() self.redirect(enki.libutil.get_local_url('accountconnect'))
def post(self): self.cleanup_item() self.log_out() self.check_CSRF() token = self.session.get('tokenregisterauth') tokenEntity = EnkiModelTokenVerify.get_by_token_type(token, 'register') if tokenEntity: submit_type = self.request.get('submittype') # Log in with email and password if submit_type == 'login': email = tokenEntity.email tokenEntity.key.delete() password = self.request.get('password') if self.log_in_with_email(email, password): self.add_infomessage('success', MSG.SUCCESS(), MSG.LOGGED_IN()) self.redirect_to_relevant_page() else: error_message = MSG.WRONG_EMAIL_OR_PW() backoff_timer = self.get_backoff_timer(email) if backoff_timer != 0: error_message = MSG.TIMEOUT( enki.libutil.format_timedelta(backoff_timer)) self.render_tmpl('login.html', active_menu='login', authhandlers=settings.HANDLERS, email=email, error=error_message) elif submit_type == 'recoverpass': email = tokenEntity.email tokenEntity.key.delete() self.redirect( enki.libutil.get_local_url('passwordrecover', {'email': email})) # Create a new account using the OAuth provider but without the email elif submit_type == 'register': email = tokenEntity.email tokenEntity.email = '' tokenEntity.put() self.add_infomessage( 'info', MSG.INFORMATION(), MSG.REGISTRATION_INFO_EMAIL_CANNOT_USE(email)) self.redirect( enki.libutil.get_local_url('registeroauthconfirm')) else: tokenEntity.key.delete() self.add_infomessage('info', MSG.INFORMATION(), MSG.LOGIN_FAILED()) self.redirect(enki.libutil.get_local_url('home')) else: self.abort(404)
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 authId = loginInfo[ 'provider_name' ] + ':' + loginInfo[ 'provider_uid' ] if authId: # modify existing or create user user = self.get_or_create_user_from_authid( authId, email, allow_create = False ) if user: self.log_in_session_token_create( user ) self.add_infomessage( 'success', MSG.SUCCESS( ), MSG.LOGGED_IN()) self.redirect_to_relevant_page() else: # generate & store a verification token and the auth provider. save the token number in the session. register_token = enki.libuser.get_VerifyToken_by_authid_type( authId, '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, auth_ids_provider = authId, type = 'register' ) register_token.put() self.session[ 'tokenregisterauth' ] = token self.redirect( enki.libutil.get_local_url( 'registeroauthconfirm' ) ) else: self.redirect_to_relevant_page()
def email_change( self, token ): email = token.email user_id = token.user_id # change the email user = self.set_email( email, user_id ) if user: # delete all potential remaining email verify tokens for that user tokens = EnkiModelTokenVerify.fetch_keys_by_user_id_type( user_id, 'emailchange' ) if tokens: ndb.delete_multi( tokens ) # note: the old email remains saved in the rollback token db else: # delete the email verification token token.key.delete()
def get_logged_in(self): tokenEntity = EnkiModelTokenVerify.get_by_user_id_type( self.user_id, 'loginaddconfirm_2') if tokenEntity: provider_name, provider_uid = tokenEntity.auth_ids_provider.partition( ':')[::2] tokenEntity.type = 'loginaddconfirm_3' tokenEntity.put() self.render_tmpl('loginaddconfirm.html', active_menu='profile', provider_name=provider_name, provider_uid=provider_uid, token=tokenEntity.token) else: self.redirect(enki.libutil.get_local_url('accountconnect'))
def email_rollback( self, token ): email = token.email user_id = token.user_id # change the email user = self.set_email( email, user_id ) if user: # retrieve all rollback tokens that are more recent, including the current one, and delete them tokenDateCreated = token.time_created youngerTokens = enki.libuser.fetch_keys_RollbackToken_by_time( user_id, tokenDateCreated ) if youngerTokens: ndb.delete_multi( youngerTokens ) # delete all potential remaining email verify tokens for that user userTokens = EnkiModelTokenVerify.fetch_keys_by_user_id_type( user_id, 'emailchange' ) if userTokens: ndb.delete_multi( userTokens )
def email_change(self, token): email = token.email user_id = token.user_id # change the email user = self.set_email(email, user_id) if user: # delete all potential remaining email verify tokens for that user tokens = EnkiModelTokenVerify.fetch_keys_by_user_id_type( user_id, 'emailchange') if tokens: ndb.delete_multi(tokens) # note: the old email remains saved in the rollback token db else: # delete the email verification token token.key.delete()
def email_rollback(self, token): email = token.email user_id = token.user_id # change the email user = self.set_email(email, user_id) if user: # retrieve all rollback tokens that are more recent, including the current one, and delete them tokenDateCreated = token.time_created youngerTokens = EnkiModelTokenEmailRollback.fetch_keys_by_user_id_time( user_id, tokenDateCreated) if youngerTokens: ndb.delete_multi(youngerTokens) # delete all potential remaining email verify tokens for that user userTokens = EnkiModelTokenVerify.fetch_keys_by_user_id_type( user_id, 'emailchange') if userTokens: ndb.delete_multi(userTokens)
def cleanup_item(self): likelyhood = 10 # occurs with a probability of 1% number = random.randint(1, 1000) if number < likelyhood: ndb.delete_multi_async(self.fetch_old_backoff_timers(3)) ndb.delete_multi_async(self.fetch_old_auth_tokens(3)) ndb.delete_multi_async(self.fetch_old_sessions(3)) ndb.delete_multi_async( enki.librestapi.fetch_EnkiModelRestAPIConnectToken_expired()) ndb.delete_multi_async( enki.librestapi.fetch_EnkiModelRestAPIDataStore_expired()) ndb.delete_multi_async( EnkiModelTokenVerify.fetch_old_tokens_by_types( 0.007, [ 'loginaddconfirm_1', 'loginaddconfirm_2', 'loginaddconfirm_3' ])) enki.librestapi.refresh_EnkiModelRestAPIConnectToken_non_expiring()
def post(self): secret = xstr(self.request.get('secret')) if secret == settings.SECRET_FASTSPRING or enki.libutil.is_debug( ) or settings.ENKI_EMULATE_STORE: licence_key_bundle = xstr(self.request.get('licence_key')) purchase_price = xstr(self.request.get('purchase_price')) order_id = xstr(self.request.get('order_id')) product_name = xstr(self.request.get('product_name')) purchaser_email = xstr(self.request.get('purchaser_email')) shop_name = xstr(self.request.get('shop_name')) quantity = xint(self.request.get('quantity')) if secret == settings.SECRET_FASTSPRING: is_test = self.request.get('is_test') if is_test.capitalize() == 'True': order_type = 'test' else: order_type = 'purchase' else: order_type = xstr(self.request.get('order_type')) purchaser_user_id = None token_purchasebyuser = xstr(self.request.get('referrer')) if token_purchasebyuser: token = EnkiModelTokenVerify.get_by_token_type( token_purchasebyuser, 'purchasebyuser') if token: purchaser_user_id = token.user_id token.key.delete() licence_keys = licence_key_bundle.replace('-', '').split() for licence_key in licence_keys: item = EnkiModelProductKey(licence_key=licence_key, purchase_price=purchase_price, order_id=order_id, product_name=product_name, purchaser_email=purchaser_email, shop_name=shop_name, quantity=quantity, purchaser_user_id=purchaser_user_id, order_type=order_type) item.put() return
def post( self ): self.cleanup_item() self.log_out() self.check_CSRF() token = self.session.get('tokenregisterauth') tokenEntity = EnkiModelTokenVerify.get_by_token_type(token, 'register') if tokenEntity: submit_type = self.request.get( 'submittype' ) # Log in with email and password if submit_type == 'login': email = tokenEntity.email tokenEntity.key.delete() password = self.request.get( 'password' ) if self.log_in_with_email( email, password ): self.add_infomessage( 'success', MSG.SUCCESS(), MSG.LOGGED_IN()) self.redirect_to_relevant_page() else: error_message = MSG.WRONG_EMAIL_OR_PW() backoff_timer = self.get_backoff_timer( email ) if backoff_timer != 0: error_message = MSG.TIMEOUT( enki.libutil.format_timedelta( backoff_timer )) self.render_tmpl( 'login.html', active_menu = 'login', authhandlers = settings.HANDLERS, email = email, error = error_message ) elif submit_type == 'recoverpass': email = tokenEntity.email tokenEntity.key.delete() self.redirect( enki.libutil.get_local_url( 'passwordrecover', { 'email': email })) # Create a new account using the OAuth provider but without the email elif submit_type == 'register': email = tokenEntity.email tokenEntity.email = '' tokenEntity.put() self.add_infomessage( 'info', MSG.INFORMATION() , MSG.REGISTRATION_INFO_EMAIL_CANNOT_USE( email )) self.redirect( enki.libutil.get_local_url( 'registeroauthconfirm' )) else: tokenEntity.key.delete() self.add_infomessage( 'info', MSG.INFORMATION(), MSG.LOGIN_FAILED()) self.redirect( enki.libutil.get_local_url( 'home' )) else: self.abort(404)
def post(self, **kwargs): self.check_CSRF(), token = kwargs['verifytoken'] tokenEntity = EnkiModelTokenVerify.get_by_token_type(token, 'register') if tokenEntity: email = tokenEntity.email password = self.request.get('password') result = enki.libuser.validate_password(password) link = enki.libutil.get_local_url('registerconfirm', {'verifytoken': token}) if result == enki.libutil.ENKILIB_OK: result = self.create_user_from_email_pw(email, password) if result == enki.libutil.ENKILIB_OK: self.add_infomessage('success', MSG.SUCCESS(), MSG.ACCOUNT_CREATED()) self.log_in_with_email(email, password) self.redirect_to_relevant_page() elif result == enki.handlerbase.ERROR_USER_NOT_CREATED: error_message = MSG.FAIL_REGISTRATION() self.render_tmpl('register.html', active_menu='register', email=email, error=error_message) else: error_message = '' if result == enki.libuser.ERROR_PASSWORD_BLANK: error_message = MSG.MISSING_PW() elif result == enki.libuser.ERROR_PASSWORD_TOO_SHORT: length = len(password) error_message = " ".join([ MSG.PW_TOO_SHORT(length), MSG.PW_ENSURE_MIN_LENGTH( self.app.config.get('enki').get('user').get( 'PASSWORD_LENGTH_MIN')) ]) self.render_tmpl('registerconfirm.html', active_menu='register', email=email, url=link, error=error_message) else: self.abort(404)
def post( self ): secret = xstr( self.request.get( 'secret' )) if secret == settings.SECRET_FASTSPRING or enki.libutil.is_debug( ) or settings.ENKI_EMULATE_STORE: licence_key_bundle = xstr( self.request.get( 'licence_key' )) purchase_price = xstr( self.request.get( 'purchase_price' )) order_id = xstr(self.request.get( 'order_id' )) product_name = xstr( self.request.get( 'product_name' )) purchaser_email = xstr( self.request.get( 'purchaser_email' )) shop_name = xstr( self.request.get( 'shop_name' )) quantity = xint( self.request.get( 'quantity' )) purchaser_user_id = None token_purchasebyuser = xstr( self.request.get( 'referrer' )) if token_purchasebyuser: token = EnkiModelTokenVerify.get_by_token_type( token_purchasebyuser, 'purchasebyuser' ) if token: purchaser_user_id = token.user_id token.key.delete() is_test = self.request.get( 'is_test' ) if is_test: order_type = 'test' if enki.libutil.is_debug() or settings.ENKI_EMULATE_STORE: order_type = 'emulated' licence_keys = licence_key_bundle.replace( '-', '' ).split() for licence_key in licence_keys: item = EnkiModelProductKey( licence_key = licence_key, purchase_price = purchase_price, order_id = order_id, product_name = product_name, purchaser_email = purchaser_email, shop_name = shop_name, quantity = quantity, purchaser_user_id = purchaser_user_id, order_type = order_type ) item.put() return
def post(self, **kwargs): self.check_CSRF() token = kwargs['verifytoken'] tokenEntity = EnkiModelTokenVerify.get_by_token_type( token, 'passwordchange') if tokenEntity: email = tokenEntity.email user = enki.libuser.get_EnkiUser(email) if user: password = self.request.get('password') result = enki.libuser.set_password(user, password) if result == enki.libutil.ENKILIB_OK: enki.libuser.delete_verifytoken_by_email( email, 'passwordchange') self.log_in_with_id(user.key.id(), password) self.add_infomessage('success', MSG.SUCCESS(), MSG.PASSWORD_SET()) self.redirect(enki.libutil.get_local_url('profile')) return else: error_message = '' if result == enki.libuser.ERROR_PASSWORD_BLANK: error_message = MSG.MISSING_PW() elif result == enki.libuser.ERROR_PASSWORD_TOO_SHORT: length = len(password) error_message = " ".join([ MSG.PW_TOO_SHORT(length), MSG.PW_ENSURE_MIN_LENGTH( self.app.config.get('enki').get('user').get( 'PASSWORD_LENGTH_MIN')) ]) self.render_tmpl('passwordrecoverconfirm.html', error=error_message) else: self.abort(401) else: self.abort(404)
def get(self): token = self.session.get('tokenregisterauth') tokenEntity = EnkiModelTokenVerify.get_by_token_type(token, 'register') if tokenEntity: provider_name, provider_uid = tokenEntity.auth_ids_provider.partition( ':')[::2] provider_email = tokenEntity.email provider_authhandler = '' for handler in settings.HANDLERS: if handler.get_provider_name() == provider_name: provider_authhandler = handler # only display the email/pw login if the user has a password email_user_has_pw = enki.libuser.user_has_password_by_email( provider_email) # list of email user's auth providers authhandlers = [] user = enki.libuser.get_EnkiUser(provider_email) for user_provider_uid in user.auth_ids_provider: for handler in settings.HANDLERS: if (handler.get_provider_name() in user_provider_uid) and (handler not in authhandlers): authhandlers.append(handler) break self.render_tmpl( 'registeroauthwithexistingemail.html', active_menu='login', token=tokenEntity, email=provider_email, email_user_has_pw=email_user_has_pw, provider_name=provider_name, provider_uid=str(provider_uid), provider_authhandler=provider_authhandler, authhandlers=authhandlers, ) else: self.abort(404)
def delete_verifytoken_by_email( email, type ): # delete all verify tokens for a given email and type (cleanup) entities = EnkiModelTokenVerify.fetch_keys_by_email_type( email, type ) if entities: ndb.delete_multi( entities )
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 post(self): if not settings.SECRET_FASTSPRING or enki.libutil.is_debug( ) or settings.ENKI_EMULATE_STORE: self.check_CSRF() product = xstr(self.request.get('product')) quantity = xint(self.request.get('quantity')) purchase_price = xstr(self.request.get('purchase_price')) purchaser_email = xstr(self.request.get('purchaser_email')) licence_keys = 'not generated' user_id = '' emulator_order_id = 'EMULATED_' + webapp2_extras.security.generate_random_string( length=10, pool=webapp2_extras.security.DIGITS) url = enki.libutil.get_local_url('genlicencefastspring') form_fields = { 'secret': 'pretendsecret', 'quantity': str(quantity) } form_data = urllib.urlencode(form_fields) result = urlfetch.fetch(url=url, payload=form_data, method=urlfetch.POST) if result.status_code == 200: licence_keys = result.content.replace('-', '') referrer = xstr(self.request.get('referrer')) token = EnkiModelTokenVerify.get_by_token_type( referrer, 'purchasebyuser') if token: user_id = token.user_id licence_key_display = [] for item in licence_keys.split(): item_dash = enki.libstore.insert_dashes_5_10(item) licence_key_display.append(item_dash) self.add_infomessage( 'info', MSG.INFORMATION(), '<h3>FastSpring Store Emulator - Step 1</h3>' + '<h4>Emulated purchase details</h4>' + '<ul>' + '<li><EnkiModelProductKey> #{FastSpring variable} = <em><emulated value></em></li>' + '<li>product_name #{orderItem.productName} = <em>' + product + '</em></li>' + '<li>order_id #{order.id} = <em>' + emulator_order_id + '</em></li>' + '<li>quantity #{orderItem.quantity} = <em>' + xstr(quantity) + '</em></li>' + '<li>purchase_price #{orderItem.totalUSD} = <em>' + purchase_price + '</em></li>' + '<li>purchaser_email #{order.customer.email} = <em>' + purchaser_email + '</em></li>' + '<li>shop_name = <em>Emulator_FastSpring</em></li>' + '<li>licence_key #{orderItem.fulfillment.licence.licences.list} = <br><em><b>' + '<br>'.join(licence_key_display) + '</b></em></li>' + '</ul>' '<h4>Internal data - generated if the purchaser was logged in when they bought the product</h4>' + '<ul>' + '<li>EnkiModelTokenVerify.user_id = purchaser user_id = <em>' + (xstr(user_id) if user_id else 'None') + '</em></li>' + '<li>EnkiModelTokenVerify.type purchasebyuser referrer #{order.referrer} = <em>' + (xstr(referrer) if referrer else 'None') + '</em></li>' + '</ul>') url = enki.libutil.get_local_url('ordercompletefastspring') form_fields = { 'licence_key': licence_keys, 'purchase_price': purchase_price, 'order_id': emulator_order_id, 'product_name': product, 'purchaser_email': purchaser_email, 'shop_name': 'Emulator_FastSpring', 'quantity': quantity, 'referrer': referrer, 'is_test': True } form_data = urllib.urlencode(form_fields) result = urlfetch.fetch(url=url, payload=form_data, method=urlfetch.POST) if result.status_code == 200: message_view_library = '' if self.is_logged_in(): message_view_library = '<p><a href="/profile" class="alert-link">View and activate licence keys</a>.</p>' self.add_infomessage( 'info', MSG.INFORMATION(), '<h3>FastSpring Store Emulator - Step 2</h3><p>Purchase records created<p>' + message_view_library) else: self.add_infomessage( 'warning', MSG.WARNING(), '<h3>FastSpring Store Emulator - Step 2 FAILED: Purchase records not created</h3>' ) 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