import { addGlobalEventProcessor , getCurrentHub } from '@sentry/hub' ; import { Event , Integration , StackFrame } from '@sentry/types' ; import { getEventDescription , isDebugBuild , isMatchingPattern , logger } from '@sentry/utils' ; const DEFAULT_IGNORE_ERRORS = [ /^Script error\.?$/ , /^Javascript error: Script error\.? on line 0$/ ] ; /** JSDoc */ interface InboundFiltersOptions { allowUrls : Array < string | RegExp > ; denyUrls : Array < string | RegExp > ; ignoreErrors : Array < string | RegExp > ; ignoreInternal : boolean ; deprecated use  InboundFiltersOptions . allowUrls instead.  whitelistUrls : Array < string | RegExp > ; deprecated use  InboundFiltersOptions . denyUrls instead.  blacklistUrls : Array < string | RegExp > ; } /** Inbound filters configurable by the user */ export class InboundFilters implements Integration { inheritDoc public static id : string = 'InboundFilters' ; inheritDoc public name : string = InboundFilters . id ; public constructor ( private readonly _options = { } ) { } inheritDoc public setupOnce ( ) { addGlobalEventProcessor ( ( event ) => { const hub = getCurrentHub ( ) ; if ( ! hub ) { return event ; } const self = hub . getIntegration ( InboundFilters ) ; if ( self ) { const client = hub . getClient ( ) ; const clientOptions = client ? client . getOptions ( ) : { } ; const options = typeof self . _mergeOptions === 'function' ? self . _mergeOptions ( clientOptions ) : { } ; if ( typeof self . _shouldDropEvent !== 'function' ) { return event ; } return self . _shouldDropEvent ( event , options ) ? null : event ; } return event ; } ) ; } /** JSDoc */ private _shouldDropEvent ( event , options ) { if ( this . _isSentryError ( event , options ) ) { if ( isDebugBuild ( ) ) { logger . warn ( `Event dropped due to being internal Sentry Error.\nEvent: ${ getEventDescription ( event ) }` ) ; } return true ; } if ( this . _isIgnoredError ( event , options ) ) { if ( isDebugBuild ( ) ) { logger . warn ( `Event dropped due to being matched by \`ignoreErrors\` option.\nEvent: ${ getEventDescription ( event ) }` ) ; } return true ; } if ( this . _isDeniedUrl ( event , options ) ) { if ( isDebugBuild ( ) ) { logger . warn ( `Event dropped due to being matched by \`denyUrls\` option.\nEvent: ${ getEventDescription ( event ) }.\nUrl: ${ this . _getEventFilterUrl ( event ) }` ) ; } return true ; } if ( ! this . _isAllowedUrl ( event , options ) ) { if ( isDebugBuild ( ) ) { logger . warn ( `Event dropped due to not being matched by \`allowUrls\` option.\nEvent: ${ getEventDescription ( event ) }.\nUrl: ${ this . _getEventFilterUrl ( event ) }` ) ; } return true ; } return false ; } /** JSDoc */ private _isSentryError ( event , options ) { if ( ! options . ignoreInternal ) { return false ; } try { return event . exception . values [ 0 ] . type === 'SentryError' ; } catch ( e ) { } return false ; } /** JSDoc */ private _isIgnoredError ( event , options ) { if ( ! options . ignoreErrors || ! options . ignoreErrors . length ) { return false ; } return this . _getPossibleEventMessages ( event ) . some ( message => ( options . ignoreErrors as Array < RegExp | string > ) . some ( pattern => isMatchingPattern ( message , pattern ) ) ) ; } /** JSDoc */ private _isDeniedUrl ( event , options ) { if ( ! options . denyUrls || ! options . denyUrls . length ) { return false ; } const url = this . _getEventFilterUrl ( event ) ; return ! url ? false : options . denyUrls . some ( pattern => isMatchingPattern ( url , pattern ) ) ; } /** JSDoc */ private _isAllowedUrl ( event , options ) { if ( ! options . allowUrls || ! options . allowUrls . length ) { return true ; } const url = this . _getEventFilterUrl ( event ) ; return ! url ? true : options . allowUrls . some ( pattern => isMatchingPattern ( url , pattern ) ) ; } /** JSDoc */ private _mergeOptions ( clientOptions = { } ) { return { allowUrls : [ ... ( this . _options . whitelistUrls || [ ] ) , ... ( this . _options . allowUrls || [ ] ) , ... ( clientOptions . whitelistUrls || [ ] ) , ... ( clientOptions . allowUrls || [ ] ) , ] , denyUrls : [ ... ( this . _options . blacklistUrls || [ ] ) , ... ( this . _options . denyUrls || [ ] ) , ... ( clientOptions . blacklistUrls || [ ] ) , ... ( clientOptions . denyUrls || [ ] ) , ] , ignoreErrors : [ ... ( this . _options . ignoreErrors || [ ] ) , ... ( clientOptions . ignoreErrors || [ ] ) , ... DEFAULT_IGNORE_ERRORS , ] , ignoreInternal : typeof this . _options . ignoreInternal !== 'undefined' ? this . _options . ignoreInternal : true , } ; } /** JSDoc */ private _getPossibleEventMessages ( event ) { if ( event . message ) { return [ event . message ] ; } if ( event . exception ) { try { const { type = '' , value = '' } = ( event . exception . values && event . exception . values [ 0 ] ) || { } ; return [ `${ value }` , `${ type }: ${ value }` ] ; } catch ( oO ) { if ( isDebugBuild ( ) ) { logger . error ( `Cannot extract message for event ${ getEventDescription ( event ) }` ) ; } return [ ] ; } } return [ ] ; } /** JSDoc */ private _getLastValidUrl ( frames = [ ] ) { for ( let i = frames . length - 1 ; i >= 0 ; i -- ) { const frame = frames [ i ] ; if ( frame && frame . filename !== '<anonymous>' && frame . filename !== '[native code]' ) { return frame . filename || null ; } } return null ; } /** JSDoc */ private _getEventFilterUrl ( event ) { try { if ( event . stacktrace ) { return this . _getLastValidUrl ( event . stacktrace . frames ) ; } let frames ; try { frames = event . exception . values [ 0 ] . stacktrace . frames ; } catch ( e ) { } return frames ? this . _getLastValidUrl ( frames ) : null ; } catch ( oO ) { if ( isDebugBuild ( ) ) { logger . error ( `Cannot extract url for event ${ getEventDescription ( event ) }` ) ; } return null ; } } }