diff --git a/chromium_src/ios/web/public/web_state.h b/chromium_src/ios/web/public/web_state.h new file mode 100644 index 000000000000..b4181fde2be3 --- /dev/null +++ b/chromium_src/ios/web/public/web_state.h @@ -0,0 +1,35 @@ +// Copyright (c) 2025 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef BRAVE_CHROMIUM_SRC_IOS_WEB_PUBLIC_WEB_STATE_H_ +#define BRAVE_CHROMIUM_SRC_IOS_WEB_PUBLIC_WEB_STATE_H_ + +#define callbacks_ \ + callbacks_; \ + \ + public: \ + template \ + void AddUntrustedInterface( \ + const GURL& url, \ + base::RepeatingCallback)> \ + callback) { \ + CHECK(!url.is_empty()); \ + untrusted_callbacks_[url].emplace( \ + std::string(Interface::Name_), \ + base::BindRepeating(&WrapCallback, std::move(callback))); \ + } \ + bool HasUntrustedInterface(const GURL& url, \ + const std::string& interface_name); \ + void BindUntrustedInterface(const GURL& url, \ + mojo::GenericPendingReceiver receiver); \ + \ + private: \ + std::map> untrusted_callbacks_ + +#include "src/ios/web/public/web_state.h" // IWYU pragma: export + +#undef callbacks_ + +#endif // BRAVE_CHROMIUM_SRC_IOS_WEB_PUBLIC_WEB_STATE_H_ diff --git a/chromium_src/ios/web/web_state/ui/crw_wk_ui_handler.mm b/chromium_src/ios/web/web_state/ui/crw_wk_ui_handler.mm new file mode 100644 index 000000000000..29d8fc49a651 --- /dev/null +++ b/chromium_src/ios/web/web_state/ui/crw_wk_ui_handler.mm @@ -0,0 +1,19 @@ +// Copyright (c) 2025 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "ios/web/public/web_client.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + +#define IsAppSpecificURL(URL) \ + IsAppSpecificURL(URL) && \ + self.mojoFacade->IsWebUIMessageAllowedForFrame(frame, origin, &prompt) + +#include "src/ios/web/web_state/ui/crw_wk_ui_handler.mm" + +#undef IsAppSpecificURL + +#pragma clang diagnostic pop diff --git a/chromium_src/ios/web/web_state/web_state.mm b/chromium_src/ios/web/web_state/web_state.mm new file mode 100644 index 000000000000..78383be82ae4 --- /dev/null +++ b/chromium_src/ios/web/web_state/web_state.mm @@ -0,0 +1,37 @@ +// Copyright (c) 2025 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "src/ios/web/web_state/web_state.mm" + +namespace web { +bool WebState::InterfaceBinder::HasUntrustedInterface( + const GURL& url, + const std::string& interface_name) { + DCHECK(!url.is_empty()); + DCHECK(!interface_name.empty()); + if (auto it = untrusted_callbacks_.find(url); + it != untrusted_callbacks_.end()) { + return it->second.find(interface_name) != it->second.end(); + } + return false; +} + +void WebState::InterfaceBinder::BindUntrustedInterface( + const GURL& url, + mojo::GenericPendingReceiver receiver) { + DCHECK(!url.is_empty()); + DCHECK(receiver.is_valid()); + if (auto it = untrusted_callbacks_.find(url); + it != untrusted_callbacks_.end()) { + if (auto jt = it->second.find(*receiver.interface_name()); + jt != it->second.end()) { + jt->second.Run(&receiver); + + GetWebClient()->BindInterfaceReceiverFromMainFrame(web_state_, + std::move(receiver)); + } + } +} +} // namespace web diff --git a/chromium_src/ios/web/webui/DEPS b/chromium_src/ios/web/webui/DEPS index 180617c759a1..5ca15e7906ad 100644 --- a/chromium_src/ios/web/webui/DEPS +++ b/chromium_src/ios/web/webui/DEPS @@ -1,5 +1,3 @@ include_rules = [ "+ios/components/webui/web_ui_url_constants.h", - "+ios/chrome/browser/shared/model/url/chrome_url_constants.h", - "+brave/ios/browser/ui/webui/brave_url_data_source_ios.h", ] diff --git a/chromium_src/ios/web/webui/mojo_facade.h b/chromium_src/ios/web/webui/mojo_facade.h new file mode 100644 index 000000000000..7c1047fa7a4a --- /dev/null +++ b/chromium_src/ios/web/webui/mojo_facade.h @@ -0,0 +1,23 @@ +// Copyright (c) 2025 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef BRAVE_CHROMIUM_SRC_IOS_WEB_WEBUI_MOJO_FACADE_H_ +#define BRAVE_CHROMIUM_SRC_IOS_WEB_WEBUI_MOJO_FACADE_H_ + +#include + +#include "url/gurl.h" + +#define HandleMojoMessage \ + Dummy(); \ + bool IsWebUIMessageAllowedForFrame(WKFrameInfo* frame, const GURL& origin, \ + NSString** prompt); \ + std::string HandleMojoMessage + +#include "src/ios/web/webui/mojo_facade.h" // IWYU pragma: export + +#undef HandleMojoMessage + +#endif // BRAVE_CHROMIUM_SRC_IOS_WEB_WEBUI_MOJO_FACADE_H_ diff --git a/chromium_src/ios/web/webui/mojo_facade.mm b/chromium_src/ios/web/webui/mojo_facade.mm new file mode 100644 index 000000000000..3b6ccc22fe6e --- /dev/null +++ b/chromium_src/ios/web/webui/mojo_facade.mm @@ -0,0 +1,51 @@ +// Copyright (c) 2025 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "src/ios/web/webui/mojo_facade.mm" + +namespace web { +bool MojoFacade::IsWebUIMessageAllowedForFrame(WKFrameInfo* frame, + const GURL& origin, + NSString** prompt) { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + CHECK(prompt && *prompt); + + auto name_and_args = + GetMessageNameAndArguments(base::SysNSStringToUTF8(*prompt)); + + // If the scheme is untrusted + if (name_and_args.name == "Mojo.bindInterface" && + origin.scheme() == "chrome-untrusted") { + const base::Value::Dict& args = name_and_args.args; + const std::string* interface_name = args.FindString("interfaceName"); + CHECK(interface_name); + + // Check if the requested interface is registered + bool can_bind_interface = + web_state_->GetInterfaceBinderForMainFrame()->HasUntrustedInterface( + origin, *interface_name); + + if (can_bind_interface) { + std::optional pipe_id = args.FindInt("requestHandle"); + CHECK(pipe_id.has_value()); + + mojo::ScopedMessagePipeHandle pipe = TakePipeFromId(*pipe_id); + CHECK(pipe.is_valid()); + web_state_->GetInterfaceBinderForMainFrame()->BindUntrustedInterface( + origin, + mojo::GenericPendingReceiver(*interface_name, std::move(pipe))); + + // Set the prompt to invalid, so that HandleMojoMessage will do nothing. + *prompt = @"{\"name\":\"Mojo.invalidInterface\",\"args\":{}}"; + } + } + + return true; +} + +std::string MojoFacade::Dummy() { + return ""; +} +} // namespace web diff --git a/chromium_src/ios/web/webui/web_ui_ios_data_source_impl.h b/chromium_src/ios/web/webui/web_ui_ios_data_source_impl.h deleted file mode 100644 index 4a6881e504aa..000000000000 --- a/chromium_src/ios/web/webui/web_ui_ios_data_source_impl.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2024 The Brave Authors. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at https://mozilla.org/MPL/2.0/. - -#ifndef BRAVE_CHROMIUM_SRC_IOS_WEB_WEBUI_WEB_UI_IOS_DATA_SOURCE_IMPL_H_ -#define BRAVE_CHROMIUM_SRC_IOS_WEB_WEBUI_WEB_UI_IOS_DATA_SOURCE_IMPL_H_ - -#include -#include -#include - -#include "base/containers/flat_map.h" -#include "ios/web/public/webui/web_ui_ios_data_source.h" -#include "services/network/public/mojom/content_security_policy.mojom.h" - -class BraveWebUIIOSDataSource; - -#define should_replace_i18n_in_js_ \ - should_replace_i18n_in_js_; \ - friend BraveWebUIIOSDataSource -#include "src/ios/web/webui/web_ui_ios_data_source_impl.h" // IWYU pragma: export -#undef should_replace_i18n_in_js_ - -class BraveWebUIIOSDataSource : public web::WebUIIOSDataSourceImpl { - public: - static web::WebUIIOSDataSource* Create(const std::string& source_name); - - // Brave CSP's & Security implementation: - virtual void OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName directive, - const std::string& value); - - virtual void AddFrameAncestor(const GURL& frame_ancestor); - virtual void DisableTrustedTypesCSP(); - - protected: - ~BraveWebUIIOSDataSource() override; - - private: - class InternalDataSource; - friend class InternalDataSource; - friend class WebUIIOSDataSourceImpl; - explicit BraveWebUIIOSDataSource(const std::string& source_name); - - // Brave CSP's & Security variables: - base::flat_map csp_overrides_; - std::set frame_ancestors_; -}; - -#endif // BRAVE_CHROMIUM_SRC_IOS_WEB_WEBUI_WEB_UI_IOS_DATA_SOURCE_IMPL_H_ diff --git a/chromium_src/ios/web/webui/web_ui_ios_data_source_impl.mm b/chromium_src/ios/web/webui/web_ui_ios_data_source_impl.mm deleted file mode 100644 index a7113ac8e484..000000000000 --- a/chromium_src/ios/web/webui/web_ui_ios_data_source_impl.mm +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2024 The Brave Authors. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at https://mozilla.org/MPL/2.0/. - -#include "ios/web/webui/web_ui_ios_data_source_impl.h" - -#include "base/memory/raw_ptr.h" -#include "brave/ios/browser/ui/webui/brave_url_data_source_ios.h" -#include "ios/chrome/browser/shared/model/url/chrome_url_constants.h" -#include "ios/components/webui/web_ui_url_constants.h" - -// static -web::WebUIIOSDataSource* BraveWebUIIOSDataSource::Create( - const std::string& source_name) { - return new BraveWebUIIOSDataSource(source_name); -} - -class BraveWebUIIOSDataSource::InternalDataSource - : public BraveURLDataSourceIOS { - public: - InternalDataSource(web::WebUIIOSDataSourceImpl* parent) : parent_(parent) {} - ~InternalDataSource() override {} - - std::string GetSource() const override { return parent_->GetSource(); } - - void StartDataRequest( - const std::string& path, - web::URLDataSourceIOS::GotDataCallback callback) override { - return parent_->StartDataRequest(path, std::move(callback)); - } - - std::string GetMimeType(const std::string& path) const override { - return parent_->GetMimeType(path); - } - - bool ShouldReplaceExistingSource() const override { - return parent_->replace_existing_source_; - } - - bool ShouldReplaceI18nInJS() const override { - return parent_->ShouldReplaceI18nInJS(); - } - - bool AllowCaching() const override { return false; } - - bool ShouldDenyXFrameOptions() const override { - return parent_->deny_xframe_options_; - } - - std::string GetContentSecurityPolicy( - network::mojom::CSPDirectiveName directive) const override { - auto* parent = static_cast(parent_); - - // Check CSP overrides - if (parent->csp_overrides_.contains(directive)) { - return parent->csp_overrides_.at(directive); - } - - // Check Frame-Ancestors overrides - if (directive == network::mojom::CSPDirectiveName::FrameAncestors) { - std::string frame_ancestors; - if (parent->frame_ancestors_.empty()) { - frame_ancestors += " 'none'"; - } - - for (const GURL& frame_ancestor : parent->frame_ancestors_) { - frame_ancestors += " " + frame_ancestor.spec(); - } - return "frame-ancestors" + frame_ancestors + ";"; - } - - return BraveURLDataSourceIOS::GetContentSecurityPolicy(directive); - } - - private: - raw_ptr parent_; -}; - -// WebUIIOSDataSource implementation: - -BraveWebUIIOSDataSource::BraveWebUIIOSDataSource(const std::string& source_name) - : web::WebUIIOSDataSourceImpl(source_name) { - CHECK(!source_name.ends_with("://")); -} - -BraveWebUIIOSDataSource::~BraveWebUIIOSDataSource() = default; - -// Brave CSP's & Security implementation: - -void BraveWebUIIOSDataSource::OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName directive, - const std::string& value) { - csp_overrides_.insert_or_assign(directive, value); -} - -void BraveWebUIIOSDataSource::AddFrameAncestor(const GURL& frame_ancestor) { - // Do not allow a wildcard to be a frame ancestor or it will allow any website - // to embed the WebUI. - CHECK(frame_ancestor.SchemeIs(kChromeUIScheme)); - frame_ancestors_.insert(frame_ancestor); -} - -void BraveWebUIIOSDataSource::DisableTrustedTypesCSP() { - // TODO(crbug.com/40137141): Trusted Type remaining WebUI - // This removes require-trusted-types-for and trusted-types directives - // from the CSP header. - OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::RequireTrustedTypesFor, std::string()); - OverrideContentSecurityPolicy(network::mojom::CSPDirectiveName::TrustedTypes, - std::string()); -} - -#define URLDataSourceIOSImpl(SOURCE_NAME, DATA_SOURCE) \ - URLDataSourceIOSImpl(SOURCE_NAME, \ - new BraveWebUIIOSDataSource::InternalDataSource(this)) -#include "src/ios/web/webui/web_ui_ios_data_source_impl.mm" -#undef URLDataSourceIOSImpl diff --git a/ios/browser/brave_web_client.h b/ios/browser/brave_web_client.h index faf2f22c5f1d..92f630d09ba8 100644 --- a/ios/browser/brave_web_client.h +++ b/ios/browser/brave_web_client.h @@ -6,10 +6,12 @@ #ifndef BRAVE_IOS_BROWSER_BRAVE_WEB_CLIENT_H_ #define BRAVE_IOS_BROWSER_BRAVE_WEB_CLIENT_H_ +#include #include #include #include +#include "base/functional/callback_forward.h" #include "ios/chrome/browser/web/model/chrome_web_client.h" class BraveWebClient : public ChromeWebClient { diff --git a/ios/browser/brave_web_client.mm b/ios/browser/brave_web_client.mm index 6f85ebc6b2ff..e52e01dee8c4 100644 --- a/ios/browser/brave_web_client.mm +++ b/ios/browser/brave_web_client.mm @@ -6,12 +6,16 @@ #import "brave/ios/browser/brave_web_client.h" #include "base/functional/bind.h" +#include "base/json/json_reader.h" +#include "base/strings/sys_string_conversions.h" #include "brave/components/constants/url_constants.h" #include "brave/ios/browser/brave_web_main_parts.h" #include "ios/chrome/browser/shared/model/url/chrome_url_constants.h" #include "ios/components/webui/web_ui_url_constants.h" #import "ios/public/provider/chrome/browser/url_rewriters/url_rewriters_api.h" #import "ios/web/public/navigation/browser_url_rewriter.h" +#include "ios/web/public/thread/web_thread.h" +#include "net/base/apple/url_conversions.h" #include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc) diff --git a/ios/browser/ui/webui/BUILD.gn b/ios/browser/ui/webui/BUILD.gn index 24317dec88da..f4a460623b72 100644 --- a/ios/browser/ui/webui/BUILD.gn +++ b/ios/browser/ui/webui/BUILD.gn @@ -9,12 +9,8 @@ import("//mojo/public/tools/bindings/mojom.gni") source_set("webui") { sources = [ - "brave_url_data_source_ios.h", - "brave_url_data_source_ios.mm", "brave_web_ui_controller_factory.h", "brave_web_ui_controller_factory.mm", - "brave_webui_data_source.h", - "brave_webui_data_source.mm", "brave_webui_source.h", "brave_webui_source.mm", ] @@ -23,6 +19,7 @@ source_set("webui") { "//brave/components/constants", "//brave/components/webui", "//brave/ios/browser/ui/webui/ads", + "//brave/ios/browser/ui/webui/public", "//brave/ios/browser/ui/webui/skus", "//components/prefs", "//components/profile_metrics", diff --git a/ios/browser/ui/webui/brave_webui_data_source.h b/ios/browser/ui/webui/brave_webui_data_source.h deleted file mode 100644 index eec623483cb7..000000000000 --- a/ios/browser/ui/webui/brave_webui_data_source.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2024 The Brave Authors. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at https://mozilla.org/MPL/2.0/. - -#ifndef BRAVE_IOS_BROWSER_UI_WEBUI_BRAVE_WEBUI_DATA_SOURCE_H_ -#define BRAVE_IOS_BROWSER_UI_WEBUI_BRAVE_WEBUI_DATA_SOURCE_H_ - -#include -#include -#include -#include - -#include "base/functional/callback.h" -#include "base/values.h" -#include "ios/web/public/webui/url_data_source_ios.h" -#include "ios/web/webui/url_data_manager_ios.h" -#include "ui/base/template_expressions.h" - -namespace network::mojom { -enum class CSPDirectiveName : std::int32_t; -} // namespace network::mojom - -namespace webui { -struct LocalizedString; -struct ResourcePath; -} // namespace webui - -class BraveWebUIDataSource : public web::URLDataSourceIOS { - public: - BraveWebUIDataSource(); - - ~BraveWebUIDataSource() override; - - BraveWebUIDataSource(const BraveWebUIDataSource&) = delete; - BraveWebUIDataSource& operator=(const BraveWebUIDataSource&) = delete; - - void AddString(const std::string& name, const std::u16string& value); - void AddString(const std::string& name, const std::string& value); - void AddLocalizedString(const std::string& name, int ids); - void AddLocalizedStrings(const base::Value::Dict& localized_strings); - void AddLocalizedStrings(base::span strings); - void AddBoolean(const std::string& name, bool value); - void UseStringsJs(); - void EnableReplaceI18nInJS(); - void AddResourcePath(const std::string& path, int resource_id); - void AddResourcePaths(base::span paths); - void SetDefaultResource(int resource_id); - void DisableDenyXFrameOptions(); - const ui::TemplateReplacements* GetReplacements() const; - - void OverrideContentSecurityPolicy(network::mojom::CSPDirectiveName directive, - const std::string& value); - void AddFrameAncestor(const GURL& frame_ancestor); - void DisableTrustedTypesCSP(); - - private: - void EnsureLoadTimeDataDefaultsAdded(); - void SendLocalizedStringsAsJSON(GotDataCallback callback, - bool from_js_module); - int PathToIdrOrDefault(const std::string& path) const; - - // web::URLDataSourceIOS overrides: - std::string GetSource() const override; - void StartDataRequest(const std::string& path, - GotDataCallback callback) override; - std::string GetMimeType(const std::string& path) const override; - bool ShouldReplaceExistingSource() const override; - bool ShouldReplaceI18nInJS() const override; - bool AllowCaching() const override; - bool ShouldDenyXFrameOptions() const override; - - bool ShouldServiceRequest(const GURL& url) const override; - std::string GetContentSecurityPolicy( - network::mojom::CSPDirectiveName directive) const override; - std::string GetContentSecurityPolicyObjectSrc() const override; - std::string GetContentSecurityPolicyFrameSrc() const override; - - int default_resource_; - bool use_strings_js_; - std::map path_to_idr_map_; - base::Value::Dict localized_strings_; - ui::TemplateReplacements replacements_; - bool deny_xframe_options_; - bool load_time_data_defaults_added_; - bool replace_existing_source_; - bool should_replace_i18n_in_js_; - - base::flat_map csp_overrides_; - std::set frame_ancestors_; -}; - -#endif // BRAVE_IOS_BROWSER_UI_WEBUI_BRAVE_WEBUI_DATA_SOURCE_H_ diff --git a/ios/browser/ui/webui/brave_webui_data_source.mm b/ios/browser/ui/webui/brave_webui_data_source.mm deleted file mode 100644 index 374327d7daab..000000000000 --- a/ios/browser/ui/webui/brave_webui_data_source.mm +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright (c) 2024 The Brave Authors. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at https://mozilla.org/MPL/2.0/. - -#include "brave/ios/browser/ui/webui/brave_webui_data_source.h" - -#include "base/functional/bind.h" -#include "base/memory/raw_ptr.h" -#include "base/memory/ref_counted_memory.h" -#include "base/strings/strcat.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "ios/chrome/browser/shared/model/url/chrome_url_constants.h" -#include "ios/web/public/web_client.h" -#include "services/network/public/mojom/content_security_policy.mojom.h" -#include "ui/base/webui/jstemplate_builder.h" -#include "ui/base/webui/resource_path.h" -#include "ui/base/webui/web_ui_util.h" - -BraveWebUIDataSource::BraveWebUIDataSource() - : default_resource_(-1), - use_strings_js_(false), - deny_xframe_options_(true), - load_time_data_defaults_added_(false), - replace_existing_source_(true), - should_replace_i18n_in_js_(false) {} - -BraveWebUIDataSource::~BraveWebUIDataSource() = default; - -void BraveWebUIDataSource::AddString(const std::string& name, - const std::u16string& value) { - localized_strings_.Set(name, value); - replacements_[name] = base::UTF16ToUTF8(value); -} - -void BraveWebUIDataSource::AddString(const std::string& name, - const std::string& value) { - localized_strings_.Set(name, value); - replacements_[name] = value; -} - -void BraveWebUIDataSource::AddLocalizedString(const std::string& name, - int ids) { - localized_strings_.Set(name, web::GetWebClient()->GetLocalizedString(ids)); - replacements_[name] = - base::UTF16ToUTF8(web::GetWebClient()->GetLocalizedString(ids)); -} - -void BraveWebUIDataSource::AddLocalizedStrings( - const base::Value::Dict& localized_strings) { - localized_strings_.Merge(localized_strings.Clone()); - ui::TemplateReplacementsFromDictionaryValue(localized_strings, - &replacements_); -} - -void BraveWebUIDataSource::AddLocalizedStrings( - base::span strings) { - for (const auto& str : strings) { - AddLocalizedString(str.name, str.id); - } -} - -void BraveWebUIDataSource::AddBoolean(const std::string& name, bool value) { - localized_strings_.Set(name, value); -} - -void BraveWebUIDataSource::UseStringsJs() { - use_strings_js_ = true; -} - -void BraveWebUIDataSource::EnableReplaceI18nInJS() { - should_replace_i18n_in_js_ = true; -} - -bool BraveWebUIDataSource::ShouldReplaceI18nInJS() const { - return should_replace_i18n_in_js_; -} - -void BraveWebUIDataSource::AddResourcePath(const std::string& path, - int resource_id) { - path_to_idr_map_[path] = resource_id; -} - -void BraveWebUIDataSource::AddResourcePaths( - base::span paths) { - for (const auto& path : paths) { - AddResourcePath(path.path, path.id); - } -} - -void BraveWebUIDataSource::SetDefaultResource(int resource_id) { - default_resource_ = resource_id; -} - -void BraveWebUIDataSource::DisableDenyXFrameOptions() { - deny_xframe_options_ = false; -} - -const ui::TemplateReplacements* BraveWebUIDataSource::GetReplacements() const { - return &replacements_; -} - -void BraveWebUIDataSource::OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName directive, - const std::string& value) { - csp_overrides_.insert_or_assign(directive, value); -} - -void BraveWebUIDataSource::AddFrameAncestor(const GURL& frame_ancestor) { - // Do not allow a wildcard to be a frame ancestor or it will allow any website - // to embed the WebUI. - CHECK(frame_ancestor.SchemeIs(kChromeUIScheme) || - frame_ancestor.SchemeIs(kChromeUIUntrustedScheme)); - frame_ancestors_.insert(frame_ancestor); -} - -void BraveWebUIDataSource::DisableTrustedTypesCSP() { - // TODO(crbug.com/40137141): Trusted Type remaining WebUI - // This removes require-trusted-types-for and trusted-types directives - // from the CSP header. - OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::RequireTrustedTypesFor, std::string()); - OverrideContentSecurityPolicy(network::mojom::CSPDirectiveName::TrustedTypes, - std::string()); -} - -// URLDataSourceIOS - -std::string BraveWebUIDataSource::GetSource() const { - return base::StrCat( - {kChromeUIUntrustedScheme, url::kStandardSchemeSeparator}); -} - -void BraveWebUIDataSource::StartDataRequest(const std::string& path, - GotDataCallback callback) { - EnsureLoadTimeDataDefaultsAdded(); - - if (use_strings_js_) { - bool from_js_module = path == "strings.m.js"; - if (from_js_module || path == "strings.js") { - SendLocalizedStringsAsJSON(std::move(callback), from_js_module); - return; - } - } - - int resource_id = PathToIdrOrDefault(path); - DCHECK_NE(resource_id, -1); - scoped_refptr response( - web::GetWebClient()->GetDataResourceBytes(resource_id)); - std::move(callback).Run(response); -} - -std::string BraveWebUIDataSource::GetMimeType(const std::string& path) const { - if (base::EndsWith(path, ".png", base::CompareCase::INSENSITIVE_ASCII)) { - return "image/png"; - } - - if (base::EndsWith(path, ".gif", base::CompareCase::INSENSITIVE_ASCII)) { - return "image/gif"; - } - - if (base::EndsWith(path, ".jpg", base::CompareCase::INSENSITIVE_ASCII)) { - return "image/jpg"; - } - - if (base::EndsWith(path, ".js", base::CompareCase::INSENSITIVE_ASCII)) { - return "application/javascript"; - } - - if (base::EndsWith(path, ".json", base::CompareCase::INSENSITIVE_ASCII)) { - return "application/json"; - } - - if (base::EndsWith(path, ".pdf", base::CompareCase::INSENSITIVE_ASCII)) { - return "application/pdf"; - } - - if (base::EndsWith(path, ".css", base::CompareCase::INSENSITIVE_ASCII)) { - return "text/css"; - } - - if (base::EndsWith(path, ".svg", base::CompareCase::INSENSITIVE_ASCII)) { - return "image/svg+xml"; - } - - return "text/html"; -} - -bool BraveWebUIDataSource::ShouldReplaceExistingSource() const { - return replace_existing_source_; -} - -bool BraveWebUIDataSource::AllowCaching() const { - return false; -} - -bool BraveWebUIDataSource::ShouldDenyXFrameOptions() const { - return deny_xframe_options_; -} - -bool BraveWebUIDataSource::ShouldServiceRequest(const GURL& url) const { - return web::URLDataSourceIOS::ShouldServiceRequest(url); -} - -std::string BraveWebUIDataSource::GetContentSecurityPolicy( - network::mojom::CSPDirectiveName directive) const { - if (csp_overrides_.contains(directive)) { - return csp_overrides_.at(directive); - } else if (directive == network::mojom::CSPDirectiveName::FrameAncestors) { - std::string frame_ancestors; - if (frame_ancestors_.size() == 0) { - frame_ancestors += " 'none'"; - } - for (const GURL& frame_ancestor : frame_ancestors_) { - frame_ancestors += " " + frame_ancestor.spec(); - } - return "frame-ancestors" + frame_ancestors + ";"; - } - return web::URLDataSourceIOS::GetContentSecurityPolicy(directive); -} - -std::string BraveWebUIDataSource::GetContentSecurityPolicyObjectSrc() const { - if (ShouldAddContentSecurityPolicy()) { - std::string csp_header; - - const network::mojom::CSPDirectiveName kAllDirectives[] = { - network::mojom::CSPDirectiveName::BaseURI, - network::mojom::CSPDirectiveName::ChildSrc, - network::mojom::CSPDirectiveName::ConnectSrc, - network::mojom::CSPDirectiveName::DefaultSrc, - network::mojom::CSPDirectiveName::FencedFrameSrc, - network::mojom::CSPDirectiveName::FormAction, - network::mojom::CSPDirectiveName::FontSrc, - network::mojom::CSPDirectiveName::ImgSrc, - network::mojom::CSPDirectiveName::MediaSrc, - network::mojom::CSPDirectiveName::ObjectSrc, - network::mojom::CSPDirectiveName::RequireTrustedTypesFor, - network::mojom::CSPDirectiveName::ScriptSrc, - network::mojom::CSPDirectiveName::StyleSrc, - network::mojom::CSPDirectiveName::TrustedTypes, - network::mojom::CSPDirectiveName::WorkerSrc}; - - for (auto& directive : kAllDirectives) { - csp_header.append(GetContentSecurityPolicy(directive)); - } - - // TODO(crbug.com/40118579): Both CSP frame ancestors and XFO headers may be - // added to the response but frame ancestors would take precedence. In the - // future, XFO will be removed so when that happens remove the check and - // always add frame ancestors. - if (ShouldDenyXFrameOptions()) { - csp_header.append(GetContentSecurityPolicy( - network::mojom::CSPDirectiveName::FrameAncestors)); - } - - return csp_header; - } - - return web::URLDataSourceIOS::GetContentSecurityPolicyObjectSrc(); -} - -std::string BraveWebUIDataSource::GetContentSecurityPolicyFrameSrc() const { - if (csp_overrides_.contains(network::mojom::CSPDirectiveName::FrameSrc)) { - return csp_overrides_.at(network::mojom::CSPDirectiveName::FrameSrc); - } - - std::string frame_src = - GetContentSecurityPolicy(network::mojom::CSPDirectiveName::FrameSrc); - if (!frame_src.empty()) { - return frame_src; - } - - // See url_data_manager_ios_backend.mm chromium_src override for more details - return web::URLDataSourceIOS::GetContentSecurityPolicyFrameSrc(); -} - -void BraveWebUIDataSource::EnsureLoadTimeDataDefaultsAdded() { - if (load_time_data_defaults_added_) { - return; - } - - load_time_data_defaults_added_ = true; - base::Value::Dict defaults; - webui::SetLoadTimeDataDefaults(web::GetWebClient()->GetApplicationLocale(), - &defaults); - AddLocalizedStrings(defaults); -} - -void BraveWebUIDataSource::SendLocalizedStringsAsJSON( - URLDataSourceIOS::GotDataCallback callback, - bool from_js_module) { - std::string template_data; - webui::AppendJsonJS(localized_strings_, &template_data, from_js_module); - std::move(callback).Run( - base::MakeRefCounted(std::move(template_data))); -} - -int BraveWebUIDataSource::PathToIdrOrDefault(const std::string& path) const { - auto it = path_to_idr_map_.find(path); - return it == path_to_idr_map_.end() ? default_resource_ : it->second; -} diff --git a/ios/browser/ui/webui/brave_webui_source.mm b/ios/browser/ui/webui/brave_webui_source.mm index 7dc52a37c15e..31331e18d291 100644 --- a/ios/browser/ui/webui/brave_webui_source.mm +++ b/ios/browser/ui/webui/brave_webui_source.mm @@ -12,11 +12,11 @@ #include "base/strings/utf_string_conversions.h" #include "brave/components/constants/url_constants.h" #include "brave/components/webui/webui_resources.h" +#include "brave/ios/browser/ui/webui/public/brave_web_ui_ios_data_source.h" #include "build/build_config.h" #include "components/grit/components_resources.h" #include "ios/chrome/browser/shared/model/profile/profile_ios.h" #include "ios/web/public/webui/web_ui_ios_data_source.h" -#include "ios/web/webui/web_ui_ios_data_source_impl.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/webui/resource_path.h" #include "ui/base/webui/web_ui_util.h" diff --git a/ios/browser/ui/webui/public/BUILD.gn b/ios/browser/ui/webui/public/BUILD.gn new file mode 100644 index 000000000000..1f54146137ea --- /dev/null +++ b/ios/browser/ui/webui/public/BUILD.gn @@ -0,0 +1,27 @@ +# Copyright (c) 2024 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + +import("//brave/build/config.gni") +import("//build/config/features.gni") +import("//mojo/public/tools/bindings/mojom.gni") + +source_set("public") { + sources = [ + "brave_url_data_source_ios.h", + "brave_url_data_source_ios.mm", + "brave_web_ui_ios_data_source.h", + "brave_web_ui_ios_data_source.mm", + ] + + deps = [ + "//ios/chrome/browser/shared/model/url:constants", + "//ios/components/webui:url_constants", + "//ios/web/public", + "//ios/web/public/webui", + "//ios/web/webui:webui", + "//services/network/public/mojom", + "//ui/base", + ] +} diff --git a/ios/browser/ui/webui/public/DEPS b/ios/browser/ui/webui/public/DEPS new file mode 100644 index 000000000000..ac4e721b9049 --- /dev/null +++ b/ios/browser/ui/webui/public/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+ios/web/webui", +] \ No newline at end of file diff --git a/ios/browser/ui/webui/brave_url_data_source_ios.h b/ios/browser/ui/webui/public/brave_url_data_source_ios.h similarity index 80% rename from ios/browser/ui/webui/brave_url_data_source_ios.h rename to ios/browser/ui/webui/public/brave_url_data_source_ios.h index e2226d1df97d..765fdd34f14b 100644 --- a/ios/browser/ui/webui/brave_url_data_source_ios.h +++ b/ios/browser/ui/webui/public/brave_url_data_source_ios.h @@ -3,8 +3,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -#ifndef BRAVE_IOS_BROWSER_UI_WEBUI_BRAVE_URL_DATA_SOURCE_IOS_H_ -#define BRAVE_IOS_BROWSER_UI_WEBUI_BRAVE_URL_DATA_SOURCE_IOS_H_ +#ifndef BRAVE_IOS_BROWSER_UI_WEBUI_PUBLIC_BRAVE_URL_DATA_SOURCE_IOS_H_ +#define BRAVE_IOS_BROWSER_UI_WEBUI_PUBLIC_BRAVE_URL_DATA_SOURCE_IOS_H_ #include @@ -27,4 +27,4 @@ class BraveURLDataSourceIOS : public web::URLDataSourceIOS { base::flat_map csp_overrides_; }; -#endif // BRAVE_IOS_BROWSER_UI_WEBUI_BRAVE_URL_DATA_SOURCE_IOS_H_ +#endif // BRAVE_IOS_BROWSER_UI_WEBUI_PUBLIC_BRAVE_URL_DATA_SOURCE_IOS_H_ diff --git a/ios/browser/ui/webui/brave_url_data_source_ios.mm b/ios/browser/ui/webui/public/brave_url_data_source_ios.mm similarity index 98% rename from ios/browser/ui/webui/brave_url_data_source_ios.mm rename to ios/browser/ui/webui/public/brave_url_data_source_ios.mm index b2d73eeca15b..a6733bc6569a 100644 --- a/ios/browser/ui/webui/brave_url_data_source_ios.mm +++ b/ios/browser/ui/webui/public/brave_url_data_source_ios.mm @@ -3,7 +3,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -#include "brave/ios/browser/ui/webui/brave_url_data_source_ios.h" +#include "brave/ios/browser/ui/webui/public/brave_url_data_source_ios.h" #include "base/no_destructor.h" #include "base/strings/strcat.h" diff --git a/ios/browser/ui/webui/public/brave_web_ui_ios_data_source.h b/ios/browser/ui/webui/public/brave_web_ui_ios_data_source.h new file mode 100644 index 000000000000..544433d1445c --- /dev/null +++ b/ios/browser/ui/webui/public/brave_web_ui_ios_data_source.h @@ -0,0 +1,100 @@ +// Copyright (c) 2024 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef BRAVE_IOS_BROWSER_UI_WEBUI_PUBLIC_BRAVE_WEB_UI_IOS_DATA_SOURCE_H_ +#define BRAVE_IOS_BROWSER_UI_WEBUI_PUBLIC_BRAVE_WEB_UI_IOS_DATA_SOURCE_H_ + +#include +#include +#include + +#include "base/containers/flat_map.h" +#include "ios/web/public/webui/url_data_source_ios.h" +#include "ios/web/public/webui/web_ui_ios_data_source.h" +#include "ios/web/webui/url_data_source_ios_impl.h" +#include "services/network/public/mojom/content_security_policy.mojom.h" + +namespace webui { +struct LocalizedString; +struct ResourcePath; +} // namespace webui + +class BraveWebUIIOSDataSource : public web::URLDataSourceIOSImpl, + public web::WebUIIOSDataSource { + public: + static web::WebUIIOSDataSource* Create(const std::string& source_name); + + BraveWebUIIOSDataSource(const BraveWebUIIOSDataSource&) = delete; + BraveWebUIIOSDataSource& operator=(const BraveWebUIIOSDataSource&) = delete; + + // WebUIIOSDataSource implementation: + void AddString(const std::string& name, const std::u16string& value) override; + void AddString(const std::string& name, const std::string& value) override; + void AddLocalizedString(const std::string& name, int ids) override; + void AddLocalizedStrings(const base::Value::Dict& localized_strings) override; + void AddLocalizedStrings( + base::span strings) override; + void AddBoolean(const std::string& name, bool value) override; + void UseStringsJs() override; + void EnableReplaceI18nInJS() override; + bool ShouldReplaceI18nInJS() const override; + void AddResourcePath(const std::string& path, int resource_id) override; + void AddResourcePaths(base::span paths) override; + void SetDefaultResource(int resource_id) override; + void DisableDenyXFrameOptions() override; + const ui::TemplateReplacements* GetReplacements() const override; + + // Brave CSP's & Security implementation: + virtual void OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName directive, + const std::string& value); + + virtual void AddFrameAncestor(const GURL& frame_ancestor); + virtual void DisableTrustedTypesCSP(); + + protected: + ~BraveWebUIIOSDataSource() override; + + // URLDataSourceIOS overrides: + virtual std::string GetSource() const; + virtual void StartDataRequest( + const std::string& path, + web::URLDataSourceIOS::GotDataCallback callback); + virtual std::string GetMimeType(const std::string& path) const; + virtual bool ShouldReplaceExistingSource() const; + virtual bool ShouldDenyXFrameOptions() const; + virtual bool ShouldServiceRequest(const GURL& url) const; + + private: + class InternalDataSource; + friend class InternalDataSource; + + explicit BraveWebUIIOSDataSource(const std::string& source_name); + + // URLDataSourceIOS implementation: + void EnsureLoadTimeDataDefaultsAdded(); + void SendLocalizedStringsAsJSON( + web::URLDataSourceIOS::GotDataCallback callback, + bool from_js_module); + int PathToIdrOrDefault(const std::string& path) const; + + // WebUIIOSDataSource variables: + int default_resource_; + bool use_strings_js_; + std::map path_to_idr_map_; + base::Value::Dict localized_strings_; + ui::TemplateReplacements replacements_; + bool deny_xframe_options_; + bool load_time_data_defaults_added_; + bool replace_existing_source_; + bool should_replace_i18n_in_js_; + std::optional supported_scheme_; + + // Brave CSP's & Security variables: + base::flat_map csp_overrides_; + std::set frame_ancestors_; +}; + +#endif // BRAVE_IOS_BROWSER_UI_WEBUI_PUBLIC_BRAVE_WEB_UI_IOS_DATA_SOURCE_H_ diff --git a/ios/browser/ui/webui/public/brave_web_ui_ios_data_source.mm b/ios/browser/ui/webui/public/brave_web_ui_ios_data_source.mm new file mode 100644 index 000000000000..221d683a900e --- /dev/null +++ b/ios/browser/ui/webui/public/brave_web_ui_ios_data_source.mm @@ -0,0 +1,309 @@ +// Copyright (c) 2024 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "brave/ios/browser/ui/webui/public/brave_web_ui_ios_data_source.h" + +#include "base/containers/span.h" +#include "base/functional/bind.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/ref_counted_memory.h" +#include "base/strings/strcat.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "brave/ios/browser/ui/webui/public/brave_url_data_source_ios.h" +#include "ios/chrome/browser/shared/model/url/chrome_url_constants.h" +#include "ios/components/webui/web_ui_url_constants.h" +#include "ios/web/public/web_client.h" +#include "ios/web/public/webui/web_ui_ios_data_source.h" +#include "ui/base/webui/jstemplate_builder.h" +#include "ui/base/webui/resource_path.h" +#include "ui/base/webui/web_ui_util.h" + +// static +web::WebUIIOSDataSource* BraveWebUIIOSDataSource::Create( + const std::string& source_name) { + return new BraveWebUIIOSDataSource(source_name); +} + +class BraveWebUIIOSDataSource::InternalDataSource + : public BraveURLDataSourceIOS { + public: + InternalDataSource(BraveWebUIIOSDataSource* parent) : parent_(parent) {} + ~InternalDataSource() override {} + + std::string GetSource() const override { return parent_->GetSource(); } + + void StartDataRequest(const std::string& path, + URLDataSourceIOS::GotDataCallback callback) override { + return parent_->StartDataRequest(path, std::move(callback)); + } + + std::string GetMimeType(const std::string& path) const override { + return parent_->GetMimeType(path); + } + + bool ShouldReplaceExistingSource() const override { + return parent_->replace_existing_source_; + } + + bool ShouldReplaceI18nInJS() const override { + return parent_->ShouldReplaceI18nInJS(); + } + + bool AllowCaching() const override { return false; } + + std::string GetContentSecurityPolicy( + network::mojom::CSPDirectiveName directive) const override { + // Check CSP overrides + if (parent_->csp_overrides_.contains(directive)) { + return parent_->csp_overrides_.at(directive); + } + + // Check Frame-Ancestors overrides + if (directive == network::mojom::CSPDirectiveName::FrameAncestors) { + std::string frame_ancestors; + if (parent_->frame_ancestors_.empty()) { + frame_ancestors += " 'none'"; + } + + for (const GURL& frame_ancestor : parent_->frame_ancestors_) { + frame_ancestors += " " + frame_ancestor.spec(); + } + return "frame-ancestors" + frame_ancestors + ";"; + } + + return BraveURLDataSourceIOS::GetContentSecurityPolicy(directive); + } + + bool ShouldDenyXFrameOptions() const override { + return parent_->deny_xframe_options_; + } + + bool ShouldServiceRequest(const GURL& url) const override { + if (parent_->supported_scheme_.has_value()) { + return url.SchemeIs(parent_->supported_scheme_.value()); + } + + return BraveURLDataSourceIOS::ShouldServiceRequest(url); + } + + private: + raw_ptr parent_; +}; + +// WebUIIOSDataSource implementation: + +BraveWebUIIOSDataSource::BraveWebUIIOSDataSource(const std::string& source_name) + : URLDataSourceIOSImpl(source_name, new InternalDataSource(this)), + default_resource_(-1), + use_strings_js_(false), + deny_xframe_options_(true), + load_time_data_defaults_added_(false), + replace_existing_source_(true), + should_replace_i18n_in_js_(false) { + CHECK(!source_name.ends_with("://")); +} + +BraveWebUIIOSDataSource::~BraveWebUIIOSDataSource() = default; + +void BraveWebUIIOSDataSource::AddString(const std::string& name, + const std::u16string& value) { + localized_strings_.Set(name, value); + replacements_[name] = base::UTF16ToUTF8(value); +} + +void BraveWebUIIOSDataSource::AddString(const std::string& name, + const std::string& value) { + localized_strings_.Set(name, value); + replacements_[name] = value; +} + +void BraveWebUIIOSDataSource::AddLocalizedString(const std::string& name, + int ids) { + localized_strings_.Set(name, web::GetWebClient()->GetLocalizedString(ids)); + replacements_[name] = + base::UTF16ToUTF8(web::GetWebClient()->GetLocalizedString(ids)); +} + +void BraveWebUIIOSDataSource::AddLocalizedStrings( + const base::Value::Dict& localized_strings) { + localized_strings_.Merge(localized_strings.Clone()); + ui::TemplateReplacementsFromDictionaryValue(localized_strings, + &replacements_); +} + +void BraveWebUIIOSDataSource::AddLocalizedStrings( + base::span strings) { + for (const auto& str : strings) { + AddLocalizedString(str.name, str.id); + } +} + +void BraveWebUIIOSDataSource::AddBoolean(const std::string& name, bool value) { + localized_strings_.Set(name, value); +} + +void BraveWebUIIOSDataSource::UseStringsJs() { + use_strings_js_ = true; +} + +void BraveWebUIIOSDataSource::EnableReplaceI18nInJS() { + should_replace_i18n_in_js_ = true; +} + +bool BraveWebUIIOSDataSource::ShouldReplaceI18nInJS() const { + return should_replace_i18n_in_js_; +} + +void BraveWebUIIOSDataSource::AddResourcePath(const std::string& path, + int resource_id) { + path_to_idr_map_[path] = resource_id; +} + +void BraveWebUIIOSDataSource::AddResourcePaths( + base::span paths) { + for (const auto& path : paths) { + AddResourcePath(path.path, path.id); + } +} + +void BraveWebUIIOSDataSource::SetDefaultResource(int resource_id) { + default_resource_ = resource_id; +} + +void BraveWebUIIOSDataSource::DisableDenyXFrameOptions() { + deny_xframe_options_ = false; +} + +const ui::TemplateReplacements* BraveWebUIIOSDataSource::GetReplacements() + const { + return &replacements_; +} + +// URLDataSourceIOS implementation: + +std::string BraveWebUIIOSDataSource::GetSource() const { + return base::StrCat({kChromeUIScheme, url::kStandardSchemeSeparator}); +} + +void BraveWebUIIOSDataSource::StartDataRequest( + const std::string& path, + web::URLDataSourceIOS::GotDataCallback callback) { + EnsureLoadTimeDataDefaultsAdded(); + + if (use_strings_js_) { + bool from_js_module = path == "strings.m.js"; + if (from_js_module || path == "strings.js") { + SendLocalizedStringsAsJSON(std::move(callback), from_js_module); + return; + } + } + + int resource_id = PathToIdrOrDefault(path); + DCHECK_NE(resource_id, -1); + scoped_refptr response( + web::GetWebClient()->GetDataResourceBytes(resource_id)); + std::move(callback).Run(response); +} + +std::string BraveWebUIIOSDataSource::GetMimeType( + const std::string& path) const { + if (base::EndsWith(path, ".png", base::CompareCase::INSENSITIVE_ASCII)) { + return "image/png"; + } + + if (base::EndsWith(path, ".gif", base::CompareCase::INSENSITIVE_ASCII)) { + return "image/gif"; + } + + if (base::EndsWith(path, ".jpg", base::CompareCase::INSENSITIVE_ASCII)) { + return "image/jpg"; + } + + if (base::EndsWith(path, ".js", base::CompareCase::INSENSITIVE_ASCII)) { + return "application/javascript"; + } + + if (base::EndsWith(path, ".json", base::CompareCase::INSENSITIVE_ASCII)) { + return "application/json"; + } + + if (base::EndsWith(path, ".pdf", base::CompareCase::INSENSITIVE_ASCII)) { + return "application/pdf"; + } + + if (base::EndsWith(path, ".css", base::CompareCase::INSENSITIVE_ASCII)) { + return "text/css"; + } + + if (base::EndsWith(path, ".svg", base::CompareCase::INSENSITIVE_ASCII)) { + return "image/svg+xml"; + } + + return "text/html"; +} + +bool BraveWebUIIOSDataSource::ShouldReplaceExistingSource() const { + return replace_existing_source_; +} + +bool BraveWebUIIOSDataSource::ShouldDenyXFrameOptions() const { + return deny_xframe_options_; +} + +bool BraveWebUIIOSDataSource::ShouldServiceRequest(const GURL& url) const { + return web::GetWebClient()->IsAppSpecificURL(url); +} + +void BraveWebUIIOSDataSource::EnsureLoadTimeDataDefaultsAdded() { + if (load_time_data_defaults_added_) { + return; + } + + load_time_data_defaults_added_ = true; + base::Value::Dict defaults; + webui::SetLoadTimeDataDefaults(web::GetWebClient()->GetApplicationLocale(), + &defaults); + AddLocalizedStrings(defaults); +} + +void BraveWebUIIOSDataSource::SendLocalizedStringsAsJSON( + web::URLDataSourceIOS::GotDataCallback callback, + bool from_js_module) { + std::string template_data; + webui::AppendJsonJS(localized_strings_, &template_data, from_js_module); + std::move(callback).Run( + base::MakeRefCounted(std::move(template_data))); +} + +int BraveWebUIIOSDataSource::PathToIdrOrDefault(const std::string& path) const { + auto it = path_to_idr_map_.find(path); + return it == path_to_idr_map_.end() ? default_resource_ : it->second; +} + +// Brave CSP's & Security implementation: + +void BraveWebUIIOSDataSource::OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName directive, + const std::string& value) { + csp_overrides_.insert_or_assign(directive, value); +} + +void BraveWebUIIOSDataSource::AddFrameAncestor(const GURL& frame_ancestor) { + // Do not allow a wildcard to be a frame ancestor or it will allow any website + // to embed the WebUI. + CHECK(frame_ancestor.SchemeIs(kChromeUIScheme)); + frame_ancestors_.insert(frame_ancestor); +} + +void BraveWebUIIOSDataSource::DisableTrustedTypesCSP() { + // TODO(crbug.com/40137141): Trusted Type remaining WebUI + // This removes require-trusted-types-for and trusted-types directives + // from the CSP header. + OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::RequireTrustedTypesFor, std::string()); + OverrideContentSecurityPolicy(network::mojom::CSPDirectiveName::TrustedTypes, + std::string()); +}