Example #1
0
    def _extract_filters(self, queryparams=None):
        """Extracts filters from QueryString parameters."""
        if not queryparams:
            queryparams = self.request.GET

        filters = []

        for param, value in queryparams.items():
            param = param.strip()
            value = native_value(value)

            # Ignore specific fields
            if param.startswith('_') and param not in ('_since',
                                                       '_to',
                                                       '_before'):
                continue

            # Handle the _since specific filter.
            if param in ('_since', '_to', '_before'):
                if not isinstance(value, six.integer_types):
                    error_details = {
                        'name': param,
                        'location': 'querystring',
                        'description': 'Invalid value for %s' % param
                    }
                    raise_invalid(self.request, **error_details)

                if param == '_since':
                    operator = COMPARISON.GT
                else:
                    if param == '_to':
                        message = ('_to is now deprecated, '
                                   'you should use _before instead')
                        url = ('http://cliquet.rtfd.org/en/2.4.0/api/resource'
                               '.html#list-of-available-url-parameters')
                        send_alert(self.request, message, url)
                    operator = COMPARISON.LT
                filters.append(
                    Filter(self.collection.modified_field, value, operator)
                )
                continue

            m = re.match(r'^(min|max|not|lt|gt)_(\w+)$', param)
            if m:
                keyword, field = m.groups()
                operator = getattr(COMPARISON, keyword.upper())
            else:
                operator, field = COMPARISON.EQ, param

            if not self.is_known_field(field):
                error_details = {
                    'location': 'querystring',
                    'description': "Unknown filter field '{0}'".format(param)
                }
                raise_invalid(self.request, **error_details)

            filters.append(Filter(field, value, operator))

        return filters
Example #2
0
 def test_send_alert_url_can_be_specified(self):
     request = DummyRequest()
     send_alert(request, 'Message', 'error_url')
     self.verify_alert_header(request, {
         'code': 'soft-eol',
         'message': 'Message',
         'url': 'error_url'
     })
Example #3
0
 def test_send_alert_url_can_be_specified(self):
     request = DummyRequest()
     send_alert(request, 'Message', 'error_url')
     self.verify_alert_header(request, {
         'code': 'soft-eol',
         'message': 'Message',
         'url': 'error_url'
     })
Example #4
0
 def test_send_alert_code_can_be_specified(self):
     request = DummyRequest()
     request.registry.settings['project_docs'] = 'docs_url'
     send_alert(request, 'Message', code='hard-eol')
     self.verify_alert_header(request, {
         'code': 'hard-eol',
         'message': 'Message',
         'url': 'docs_url'
     })
Example #5
0
 def test_send_alert_default_to_project_url(self):
     request = DummyRequest()
     request.registry.settings['project_docs'] = 'docs_url'
     send_alert(request, 'Message')
     self.verify_alert_header(request, {
         'code': 'soft-eol',
         'message': 'Message',
         'url': 'docs_url'
     })
Example #6
0
 def test_send_alert_code_can_be_specified(self):
     request = DummyRequest()
     request.registry.settings['project_docs'] = 'docs_url'
     send_alert(request, 'Message', code='hard-eol')
     self.verify_alert_header(request, {
         'code': 'hard-eol',
         'message': 'Message',
         'url': 'docs_url'
     })
Example #7
0
 def test_send_alert_default_to_project_url(self):
     request = DummyRequest()
     request.registry.settings['project_docs'] = 'docs_url'
     send_alert(request, 'Message')
     self.verify_alert_header(request, {
         'code': 'soft-eol',
         'message': 'Message',
         'url': 'docs_url'
     })
Example #8
0
    def eos_tween(request):
        eos_date = registry.settings["eos"]
        eos_url = registry.settings["eos_url"]
        eos_message = registry.settings["eos_message"]
        if not eos_date:
            return handler(request)

        eos_date = dateparser.parse(eos_date)
        if eos_date > datetime.now():
            code = "soft-eol"
            request.response = handler(request)
        else:
            code = "hard-eol"
            request.response = errors.http_error(
                HTTPGone(), errno=errors.ERRORS.SERVICE_DEPRECATED, message=deprecation_msg
            )

        errors.send_alert(request, eos_message, url=eos_url, code=code)
        return request.response
