Commit d4838474 authored by jessing's avatar jessing Committed by Commit Bot

[system-web-apps] Add chrome-untrusted iframe to sample system web app

An example of how to embed a chrome-untrusted iframe into a system web
app.

To do so, we need to add abstract methods in WebUI despite WebUIImpl
being the only class to actually implement it. This is so the
WebUIController can add requestable schemes so the WebUI can request
the chrome-untrusted resource.

Bug: 1048951
Change-Id: Ia3152e21412845cf421df74bb00a16e0a8f264b8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2037186
Commit-Queue: Jessica Huang <jessing@google.com>
Reviewed-by: default avatarcalamity <calamity@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Auto-Submit: Jessica Huang <jessing@google.com>
Cr-Commit-Position: refs/heads/master@{#742999}
parent 235906bc
......@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//chrome/test/base/js2gtest.gni")
import("//third_party/closure_compiler/compile_js.gni")
assert(is_chromeos, "Sample System Web App is Chrome OS only")
assert(!is_official_build,
......@@ -24,8 +25,15 @@ static_library("sample_system_web_app_ui") {
]
}
group("closure_compile") {
deps = [ "resources/js:closure_compile" ]
js_type_check("closure_compile") {
deps = [ ":app" ]
}
js_library("app") {
sources = [
"app.js",
"receiver.js",
]
}
js2gtest("browser_tests_js") {
......
......@@ -2,5 +2,6 @@ include_rules = [
# Do not add chrome here (use a delegate instead).
"+chromeos/grit/chromeos_sample_system_web_app_resources.h",
"+content/public/browser",
"+content/public/common",
"+ui/webui",
]
<!-- Copyright 2020 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. -->
<!DOCTYPE html>
<meta charset="utf-8">
<title>Untrusted Sample System Web App</title>
<h1 id='untrusted-title'>Sample System Web App</h1>
<script src="receiver.js"></script>
\ No newline at end of file
......@@ -2,5 +2,5 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var header = document.getElementById('header');
var header = document.getElementById('title');
header.textContent = 'Sample System Web App';
......@@ -4,6 +4,9 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Sample System Web App</title>
<h1 id="header">Sample System Web App</h1>
<header id='title'></header>
<br>
<a href="/sandbox.html"><button>Untrusted</button></a>
<!-- Below mojo script required to run browser tests -->
<script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
<script src='app.js'></script>
\ No newline at end of file
# Copyright 2019 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.
import("//third_party/closure_compiler/compile_js.gni")
js_type_check("closure_compile") {
deps = [ ":app" ]
}
js_library("app") {
}
// Copyright 2020 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 header = document.getElementById('untrusted-title');
header.textContent = 'Untrusted Sample System Web App';
// For testing purposes: notify the parent window the iframe has been embedded
// successfully.
window.addEventListener('message', event => {
if (event.origin.startsWith('chrome://sample-system-web-app')) {
window.parent.postMessage(
{'success': true}, 'chrome://sample-system-web-app');
}
});
\ No newline at end of file
......@@ -12,13 +12,18 @@
</outputs>
<release seq="1">
<includes>
<!-- Privileged app host contents. -->
<if expr="is_official_build == false">
<!-- Privileged app host contents. -->
<include name="IDR_SAMPLE_SYSTEM_WEB_APP_INDEX_HTML" file="index.html" type="BINDATA" compress="gzip" />
<include name="IDR_SAMPLE_SYSTEM_WEB_APP_PWA_HTML" file="pwa.html" type="BINDATA" compress="gzip" />
<include name="IDR_SAMPLE_SYSTEM_WEB_APP_JS" file="js/app.js" type="BINDATA" compress="gzip" />
<include name="IDR_SAMPLE_SYSTEM_WEB_APP_SANDBOX_HTML" file="sandbox.html" type="BINDATA" compress="gzip" />
<include name="IDR_SAMPLE_SYSTEM_WEB_APP_JS" file="app.js" type="BINDATA" compress="gzip" />
<include name="IDR_SAMPLE_SYSTEM_WEB_APP_MANIFEST" file="manifest.json" type="BINDATA" compress="gzip" />
<include name="IDR_SAMPLE_SYSTEM_WEB_APP_ICON_192" file="app_icon_192.png" type="BINDATA" compress="gzip" />
<!-- Untrusted app contents. -->
<include name="IDR_SAMPLE_SYSTEM_WEB_APP_APP_HTML" file="app.html" type="BINDATA" compress="gzip" />
<include name="IDR_SAMPLE_SYSTEM_WEB_APP_RECEIVER_JS" file="receiver.js" type="BINDATA" compress="gzip" />
</if>
</includes>
</release>
......
<!-- Copyright 2020 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. -->
<!DOCTYPE html>
<meta charset="utf-8">
<title>Sample System Web App</title>
<iframe src="chrome-untrusted://sample-system-web-app/app.html"></iframe>
<!-- Below mojo script required to run browser tests -->
<script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
\ No newline at end of file
......@@ -11,32 +11,56 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/common/url_constants.h"
namespace chromeos {
content::WebUIDataSource* CreateUntrustedSampleSystemWebAppDataSource() {
content::WebUIDataSource* untrusted_source =
content::WebUIDataSource::Create(kChromeUIUntrustedSampleSystemWebAppURL);
untrusted_source->AddResourcePath("app.html",
IDR_SAMPLE_SYSTEM_WEB_APP_APP_HTML);
untrusted_source->AddResourcePath("receiver.js",
IDR_SAMPLE_SYSTEM_WEB_APP_RECEIVER_JS);
untrusted_source->AddFrameAncestor(GURL(kChromeUISampleSystemWebAppURL));
return untrusted_source;
}
SampleSystemWebAppUI::SampleSystemWebAppUI(content::WebUI* web_ui)
: ui::MojoWebUIController(web_ui) {
auto html_source = base::WrapUnique(
auto trusted_source = base::WrapUnique(
content::WebUIDataSource::Create(kChromeUISampleSystemWebAppHost));
html_source->AddResourcePath("", IDR_SAMPLE_SYSTEM_WEB_APP_INDEX_HTML);
html_source->AddResourcePath("pwa.html", IDR_SAMPLE_SYSTEM_WEB_APP_PWA_HTML);
html_source->AddResourcePath("app.js", IDR_SAMPLE_SYSTEM_WEB_APP_JS);
html_source->AddResourcePath("manifest.json",
IDR_SAMPLE_SYSTEM_WEB_APP_MANIFEST);
html_source->AddResourcePath("app_icon_192.png",
IDR_SAMPLE_SYSTEM_WEB_APP_ICON_192);
trusted_source->AddResourcePath("", IDR_SAMPLE_SYSTEM_WEB_APP_INDEX_HTML);
trusted_source->AddResourcePath("pwa.html",
IDR_SAMPLE_SYSTEM_WEB_APP_PWA_HTML);
trusted_source->AddResourcePath("sandbox.html",
IDR_SAMPLE_SYSTEM_WEB_APP_SANDBOX_HTML);
trusted_source->AddResourcePath("app.js", IDR_SAMPLE_SYSTEM_WEB_APP_JS);
trusted_source->AddResourcePath("manifest.json",
IDR_SAMPLE_SYSTEM_WEB_APP_MANIFEST);
trusted_source->AddResourcePath("app_icon_192.png",
IDR_SAMPLE_SYSTEM_WEB_APP_ICON_192);
#if !DCHECK_IS_ON()
// If a user goes to an invalid url and non-DCHECK mode (DHECK = debug mode)
// is set, serve a default page so the user sees your default page instead
// of an unexpected error. But if DCHECK is set, the user will be a
// developer and be able to identify an error occurred.
html_source->SetDefaultResource(IDR_SAMPLE_SYSTEM_WEB_APP_INDEX_HTML);
trusted_source->SetDefaultResource(IDR_SAMPLE_SYSTEM_WEB_APP_INDEX_HTML);
#endif // !DCHECK_IS_ON()
content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(),
html_source.release());
// We need a CSP override to use the chrome-untrusted:// scheme in the host.
std::string csp =
std::string("frame-src ") + kChromeUIUntrustedSampleSystemWebAppURL + ";";
trusted_source->OverrideContentSecurityPolicyChildSrc(csp);
auto* browser_context = web_ui->GetWebContents()->GetBrowserContext();
content::WebUIDataSource::Add(browser_context, trusted_source.release());
content::WebUIDataSource::Add(browser_context,
CreateUntrustedSampleSystemWebAppDataSource());
// Add ability to request chrome-untrusted: URLs
web_ui->AddRequestableScheme(content::kChromeUIUntrustedScheme);
}
SampleSystemWebAppUI::~SampleSystemWebAppUI() = default;
......
......@@ -7,6 +7,7 @@
*/
const HOST_ORIGIN = 'chrome://sample-system-web-app';
const UNTRUSTED_HOST_ORIGIN = 'chrome-untrusted://sample-system-web-app';
var SampleSystemWebAppUIBrowserTest = class extends testing.Test {
/** @override */
......@@ -23,8 +24,40 @@ var SampleSystemWebAppUIBrowserTest = class extends testing.Test {
// Tests that chrome://sample-system-web-app runs js file and that it goes
// somewhere instead of 404ing or crashing.
TEST_F('SampleSystemWebAppUIBrowserTest', 'HasChromeSchemeURL', () => {
const header = document.querySelector('h1');
const header = document.querySelector('header');
assertEquals(header.innerText, 'Sample System Web App');
assertEquals(document.location.origin, HOST_ORIGIN);
});
var SampleSystemWebAppUIUntrustedBrowserTest = class extends testing.Test {
/** @override */
get browsePreload() {
return HOST_ORIGIN + '/sandbox.html';
}
/** @override */
get runAccessibilityChecks() {
return false;
}
/** @override */
get isAsync() {
return true;
}
};
// Tests that chrome://sample-system-web-app/sandbox.html embeds a
// chrome-untrusted:// iframe
TEST_F(
'SampleSystemWebAppUIUntrustedBrowserTest', 'HasChromeUntrustedIframe',
() => {
const iframe = document.querySelector('iframe');
window.onmessage =
(event) => {
assertEquals(event.origin, UNTRUSTED_HOST_ORIGIN);
assertEquals(event.data.success, true);
testDone();
};
iframe.contentWindow.postMessage('hello', UNTRUSTED_HOST_ORIGIN);
});
......@@ -8,5 +8,7 @@ namespace chromeos {
const char kChromeUISampleSystemWebAppHost[] = "sample-system-web-app";
const char kChromeUISampleSystemWebAppURL[] = "chrome://sample-system-web-app";
const char kChromeUIUntrustedSampleSystemWebAppURL[] =
"chrome-untrusted://sample-system-web-app/";
} // namespace chromeos
......@@ -9,6 +9,7 @@ namespace chromeos {
extern const char kChromeUISampleSystemWebAppHost[];
extern const char kChromeUISampleSystemWebAppURL[];
extern const char kChromeUIUntrustedSampleSystemWebAppURL[];
} // namespace chromeos
......
......@@ -51,8 +51,8 @@ class CONTENT_EXPORT WebUIImpl : public WebUI,
void OverrideTitle(const base::string16& title) override;
int GetBindings() override;
void SetBindings(int bindings) override;
const std::vector<std::string>& GetRequestableSchemes();
void AddRequestableScheme(const char* scheme);
const std::vector<std::string>& GetRequestableSchemes() override;
void AddRequestableScheme(const char* scheme) override;
void AddMessageHandler(std::unique_ptr<WebUIMessageHandler> handler) override;
void RegisterMessageCallback(base::StringPiece message,
const MessageCallback& callback) override;
......
......@@ -69,6 +69,10 @@ class CONTENT_EXPORT WebUI {
virtual int GetBindings() = 0;
virtual void SetBindings(int bindings) = 0;
// Allows a scheme to be requested which is provided by the WebUIController.
virtual const std::vector<std::string>& GetRequestableSchemes() = 0;
virtual void AddRequestableScheme(const char* scheme) = 0;
virtual void AddMessageHandler(
std::unique_ptr<WebUIMessageHandler> handler) = 0;
......
......@@ -67,6 +67,16 @@ void TestWebUI::SetBindings(int bindings) {
bindings_ = bindings;
}
const std::vector<std::string>& TestWebUI::GetRequestableSchemes() {
NOTIMPLEMENTED();
return std::move(std::vector<std::string>());
}
void TestWebUI::AddRequestableScheme(const char* scheme) {
NOTIMPLEMENTED();
return;
}
void TestWebUI::AddMessageHandler(
std::unique_ptr<WebUIMessageHandler> handler) {
handler->set_web_ui(this);
......
......@@ -37,6 +37,8 @@ class TestWebUI : public WebUI {
void OverrideTitle(const base::string16& title) override {}
int GetBindings() override;
void SetBindings(int bindings) override;
const std::vector<std::string>& GetRequestableSchemes() override;
void AddRequestableScheme(const char* scheme) override;
void AddMessageHandler(std::unique_ptr<WebUIMessageHandler> handler) override;
void RegisterMessageCallback(base::StringPiece message,
const MessageCallback& callback) override;
......
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