// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/webui/web_applications/test/js_library_test.h"
#include <string>
#include <utility>
#include "base/base_paths.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/memory/ref_counted_memory.h"
#include "base/path_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_controller_factory.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/scoped_web_ui_controller_factory_registration.h"
#include "services/network/public/mojom/content_security_policy.mojom.h"
#include "ui/webui/mojo_web_ui_controller.h"
#include "url/gurl.h"
namespace {
constexpr base::FilePath::CharType kRootDir[] =
FILE_PATH_LITERAL("ash/webui/system_apps/public/js/");
constexpr char kSystemAppTestHost[] = "system-app-test";
constexpr char kSystemAppTestURL[] = "chrome://system-app-test";
constexpr char kUntrustedSystemAppTestURL[] =
"chrome-untrusted://system-app-test/";
bool IsSystemAppTestURL(const GURL& url) {
return url.SchemeIs(content::kChromeUIScheme) &&
url.host() == kSystemAppTestHost;
}
void HandleRequest(const std::string& url_path,
content::WebUIDataSource::GotDataCallback callback) {
const auto& path_for_key = [url_path](base::BasePathKey key) {
base::FilePath path;
CHECK(base::PathService::Get(key, &path));
path = path.Append(kRootDir);
path = path.AppendASCII(url_path.substr(0, url_path.find('?')));
return path;
};
// First try the source dir, then try generated files.
base::FilePath path = path_for_key(base::BasePathKey::DIR_SRC_TEST_DATA_ROOT);
std::string contents;
{
base::ScopedAllowBlockingForTesting allow_blocking;
if (!base::PathExists(path)) {
path = path_for_key(base::BasePathKey::DIR_GEN_TEST_DATA_ROOT);
}
CHECK(base::ReadFileToString(path, &contents)) << path.value();
}
std::move(callback).Run(
base::MakeRefCounted<base::RefCountedString>(std::move(contents)));
}
void SetRequestFilterForDataSource(content::WebUIDataSource& data_source) {
data_source.SetRequestFilter(
base::BindRepeating([](const std::string& path) { return true; }),
base::BindRepeating(&HandleRequest));
}
void CreateAndAddTrustedSystemAppTestDataSource(
content::BrowserContext* browser_context) {
content::WebUIDataSource* trusted_source =
content::WebUIDataSource::CreateAndAdd(browser_context,
kSystemAppTestHost);
// We need a CSP override to be able to embed a chrome-untrusted:// iframe.
std::string csp =
std::string("frame-src ") + kUntrustedSystemAppTestURL + ";";
trusted_source->OverrideContentSecurityPolicy(
network::mojom::CSPDirectiveName::FrameSrc, csp);
trusted_source->OverrideContentSecurityPolicy(
network::mojom::CSPDirectiveName::ScriptSrc,
"script-src chrome://resources chrome://webui-test 'self';");
SetRequestFilterForDataSource(*trusted_source);
}
void CreateAndAddUntrustedSystemAppTestDataSource(
content::BrowserContext* browser_context) {
content::WebUIDataSource* untrusted_source =
content::WebUIDataSource::CreateAndAdd(browser_context,
kUntrustedSystemAppTestURL);
untrusted_source->AddFrameAncestor(GURL(kSystemAppTestURL));
SetRequestFilterForDataSource(*untrusted_source);
}
class JsLibraryTestWebUIController : public ui::MojoWebUIController {
public:
explicit JsLibraryTestWebUIController(content::WebUI* web_ui)
: ui::MojoWebUIController(web_ui) {
auto* browser_context = web_ui->GetWebContents()->GetBrowserContext();
CreateAndAddTrustedSystemAppTestDataSource(browser_context);
CreateAndAddUntrustedSystemAppTestDataSource(browser_context);
// Add ability to request chrome-untrusted: URLs
web_ui->AddRequestableScheme(content::kChromeUIUntrustedScheme);
}
};
class JsLibraryTestWebUIControllerFactory
: public content::WebUIControllerFactory {
public:
JsLibraryTestWebUIControllerFactory() = default;
~JsLibraryTestWebUIControllerFactory() override = default;
std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL(
content::WebUI* web_ui,
const GURL& url) override {
return std::make_unique<JsLibraryTestWebUIController>(web_ui);
}
content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
const GURL& url) override {
if (IsSystemAppTestURL(url)) {
return reinterpret_cast<content::WebUI::TypeID>(this);
}
return content::WebUI::kNoWebUI;
}
bool UseWebUIForURL(content::BrowserContext* browser_context,
const GURL& url) override {
return IsSystemAppTestURL(url);
}
private:
content::ScopedWebUIControllerFactoryRegistration scoped_registration_{this};
};
} // namespace
JsLibraryTest::JsLibraryTest()
: factory_(std::make_unique<JsLibraryTestWebUIControllerFactory>()) {}
JsLibraryTest::~JsLibraryTest() = default;