Example #9
0
    def eos_tween(request):
        eos_date = registry.settings['eos']
        eos_url = registry.settings['eos_url']
        eos_message = registry.settings['eos_message']
        if not eos_date:
            return handler(request)

        eos_date = dateparser.parse(eos_date)
        if eos_date > datetime.now():
            code = "soft-eol"
            request.response = handler(request)
        else:
            code = "hard-eol"
            request.response = errors.http_error(
                HTTPGone(),
                errno=errors.ERRORS.SERVICE_DEPRECATED,
                message=deprecation_msg)

        errors.send_alert(request, eos_message, url=eos_url, code=code)
        return request.response
Example #10
0
    def _extract_filters(self, queryparams=None):
        """Extracts filters from QueryString parameters."""
        if not queryparams:
            queryparams = self.request.GET

        filters = []

        for param, paramvalue in queryparams.items():
            param = param.strip()

            error_details = {
                'name': param,
                'location': 'querystring',
                'description': 'Invalid value for %s' % param
            }

            # Ignore specific fields
            if param.startswith('_') and param not in ('_since',
                                                       '_to',
                                                       '_before'):
                continue

            # Handle the _since specific filter.
            if param in ('_since', '_to', '_before'):
                value = native_value(paramvalue.strip('"'))

                if not isinstance(value, six.integer_types):
                    raise_invalid(self.request, **error_details)

                if param == '_since':
                    operator = COMPARISON.GT
                else:
                    if param == '_to':
                        message = ('_to is now deprecated, '
                                   'you should use _before instead')
                        url = ('http://cliquet.rtfd.org/en/2.4.0/api/resource'
                               '.html#list-of-available-url-parameters')
                        send_alert(self.request, message, url)
                    operator = COMPARISON.LT
                filters.append(
                    Filter(self.model.modified_field, value, operator)
                )
                continue

            m = re.match(r'^(min|max|not|lt|gt|in|exclude)_(\w+)$', param)
            if m:
                keyword, field = m.groups()
                operator = getattr(COMPARISON, keyword.upper())
            else:
                operator, field = COMPARISON.EQ, param

            if not self.is_known_field(field):
                error_msg = "Unknown filter field '{0}'".format(param)
                error_details['description'] = error_msg
                raise_invalid(self.request, **error_details)

            value = native_value(paramvalue)
            if operator in (COMPARISON.IN, COMPARISON.EXCLUDE):
                value = set([native_value(v) for v in paramvalue.split(',')])

                all_integers = all([isinstance(v, six.integer_types)
                                    for v in value])
                all_strings = all([isinstance(v, six.text_type)
                                   for v in value])
                has_invalid_value = (
                    (field == self.model.id_field and not all_strings) or
                    (field == self.model.modified_field and not all_integers)
                )
                if has_invalid_value:
                    raise_invalid(self.request, **error_details)

            filters.append(Filter(field, value, operator))

        return filters
