demo_mode_app_untrusted_ui.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/webui/demo_mode_app_ui/demo_mode_app_untrusted_ui.h"
  5. #include <memory>
  6. #include "ash/constants/ash_features.h"
  7. #include "ash/webui/demo_mode_app_ui/demo_mode_untrusted_page_handler.h"
  8. #include "ash/webui/demo_mode_app_ui/url_constants.h"
  9. #include "ash/webui/grit/ash_demo_mode_app_resources.h"
  10. #include "ash/webui/grit/ash_demo_mode_app_resources_map.h"
  11. #include "base/containers/fixed_flat_set.h"
  12. #include "base/files/file_util.h"
  13. #include "base/memory/ref_counted_memory.h"
  14. #include "base/task/thread_pool.h"
  15. #include "content/public/browser/web_contents.h"
  16. #include "content/public/browser/web_ui.h"
  17. #include "content/public/browser/web_ui_data_source.h"
  18. #include "content/public/common/url_constants.h"
  19. #include "services/network/public/mojom/content_security_policy.mojom.h"
  20. #include "ui/views/widget/widget.h"
  21. namespace ash {
  22. DemoModeAppUntrustedUIConfig::DemoModeAppUntrustedUIConfig(
  23. base::RepeatingCallback<base::FilePath()> component_path_producer)
  24. : content::WebUIConfig(content::kChromeUIUntrustedScheme,
  25. kChromeUntrustedUIDemoModeAppHost),
  26. component_path_producer_(std::move(component_path_producer)) {}
  27. DemoModeAppUntrustedUIConfig::~DemoModeAppUntrustedUIConfig() = default;
  28. std::unique_ptr<content::WebUIController>
  29. DemoModeAppUntrustedUIConfig::CreateWebUIController(content::WebUI* web_ui) {
  30. return std::make_unique<DemoModeAppUntrustedUI>(
  31. web_ui, component_path_producer_.Run());
  32. }
  33. bool DemoModeAppUntrustedUIConfig::IsWebUIEnabled(
  34. content::BrowserContext* browser_context) {
  35. return ash::features::IsDemoModeSWAEnabled();
  36. }
  37. scoped_refptr<base::RefCountedMemory> ReadFile(
  38. const base::FilePath& absolute_resource_path) {
  39. std::string data;
  40. base::ReadFileToString(absolute_resource_path, &data);
  41. return base::RefCountedString::TakeString(&data);
  42. }
  43. bool ShouldSourceFromComponent(
  44. const base::flat_set<std::string>& webui_resource_paths,
  45. const std::string& path) {
  46. // TODO(b/232945108): Consider changing this logic to check if the absolute
  47. // path exists in the component. This would still allow us show the default
  48. // WebUI resource if the requested path isn't found.
  49. return !webui_resource_paths.contains(path);
  50. }
  51. void DemoModeAppUntrustedUI::SourceDataFromComponent(
  52. const base::FilePath& component_path,
  53. const std::string& resource_path,
  54. content::WebUIDataSource::GotDataCallback callback) {
  55. // Convert to GURL to strip out query params and URL fragments
  56. //
  57. // TODO (b/234170189): Verify that query params won't be used in the prod Demo
  58. // App, or add support for them here instead of ignoring them.
  59. GURL full_url = GURL(kChromeUntrustedUIDemoModeAppURL + resource_path);
  60. // Trim leading slash from path
  61. std::string path = full_url.path().substr(1);
  62. base::FilePath absolute_resource_path = component_path.AppendASCII(path);
  63. base::ThreadPool::PostTaskAndReplyWithResult(
  64. FROM_HERE, {base::MayBlock()},
  65. base::BindOnce(&ReadFile, absolute_resource_path), std::move(callback));
  66. }
  67. DemoModeAppUntrustedUI::DemoModeAppUntrustedUI(content::WebUI* web_ui,
  68. base::FilePath component_path)
  69. : ui::UntrustedWebUIController(web_ui) {
  70. // We tack the resource path onto this component path, so CHECK that it's
  71. // absolute so ".." parent references can't be used as an exploit
  72. DCHECK(component_path.IsAbsolute());
  73. content::WebUIDataSource* data_source =
  74. content::WebUIDataSource::CreateAndAdd(
  75. web_ui->GetWebContents()->GetBrowserContext(),
  76. kChromeUntrustedUIDemoModeAppURL);
  77. base::flat_set<std::string> webui_resource_paths;
  78. // Add required resources.
  79. for (size_t i = 0; i < kAshDemoModeAppResourcesSize; ++i) {
  80. data_source->AddResourcePath(kAshDemoModeAppResources[i].path,
  81. kAshDemoModeAppResources[i].id);
  82. webui_resource_paths.insert(kAshDemoModeAppResources[i].path);
  83. }
  84. data_source->SetDefaultResource(IDR_ASH_DEMO_MODE_APP_DEMO_MODE_APP_HTML);
  85. // Add empty string so default resource is still shown for
  86. // chrome-untrusted://demo-mode-app
  87. webui_resource_paths.insert("");
  88. data_source->SetRequestFilter(
  89. base::BindRepeating(&ShouldSourceFromComponent, webui_resource_paths),
  90. base::BindRepeating(&SourceDataFromComponent, component_path));
  91. }
  92. DemoModeAppUntrustedUI::~DemoModeAppUntrustedUI() = default;
  93. void DemoModeAppUntrustedUI::BindInterface(
  94. mojo::PendingReceiver<mojom::demo_mode::UntrustedPageHandlerFactory>
  95. factory) {
  96. if (demo_mode_page_factory_.is_bound()) {
  97. demo_mode_page_factory_.reset();
  98. }
  99. demo_mode_page_factory_.Bind(std::move(factory));
  100. }
  101. void DemoModeAppUntrustedUI::CreatePageHandler(
  102. mojo::PendingReceiver<mojom::demo_mode::UntrustedPageHandler> handler) {
  103. views::Widget* widget = views::Widget::GetWidgetForNativeWindow(
  104. web_ui()->GetWebContents()->GetTopLevelNativeWindow());
  105. demo_mode_page_handler_ = std::make_unique<DemoModeUntrustedPageHandler>(
  106. std::move(handler), widget);
  107. }
  108. WEB_UI_CONTROLLER_TYPE_IMPL(DemoModeAppUntrustedUI)
  109. } // namespace ash