Skip to content

Commit

Permalink
Web Share: restrict URL scheme to http and https
Browse files Browse the repository at this point in the history
We now follow the recent spec change limiting the permitted scheme
for shared urls to http and https - see
w3c/web-share#173
w3c/web-share#174
w3c/web-share#177

We make an exception if the page performing the share it itself loaded
from a different scheme (e.g. file) - in that case we allow the same
scheme to be used for the shared url.

Bug: 1131755
Change-Id: I6abf0f9acd40ef79ec49379314e2ef3a81d3467e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2425977
Commit-Queue: Eric Willigers <ericwilligers@chromium.org>
Reviewed-by: Glen Robertson <glenrob@chromium.org>
Auto-Submit: Eric Willigers <ericwilligers@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810180}
GitOrigin-RevId: 060b7f1b2de01048a934bc4aca41973edaf4d12c
  • Loading branch information
ericwilligers authored and copybara-github committed Sep 24, 2020
1 parent 5bb06dd commit f06b6ac
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 39 deletions.
4 changes: 3 additions & 1 deletion blink/renderer/modules/webshare/navigator_share.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ bool CanShareInternal(const LocalDOMWindow& window,

if (data.hasUrl()) {
url = window.CompleteURL(data.url());
if (!url.IsValid()) {
if (!url.IsValid() ||
(!url.ProtocolIsInHTTPFamily() &&
url.Protocol() != window.document()->BaseURL().Protocol())) {
if (exception_state) {
exception_state->ThrowTypeError("Invalid URL");
}
Expand Down
1 change: 0 additions & 1 deletion blink/web_tests/TestExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -2703,7 +2703,6 @@ crbug.com/626703 [ Mac10.14 ] external/wpt/pointerevents/compat/pointerevent_mou
crbug.com/626703 [ Mac10.15 ] external/wpt/pointerevents/compat/pointerevent_mouse-pointer-preventdefault.html [ Timeout Pass Failure ]
crbug.com/626703 [ Mac10.15 ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller.https.html [ Failure ]
crbug.com/626703 [ Mac10.14 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/valid-image-before-load.https.html [ Failure ]
crbug.com/626703 external/wpt/web-share/share-url-invalid.https.html [ Crash ]
crbug.com/626703 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/pageshow-event.window.html [ Timeout ]
crbug.com/626703 [ Win7 ] external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html [ Failure Timeout ]
crbug.com/626703 external/wpt/content-security-policy/frame-src/frame-src-same-document.sub.html [ Timeout ]
Expand Down
1 change: 0 additions & 1 deletion blink/web_tests/android/WebviewWPTExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -4516,7 +4516,6 @@ crbug.com/1050754 external/wpt/web-share/canShare.tentative.https.html [ Failure
crbug.com/1050754 external/wpt/web-share/idlharness.https.window.html [ Failure ]
crbug.com/1050754 external/wpt/web-share/share-empty.https.html [ Failure ]
crbug.com/1050754 external/wpt/web-share/share-sharePromise-internal-slot.https.html [ Timeout ]
crbug.com/1050754 external/wpt/web-share/share-url-invalid.https.html [ Failure ]
crbug.com/1050754 external/wpt/web-share/share-without-user-gesture.https.html [ Failure ]
crbug.com/1050754 external/wpt/webaudio/idlharness.https.window.html [ Failure ]
crbug.com/1050754 external/wpt/webaudio/the-audio-api/processing-model/cycle-without-delay.html [ Failure ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,74 +11,74 @@
'use strict';

test(() => {
assert_equals(navigator.canShare(), false);
assert_false(navigator.canShare());
}, 'canShare with no arguments (same as empty dictionary)');

test(() => {
assert_equals(navigator.canShare({}), false);
assert_false(navigator.canShare({}));
}, 'canShare with an empty dictionary');

test(() => {
assert_equals(navigator.canShare(undefined), false);
assert_false(navigator.canShare(undefined));
}, 'canShare with a undefined argument (same as empty dictionary)');

test(() => {
assert_equals(navigator.canShare(null), false);
assert_false(navigator.canShare(null));
}, 'canShare with a null argument (same as empty dictionary)');

test(() => {
assert_equals(navigator.canShare({unused: 'unexpected field'}), false);
assert_false(navigator.canShare({unused: 'unexpected field'}));
}, 'canShare with a dictionary containing only surplus fields');

test(() => {
// URL is invalid in that the URL Parser returns failure (port is too
// large).
const url = 'http://example.com:65536';
assert_equals(navigator.canShare({url}), false);
assert_false(navigator.canShare({url}));
}, 'canShare with an invalid URL');

test(() => {
assert_equals(navigator.canShare({title: undefined}), false);
assert_false(navigator.canShare({url: 'data:the url'}));
}, 'canShare with data URL');

test(() => {
assert_false(navigator.canShare({title: undefined}));
}, 'canShare with attribute undefined is equivalent to omitting the attribute');

test(() => {
assert_equals(navigator.canShare({title: 'subject'}), true);
assert_true(navigator.canShare({title: 'subject'}));
}, 'canShare with title');

test(() => {
assert_equals(navigator.canShare({text: 'body'}), true);
assert_true(navigator.canShare({text: 'body'}));
}, 'canShare with text');

test(() => {
assert_equals(navigator.canShare({url: 'https://www.example.com/some/path?some_query#some_fragment'}), true);
assert_true(navigator.canShare({url: 'https://www.example.com/some/path?some_query#some_fragment'}));
}, 'canShare with URL');

test(() => {
assert_equals(navigator.canShare({title: null}), true);
assert_true(navigator.canShare({title: null}));
}, 'canShare with null attribute');

test(() => {
assert_equals(navigator.canShare({text: 123}), true);
assert_true(navigator.canShare({text: 123}));
}, 'canShare with number');

test(() => {
assert_equals(navigator.canShare({url: {toString() { return 'https://example.com/'; }}}), true);
assert_true(navigator.canShare({url: {toString() { return 'https://example.com/'; }}}));
}, 'canShare with object');

test(() => {
assert_equals(navigator.canShare({title: 'subject', text: 'body', url: 'https://example.com/', unused: 'unexpected field'}), true);
assert_true(navigator.canShare({title: 'subject', text: 'body', url: 'https://example.com/', unused: 'unexpected field'}));
}, 'canShare with unexpected field');

test(() => {
assert_equals(navigator.canShare({url: 'data:the url'}), true);
}, 'canShare with data URL');

test(() => {
assert_equals(navigator.canShare({url: ''}), true);
assert_true(navigator.canShare({url: ''}));
}, 'canShare with empty URL');

test(() => {
assert_equals(navigator.canShare({url: '//www.example.com/some/path?some_query#some_fragment'}), true);
assert_true(navigator.canShare({url: '//www.example.com/some/path?some_query#some_fragment'}));
}, 'canShare with URL having no scheme');
</script>
</body>
Expand Down
20 changes: 15 additions & 5 deletions blink/web_tests/webshare/share-error.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,38 @@
}

share_test(mock => {
mock.pushShareResult('the title', 'the message', 'data:the url',
mock.pushShareResult('the title', 'the message', 'https://example.com/',
blink.mojom.ShareError.CANCELED);
return callWithKeyDown(() => assertRejectsWithError(
navigator.share({
title: 'the title',
text: 'the message',
url: 'data:the url'
url: 'https://example.com/'
}),
'AbortError'));
}, 'share with user cancellation');

share_test(mock => {
mock.pushShareResult('the title', 'the message', 'data:the url',
mock.pushShareResult('the title', 'the message', 'https://example.com/',
blink.mojom.ShareError.INTERNAL_ERROR);
return callWithKeyDown(() => assertRejectsWithError(
navigator.share({
title: 'the title',
text: 'the message',
url: 'data:the url'
url: 'https://example.com/'
}),
'AbortError'));
}, 'share with invalid url template');
}, 'share with internal error');

share_test(mock => {
return callWithKeyDown(() => assertRejectsWithError(
navigator.share({
title: 'the title',
text: 'the message',
url: 'data:foo'
}),
'TypeError'));
}, 'share with data url');

share_test(mock => {
return callWithKeyDown(async () => {
Expand Down
6 changes: 0 additions & 6 deletions blink/web_tests/webshare/share-success.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@
return callWithKeyDown(() => navigator.share({url: url}));
}, 'successful share with an empty URL');

share_test(mock => {
const url = 'data:foo';
mock.pushShareResult('', '', getAbsoluteUrl(url), blink.mojom.ShareError.OK);
return callWithKeyDown(() => navigator.share({url: url}));
}, 'successful share with a data URL');

share_test(mock => {
const url = 'http://example.com/foo\\ab%63\r\n\t "<>`{}';
// Expect '\' to normalize to '/', "%63" to normalize to 'c', '\r\n\t'
Expand Down
11 changes: 6 additions & 5 deletions blink/web_tests/webshare/share-types.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@
}

share_test(mock => {
mock.pushShareResult('true', 'the object', getAbsoluteUrl('384957'),
mock.pushShareResult('true', 'the object', 'http://example.com/',
blink.mojom.ShareError.OK);

const objectWithToString = {toString() { return 'the object'; }};
const textWithToString = {toString() { return 'the object'; }};
const urlWithToString = {toString() { return 'http://example.com/'; }};
return callWithKeyDown(() => navigator.share(
{title: true, text: objectWithToString, url: 384957}));
{title: true, text: textWithToString, url: urlWithToString}));
}, 'share of types other than string (expect implicitly converted to string)');

share_test(mock => {
// null fields should convert into the string 'null' (because the field is
// not nullable, it just converts to a string like any other type).
mock.pushShareResult('null', '', getAbsoluteUrl('null'),
mock.pushShareResult('null', '', '',
blink.mojom.ShareError.OK);
return callWithKeyDown(() => navigator.share(
{title: null, text: undefined, url: null}));
{title: null, text: undefined}));
}, 'share of null/undefined dict values');

</script>

0 comments on commit f06b6ac

Please sign in to comment.