Skip to content

Commit

Permalink
Fix: Support allowUrls, denyUrls (#2271)
Browse files Browse the repository at this point in the history
* moved regex matcher into regex utils

* add allowUrls, denyUrls for web

* add changelog entry for allowUrls and denyUrls

* add conditional import for non web platforms

* fix multiplatform build

* fix wording in sentry options

* Update dart/lib/src/utils/regex_utils.dart

Co-authored-by: Giancarlo Buenaflor <giancarlo_buenaflor@yahoo.com>

* Update dart/lib/src/sentry_options.dart

Co-authored-by: Giancarlo Buenaflor <giancarlo_buenaflor@yahoo.com>

* Update dart/lib/src/sentry_options.dart

Co-authored-by: Giancarlo Buenaflor <giancarlo_buenaflor@yahoo.com>

* add tests for isMatchingRegexPattern

* simplified allowUrls and denyUrls handling

* moved allowUrls and denyUrls from dart to flutter

* add event processor for html

* rephrased documentation and split up tests for web and mobile platform.

* add expected error

* Update scripts/publish_validation/bin/publish_validation.dart

Co-authored-by: Giancarlo Buenaflor <giancarlo_buenaflor@yahoo.com>

* Update flutter/lib/src/event_processor/url_filter/html_url_filter_event_processor.dart

Co-authored-by: Giancarlo Buenaflor <giancarlo_buenaflor@yahoo.com>

* Update flutter/lib/src/event_processor/url_filter/web_url_filter_event_processor.dart

Co-authored-by: Giancarlo Buenaflor <giancarlo_buenaflor@yahoo.com>

* modified code to go through stacktrace frames

* change matching to window.location

---------

Co-authored-by: Giancarlo Buenaflor <giancarlo_buenaflor@yahoo.com>
  • Loading branch information
martinhaintz and buenaflor authored Sep 9, 2024
1 parent f1c905b commit 77db8d4
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 127 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,23 @@ class WebUrlFilterEventProcessor implements UrlFilterEventProcessor {
this._options,
);

final html.Window _window = html.window;
final SentryFlutterOptions _options;

@override
SentryEvent? apply(SentryEvent event, Hint hint) {
final frames = _getStacktraceFrames(event);
final lastPath = frames?.first?.absPath;

if (lastPath == null) {
return event;
}
final url = _window.location.toString();

if (_options.allowUrls.isNotEmpty &&
!isMatchingRegexPattern(lastPath, _options.allowUrls)) {
!isMatchingRegexPattern(url, _options.allowUrls)) {
return null;
}

if (_options.denyUrls.isNotEmpty &&
isMatchingRegexPattern(lastPath, _options.denyUrls)) {
isMatchingRegexPattern(url, _options.denyUrls)) {
return null;
}

return event;
}

Iterable<SentryStackFrame?>? _getStacktraceFrames(SentryEvent event) {
if (event.exceptions?.isNotEmpty == true) {
return event.exceptions?.first.stackTrace?.frames;
}
if (event.threads?.isNotEmpty == true) {
final stacktraces = event.threads?.map((e) => e.stacktrace);
return stacktraces
?.where((element) => element != null)
.expand((element) => element!.frames);
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,23 @@ class WebUrlFilterEventProcessor implements UrlFilterEventProcessor {
this._options,
);

final web.Window _window = web.window;
final SentryFlutterOptions _options;

@override
SentryEvent? apply(SentryEvent event, Hint hint) {
final frames = _getStacktraceFrames(event);
final lastPath = frames?.first?.absPath;

if (lastPath == null) {
return event;
}
final url = _window.location.toString();

if (_options.allowUrls.isNotEmpty &&
!isMatchingRegexPattern(lastPath, _options.allowUrls)) {
!isMatchingRegexPattern(url, _options.allowUrls)) {
return null;
}

if (_options.denyUrls.isNotEmpty &&
isMatchingRegexPattern(lastPath, _options.denyUrls)) {
isMatchingRegexPattern(url, _options.denyUrls)) {
return null;
}

return event;
}

Iterable<SentryStackFrame?>? _getStacktraceFrames(SentryEvent event) {
if (event.exceptions?.isNotEmpty == true) {
return event.exceptions?.first.stackTrace?.frames;
}
if (event.threads?.isNotEmpty == true) {
final stacktraces = event.threads?.map((e) => e.stacktrace);
return stacktraces
?.where((element) => element != null)
.expand((element) => element!.frames);
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import 'package:sentry_flutter/src/event_processor/url_filter/url_filter_event_p

// can be tested on command line with
// `flutter test --platform=chrome test/event_processor/url_filter/web_url_filter_event_processor_test.dart`
// The URL looks something like this: http://localhost:58551/event_processor/url_filter/web_url_filter_event_processor_test.html

void main() {
group(UrlFilterEventProcessor, () {
late Fixture fixture;
Expand All @@ -16,57 +18,53 @@ void main() {
});

test('returns event if no allowUrl and no denyUrl is set', () async {
SentryEvent? event = SentryEvent(
request: SentryRequest(
url: 'foo.bar',
),
);
final event = SentryEvent();
final eventProcessor = fixture.getSut();

var eventProcessor = fixture.getSut();
event = await eventProcessor.apply(event, Hint());
final processedEvent = await eventProcessor.apply(event, Hint());

expect(event, isNotNull);
expect(processedEvent, isNotNull);
});

test('returns null if allowUrl is set and does not match with url',
() async {
final event = _createEventWithException("foo.bar");
final event = SentryEvent();
fixture.options.allowUrls = ["another.url"];
final eventProcessor = fixture.getSut();

var eventProcessor = fixture.getSut();
final processedEvent = await eventProcessor.apply(event, Hint());

expect(processedEvent, isNull);
});

test('returns event if allowUrl is set and does partially match with url',
() async {
final event = _createEventWithException("foo.bar");
fixture.options.allowUrls = ["bar"];
final event = SentryEvent();
fixture.options.allowUrls = ["event_processor_test"];
final eventProcessor = fixture.getSut();

var eventProcessor = fixture.getSut();
final processedEvent = await eventProcessor.apply(event, Hint());

expect(processedEvent, isNotNull);
});

test('returns event if denyUrl is set and does not match with url',
() async {
final event = _createEventWithException("foo.bar");
final event = SentryEvent();
fixture.options.denyUrls = ["another.url"];
final eventProcessor = fixture.getSut();

var eventProcessor = fixture.getSut();
final processedEvent = await eventProcessor.apply(event, Hint());

expect(processedEvent, isNotNull);
});

test('returns null if denyUrl is set and partially matches with url',
() async {
final event = _createEventWithException("foo.bar");
fixture.options.denyUrls = ["bar"];
final event = SentryEvent();
fixture.options.denyUrls = ["event_processor_test"];
final eventProcessor = fixture.getSut();

var eventProcessor = fixture.getSut();
final processedEvent = await eventProcessor.apply(event, Hint());

expect(processedEvent, isNull);
Expand All @@ -75,13 +73,11 @@ void main() {
test(
'returns null if it is part of the allowed domain, but blocked for subdomain',
() async {
final event = _createEventWithException(
"this.is/a/special/url/for-testing/this-feature");

fixture.options.allowUrls = ["^this.is/.*\$"];
fixture.options.denyUrls = ["special"];
final event = SentryEvent();
fixture.options.allowUrls = [".*localhost.*\$"];
fixture.options.denyUrls = ["event"];
final eventProcessor = fixture.getSut();

var eventProcessor = fixture.getSut();
final processedEvent = await eventProcessor.apply(event, Hint());

expect(processedEvent, isNull);
Expand All @@ -90,12 +86,11 @@ void main() {
test(
'returns event if it is part of the allowed domain, and not of the blocked for subdomain',
() async {
final event = _createEventWithException(
"this.is/a/test/url/for-testing/this-feature");
fixture.options.allowUrls = ["^this.is/.*\$"];
final event = SentryEvent();
fixture.options.allowUrls = [".*localhost.*\$"];
fixture.options.denyUrls = ["special"];
final eventProcessor = fixture.getSut();

var eventProcessor = fixture.getSut();
final processedEvent = await eventProcessor.apply(event, Hint());

expect(processedEvent, isNotNull);
Expand All @@ -104,60 +99,15 @@ void main() {
test(
'returns null if it is not part of the allowed domain, and not of the blocked for subdomain',
() async {
final event = _createEventWithException(
"another.url/for/a/test/testing/this-feature");
final event = SentryEvent();
fixture.options.allowUrls = ["^this.is/.*\$"];
fixture.options.denyUrls = ["special"];
final eventProcessor = fixture.getSut();

var eventProcessor = fixture.getSut();
final processedEvent = await eventProcessor.apply(event, Hint());

expect(processedEvent, isNull);
});

test(
'returns event if denyUrl is set and not matching with url of first exception',
() async {
final frame1 = SentryStackFrame(absPath: "test.url");
final st1 = SentryStackTrace(frames: [frame1]);
final exception1 = SentryException(
type: "test-type", value: "test-value", stackTrace: st1);

final frame2 = SentryStackFrame(absPath: "foo.bar");
final st2 = SentryStackTrace(frames: [frame2]);
final exception2 = SentryException(
type: "test-type", value: "test-value", stackTrace: st2);

SentryEvent event = SentryEvent(exceptions: [exception1, exception2]);

fixture.options.denyUrls = ["bar"];

var eventProcessor = fixture.getSut();
final processedEvent = await eventProcessor.apply(event, Hint());

expect(processedEvent, isNotNull);
});

test(
'returns event if denyUrl is set and not matching with url of first stacktraceframe',
() async {
final frame1 = SentryStackFrame(absPath: "test.url");
final st1 = SentryStackTrace(frames: [frame1]);
final thread1 = SentryThread(stacktrace: st1);

final frame2 = SentryStackFrame(absPath: "foo.bar");
final st2 = SentryStackTrace(frames: [frame2]);
final thread2 = SentryThread(stacktrace: st2);

SentryEvent event = SentryEvent(threads: [thread1, thread2]);

fixture.options.denyUrls = ["bar"];

var eventProcessor = fixture.getSut();
final processedEvent = await eventProcessor.apply(event, Hint());

expect(processedEvent, isNotNull);
});
});
}

Expand All @@ -167,13 +117,3 @@ class Fixture {
return UrlFilterEventProcessor(options);
}
}

SentryEvent _createEventWithException(String url) {
final frame = SentryStackFrame(absPath: url);
final st = SentryStackTrace(frames: [frame]);
final exception =
SentryException(type: "test-type", value: "test-value", stackTrace: st);
SentryEvent event = SentryEvent(exceptions: [exception]);

return event;
}

0 comments on commit 77db8d4

Please sign in to comment.