def __has_reached_max_unver_testmins(account_id, testmin): ''' @description: - returns True if the user enrolled unverified testmin more than the allowed (per day), else False - updates array of ''' testmin = '639%s' % str(testmin[-9:]) unver_req = Verification.get_code_unverified_requests(account_id) if not unver_req: # return False and create redis list # (for counting and comparison) unverified_mob_list = [testmin] Verification.set_code_unverified_requests(account_id, unverified_mob_list) return False unver_req = loads(unver_req) if unver_req and len(unver_req) >= MAX_CODE_REQUEST and \ testmin not in unver_req: return True if testmin not in unver_req: unver_req.append(testmin) Verification.set_code_unverified_requests(account_id, unver_req) return False
def test_push_email_to_queue(self): ''' test if emails are pushed to the queue in FIFO manner ''' for x in range( 3 ): Verification.add_email_to_reg_queue( email='kirby@kirby-agudelo%s.net'%x )
def send_mt_message(account_id, suffix, testmin, mt_message, client_id, secret_key): ''' uses API to send MT message to user ''' gen_logger = sms_api_logger.GeneralLogger() if not mt_message: message_id = send_trial_mt(suffix, testmin, SENT_TRIAL_MESSAGE % DEFAULT_MESSAGE, client_id, secret_key) elif len(mt_message) > MESSAGE_LEN: message_id = None else: message_id = send_trial_mt(suffix, testmin, SENT_TRIAL_MESSAGE % mt_message, client_id, secret_key) gen_logger.info('Hitting API to sending MT message', {'account_id': account_id, 'mobile': testmin, 'suffix': suffix, 'message_id': message_id}) Verification.set_message_sent_to_pending( testmin[-12:], message_id) return message_id
def process_testmin_code_verification(suffix, account_id, testmin, code): ''' @description: - handles testmin code verificition ''' gen_logger = sms_api_logger.GeneralLogger() testmin = '639%s' % str(testmin[-9:]) correct_code = __get_vercode(account_id, testmin) if not __is_code_correct(correct_code, code): gen_logger.error( 'testmin enrollment -- incorrect pincode', { 'account_id': account_id, 'mobile': testmin, 'code': code, 'suffix': suffix }) raise WrongCodeException(account_id, testmin, code) if __is_code_expired (correct_code) and \ __has_reached_max_code_request(account_id, testmin): gen_logger.error( 'testmin enrollment -- expired pincode, max code requests', { 'account_id': account_id, 'mobile': testmin, 'code': code, 'suffix': suffix }) raise ExpiredCodeMaxCodeRequestException(account_id, testmin, code) if __is_code_expired(correct_code): gen_logger.error( 'testmin enrollment -- expired pincode', { 'account_id': account_id, 'mobile': testmin, 'code': code, 'suffix': suffix }) raise ExpiredCodeException(account_id, testmin, code) __save_testmin(account_id, testmin) ContentProviders.update_cached_api_min(suffix, testmin) Verification.delete_mobile_code(account_id, testmin)
def forgot_password_send( email ): ''' @param email: the email of the user to send the password executes process for "forgot password" procedure email is sent to email address identified by "email" parameter ''' # 1. check if email is invalid or unregistered valid_email_format = email_tool.is_email_format_valid( email ) if not valid_email_format: raise InvalidEmailFormatError() # check if email is registered account_object = account = Account.get( email=email ) if account_object is None : raise AccountNotExist('account does not exist') else : if account_object.is_pending() is True : raise PendingAccountAlreadyExisting() # verification will now be created verification_object = Verification.create_new_forgot_password_verification( account_object=account_object ) if verification_object : verification_object.add_forgot_password_email_to_queue()
def has_reached_max_wrong_code_tries(account_id, testmin): ''' @description: - returns True if user has inputted wrong codes more than allowed, else False - uses redis incr ''' testmin = '639%s' % str(testmin[-9:]) code_tries = Verification.incr_code_tries(account_id=account_id, testmin=testmin) # if code_tries and int(code_tries) > MAX_CODE_TRIES: gen_logger = sms_api_logger.GeneralLogger() gen_logger.info('testmin enrollment -- max pincode retries', { 'account_id': account_id, 'mobile': testmin }) # return True # return False if code_tries: return int(code_tries) return None
def is_valid_forget_password_code( code ): ''' checks if code is valid @return: Boolean . if code is valid or not (exists in database and is PASSWORD-type verification) @raise VerificationExpired: on expired verification ''' verification_object = Verification.get_forgot_password_verify_by_code( code=code ) if verification_object : # check if password verification is expired print 'expiry is', type(verification_object.date_expiry) if verification_object.date_expiry < datetime.now() : raise VerificationExpired() return True else: return False
def change_password_by_code( code, new_password ): ''' resets the password given the verification code ''' #check if password is valid # if len(new_password) < 8 or len(new_password) > 32 : # raise password_tool.InvalidPasswordLength('invalid old password. too short / too long') if password_tool.is_valid_password_format( password=new_password ) is not True : raise InvalidPasswordFormat('invalid format') verification_object = Verification.get_forgot_password_verify_by_code( code=code ) #print verification_object account_object = Account.get( account_id=verification_object.account_id ) if account_object : encrypted_new_password = password_tool.encrypt( password=new_password ) result = account_object.save_new_password( new_password=encrypted_new_password ) if result : verification_object.destroy() return True return False
def set_message_sent_to_success(mobile, message_id): gen_logger = sms_api_logger.GeneralLogger() try: return Verification.set_message_sent_to_success( mobile, message_id) except Exception, e: gen_logger.error('TEST MT sent status to SUCCESS', {'mobile': mobile, 'message_id': message_id})
def __get_vercode(account_id, testmin): ''' @description: - returns the verification code ''' testmin = '639%s' % str(testmin[-9:]) correct_code = Verification.get_mobile_code(account_id=account_id, testmin=testmin) return correct_code
def create_new_signup_verification(self, account_id, email, code, resend_code, expiration_delta=None): ''' writes signup verification to verification table @param account_id: the account id assigned to the pending user @param email: the email used by the registering user @param code : String the unique string that will publicly identify the verification @param expiration_delta : python timedelta , denotes duration of validity of the verification @author: vincent agudelo ''' verification_id = None new_verification_object = None params = { 'email': email, 'account_id': account_id, 'code': code, 'resend_code': resend_code, 'category': 'SIGNUP' } if expiration_delta: params['date_expiry'] = ( datetime.now() + expiration_delta).strftime('%Y-%m-%d %H:%M:%S') try: verification_id = self.__insert_to_database(params) new_verification_object = Verification() new_verification_object.verification_id = verification_id new_verification_object.email = email new_verification_object.verification_category = 'SIGNUP' new_verification_object.account_id = account_id new_verification_object.code = code new_verification_object.resend_code = resend_code except Exception, e: raise VerificationError( 'could not create verification record: %s' % e)
def resend_forgot_password_by_code( code ): verification_object = Verification.get_forgot_password_verify_by_code( code=code ) if verification_object : # step 1 update expiry verification_object.update_forgot_password_expiry() # step 2 add to email queue verification_object.add_forgot_password_email_to_queue() else : raise VerificationError('does not exist')
def __has_reached_max_code_request(account_id, testmin): ''' @description: - returns True if user requested code for than the allowed times, else False ''' testmin = '639%s' % str(testmin[-9:]) request_count = Verification.incr_code_request_count(account_id=account_id, testmin=testmin) if request_count and int(request_count) > (MAX_CODE_REQUEST): return True return False
def create_new_change_email_verification(self, account_object, new_email, code, expiration_delta, resend_code): verification_object = None params = { 'email': new_email, 'account_id': account_object.account_id, 'code': code, 'resend_code': resend_code, 'category': self.valid_categories['change_email'], 'date_expiry': (datetime.now() + expiration_delta).strftime('%Y-%m-%d %H:%M:%S') } try: verification_id = self.__insert_to_database(params) if verification_id: verification_object = Verification() verification_object.verification_id = verification_id verification_object.email = params['email'] verification_object.verification_category = params['category'] verification_object.account_id = params['account_id'] verification_object.code = params['code'] verification_object.resend_code = params['resend_code'] except Exception, e: raise VerificationError( 'could not create verification record: %s' % e)
def __save_code(account_id, code=None, testmin=None, ver_id=None): ''' saves the code generated in the Verification table ''' if testmin: testmin = '639%s' % str(testmin[-9:]) gen_logger = sms_api_logger.GeneralLogger() try: ver_obj = Verification.get_mobile_code(account_id=account_id, testmin=testmin) if ver_obj or ver_id: if not ver_id: ver_id = ver_obj['id'] if code: Verification.update_mobile_code(account_id=account_id, code=code, mobile=testmin, ver_id=ver_id) else: Verification.update_mobile_code(account_id=account_id, mobile=testmin, ver_id=ver_id) gen_logger.info('testmin enrollment -- updating pincode', {'account_id': account_id}) return ver_obj['id'] if not ver_id else ver_id else: gen_logger.info('testmin enrollment -- saving pincode', { 'account_id': account_id, 'pincode': code }) return Verification.save_mobile_code(account_id=account_id, code=code, mobile=testmin) except DuplicateVerificationCodeException, e: gen_logger.info('testmin enrollment -- pincode not unique', { 'account_id': account_id, 'error': str(e) }) save_code(account_id, code, testmin)
def get_verification(self, verification_id=None, code=None, email=None, mobile=None, category=None, account_id=None, resend_code=None): ''' retrieves verification information based on information in given object ''' verification_object = None criteria = {} if verification_id: criteria['id'] = verification_id if code: criteria['code'] = code if account_id: criteria['account_id'] = account_id if category: criteria['category'] = category if mobile: criteria['mobile'] = mobile if email: criteria['email'] = email if resend_code: criteria['resend_code'] = resend_code if criteria: table_cols = [ 'id', 'email', 'account_id', 'code', 'mobile', 'category', 'date_expiry', 'send_status', 'resend_code' ] try: result = self.dbconn.execute_select(table_name='verification', conditions=criteria, operator='AND', table_cols=table_cols, fetchall=False) except Exception, e: raise VerificationError('unable to retrieve verification: %s' % e) if result: verification_object = Verification() verification_object.verification_id = result['id'] verification_object.email = result['email'] verification_object.account_id = result['account_id'] verification_object.code = result['code'] verification_object.resend_code = result['resend_code'] verification_object.mobile = result['mobile'] verification_object.verification_category = result['category'] # magically retured as datetime object verification_object.date_expiry = result['date_expiry']
def test_valid_code(self): invalid_long_code = 'c70a4ef428ca65ee0d8b23fd3a33bf1b' Verification.get( code=invalid_long_code )
def get_message_sent_status(mobile, message_id): return Verification.get_message_sent_status( mobile, message_id)
def get_min(account_id, ver_id): min = Verification.get_min(account_id, ver_id) if min and 'mobile' in min: return min['mobile']
def register_user(first_name, last_name, email, company_name, address, password, password_again=''): # a collector of INLINE errors used for display errors = {} # for inline error empty input field if not email: errors['invalid_email'] = SPIELS['gerror'] if not password: errors['invalid_password'] = SPIELS['gerror'] if not password_again: errors['passwords_dont_match'] = SPIELS['gerror'] l = sms_api_logger.GeneralLogger() l.info('start registration sequence', {'email': email}) #check password if 'invalid_password' not in errors and password_tool.is_new_password_valid( password) is False: l.error('invalid password format') errors['invalid_password'] = SPIELS['ierror3'] # raise password_tool.InvalidPasswordFormat( 'invalid password format' ) if 'passwords_dont_match' not in errors and password_again: # this checking is only used because this function # might still be used by others without this param if password != password_again: l.error('password do not match') errors['passwords_dont_match'] = SPIELS['ierror2'] # check email address if in valid format if 'invalid_email' not in errors and not reg_email_tool.is_email_format_valid( email): l.error('invalid email format') errors['invalid_email'] = SPIELS['ierror1'] # raise reg_email_tool.InvalidEmailFormatError( ) # this serves as input checking. # if error dict has content, display inline error # messages to user if errors: return errors encrypted_password = password_tool.encrypt(password) result = False new_user_account = Account() new_user_account.first_name = first_name new_user_account.last_name = last_name new_user_account.email = email new_user_account.company = company_name new_user_account.address = address new_user_account.password = encrypted_password # if duplicate email exists in database # check if that is pending or active # raise respective error try: pending_created = new_user_account.create_pending_account() if pending_created: l.info('pending user created', { 'email': email, 'account id': new_user_account.account_id }) try: verifi_object = Verification.create_new_signup_verification( new_user_account.account_id, new_user_account.email) if verifi_object: l.info('sending verification to email queue', { 'code': verifi_object.code, 'email': verifi_object.email }) verifi_object.add_email_to_reg_queue() except Exception, e: l.error('could not save pending user', e) # most likely the verification was not save # delete pending user and ask user to create again new_user_account.delete_if_pending() raise AccountSaveException( 'unable to save verification object: %s. pending user id=%s deleted' % (e, new_user_account.account_id)) result = True except DuplicateEmailException, e: # the same email exists in database # no more INSERT will execute from here # # check what user that is suspected_account = Account.get_raw_info(email=email) if suspected_account.is_active(): #print 'suspected account is currently active' l.error('trying to register email of current active account') raise ActiveAccountAlreadyExisting( '%s is an active account; id=%s' % (email, suspected_account.account_id)) elif suspected_account.is_pending(): l.info('trying to register email of pending account', email) #get verification object verifi = Verification.get(email=email, account_id=suspected_account.account_id) #print 'suspected account is currently pending' raise PendingAccountAlreadyExisting(verifi)
if verifi_type == 'SIGNUP': subject = 'Verify email address to start using Chikka API' elif verifi_type == 'CHANGEEMAIL': subject = 'Verify email address to start using Chikka API' elif verifi_type == 'PASSWORD': subject = 'You requested for password reset ' key = 'emailcontent:%s' % verifi_id l.debug('retrieving email contents from cache', {'key', key}) email_content = redisconn.get(key) if not email_content: # in case content was eraseed l.debug('missing email content, rebuilding', {'type': verifi_type}) verification_object = Verification.get( verification_id=verifi_id) if verifi_type == 'SIGNUP': email_content = verification_object.generate_signup_email_content( ) elif verifi_type == 'CHANGEEMAIL': email_content = verification_object.generate_change_email_verify_content( ) elif verifi_type == 'PASSWORD': email_content = verification_object.generate_forget_password_content( ) html_content = email_content.replace("\n", '<br>') #--- mailer configs mail_from = values['mailer']['mail_from_address'] mailer_host = values['mailer']['host']