Example #11
0
def build_sync_client(request):
    # Get the BID assertion
    is_authorization_defined = AUTHORIZATION_HEADER in request.headers
    starts_with_browser_id = False
    if is_authorization_defined:
        authorization = request.headers[AUTHORIZATION_HEADER].lower()
        starts_with_browser_id = authorization.startswith("browserid ")

    if not is_authorization_defined or not starts_with_browser_id:
        msg = "Provide a BID assertion %s header." % AUTHORIZATION_HEADER
        response = http_error(httpexceptions.HTTPUnauthorized(), errno=ERRORS.MISSING_AUTH_TOKEN, message=msg)
        response.headers.extend(forget(request))
        raise response

    bucket_id = request.matchdict["bucket_id"]
    is_client_state_header_defined = CLIENT_STATE_HEADER in request.headers

    if bucket_id == "syncto":
        if not is_client_state_header_defined:
            msg = "Provide the tokenserver %s header." % CLIENT_STATE_HEADER
            response = http_error(httpexceptions.HTTPUnauthorized(), errno=ERRORS.MISSING_AUTH_TOKEN, message=msg)
            response.headers.extend(forget(request))
            raise response
        client_state = request.headers[CLIENT_STATE_HEADER]
    elif len(bucket_id) != CLIENT_STATE_LENGTH:
        msg = "The provided bucket ID is incorrect."
        response = http_error(httpexceptions.HTTPUnauthorized(), errno=ERRORS.MISSING_AUTH_TOKEN, message=msg)
        response.headers.extend(forget(request))
        raise response
    else:
        client_state = bucket_id

    if is_client_state_header_defined:
        send_alert(request, "%s header is deprecated and should not be " "provided anymore." % CLIENT_STATE_HEADER)

    authorization_header = request.headers[AUTHORIZATION_HEADER]
    bid_assertion = authorization_header.split(" ", 1)[1]

    settings = request.registry.settings
    cache = request.registry.cache
    statsd = request.registry.statsd
    token_server_url = settings["token_server_url"]

    hmac_secret = settings["cache_hmac_secret"]
    cache_key = "credentials_%s" % utils.hmac_digest(hmac_secret, bid_assertion)
    ca_bundle = settings["certificate_ca_bundle"]

    encrypted_credentials = cache.get(cache_key)

    if not encrypted_credentials:
        settings_ttl = int(settings["cache_credentials_ttl_seconds"])
        bid_ttl = _extract_bid_assertion_ttl(bid_assertion)
        ttl = min(settings_ttl, bid_ttl or settings_ttl)

        tokenserver = TokenserverClient(bid_assertion, client_state, token_server_url, verify=ca_bundle)
        if statsd:
            statsd.watch_execution_time(tokenserver, prefix="tokenserver")
        credentials = tokenserver.get_hawk_credentials(duration=ttl)
        encrypted = encrypt(json.dumps(credentials), client_state, hmac_secret)
        cache.set(cache_key, encrypted, ttl)
    else:
        credentials = json.loads(decrypt(encrypted_credentials, client_state, hmac_secret))

    if statsd:
        timer = statsd.timer("syncclient.start_time")
        timer.start()

    sync_client = SyncClient(verify=ca_bundle, **credentials)

    if statsd:
        timer.stop()
        statsd.watch_execution_time(sync_client, prefix="syncclient")

    return sync_client
Example #12
0
    def _extract_filters(self, queryparams=None):
        """Extracts filters from QueryString parameters."""
        if not queryparams:
            queryparams = self.request.GET

        filters = []

        for param, paramvalue in queryparams.items():
            param = param.strip()

            error_details = {
                'name': param,
                'location': 'querystring',
                'description': 'Invalid value for %s' % param
            }

            # Ignore specific fields
            if param.startswith('_') and param not in ('_since', '_to',
                                                       '_before'):
                continue

            # Handle the _since specific filter.
            if param in ('_since', '_to', '_before'):
                value = native_value(paramvalue.strip('"'))

                if not isinstance(value, six.integer_types):
                    raise_invalid(self.request, **error_details)

                if param == '_since':
                    operator = COMPARISON.GT
                else:
                    if param == '_to':
                        message = ('_to is now deprecated, '
                                   'you should use _before instead')
                        url = ('http://cliquet.rtfd.org/en/2.4.0/api/resource'
                               '.html#list-of-available-url-parameters')
                        send_alert(self.request, message, url)
                    operator = COMPARISON.LT
                filters.append(
                    Filter(self.model.modified_field, value, operator))
                continue

            m = re.match(r'^(min|max|not|lt|gt|in|exclude)_(\w+)$', param)
            if m:
                keyword, field = m.groups()
                operator = getattr(COMPARISON, keyword.upper())
            else:
                operator, field = COMPARISON.EQ, param

            if not self.is_known_field(field):
                error_msg = "Unknown filter field '{0}'".format(param)
                error_details['description'] = error_msg
                raise_invalid(self.request, **error_details)

            value = native_value(paramvalue)
            if operator in (COMPARISON.IN, COMPARISON.EXCLUDE):
                value = set([native_value(v) for v in paramvalue.split(',')])

                all_integers = all(
                    [isinstance(v, six.integer_types) for v in value])
                all_strings = all(
                    [isinstance(v, six.text_type) for v in value])
                has_invalid_value = (
                    (field == self.model.id_field and not all_strings) or
                    (field == self.model.modified_field and not all_integers))
                if has_invalid_value:
                    raise_invalid(self.request, **error_details)

            filters.append(Filter(field, value, operator))

        return filters