Exemple #1
0
def check_rate_limit() -> None:
    """
    Check whether or not a user has exceeded the rate limits specified in the
    config. Rate limits per API key or session and per user are recorded.
    The redis database is used to keep track of caching, by incrementing
    "rate limit" cache keys on each request and setting a timeout on them.
    The rate limit can be adjusted in the configuration file.

    :raises APIException: If the rate limit has been exceeded
    """
    if not flask.g.user:
        return check_rate_limit_unauthenticated()

    user_cache_key = f'rate_limit_user_{flask.g.user.id}'
    key_cache_key = f'rate_limit_api_key_{flask.g.api_key.hash}'

    auth_specific_requests = cache.inc(
        key_cache_key, timeout=app.config['RATE_LIMIT_AUTH_SPECIFIC'][1]
    )
    if auth_specific_requests > app.config['RATE_LIMIT_AUTH_SPECIFIC'][0]:
        time_left = cache.ttl(key_cache_key)
        raise APIException(
            f'Client rate limit exceeded. {time_left} seconds until lock expires.'
        )

    user_specific_requests = cache.inc(
        user_cache_key, timeout=app.config['RATE_LIMIT_PER_USER'][1]
    )
    if user_specific_requests > app.config['RATE_LIMIT_PER_USER'][0]:
        time_left = cache.ttl(user_cache_key)
        raise APIException(
            f'User rate limit exceeded. {time_left} seconds until lock expires.'
        )
Exemple #2
0
def test_cache_inc_key_already_exists(app, client):
    """Incrementing an already-existing key just increments it."""
    assert cache.set('test-inc-key', 3, timeout=15)
    value = cache.inc('test-inc-key', 4, timeout=80)
    time_left = cache.ttl('test-inc-key')
    assert value == 7
    assert time_left > 13 and time_left < 16
Exemple #3
0
    def test_route():
        cache.set('key3', 1)
        cache.inc('key1')
        cache.get('key2')
        cache.ttl('key2')
        cache.ttl('key3')
        cache.get('key3')
        cache.delete('key3')
        cache.delete('key4')

        assert cache.has('key1')
        assert flask.g.cache_keys['inc'] == {'key1'}
        assert flask.g.cache_keys['get'] == {'key3'}
        assert flask.g.cache_keys['set'] == {'key3'}
        assert flask.g.cache_keys['delete'] == {'key3'}
        assert flask.g.cache_keys['ttl'] == {'key3'}
        assert flask.g.cache_keys['has'] == {'key1'}
        return flask.jsonify('complete')
Exemple #4
0
def check_rate_limit_unauthenticated() -> None:
    """Applies a harsher 30 req / minute to unauthenticated users."""
    cache_key = f'rate_limit_unauth_{flask.request.remote_addr}'
    requests = cache.inc(cache_key, timeout=60)
    if requests > 30:
        time_left = cache.ttl(cache_key)
        raise APIException(
            f'Unauthenticated rate limit exceeded. {time_left} seconds until lock expires.'
        )
Exemple #5
0
def test_cache_inc_key_new(app, client):
    """Incrementing a nonexistent key should create it."""
    value = cache.inc('test-inc-key', 2, timeout=60)
    time_left = cache.ttl('test-inc-key')
    assert value == 2
    assert time_left < 61