Commit 1d90c425 authored by creis's avatar creis Committed by Commit bot

Don't kill Chrome Apps that make XHRs from guests.

It's possible for the app to make CORS requests from its guests without
any webview-accessible-resources, via injected content scripts.

BUG=613335
TEST=See bug comment 37 for a repro app.

Review-Url: https://codereview.chromium.org/2803963002
Cr-Commit-Position: refs/heads/master@{#462704}
parent 99cc887a
...@@ -2241,6 +2241,13 @@ IN_PROC_BROWSER_TEST_P(WebViewTest, MAYBE_TearDownTest) { ...@@ -2241,6 +2241,13 @@ IN_PROC_BROWSER_TEST_P(WebViewTest, MAYBE_TearDownTest) {
LoadAndLaunchPlatformApp("web_view/simple", "WebViewTest.LAUNCHED"); LoadAndLaunchPlatformApp("web_view/simple", "WebViewTest.LAUNCHED");
} }
// Tests that an app can inject a content script into a webview, and that it can
// send cross-origin requests with CORS headers.
IN_PROC_BROWSER_TEST_P(WebViewTest, ContentScriptFetch) {
TestHelper("testContentScriptFetch", "web_view/content_script_fetch",
NEEDS_TEST_SERVER);
}
// In following GeolocationAPIEmbedderHasNoAccess* tests, embedder (i.e. the // In following GeolocationAPIEmbedderHasNoAccess* tests, embedder (i.e. the
// platform app) does not have geolocation permission for this test. // platform app) does not have geolocation permission for this test.
// No matter what the API does, geolocation permission would be denied. // No matter what the API does, geolocation permission would be denied.
......
...@@ -202,15 +202,17 @@ content::HeaderInterceptorResult CheckOriginHeader( ...@@ -202,15 +202,17 @@ content::HeaderInterceptorResult CheckOriginHeader(
return content::HeaderInterceptorResult::FAIL; return content::HeaderInterceptorResult::FAIL;
// Check for platform app origins. These can only be committed by the app // Check for platform app origins. These can only be committed by the app
// itself, or by one if its guests if there are accessible_resources. // itself, or by one if its guests if it has the webview permission.
// Processes that incorrectly claim to be an app should be killed. // Processes that incorrectly claim to be an app should be killed.
const ProcessMap& process_map = extension_info_map->process_map(); const ProcessMap& process_map = extension_info_map->process_map();
if (extension->is_platform_app() && if (extension->is_platform_app() &&
!process_map.Contains(extension->id(), child_id)) { !process_map.Contains(extension->id(), child_id)) {
// This is a platform app origin not in the app's own process. If there // This is a platform app origin not in the app's own process. If it cannot
// are no accessible resources, this is illegal. // create webviews, this is illegal.
if (!extension->GetManifestData(manifest_keys::kWebviewAccessibleResources)) if (!extension->permissions_data()->HasAPIPermission(
extensions::APIPermission::kWebView)) {
return content::HeaderInterceptorResult::KILL; return content::HeaderInterceptorResult::KILL;
}
// If there are accessible resources, the origin is only legal if the // If there are accessible resources, the origin is only legal if the
// given process is a guest of the app. // given process is a guest of the app.
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var embedder = null;
function reportResult(result) {
var msg = ['fetch-' + result];
embedder.postMessage(JSON.stringify(msg), '*');
}
window.addEventListener('message', function(e) {
embedder = e.source;
var data = JSON.parse(e.data);
if (data[0] == 'start-fetch') {
fetch('http://127.0.0.1:' + location.port + '/extensions/xhr.txt')
.then((result) => result.text())
.then((text) => {
reportResult(
(text == 'File to request via XHR.\n') ? 'success' : 'failure');
})
.catch(err => {
reportResult('failure');
});
} else {
reportResult('unexpected-message');
}
});
window.console.log('Script has been successfully injected.');
<!--
* Copyright 2017 The Chromium Authors. All rights reserved. Use of this
* source code is governed by a BSD-style license that can be found in the
* LICENSE file.
-->
<html>
<body>
<div id="webview-tag-container"></div>
<script src="embedder.js"></script>
</body>
</html>
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var embedder = {};
embedder.test = {};
embedder.baseGuestURL = '';
embedder.guestURL = '';
window.runTest = function(testName) {
if (!embedder.test.testList[testName]) {
console.log('Incorrect testName: ' + testName);
embedder.test.fail();
return;
}
// Run the test.
embedder.test.testList[testName]();
};
// window.* exported functions end.
embedder.test.succeed = function() {
chrome.test.sendMessage('TEST_PASSED');
};
embedder.test.fail = function() {
chrome.test.sendMessage('TEST_FAILED');
};
embedder.setUp = function(config) {
embedder.baseGuestURL = 'http://localhost:' + config.testServer.port;
embedder.guestURL = embedder.baseGuestURL +
'/extensions/platform_apps/web_view/content_script_fetch/guest.html';
};
/** @private */
embedder.setUpGuest_ = function() {
document.querySelector('#webview-tag-container').innerHTML =
'<webview style="width: 100px; height: 100px;"></webview>';
var webview = document.querySelector('webview');
if (!webview) {
console.log('No <webview> element created');
embedder.test.fail();
}
return webview;
};
// Tests begin.
function testContentScriptFetch() {
var webview = embedder.setUpGuest_();
webview.addContentScripts([{
name: 'rule',
matches: ['http://localhost/*'],
js: { files: ['content_script.js'] },
run_at: 'document_start'}]);
webview.addEventListener('loadstop', function() {
var msg = ['start-fetch'];
webview.contentWindow.postMessage(JSON.stringify(msg), '*');
});
window.addEventListener('message', function(e) {
var data = JSON.parse(e.data);
if (data == 'fetch-success') {
embedder.test.succeed();
return;
}
console.log('Unexpected message: \'' + data[0] + '\'');
embedder.test.fail();
});
webview.src = embedder.guestURL;
}
embedder.test.testList = {
testContentScriptFetch: testContentScriptFetch
};
onload = function() {
chrome.test.getConfig(function(config) {
embedder.setUp(config);
chrome.test.sendMessage('Launched');
});
};
<!doctype html>
<!--
* Copyright 2017 The Chromium Authors. All rights reserved. Use of this
* source code is governed by a BSD-style license that can be found in the
* LICENSE file.
-->
<html>
<head>
<title>A simple guest that does nothing.</title>
</head>
<body>
</body>
</html>
{
"name": "Platform App Test: <webview> content script fetch",
"description": "Loads a guest which does a fetch from a content script",
"version": "1",
"permissions": [
"webview"
],
"app": {
"background": {
"scripts": ["test.js"]
}
}
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('embedder.html', {}, function () {});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment