def shuffle_current_sms_provider(excluded_provider_ids): sms_provider_candidates = [sp for sp in _sms_providers.values() if sp.sms_provider_id not in excluded_provider_ids] if not sms_provider_candidates: raise Exception('not enough sms/voice provider to switch') sms_provider = random.choice(sms_provider_candidates) redis().setex(CURRENT_SMS_PROVIDER_ID_KEY, CURRENT_SMS_PROVIDER_ALIVE_TIME_IN_SECONDS, sms_provider.sms_provider_id) return sms_provider
def remove_logged_in_user_id(purpose=None, session=None, browser_code=None): if purpose is None: purpose = get_current_http_request().website if config[purpose].is_session_ttl_enabled(): session = session or get_user_session(purpose, browser_code) if session: redis().delete(logged_in_user_id_key(session)) clear_user_session(purpose)
def remember_logged_in_user_id(user_id, browser_code=None): purpose = get_current_http_request().website user_id = unicode(user_id) session = set_user_session(purpose, browser_code or get_browser_code(), user_id) if config[purpose].is_session_ttl_enabled(): redis().setex(logged_in_user_id_key(session), config[purpose].session_ttl, user_id) if get_latest_user_id(purpose) != user_id: set_latest_user_id(purpose, user_id)
def get_current_sms_provider(): if not _sms_providers: raise Exception('no sms provider') current_sms_provider_id = redis().get(CURRENT_SMS_PROVIDER_ID_KEY) if not current_sms_provider_id: current_sms_provider_id = _sms_providers.keys()[0] redis().setex(CURRENT_SMS_PROVIDER_ID_KEY, CURRENT_SMS_PROVIDER_ALIVE_TIME_IN_SECONDS, current_sms_provider_id) sms_provider = _sms_providers[int(current_sms_provider_id)] return sms_provider
def generate_captcha(): challenge_code = uuid.uuid4().get_hex() image, answer = generate(size=(150, 30), font_size=25) redis().setex(challenge_code, CAPTCHA_ANSWER_ALIVE_TIME, answer) buffer = StringIO() image.save(buffer, 'GIF') buffer.reset() key = '{}.gif'.format(challenge_code) bucket().store(key, buffer) return challenge_code, bucket().get_url(key)
def generate_captcha(): challenge_code = uuid.uuid4().get_hex() image, answer = generate_captcha_image_and_answer(size=(150, 30), font_size=25, draw_lines=True, draw_points=True) redis().setex(captcha_redis_key(challenge_code), CAPTCHA_ANSWER_ALIVE_TIME, answer) bucket_key = captcha_bucket_key(challenge_code) with contextlib.closing(StringIO()) as buffer_: image.save(buffer_, 'GIF', transparency=0) buffer_.reset() bucket().store(bucket_key, buffer_) return challenge_code, bucket().get_url(bucket_key)
def shuffle_current_sms_provider(excluded_provider_ids): sms_provider_candidates = [ sp for sp in _sms_providers.values() if sp.sms_provider_id not in excluded_provider_ids ] if not sms_provider_candidates: raise Exception('not enough sms/voice provider to switch') sms_provider = random.choice(sms_provider_candidates) redis().setex(CURRENT_SMS_PROVIDER_ID_KEY, CURRENT_SMS_PROVIDER_ALIVE_TIME_IN_SECONDS, sms_provider.sms_provider_id) return sms_provider
def send_voice_validation_code(receiver, code, sms_code, last_sms_code=None): used_sms_provider_ids = set() sms_provider = None if last_sms_code: last_sms_provider_id = redis().get( sent_sms_redis_key(receiver, last_sms_code)) if last_sms_provider_id: used_sms_provider_ids.add(int(last_sms_provider_id)) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids) sms_provider = sms_provider or get_current_sms_provider() while True: if not sms_provider.support_voice: used_sms_provider_ids.add(sms_provider.sms_provider_id) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids) continue try: sms_provider.send_voice(receiver, code, sms_code) except SendError as e: retry_receivers = e.get_send_failed_mobiles() if not retry_receivers: return receiver = retry_receivers used_sms_provider_ids.add(sms_provider.sms_provider_id) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids) else: sms_provider.add_sent_quantity(1) break
def send_transactional_sms(receivers, sms_code, promotional, last_sms_code=None, message=None, template=None): sms_provider = get_current_sms_provider() receiver_list = get_receiver_list(receivers, sms_provider.max_receiver_count) if len(receiver_list) == 1: receivers = receiver_list[0] send(receivers, sms_code, last_sms_code=last_sms_code, promotional=promotional, message=message, template=template) with redis().pipeline() as pipe: for receiver in receivers: pipe.setex(sent_sms_redis_key(receiver, sms_code), SENT_SMS_RECORD_ALIVE_IN_SECONDS, sms_provider.sms_provider_id) pipe.execute() else: for receivers_ in receiver_list: send_transactional_sms.delay(receivers_, sms_code, promotional, last_sms_code=last_sms_code, message=message, template=template)
def validate_captcha(challenge_code, captcha_answer): request = get_current_http_request() real_answer = redis().get(challenge_code) if 'test' == VEIL_SERVER or (captcha_answer and real_answer == captcha_answer): if 'test' != VEIL_SERVER: LOGGER.info('[sensitive]validate captcha succeeded: %(site)s, %(function)s, %(uri)s, %(referer)s, %(remote_ip)s, %(user_agent)s', { 'site': request.host, 'function': 'captcha', 'uri': request.uri, 'referer': request.headers.get('Referer'), 'remote_ip': request.remote_ip, 'user_agent': request.headers.get('User-Agent') }) bucket().delete(challenge_code) return {} else: LOGGER.warn('[sensitive]validate captcha failed: %(site)s, %(function)s, %(user_answer)s, %(real_answer)s, %(uri)s, %(referer)s, %(remote_ip)s, %(user_agent)s', { 'site': request.host, 'function': 'captcha', 'user_answer': captcha_answer, 'real_answer': real_answer, 'uri': request.uri, 'referer': request.headers.get('Referer'), 'remote_ip': request.remote_ip, 'user_agent': request.headers.get('User-Agent') }) return {'captcha_answer': ['验证码{},请重新填入正确的计算结果'.format('错误' if real_answer else '过期')]}
def validate(challenge_code, captcha_answer): request = get_current_http_request() real_answer = redis().get(captcha_redis_key(challenge_code)) if VEIL_ENV.is_test or (captcha_answer and real_answer == captcha_answer): if not VEIL_ENV.is_test: LOGGER.info('[sensitive]validate captcha succeeded: %(site)s, %(function)s, %(uri)s, %(referer)s, %(remote_ip)s, %(user_agent)s', { 'site': request.host, 'function': 'captcha', 'uri': request.uri, 'referer': request.referrer.raw, 'remote_ip': request.remote_ip, 'user_agent': request.user_agent.ua_string }) return {} else: LOGGER.warn('[sensitive]validate captcha failed: %(site)s, %(function)s, %(user_answer)s, %(real_answer)s, %(uri)s, %(referer)s, %(remote_ip)s, %(user_agent)s', { 'site': request.host, 'function': 'captcha', 'user_answer': captcha_answer, 'real_answer': real_answer, 'uri': request.uri, 'referer': request.referrer.raw, 'remote_ip': request.remote_ip, 'user_agent': request.user_agent.ua_string }) return {'captcha_answer': ['验证码{},请重新填入正确的计算结果'.format('错误' if real_answer else '过期')]}
def remove_logged_in_user_ids(purpose): count = redis().del_per_pattern('lu:{}:*'.format(purpose), 2000) LOGGER.info('kicked logged-in users out: %(purpose)s, %(count)s', { 'purpose': purpose, 'count': count }) return count
def reset_balance_and_sent_quantity(self, balance): with redis().pipeline() as pipe: pipe.setex(self.balance_key_in_redis, SMS_PROVIDER_BALANCE_ALIVE_IN_SECONDS, balance) pipe.setex(self.sent_quantity_key_in_redis, SMS_PROVIDER_SENT_QUANTITY_ALIVE_IN_SECONDS, 0) pipe.execute()
def validate(challenge_code, captcha_answer): request = get_current_http_request() real_answer = redis().get(captcha_redis_key(challenge_code)) if VEIL_ENV.is_test or (captcha_answer and real_answer == captcha_answer): if not VEIL_ENV.is_test: LOGGER.info( '[sensitive]validate captcha succeeded: %(site)s, %(function)s, %(uri)s, %(referer)s, %(remote_ip)s, %(user_agent)s', { 'site': request.host, 'function': 'captcha', 'uri': request.uri, 'referer': request.referrer.raw, 'remote_ip': request.remote_ip, 'user_agent': request.user_agent.ua_string }) return {} else: LOGGER.warn( '[sensitive]validate captcha failed: %(site)s, %(function)s, %(user_answer)s, %(real_answer)s, %(uri)s, %(referer)s, %(remote_ip)s, %(user_agent)s', { 'site': request.host, 'function': 'captcha', 'user_answer': captcha_answer, 'real_answer': real_answer, 'uri': request.uri, 'referer': request.referrer.raw, 'remote_ip': request.remote_ip, 'user_agent': request.user_agent.ua_string }) return { 'captcha_answer': ['验证码{},请重新填入正确的计算结果'.format('错误' if real_answer else '过期')] }
def send(receivers, sms_code, last_sms_code=None, transactional=True, promotional=True, message=None, template=None): used_sms_provider_ids = set() sms_provider = None if last_sms_code: last_sms_provider_id = redis().get(sent_sms_redis_key(receivers[0], last_sms_code)) if last_sms_provider_id: used_sms_provider_ids.add(int(last_sms_provider_id)) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids) if not VEIL_ENV.is_prod: receivers_not_in_whitelist = set(r for r in receivers if r not in get_application_sms_whitelist()) if receivers_not_in_whitelist: LOGGER.warn('Ignored sms receivers not in the whitelist under non-public env: %(receivers_not_in_whitelist)s', { 'receivers_not_in_whitelist': receivers_not_in_whitelist }) receivers = set(receivers) receivers -= receivers_not_in_whitelist if not receivers: return sms_provider = sms_provider or get_current_sms_provider() while True: sent_receivers, need_retry_receivers = sms_provider.send(receivers, sms_code, transactional, promotional, message=message, template=objectify(from_json(template))) if sent_receivers: sms_provider.add_sent_quantity(sms_provider.get_minimal_message_quantity(message) * len(sent_receivers)) if not need_retry_receivers: break elif transactional: raise Exception('sms send transactional failed: {}'.format(need_retry_receivers)) else: receivers = need_retry_receivers used_sms_provider_ids.add(sms_provider.sms_provider_id) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids)
def send_voice_validation_code_job(receiver, code, sms_code, last_sms_code=None): used_sms_provider_ids = set() sms_provider = None if last_sms_code: last_sms_provider_id = redis().get(sent_sms_redis_key(receiver, last_sms_code)) if last_sms_provider_id: used_sms_provider_ids.add(int(last_sms_provider_id)) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids) sms_provider = sms_provider or get_current_sms_provider() while True: if not sms_provider.support_voice: used_sms_provider_ids.add(sms_provider.sms_provider_id) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids) continue try: sms_provider.send_voice(receiver, code, sms_code) except SendError as e: retry_receivers = e.get_send_failed_mobiles() if not retry_receivers: return receiver = retry_receivers used_sms_provider_ids.add(sms_provider.sms_provider_id) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids) else: sms_provider.add_sent_quantity(1) break
def send(receivers, sms_code, last_sms_code=None, transactional=True, promotional=True, message=None, template=None): used_sms_provider_ids = set() sms_provider = None if last_sms_code: last_sms_provider_id = redis().get( sent_sms_redis_key(receivers[0], last_sms_code)) if last_sms_provider_id: used_sms_provider_ids.add(int(last_sms_provider_id)) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids) if not VEIL_ENV.is_prod: receivers_not_in_whitelist = set( r for r in receivers if r not in get_application_sms_whitelist()) if receivers_not_in_whitelist: LOGGER.warn( 'Ignored sms receivers not in the whitelist under non-public env: %(receivers_not_in_whitelist)s', {'receivers_not_in_whitelist': receivers_not_in_whitelist}) receivers = set(receivers) receivers -= receivers_not_in_whitelist if not receivers: return sms_provider = sms_provider or get_current_sms_provider() while True: sent_receivers, need_retry_receivers = sms_provider.send( receivers, sms_code, transactional, promotional, message=message, template=objectify(from_json(template))) if sent_receivers: sms_provider.add_sent_quantity( sms_provider.get_minimal_message_quantity(message) * len(sent_receivers)) if not need_retry_receivers: break elif transactional: raise Exception('sms send transactional failed: {}'.format( need_retry_receivers)) else: receivers = need_retry_receivers used_sms_provider_ids.add(sms_provider.sms_provider_id) sms_provider = shuffle_current_sms_provider(used_sms_provider_ids)
def get_logged_in_user_id(purpose=None, session=None, is_session_ttl_enabled=None): """ a special case is to get the user of website B from website A """ if purpose is None: purpose = get_current_http_request().website assert purpose in config and (not session or session.purpose == purpose) session = session or get_user_session(purpose) if not session: return None is_session_ttl_enabled = is_session_ttl_enabled or config[purpose].is_session_ttl_enabled if is_session_ttl_enabled(): user_id = redis().get(logged_in_user_id_key(session)) if not user_id or user_id != session.user_id: return None return session.user_id
def get_logged_in_user_id(purpose=None, session=None, is_session_ttl_enabled=None): """ a special case is to get the user of website B from website A """ if purpose is None: purpose = get_current_http_request().website assert purpose in config and (not session or session.purpose == purpose) session = session or get_user_session(purpose) if not session: return None is_session_ttl_enabled = is_session_ttl_enabled or config[ purpose].is_session_ttl_enabled if is_session_ttl_enabled(): user_id = redis().get(logged_in_user_id_key(session)) if not user_id or user_id != session.user_id: return None return session.user_id
def refresh_user_session_ttl(session): if config[session.purpose].is_session_ttl_enabled(): redis().expire(logged_in_user_id_key(session), config[session.purpose].session_ttl)
def get_balance_in_redis(self): balance = redis().get(self.balance_key_in_redis) if balance is not None: balance = int(balance) return balance
def get_sent_quantity_in_redis(self): sent_quantity = redis().get(self.sent_quantity_key_in_redis) if sent_quantity is not None: sent_quantity = int(sent_quantity) return sent_quantity
def set_balance(self, balance): redis().setex(self.balance_key_in_redis, SMS_PROVIDER_BALANCE_ALIVE_IN_SECONDS, balance)
def add_sent_quantity(self, quantity): redis().incrby(self.sent_quantity_key_in_redis, quantity) redis().expire(self.sent_quantity_key_in_redis, SMS_PROVIDER_SENT_QUANTITY_ALIVE_IN_SECONDS)
def remove_logged_in_user_ids(purpose): count = redis().del_per_pattern('lu:{}:*'.format(purpose), 2000) LOGGER.info('kicked logged-in users out: %(purpose)s, %(count)s', {'purpose': purpose, 'count': count}) return count