Skip to content

Commit

Permalink
[url_launcher_web] Disallows launching "javascript:" URLs. (flutter#5180
Browse files Browse the repository at this point in the history
)

This PR updates the URL launcher to:

* Implement the new `launchUrl` method.
* Disallow `launch` and `launchUrl` for URLs with the `javascript:` scheme. 
* Prevent _Tabnabbing_.

### Issues

Fixes flutter/flutter#136657

### Tests

Integration tests (and mocks) updated.
  • Loading branch information
ditman authored Oct 23, 2023
1 parent a64da5c commit 5c6cb75
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 29 deletions.
5 changes: 5 additions & 0 deletions packages/url_launcher/url_launcher_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2.1.0

* Adds `launchUrl` implementation.
* Prevents _Tabnabbing_ and disallows `javascript:` URLs on `launch` and `launchUrl`.

## 2.0.20

* Migrates to `dart:ui_web` APIs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void main() {
when(mockWindow.navigator).thenReturn(mockNavigator);

// Simulate that window.open does something.
when(mockWindow.open(any, any)).thenReturn(MockWindow());
when(mockWindow.open(any, any, any)).thenReturn(MockWindow());

when(mockNavigator.userAgent).thenReturn(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36');
Expand Down Expand Up @@ -59,6 +59,10 @@ void main() {
expect(plugin.canLaunch('sms:+19725551212?body=hello%20there'),
completion(isTrue));
});

testWidgets('"javascript" URLs -> false', (WidgetTester _) async {
expect(plugin.canLaunch('javascript:alert("1")'), completion(isFalse));
});
});

group('launch', () {
Expand Down Expand Up @@ -93,57 +97,68 @@ void main() {
),
completion(isTrue));
});

testWidgets('launching a "javascript" returns false',
(WidgetTester _) async {
expect(plugin.launch('javascript:alert("1")'), completion(isFalse));
});
});

group('openNewWindow', () {
testWidgets('http urls should be launched in a new window',
(WidgetTester _) async {
plugin.openNewWindow('http://www.google.com');

verify(mockWindow.open('http://www.google.com', ''));
verify(mockWindow.open(
'http://www.google.com', '', 'noopener,noreferrer'));
});

testWidgets('https urls should be launched in a new window',
(WidgetTester _) async {
plugin.openNewWindow('https://www.google.com');

verify(mockWindow.open('https://www.google.com', ''));
verify(mockWindow.open(
'https://www.google.com', '', 'noopener,noreferrer'));
});

testWidgets('mailto urls should be launched on a new window',
(WidgetTester _) async {
plugin.openNewWindow('mailto:[email protected]');

verify(mockWindow.open('mailto:[email protected]', ''));
verify(mockWindow.open(
'mailto:[email protected]', '', 'noopener,noreferrer'));
});

testWidgets('tel urls should be launched on a new window',
(WidgetTester _) async {
plugin.openNewWindow('tel:5551234567');

verify(mockWindow.open('tel:5551234567', ''));
verify(mockWindow.open('tel:5551234567', '', 'noopener,noreferrer'));
});

testWidgets('sms urls should be launched on a new window',
(WidgetTester _) async {
plugin.openNewWindow('sms:+19725551212?body=hello%20there');

verify(mockWindow.open('sms:+19725551212?body=hello%20there', ''));
verify(mockWindow.open(
'sms:+19725551212?body=hello%20there', '', 'noopener,noreferrer'));
});
testWidgets(
'setting webOnlyLinkTarget as _self opens the url in the same tab',
(WidgetTester _) async {
plugin.openNewWindow('https://www.google.com',
webOnlyWindowName: '_self');
verify(mockWindow.open('https://www.google.com', '_self'));
verify(mockWindow.open(
'https://www.google.com', '_self', 'noopener,noreferrer'));
});

testWidgets(
'setting webOnlyLinkTarget as _blank opens the url in a new tab',
(WidgetTester _) async {
plugin.openNewWindow('https://www.google.com',
webOnlyWindowName: '_blank');
verify(mockWindow.open('https://www.google.com', '_blank'));
verify(mockWindow.open(
'https://www.google.com', '_blank', 'noopener,noreferrer'));
});

group('Safari', () {
Expand All @@ -158,43 +173,48 @@ void main() {
(WidgetTester _) async {
plugin.openNewWindow('http://www.google.com');

verify(mockWindow.open('http://www.google.com', ''));
verify(mockWindow.open(
'http://www.google.com', '', 'noopener,noreferrer'));
});

testWidgets('https urls should be launched in a new window',
(WidgetTester _) async {
plugin.openNewWindow('https://www.google.com');

verify(mockWindow.open('https://www.google.com', ''));
verify(mockWindow.open(
'https://www.google.com', '', 'noopener,noreferrer'));
});

testWidgets('mailto urls should be launched on the same window',
(WidgetTester _) async {
plugin.openNewWindow('mailto:[email protected]');

verify(mockWindow.open('mailto:[email protected]', '_top'));
verify(mockWindow.open(
'mailto:[email protected]', '_top', 'noopener,noreferrer'));
});

testWidgets('tel urls should be launched on the same window',
(WidgetTester _) async {
plugin.openNewWindow('tel:5551234567');

verify(mockWindow.open('tel:5551234567', '_top'));
verify(
mockWindow.open('tel:5551234567', '_top', 'noopener,noreferrer'));
});

testWidgets('sms urls should be launched on the same window',
(WidgetTester _) async {
plugin.openNewWindow('sms:+19725551212?body=hello%20there');

verify(
mockWindow.open('sms:+19725551212?body=hello%20there', '_top'));
verify(mockWindow.open('sms:+19725551212?body=hello%20there', '_top',
'noopener,noreferrer'));
});
testWidgets(
'mailto urls should use _blank if webOnlyWindowName is set as _blank',
(WidgetTester _) async {
plugin.openNewWindow('mailto:[email protected]',
webOnlyWindowName: '_blank');
verify(mockWindow.open('mailto:[email protected]', '_blank'));
verify(mockWindow.open(
'mailto:[email protected]', '_blank', 'noopener,noreferrer'));
});
});
});
Expand Down
Loading

0 comments on commit 5c6cb75

Please sign in to comment.