def test_get_window_of_first_exceeded_limit_none(): per_user_rate_def = RateDefinition(per_second=10) min_rate_def = RateDefinition(per_second=100) per_user_rate_def = PerUserRateDefinition(per_user_rate_def, min_rate_def) rate_limiter = RateLimiter('my_feature', per_user_rate_def.get_rate_limits) rate_limiter.iter_rates = Mock(return_value=[('second', 9, 10)]) expected_window = None actual_window = rate_limiter.get_window_of_first_exceeded_limit( 'my_domain') eq(actual_window, expected_window)
def test_rate_limit_interface(): """ Just test that very basic usage doesn't error """ per_user_rate_def = RateDefinition(per_week=50000, per_day=13000, per_second=.001) min_rate_def = RateDefinition(per_second=10) per_user_rate_def = PerUserRateDefinition(per_user_rate_def, min_rate_def) my_feature_rate_limiter = RateLimiter('my_feature', per_user_rate_def.get_rate_limits) if my_feature_rate_limiter.allow_usage('my_domain'): # ...do stuff... my_feature_rate_limiter.report_usage('my_domain')
def test_get_window_of_first_exceeded_limit_priority(): per_user_rate_def = RateDefinition(per_second=10, per_week=10) min_rate_def = RateDefinition(per_second=100) per_user_rate_def = PerUserRateDefinition(per_user_rate_def, min_rate_def) rate_limiter = RateLimiter('my_feature', per_user_rate_def.get_rate_limits) rate_limiter.iter_rates = Mock(return_value=[('', [('week', 11, 10), ('second', 11, 10)])]) expected_window = 'week' actual_window = rate_limiter.get_window_of_first_exceeded_limit( 'my_domain') eq(actual_window, expected_window)
) floor_for_small_domain = RateDefinition( per_week=100, per_day=50, per_hour=30, per_minute=10, per_second=1, ) test_rates = PerUserRateDefinition( per_user_rate_definition=rates_promised_not_to_go_lower_than.times(2.0), constant_rate_definition=floor_for_small_domain, ) submission_rate_limiter = RateLimiter( feature_key='submissions', get_rate_limits=test_rates.get_rate_limits) SHOULD_RATE_LIMIT_SUBMISSIONS = not settings.ENTERPRISE_MODE and not settings.UNIT_TESTING @run_only_when(SHOULD_RATE_LIMIT_SUBMISSIONS) @silence_and_report_error("Exception raised in the submission rate limiter", 'commcare.xform_submissions.rate_limiter_errors') def rate_limit_submission(domain): if RATE_LIMIT_SUBMISSIONS.enabled(domain, namespace=NAMESPACE_DOMAIN): return _rate_limit_submission(domain) else: _rate_limit_submission_by_delaying(domain, max_wait=15) return False
metrics_counter('commcare.two_factor.setup_requests', 1, tags={ 'status': status, 'method': method, 'window': window or 'none', }) return status != _status_accepted two_factor_rate_limiter_per_ip = RateLimiter( feature_key='two_factor_attempts_per_ip', get_rate_limits=lambda scope: get_dynamic_rate_definition( 'two_factor_attempts_per_ip', default=RateDefinition( per_week=20000, per_day=2000, per_hour=1200, per_minute=700, per_second=60, ) ).get_rate_limits(), scope_length=1, ) two_factor_rate_limiter_per_user = RateLimiter( feature_key='two_factor_attempts_per_user', get_rate_limits=lambda scope: get_dynamic_rate_definition( 'two_factor_attempts_per_user', default=RateDefinition( per_week=120, per_day=40, per_hour=8,
) from corehq.apps.data_dictionary.util import save_case_property from corehq.apps.domain.decorators import login_and_domain_required from corehq.apps.hqwebapp.decorators import use_jquery_ui from corehq.apps.hqwebapp.utils import get_bulk_upload_form from corehq.apps.settings.views import BaseProjectDataView from corehq.util.files import file_extention_from_filename from corehq.util.workbook_reading import open_any_workbook data_dictionary_rebuild_rate_limiter = RateLimiter( feature_key='data_dictionary_rebuilds_per_user', get_rate_limits=lambda scope: get_dynamic_rate_definition( 'data_dictionary_rebuilds_per_user', default=RateDefinition( per_hour=3, per_minute=2, per_second=1, ) ).get_rate_limits(), scope_length=1, ) @login_and_domain_required @toggles.DATA_DICTIONARY.required_decorator() def generate_data_dictionary(request, domain): if data_dictionary_rebuild_rate_limiter.allow_usage(domain): data_dictionary_rebuild_rate_limiter.report_usage(domain) try: util.generate_data_dictionary(domain) except util.OldExportsEnabledException: return JsonResponse({
status = _status_bad_request metrics_counter('commcare.two_factor.setup_requests', 1, tags={ 'status': status, 'method': method, }) return status != _status_accepted two_factor_setup_rate_limiter = RateLimiter( feature_key='two_factor_setup_attempts', get_rate_limits=lambda scope: get_dynamic_rate_definition( 'two_factor_setup_attempts', default=RateDefinition( per_week=15, per_day=8, per_hour=5, per_minute=3, per_second=1, ) ).get_rate_limits(), scope_length=1, # per user OR per IP ) global_two_factor_setup_rate_limiter = RateLimiter( feature_key='global_two_factor_setup_attempts', get_rate_limits=lambda: get_dynamic_rate_definition( 'global_two_factor_setup_attempts', default=RateDefinition( per_day=100, ) ).get_rate_limits(),
from corehq.util.quickcache import quickcache from corehq.util.timer import TimingContext # Danny promised in an Aug 2019 email not to enforce limits that were lower than this. # RateDefinition( # per_week=115, # per_day=23, # per_hour=3, # per_minute=0.07, # per_second=0.005, # ) == get_standard_ratio_rate_definition(events_per_day=23) # If we as a team end up regretting this decision, we'll have to reset expectations # with the Dimagi NDoH team. submission_rate_limiter = RateLimiter( feature_key='submissions', get_rate_limits=lambda domain: _get_per_user_submission_rate_definition( domain)) def _get_per_user_submission_rate_definition(domain): return PerUserRateDefinition( per_user_rate_definition=get_dynamic_rate_definition( 'submissions_per_user', default=get_standard_ratio_rate_definition(events_per_day=46), ), constant_rate_definition=get_dynamic_rate_definition( 'baseline_submissions_per_project', default=RateDefinition( per_week=100, per_day=50, per_hour=30,
RateLimiter, ) from corehq.project_limits.shortcuts import get_standard_ratio_rate_definition from corehq.toggles import RATE_LIMIT_RESTORES, NAMESPACE_DOMAIN, BLOCK_RESTORES from corehq.util.decorators import run_only_when, silence_and_report_error from corehq.util.metrics import metrics_counter RESTORES_PER_DAY = 3 restore_rate_limiter = RateLimiter( feature_key='restores', get_rate_limits=PerUserRateDefinition( per_user_rate_definition=get_standard_ratio_rate_definition( events_per_day=RESTORES_PER_DAY), constant_rate_definition=RateDefinition( per_week=50, per_day=25, per_hour=15, per_minute=5, per_second=1, ), ).get_rate_limits) SHOULD_RATE_LIMIT_RESTORES = not settings.ENTERPRISE_MODE and not settings.UNIT_TESTING @run_only_when(SHOULD_RATE_LIMIT_RESTORES) @silence_and_report_error("Exception raised in the restore rate limiter", 'commcare.restores.rate_limiter_errors') def rate_limit_restore(domain): if RATE_LIMIT_RESTORES.enabled(domain, namespace=NAMESPACE_DOMAIN):
# per_hour=3, # per_minute=0.07, # per_second=0.005, # ) == get_standard_ratio_rate_definition(events_per_day=23) # If we as a team end up regretting this decision, we'll have to reset expectations # with the Dimagi NDoH team. SUBMISSIONS_PER_DAY = 46 submission_rate_limiter = RateLimiter( feature_key='submissions', get_rate_limits=PerUserRateDefinition( per_user_rate_definition=get_standard_ratio_rate_definition( events_per_day=SUBMISSIONS_PER_DAY), constant_rate_definition=RateDefinition( per_week=100, per_day=50, per_hour=30, per_minute=10, per_second=1, ), ).get_rate_limits ) global_submission_rate_limiter = RateLimiter( feature_key='global_submissions', get_rate_limits=lambda: get_dynamic_rate_definition( 'global_submissions', default=RateDefinition( per_hour=17000, per_minute=400, per_second=30,
) base_restores_per_domain = RateDefinition( per_week=50, per_day=25, per_hour=15, per_minute=5, per_second=1, ) restore_rates = PerUserRateDefinition( per_user_rate_definition=restores_per_user, constant_rate_definition=base_restores_per_domain, ) restore_rate_limiter = RateLimiter( feature_key='restores', get_rate_limits=restore_rates.get_rate_limits) SHOULD_RATE_LIMIT_RESTORES = not settings.ENTERPRISE_MODE and not settings.UNIT_TESTING @run_only_when(SHOULD_RATE_LIMIT_RESTORES) @silence_and_report_error("Exception raised in the restore rate limiter", 'commcare.restores.rate_limiter_errors') def rate_limit_restore(domain): if RATE_LIMIT_RESTORES.enabled(domain, namespace=NAMESPACE_DOMAIN): return _rate_limit_restore(domain) else: _rate_limit_restore_test(domain) return False