def test_violated_directive(self): result = Csp.to_python(dict( document_uri='http://example.com/foo', violated_directive='style-src http://cdn.example.com', )) assert result.get_violated_directive() == ('violated-directive', 'style-src http://cdn.example.com') result = Csp.to_python(dict( document_uri='http://example.com/foo', violated_directive='style-src cdn.example.com', )) assert result.get_violated_directive() == ('violated-directive', 'style-src http://cdn.example.com') result = Csp.to_python(dict( document_uri='https://example.com/foo', violated_directive='style-src cdn.example.com', )) assert result.get_violated_directive() == ('violated-directive', 'style-src https://cdn.example.com') result = Csp.to_python(dict( document_uri='http://example.com/foo', violated_directive='style-src https://cdn.example.com', )) assert result.get_violated_directive() == ('violated-directive', 'style-src https://cdn.example.com') result = Csp.to_python(dict( document_uri='blob:example.com/foo', violated_directive='style-src cdn.example.com', )) assert result.get_violated_directive() == ('violated-directive', 'style-src blob:cdn.example.com')
def test_get_hash(self): result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='', )) assert result.get_hash() == ['script-src', "'self'"] result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='self', )) assert result.get_hash() == ['script-src', "'self'"] result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='http://example.com/lol.js', )) assert result.get_hash() == ['script-src', 'example.com'] result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='img-src', blocked_uri='data:foo', )) assert result.get_hash() == ['img-src', 'data:'] result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='img-src', blocked_uri='ftp://example.com/foo', )) assert result.get_hash() == ['img-src', 'ftp://example.com']
def test_get_culprit_directive(self): result = Csp.to_python(dict( document_uri='http://example.com/foo', blocked_uri='http://example.com/lol.css', effective_directive='style-src' )) assert result.get_culprit_directive() == ('blocked-uri', 'http://example.com/lol.css') result = Csp.to_python(dict( document_uri='http://example.com/foo', blocked_uri='', effective_directive='style-src', )) assert result.get_culprit_directive() == ('effective-directive', 'style-src') result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='', )) assert result.get_culprit_directive() == ('blocked-uri', 'self') result = Csp.to_python(dict( document_uri='http://example.com/foo', )) assert result.get_culprit_directive() == ('effective-directive', '<unknown>')
def interface(self): return Csp.to_python(dict( document_uri='http://example.com', violated_directive='style-src cdn.example.com', blocked_uri='http://example.com/lol.css', effective_directive='style-src', ))
def validate_data(self, project, data): # All keys are sent with hyphens, so we want to conver to underscores report = dict(map(lambda v: (v[0].replace('-', '_'), v[1]), data.iteritems())) try: inst = Csp.to_python(report) except Exception as exc: raise APIForbidden('Invalid CSP Report: %s' % exc) # Construct a faux Http interface based on the little information we have headers = {} if self.context.agent: headers['User-Agent'] = self.context.agent if inst.referrer: headers['Referer'] = inst.referrer return { 'logger': 'csp', 'project': project.id, 'message': inst.get_message(), 'culprit': inst.get_culprit(), 'tags': inst.get_tags(), inst.get_path(): inst.to_json(), # This is a bit weird, since we don't have nearly enough # information to create an Http interface, but # this automatically will pick up tags for the User-Agent # which is actually important here for CSP 'sentry.interfaces.Http': { 'url': inst.document_uri, 'headers': headers, }, 'sentry.interfaces.User': { 'ip_address': self.context.ip_address, } }
def test_coerce_blocked_uri_if_missing(self): result = Csp.to_python( dict( document_uri='http://example.com', effective_directive='script-src', )) assert result.blocked_uri == 'self'
def validate_data(self, project, data): # All keys are sent with hyphens, so we want to conver to underscores report = dict(map(lambda v: (v[0].replace("-", "_"), v[1]), data.iteritems())) try: inst = Csp.to_python(report) except Exception as exc: raise APIForbidden("Invalid CSP Report: %s" % exc) # Construct a faux Http interface based on the little information we have headers = {} if self.context.agent: headers["User-Agent"] = self.context.agent if inst.referrer: headers["Referer"] = inst.referrer return { "logger": "csp", "project": project.id, "message": inst.get_message(), "culprit": inst.get_culprit(), "tags": inst.get_tags(), inst.get_path(): inst.to_json(), # This is a bit weird, since we don't have nearly enough # information to create an Http interface, but # this automatically will pick up tags for the User-Agent # which is actually important here for CSP "sentry.interfaces.Http": {"url": inst.document_uri, "headers": headers}, "sentry.interfaces.User": {"ip_address": self.context.ip_address}, }
def interface(self): return Csp.to_python( dict( document_uri='http://example.com', violated_directive='style-src cdn.example.com', blocked_uri='http://example.com/lol.css', effective_directive='style-src', ))
def test_coerce_blocked_uri_if_missing(self): result = Csp.to_python( dict( document_uri='http://example.com', effective_directive='script-src', ) ) assert result.blocked_uri == 'self'
def test_get_message(self): result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='img-src', blocked_uri='http://google.com/foo', )) assert result.get_message() == "Blocked 'image' from 'google.com'" result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='style-src', blocked_uri='', )) assert result.get_message() == "Blocked inline 'style'" result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='', violated_directive="script-src 'unsafe-inline'", )) assert result.get_message() == "Blocked unsafe eval() 'script'" result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='', violated_directive="script-src 'unsafe-eval'", )) assert result.get_message() == "Blocked unsafe inline 'script'" result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='', violated_directive="script-src example.com", )) assert result.get_message( ) == "Blocked unsafe (eval() or inline) 'script'" result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D', )) assert result.get_message() == "Blocked 'script' from 'data:'" result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='data', )) assert result.get_message() == "Blocked 'script' from 'data:'"
def test_get_hash(self): result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='', ) ) assert result.get_hash() == ['script-src', "'self'"] result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='self', ) ) assert result.get_hash() == ['script-src', "'self'"] result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='http://example.com/lol.js', ) ) assert result.get_hash() == ['script-src', 'example.com'] result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='img-src', blocked_uri='data:foo', ) ) assert result.get_hash() == ['img-src', 'data:'] result = Csp.to_python( dict( document_uri='http://example.com/foo', effective_directive='img-src', blocked_uri='ftp://example.com/foo', ) ) assert result.get_hash() == ['img-src', 'ftp://example.com']
def get_metadata(self): # TODO(dcramer): pull get message into here to avoid instantiation # or ensure that these get interfaces passed instead of raw data csp = Csp.to_python(self.data['sentry.interfaces.Csp']) return { 'directive': csp.effective_directive, 'uri': csp._normalized_blocked_uri, 'message': csp.get_message(), }
def test_get_tags_stripe(self): result = Csp.to_python( dict( blocked_uri='https://api.stripe.com/v1/tokens?card[number]=xxx', effective_directive='script-src', )) assert result.get_tags() == ( ('effective-directive', 'script-src'), ('blocked-uri', 'https://api.stripe.com/v1/tokens'), )
def test_get_tags_stripe(self): result = Csp.to_python( dict( blocked_uri='https://api.stripe.com/v1/tokens?card[number]=xxx', effective_directive='script-src', ) ) assert result.get_tags() == ( ('effective-directive', 'script-src'), ('blocked-uri', 'https://api.stripe.com/v1/tokens'), )
def validate_data(self, project, data): # pop off our meta data used to hold Sentry specific stuff meta = data.pop('_meta', {}) # All keys are sent with hyphens, so we want to conver to underscores report = dict( map(lambda v: (v[0].replace('-', '_'), v[1]), data.iteritems())) try: inst = Csp.to_python(report) except Exception as exc: raise APIForbidden('Invalid CSP Report: %s' % exc) # Construct a faux Http interface based on the little information we have headers = {} if self.context.agent: headers['User-Agent'] = self.context.agent if inst.referrer: headers['Referer'] = inst.referrer data = { 'logger': 'csp', 'project': project.id, 'message': inst.get_message(), 'culprit': inst.get_culprit(), 'tags': inst.get_tags(), 'release': meta.get('release'), inst.get_path(): inst.to_json(), # This is a bit weird, since we don't have nearly enough # information to create an Http interface, but # this automatically will pick up tags for the User-Agent # which is actually important here for CSP 'sentry.interfaces.Http': { 'url': inst.document_uri, 'headers': headers, }, 'sentry.interfaces.User': { 'ip_address': self.context.ip_address, }, 'errors': [], } # Copy/pasted from above in ClientApiHelper.validate_data if data.get('release'): data['release'] = unicode(data['release']) if len(data['release']) > 64: data['errors'].append({ 'type': EventError.VALUE_TOO_LONG, 'name': 'release', 'value': data['release'], }) del data['release'] return data
def validate_data(self, project, data): # pop off our meta data used to hold Sentry specific stuff meta = data.pop('_meta', {}) # All keys are sent with hyphens, so we want to conver to underscores report = dict(map(lambda v: (v[0].replace('-', '_'), v[1]), six.iteritems(data))) try: inst = Csp.to_python(report) except Exception as exc: raise APIForbidden('Invalid CSP Report: %s' % exc) # Construct a faux Http interface based on the little information we have headers = {} if self.context.agent: headers['User-Agent'] = self.context.agent if inst.referrer: headers['Referer'] = inst.referrer data = { 'logger': 'csp', 'project': project.id, 'message': inst.get_message(), 'culprit': inst.get_culprit(), 'tags': inst.get_tags(), 'release': meta.get('release'), inst.get_path(): inst.to_json(), # This is a bit weird, since we don't have nearly enough # information to create an Http interface, but # this automatically will pick up tags for the User-Agent # which is actually important here for CSP 'sentry.interfaces.Http': { 'url': inst.document_uri, 'headers': headers, }, 'sentry.interfaces.User': { 'ip_address': self.context.ip_address, }, 'errors': [], } # Copy/pasted from above in ClientApiHelper.validate_data if data.get('release'): data['release'] = six.text_type(data['release']) if len(data['release']) > 64: data['errors'].append({ 'type': EventError.VALUE_TOO_LONG, 'name': 'release', 'value': data['release'], }) del data['release'] return data
def get_metadata(self): # TODO(dcramer): we need to avoid importing interfaces in this module # due to recursion at top level from sentry.interfaces.csp import Csp # TODO(dcramer): pull get message into here to avoid instantiation # or ensure that these get interfaces passed instead of raw data csp = Csp.to_python(self.data['sentry.interfaces.Csp']) return { 'directive': csp.effective_directive, 'uri': csp._normalized_blocked_uri, 'message': csp.get_message(), }
def test_get_message(self): result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='img-src', blocked_uri='http://google.com/foo', )) assert result.get_message() == "Blocked 'image' from 'google.com'" result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='style-src', blocked_uri='', )) assert result.get_message() == "Blocked inline 'style'" result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='', violated_directive="script-src 'unsafe-inline'", )) assert result.get_message() == "Blocked unsafe eval() 'script'" result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='', violated_directive="script-src 'unsafe-eval'", )) assert result.get_message() == "Blocked unsafe inline 'script'" result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='', violated_directive="script-src example.com", )) assert result.get_message() == "Blocked unsafe (eval() or inline) 'script'" result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D', )) assert result.get_message() == "Blocked 'script' from 'data:'" result = Csp.to_python(dict( document_uri='http://example.com/foo', effective_directive='script-src', blocked_uri='data', )) assert result.get_message() == "Blocked 'script' from 'data:'"
def test_get_culprit(self): result = Csp.to_python( dict( document_uri='http://example.com/foo', violated_directive='style-src http://cdn.example.com', effective_directive='style-src', ) ) assert result.get_culprit() == 'style-src http://cdn.example.com' result = Csp.to_python( dict( document_uri='http://example.com/foo', violated_directive='style-src cdn.example.com', effective_directive='style-src', ) ) assert result.get_culprit() == 'style-src cdn.example.com' result = Csp.to_python( dict( document_uri='https://example.com/foo', violated_directive='style-src cdn.example.com', effective_directive='style-src', ) ) assert result.get_culprit() == 'style-src cdn.example.com' result = Csp.to_python( dict( document_uri='http://example.com/foo', violated_directive='style-src https://cdn.example.com', effective_directive='style-src', ) ) assert result.get_culprit() == 'style-src https://cdn.example.com' result = Csp.to_python( dict( document_uri='http://example.com/foo', violated_directive='style-src http://example.com', effective_directive='style-src', ) ) assert result.get_culprit() == "style-src 'self'" result = Csp.to_python( dict( document_uri='http://example.com/foo', violated_directive='style-src http://example2.com example.com', effective_directive='style-src', ) ) assert result.get_culprit() == "style-src http://example2.com 'self'"
def validate_data(self, data): # pop off our meta data used to hold Sentry specific stuff meta = data.pop('_meta', {}) # All keys are sent with hyphens, so we want to conver to underscores report = {k.replace('-', '_'): v for k, v in six.iteritems(data)} try: inst = Csp.to_python(report) except Exception as exc: raise APIForbidden('Invalid CSP Report: %s' % exc) # Construct a faux Http interface based on the little information we have headers = {} if self.context.agent: headers['User-Agent'] = self.context.agent if inst.referrer: headers['Referer'] = inst.referrer data = { 'logger': 'csp', 'message': inst.get_message(), 'culprit': inst.get_culprit(), 'release': meta.get('release'), 'tags': inst.get_tags(), inst.get_path(): inst.to_json(), # This is a bit weird, since we don't have nearly enough # information to create an Http interface, but # this automatically will pick up tags for the User-Agent # which is actually important here for CSP 'sentry.interfaces.Http': { 'url': inst.document_uri, 'headers': headers, }, 'sentry.interfaces.User': { 'ip_address': self.context.ip_address, }, } return data
def test_to_python_validation_errors(self): with self.assertRaises(InterfaceValidationError): Csp.to_python( dict( effective_directive='style-src', blocked_uri='about', )) with self.assertRaises(InterfaceValidationError): Csp.to_python(dict(effective_directive='lol', )) with self.assertRaises(InterfaceValidationError): Csp.to_python( dict( effective_directive='style-src', source_file='chrome-extension://fdasfdsafdsfdsa', ))
def test_to_python_validation_errors(self): with self.assertRaises(InterfaceValidationError): Csp.to_python(dict( effective_directive='style-src', blocked_uri='about', )) with self.assertRaises(InterfaceValidationError): Csp.to_python(dict( effective_directive='lol', )) with self.assertRaises(InterfaceValidationError): Csp.to_python(dict( effective_directive='style-src', source_file='chrome-extension://fdasfdsafdsfdsa', ))
def validate_data(self, project, data): # pop off our meta data used to hold Sentry specific stuff meta = data.pop('_meta', {}) # All keys are sent with hyphens, so we want to conver to underscores report = {k.replace('-', '_'): v for k, v in six.iteritems(data)} try: inst = Csp.to_python(report) except Exception as exc: raise APIForbidden('Invalid CSP Report: %s' % exc) # Construct a faux Http interface based on the little information we have headers = {} if self.context.agent: headers['User-Agent'] = self.context.agent if inst.referrer: headers['Referer'] = inst.referrer data = { 'logger': 'csp', 'project': project.id, 'message': inst.get_message(), 'culprit': inst.get_culprit(), 'release': meta.get('release'), inst.get_path(): inst.to_json(), # This is a bit weird, since we don't have nearly enough # information to create an Http interface, but # this automatically will pick up tags for the User-Agent # which is actually important here for CSP 'sentry.interfaces.Http': { 'url': inst.document_uri, 'headers': headers, }, 'sentry.interfaces.User': { 'ip_address': self.context.ip_address, }, 'errors': [], } # Copy/pasted from above in ClientApiHelper.validate_data if data.get('release'): data['release'] = six.text_type(data['release']) if len(data['release']) > 64: data['errors'].append({ 'type': EventError.VALUE_TOO_LONG, 'name': 'release', 'value': data['release'], }) del data['release'] tags = [] for k, v in inst.get_tags(): if not v: continue if len(v) > MAX_TAG_VALUE_LENGTH: self.log.debug('Discarded invalid tag: %s=%s', k, v) data['errors'].append({ 'type': EventError.INVALID_DATA, 'name': 'tags', 'value': (k, v), }) continue if not tagstore.is_valid_value(v): self.log.debug('Discard invalid tag value: %s', v) data['errors'].append({ 'type': EventError.INVALID_DATA, 'name': 'tags', 'value': (k, v), }) continue tags.append((k, v)) if tags: data['tags'] = tags return data
def validate_data(self, data): # pop off our meta data used to hold Sentry specific stuff meta = data.pop('_meta', {}) # All keys are sent with hyphens, so we want to conver to underscores report = {k.replace('-', '_'): v for k, v in six.iteritems(data)} try: inst = Csp.to_python(report) except Exception as exc: raise APIForbidden('Invalid CSP Report: %s' % exc) # Construct a faux Http interface based on the little information we have headers = {} if self.context.agent: headers['User-Agent'] = self.context.agent if inst.referrer: headers['Referer'] = inst.referrer data = { 'logger': 'csp', 'message': inst.get_message(), 'culprit': inst.get_culprit(), 'release': meta.get('release'), inst.get_path(): inst.to_json(), # This is a bit weird, since we don't have nearly enough # information to create an Http interface, but # this automatically will pick up tags for the User-Agent # which is actually important here for CSP 'sentry.interfaces.Http': { 'url': inst.document_uri, 'headers': headers, }, 'sentry.interfaces.User': { 'ip_address': self.context.ip_address, }, 'errors': [], } # Copy/pasted from above in ClientApiHelper.validate_data if data.get('release'): data['release'] = six.text_type(data['release']) if len(data['release']) > 64: data['errors'].append( { 'type': EventError.VALUE_TOO_LONG, 'name': 'release', 'value': data['release'], } ) del data['release'] tags = [] for k, v in inst.get_tags(): if not v: continue if len(v) > MAX_TAG_VALUE_LENGTH: self.log.debug('Discarded invalid tag: %s=%s', k, v) data['errors'].append( { 'type': EventError.INVALID_DATA, 'name': 'tags', 'value': (k, v), } ) continue if not tagstore.is_valid_value(v): self.log.debug('Discard invalid tag value: %s', v) data['errors'].append( { 'type': EventError.INVALID_DATA, 'name': 'tags', 'value': (k, v), } ) continue tags.append((k, v)) if tags: data['tags'] = tags return data
def test_to_python_validation_errors(self): with self.assertRaises(InterfaceValidationError): Csp.to_python(dict(blocked_uri='about')) with self.assertRaises(InterfaceValidationError): Csp.to_python(dict(effective_directive='lol'))
def test_coerce_blocked_uri_if_script_src(self): result = Csp.to_python(dict( effective_directive='script-src' )) assert result.blocked_uri == 'self'