From 762e56e4378e260d2cffe3851c480f4142fd2753 Mon Sep 17 00:00:00 2001 From: Brandon T Date: Thu, 21 Nov 2024 13:49:29 -0500 Subject: [PATCH] Refactor into separate classes instead of chromium overrides --- .../web/public/webui/url_data_source_ios.h | 24 +- .../web/public/webui/web_ui_ios_data_source.h | 27 -- .../web/webui/url_data_manager_ios_backend.mm | 10 +- .../ios/web/webui/url_data_source_ios.mm | 139 +------- .../web/webui/web_ui_ios_data_source_impl.h | 35 -- .../web/webui/web_ui_ios_data_source_impl.mm | 74 ----- ios/BUILD.gn | 7 +- .../App/Configuration/Debug-AppStore.xcconfig | 5 + .../App/Configuration/Debug.xcconfig | 2 + .../LeoAssetsPlugin/LeoAssetsPlugin.swift | 2 +- .../Sources/Playlist/PlaylistManager.swift | 34 +- ios/browser/ui/webui/BUILD.gn | 3 +- ios/browser/ui/webui/brave_webui_source.mm | 3 +- ios/browser/ui/webui/public/BUILD.gn | 27 ++ .../webui/public/brave_url_data_source_ios.h | 30 ++ .../webui/public/brave_url_data_source_ios.mm | 135 ++++++++ .../public/brave_web_ui_ios_data_source.h | 100 ++++++ .../public/brave_web_ui_ios_data_source.mm | 309 ++++++++++++++++++ 18 files changed, 645 insertions(+), 321 deletions(-) delete mode 100644 chromium_src/ios/web/public/webui/web_ui_ios_data_source.h delete mode 100644 chromium_src/ios/web/webui/web_ui_ios_data_source_impl.h delete mode 100644 chromium_src/ios/web/webui/web_ui_ios_data_source_impl.mm create mode 100644 ios/browser/ui/webui/public/BUILD.gn create mode 100644 ios/browser/ui/webui/public/brave_url_data_source_ios.h create mode 100644 ios/browser/ui/webui/public/brave_url_data_source_ios.mm create mode 100644 ios/browser/ui/webui/public/brave_web_ui_ios_data_source.h create mode 100644 ios/browser/ui/webui/public/brave_web_ui_ios_data_source.mm diff --git a/chromium_src/ios/web/public/webui/url_data_source_ios.h b/chromium_src/ios/web/public/webui/url_data_source_ios.h index da3285337a43..e1651d5251ca 100644 --- a/chromium_src/ios/web/public/webui/url_data_source_ios.h +++ b/chromium_src/ios/web/public/webui/url_data_source_ios.h @@ -6,30 +6,12 @@ #ifndef BRAVE_CHROMIUM_SRC_IOS_WEB_PUBLIC_WEBUI_URL_DATA_SOURCE_IOS_H_ #define BRAVE_CHROMIUM_SRC_IOS_WEB_PUBLIC_WEBUI_URL_DATA_SOURCE_IOS_H_ -#include - -namespace network::mojom { -enum class CSPDirectiveName : std::int32_t; -} // namespace network::mojom - -#define GetContentSecurityPolicyObjectSrc \ - GetContentSecurityPolicyObjectSrc_ChromiumImpl() const; \ - virtual std::string GetContentSecurityPolicyObjectSrc - -#define ShouldServiceRequest \ - ShouldServiceRequest_ChromiumImpl(const GURL& url) const; \ - virtual bool ShouldServiceRequest(const GURL& url) const; \ - virtual bool ShouldAddContentSecurityPolicy() const; \ - virtual std::string GetContentSecurityPolicyFrameSrc() const; \ - virtual std::string GetContentSecurityPolicy( \ - network::mojom::CSPDirectiveName directive) const; \ - \ - private: \ - bool Dummy +#define GetContentSecurityPolicyObjectSrc \ + GetContentSecurityPolicyObjectSrc() const; \ + virtual std::string GetContentSecurityPolicyFrameSrc #import "src/ios/web/public/webui/url_data_source_ios.h" // IWYU pragma: export #undef GetContentSecurityPolicyObjectSrc -#undef ShouldServiceRequest #endif // BRAVE_CHROMIUM_SRC_IOS_WEB_PUBLIC_WEBUI_URL_DATA_SOURCE_IOS_H_ diff --git a/chromium_src/ios/web/public/webui/web_ui_ios_data_source.h b/chromium_src/ios/web/public/webui/web_ui_ios_data_source.h deleted file mode 100644 index 087adebd97dc..000000000000 --- a/chromium_src/ios/web/public/webui/web_ui_ios_data_source.h +++ /dev/null @@ -1,27 +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_PUBLIC_WEBUI_WEB_UI_IOS_DATA_SOURCE_H_ -#define BRAVE_CHROMIUM_SRC_IOS_WEB_PUBLIC_WEBUI_WEB_UI_IOS_DATA_SOURCE_H_ - -#include - -namespace network::mojom { -enum class CSPDirectiveName : std::int32_t; -} // namespace network::mojom - -#define DisableDenyXFrameOptions \ - DisableDenyXFrameOptions() = 0; \ - virtual void OverrideContentSecurityPolicy( \ - network::mojom::CSPDirectiveName directive, \ - const std::string& value) = 0; \ - virtual void AddFrameAncestor(const GURL& frame_ancestor) = 0; \ - virtual void DisableTrustedTypesCSP - -#include "src/ios/web/public/webui/web_ui_ios_data_source.h" // IWYU pragma: export - -#undef DisableDenyXFrameOptions - -#endif // BRAVE_CHROMIUM_SRC_IOS_WEB_PUBLIC_WEBUI_WEB_UI_IOS_DATA_SOURCE_H_ diff --git a/chromium_src/ios/web/webui/url_data_manager_ios_backend.mm b/chromium_src/ios/web/webui/url_data_manager_ios_backend.mm index 5d8590fe6bbf..997a7d782911 100644 --- a/chromium_src/ios/web/webui/url_data_manager_ios_backend.mm +++ b/chromium_src/ios/web/webui/url_data_manager_ios_backend.mm @@ -5,13 +5,9 @@ #include "ios/web/webui/url_data_manager_ios_backend.h" -#define ShouldDenyXFrameOptions ShouldDenyXFrameOptions()); \ - job->set_add_content_security_policy( \ - source->source()->ShouldAddContentSecurityPolicy()); \ - job->set_content_security_policy_object_source( \ - source->source()->GetContentSecurityPolicyObjectSrc()); \ - job->set_content_security_policy_frame_source( \ - source->source()->GetContentSecurityPolicyFrameSrc()); \ +#define ShouldDenyXFrameOptions ShouldDenyXFrameOptions()); \ + job->set_content_security_policy_frame_source( \ + source->source()->GetContentSecurityPolicyFrameSrc()); \ void(void #include "src/ios/web/webui/url_data_manager_ios_backend.mm" diff --git a/chromium_src/ios/web/webui/url_data_source_ios.mm b/chromium_src/ios/web/webui/url_data_source_ios.mm index 18bce46a4503..2bdda3d3c90b 100644 --- a/chromium_src/ios/web/webui/url_data_source_ios.mm +++ b/chromium_src/ios/web/webui/url_data_source_ios.mm @@ -5,149 +5,14 @@ #include "ios/web/public/webui/url_data_source_ios.h" -#include "base/containers/span.h" -#include "base/no_destructor.h" -#include "base/strings/strcat.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "ios/components/webui/web_ui_url_constants.h" -#include "services/network/public/mojom/content_security_policy.mojom.h" - -namespace { - -// A chrome-untrusted data source's name starts with chrome-untrusted://. -bool IsChromeUntrustedDataSource(const web::URLDataSourceIOS* source) { - static const base::NoDestructor kChromeUntrustedSourceNamePrefix( - base::StrCat({kChromeUIUntrustedScheme, url::kStandardSchemeSeparator})); - - return base::StartsWith(source->GetSource(), - *kChromeUntrustedSourceNamePrefix, - base::CompareCase::SENSITIVE); -} - -} // namespace - namespace web { -bool URLDataSourceIOS::ShouldAddContentSecurityPolicy() const { - return true; -} - -bool URLDataSourceIOS::ShouldServiceRequest(const GURL& url) const { - return URLDataSourceIOS::ShouldServiceRequest_ChromiumImpl(url); -} - -std::string URLDataSourceIOS::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 URLDataSourceIOS::GetContentSecurityPolicyObjectSrc_ChromiumImpl(); -} std::string URLDataSourceIOS::GetContentSecurityPolicyFrameSrc() const { - std::string frame_src = - GetContentSecurityPolicy(network::mojom::CSPDirectiveName::FrameSrc); - if (!frame_src.empty()) { - return frame_src; - } - + // Default for iOS: + // https://source.chromium.org/chromium/chromium/src/+/main:ios/web/webui/url_data_manager_ios_backend.mm;l=511?q=set_content_security_policy_frame_source&ss=chromium%2Fchromium%2Fsrc return "frame-src 'none';"; } -std::string URLDataSourceIOS::GetContentSecurityPolicy( - network::mojom::CSPDirectiveName directive) const { - switch (directive) { - case network::mojom::CSPDirectiveName::ChildSrc: - return "child-src 'none';"; - case network::mojom::CSPDirectiveName::DefaultSrc: - return IsChromeUntrustedDataSource(this) ? "default-src 'self';" - : std::string(); - case network::mojom::CSPDirectiveName::ObjectSrc: - return "object-src 'none';"; - case network::mojom::CSPDirectiveName::ScriptSrc: - // Note: Do not add 'unsafe-eval' here. Instead override CSP for the - // specific pages that need it, see context http://crbug.com/525224. - return IsChromeUntrustedDataSource(this) - ? base::StrCat({"script-src", kChromeUIUntrustedScheme, - url::kStandardSchemeSeparator, - "resources 'self';"}) - : "script-src chrome://resources 'self';"; - case network::mojom::CSPDirectiveName::FrameAncestors: - return "frame-ancestors 'none';"; - case network::mojom::CSPDirectiveName::RequireTrustedTypesFor: - return "require-trusted-types-for 'script';"; - case network::mojom::CSPDirectiveName::TrustedTypes: - return "trusted-types;"; - case network::mojom::CSPDirectiveName::BaseURI: - return IsChromeUntrustedDataSource(this) ? "base-uri 'none';" - : std::string(); - case network::mojom::CSPDirectiveName::FormAction: - return IsChromeUntrustedDataSource(this) ? "form-action 'none';" - : std::string(); - case network::mojom::CSPDirectiveName::BlockAllMixedContent: - case network::mojom::CSPDirectiveName::ConnectSrc: - case network::mojom::CSPDirectiveName::FencedFrameSrc: - case network::mojom::CSPDirectiveName::FrameSrc: - case network::mojom::CSPDirectiveName::FontSrc: - case network::mojom::CSPDirectiveName::ImgSrc: - case network::mojom::CSPDirectiveName::ManifestSrc: - case network::mojom::CSPDirectiveName::MediaSrc: - case network::mojom::CSPDirectiveName::ReportURI: - case network::mojom::CSPDirectiveName::Sandbox: - case network::mojom::CSPDirectiveName::ScriptSrcAttr: - case network::mojom::CSPDirectiveName::ScriptSrcElem: - case network::mojom::CSPDirectiveName::StyleSrc: - case network::mojom::CSPDirectiveName::StyleSrcAttr: - case network::mojom::CSPDirectiveName::StyleSrcElem: - case network::mojom::CSPDirectiveName::UpgradeInsecureRequests: - case network::mojom::CSPDirectiveName::TreatAsPublicAddress: - case network::mojom::CSPDirectiveName::WorkerSrc: - case network::mojom::CSPDirectiveName::ReportTo: - case network::mojom::CSPDirectiveName::Unknown: - return std::string(); - } -} - } // namespace web -#define GetContentSecurityPolicyObjectSrc \ - GetContentSecurityPolicyObjectSrc_ChromiumImpl - -#define ShouldServiceRequest ShouldServiceRequest_ChromiumImpl - #include "src/ios/web/webui/url_data_source_ios.mm" - -#undef ShouldServiceRequest -#undef GetContentSecurityPolicyObjectSrc 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 89e8cf7701bd..000000000000 --- a/chromium_src/ios/web/webui/web_ui_ios_data_source_impl.h +++ /dev/null @@ -1,35 +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 - -namespace network::mojom { -enum class CSPDirectiveName : std::int32_t; -} // namespace network::mojom - -#define should_replace_i18n_in_js_ \ - should_replace_i18n_in_js_; \ - \ - public: \ - void OverrideContentSecurityPolicy( \ - network::mojom::CSPDirectiveName directive, const std::string& value) \ - override; \ - void AddFrameAncestor(const GURL& frame_ancestor) override; \ - void DisableTrustedTypesCSP() override; \ - \ - private: \ - base::flat_map \ - csp_overrides_; \ - std::set frame_ancestors_ - -#include "src/ios/web/webui/web_ui_ios_data_source_impl.h" // IWYU pragma: export - -#undef should_replace_i18n_in_js_ - -#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 f7dab1ee20c4..000000000000 --- a/chromium_src/ios/web/webui/web_ui_ios_data_source_impl.mm +++ /dev/null @@ -1,74 +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 "ios/components/webui/web_ui_url_constants.h" -#include "ios/web/public/webui/web_ui_ios_data_source.h" -#include "services/network/public/mojom/content_security_policy.mojom.h" - -namespace web { - -void WebUIIOSDataSourceImpl::OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName directive, - const std::string& value) { - csp_overrides_.insert_or_assign(directive, value); -} - -void WebUIIOSDataSourceImpl::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 WebUIIOSDataSourceImpl::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()); -} - -} // namespace web - -#define ShouldDenyXFrameOptions \ - Dummy() const; \ - std::string GetContentSecurityPolicy( \ - network::mojom::CSPDirectiveName directive) const override; \ - bool ShouldDenyXFrameOptions - -#include "src/ios/web/webui/web_ui_ios_data_source_impl.mm" - -#undef ShouldDenyXFrameOptions - -namespace web { - -bool WebUIIOSDataSourceImpl::InternalDataSource::Dummy() const { - return false; -} - -std::string -WebUIIOSDataSourceImpl::InternalDataSource::GetContentSecurityPolicy( - network::mojom::CSPDirectiveName directive) const { - if (parent_->csp_overrides_.contains(directive)) { - return parent_->csp_overrides_.at(directive); - } else if (directive == network::mojom::CSPDirectiveName::FrameAncestors) { - std::string frame_ancestors; - if (parent_->frame_ancestors_.size() == 0) { - frame_ancestors += " 'none'"; - } - for (const GURL& frame_ancestor : parent_->frame_ancestors_) { - frame_ancestors += " " + frame_ancestor.spec(); - } - return "frame-ancestors" + frame_ancestors + ";"; - } - - return URLDataSourceIOS::GetContentSecurityPolicy(directive); -} - -} // namespace web diff --git a/ios/BUILD.gn b/ios/BUILD.gn index 066f97ed6038..49d483afe32b 100644 --- a/ios/BUILD.gn +++ b/ios/BUILD.gn @@ -53,8 +53,11 @@ assert(is_debug || current_cpu != "arm64" || use_lld, config("internal_config") { visibility = [ ":*" ] - ldflags = - [ "-Wl,-rpath,/usr/lib/swift,-rpath,@executable_path/../Frameworks" ] + ldflags = [ + "-Wl,-rpath,/usr/lib/swift,-rpath,@executable_path/../Frameworks", + "-fstandalone-debug", + "-fno-limit-debug-info", + ] } group("brave_ios") { diff --git a/ios/brave-ios/App/Configuration/Debug-AppStore.xcconfig b/ios/brave-ios/App/Configuration/Debug-AppStore.xcconfig index aa18dc9da706..40349e3778db 100644 --- a/ios/brave-ios/App/Configuration/Debug-AppStore.xcconfig +++ b/ios/brave-ios/App/Configuration/Debug-AppStore.xcconfig @@ -13,3 +13,8 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG BRAVE_CHANNEL_RELEASE $(brave_swift_ // Manual Code-Signing DEVELOPMENT_TEAM = KL8N8XSYF4 CODE_SIGN_STYLE = Manual + +RETAIN_RAW_BINARIES = YES +GCC_DEBUGGING_SYMBOLS = default +STRIP_INSTALLED_PRODUCT = NO +OTHER_LDFLAGS = $(OTHER_LDFLAGS) -fstandalone-debug -fno-limit-debug-info diff --git a/ios/brave-ios/App/Configuration/Debug.xcconfig b/ios/brave-ios/App/Configuration/Debug.xcconfig index 3513dae9d9ee..4b81876d5e61 100644 --- a/ios/brave-ios/App/Configuration/Debug.xcconfig +++ b/ios/brave-ios/App/Configuration/Debug.xcconfig @@ -25,3 +25,5 @@ OTHER_SWIFT_FLAGS=$(brave_ios_debug_prefix_map_flag) ENABLE_TESTABILITY = YES GCC_PREPROCESSOR_DEFINITIONS= DEBUG=1 + +OTHER_LDFLAGS = $(OTHER_LDFLAGS) -fstandalone-debug -fno-limit-debug-info diff --git a/ios/brave-ios/Plugins/LeoAssetsPlugin/LeoAssetsPlugin.swift b/ios/brave-ios/Plugins/LeoAssetsPlugin/LeoAssetsPlugin.swift index a6c6a2f197be..a40b0a1a16bb 100644 --- a/ios/brave-ios/Plugins/LeoAssetsPlugin/LeoAssetsPlugin.swift +++ b/ios/brave-ios/Plugins/LeoAssetsPlugin/LeoAssetsPlugin.swift @@ -25,7 +25,7 @@ struct LeoAssetsPlugin: BuildToolPlugin { } // Check to make sure the plugin is being used correctly in SPM - guard let target = target as? SourceModuleTarget else { + guard target is SourceModuleTarget else { Diagnostics.error("Attempted to use `LeoAssetsPlugin` on an unsupported module target") return [] } diff --git a/ios/brave-ios/Sources/Playlist/PlaylistManager.swift b/ios/brave-ios/Sources/Playlist/PlaylistManager.swift index dda66c1dc6bd..d3ecc23b22c8 100644 --- a/ios/brave-ios/Sources/Playlist/PlaylistManager.swift +++ b/ios/brave-ios/Sources/Playlist/PlaylistManager.swift @@ -825,34 +825,38 @@ extension PlaylistManager { // Accessing tracks blocks the main-thread if not already loaded // So we first need to check the track status before attempting to access it! - var error: NSError? - let trackStatus = asset.statusOfValue(forKey: "tracks", error: &error) + let trackStatus = asset.status(of: .tracks) - if trackStatus == .loaded { - if !asset.tracks.isEmpty, - let track = asset.tracks(withMediaType: .video).first - ?? asset.tracks(withMediaType: .audio).first + if case .loaded(let tracks) = trackStatus { + if !tracks.isEmpty, + let track = tracks.first(where: { $0.mediaType == .video }) + ?? tracks.first(where: { $0.mediaType == .audio }) { - if track.timeRange.duration.isIndefinite { - return TimeInterval.infinity - } else { - return track.timeRange.duration.seconds + do { + let duration = try await track.load(.timeRange).duration + if duration.isIndefinite { + return TimeInterval.infinity + } + + return duration.seconds + } catch { + Logger.module.error("Failed to load asset timeRange: \(error.localizedDescription)") } } } // Accessing duration or commonMetadata blocks the main-thread if not already loaded // So we first need to check the track status before attempting to access it! - let durationStatus = asset.statusOfValue(forKey: "duration", error: &error) - if durationStatus == .loaded { + let durationStatus = asset.status(of: .duration) + if case .loaded(let duration) = durationStatus { // If it's live/indefinite - if asset.duration.isIndefinite { + if duration.isIndefinite { return TimeInterval.infinity } // If it's a valid duration - if abs(asset.duration.seconds.distance(to: 0.0)) >= tolerance { - return asset.duration.seconds + if abs(duration.seconds.distance(to: 0.0)) >= tolerance { + return duration.seconds } } diff --git a/ios/browser/ui/webui/BUILD.gn b/ios/browser/ui/webui/BUILD.gn index d90b5d1abf52..f4a460623b72 100644 --- a/ios/browser/ui/webui/BUILD.gn +++ b/ios/browser/ui/webui/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2023 The Brave Authors. All rights reserved. +# 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/. @@ -19,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_source.mm b/ios/browser/ui/webui/brave_webui_source.mm index baaa688e9806..31331e18d291 100644 --- a/ios/browser/ui/webui/brave_webui_source.mm +++ b/ios/browser/ui/webui/brave_webui_source.mm @@ -12,6 +12,7 @@ #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" @@ -36,7 +37,7 @@ void CustomizeWebUIHTMLSource(web::WebUIIOS* web_ui, size_t resource_map_size, int html_resource_id, bool disable_trusted_types_csp) { - web::WebUIIOSDataSource* source = web::WebUIIOSDataSource::Create(name); + web::WebUIIOSDataSource* source = BraveWebUIIOSDataSource::Create(name); web::WebUIIOSDataSource::Add(ProfileIOS::FromWebUIIOS(web_ui), source); source->UseStringsJs(); 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/brave_url_data_source_ios.h b/ios/browser/ui/webui/public/brave_url_data_source_ios.h new file mode 100644 index 000000000000..765fdd34f14b --- /dev/null +++ b/ios/browser/ui/webui/public/brave_url_data_source_ios.h @@ -0,0 +1,30 @@ +// 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_URL_DATA_SOURCE_IOS_H_ +#define BRAVE_IOS_BROWSER_UI_WEBUI_PUBLIC_BRAVE_URL_DATA_SOURCE_IOS_H_ + +#include + +#include "ios/web/public/webui/url_data_source_ios.h" +#include "services/network/public/mojom/content_security_policy.mojom.h" + +class BraveURLDataSourceIOS : public web::URLDataSourceIOS { + public: + BraveURLDataSourceIOS(); + ~BraveURLDataSourceIOS() override; + + virtual std::string GetContentSecurityPolicy( + network::mojom::CSPDirectiveName directive) const; + + private: + std::string GetContentSecurityPolicyObjectSrc() const override; + std::string GetContentSecurityPolicyFrameSrc() const override; + + // Brave CSP's & Security variables: + base::flat_map csp_overrides_; +}; + +#endif // BRAVE_IOS_BROWSER_UI_WEBUI_PUBLIC_BRAVE_URL_DATA_SOURCE_IOS_H_ diff --git a/ios/browser/ui/webui/public/brave_url_data_source_ios.mm b/ios/browser/ui/webui/public/brave_url_data_source_ios.mm new file mode 100644 index 000000000000..a6733bc6569a --- /dev/null +++ b/ios/browser/ui/webui/public/brave_url_data_source_ios.mm @@ -0,0 +1,135 @@ +// 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_url_data_source_ios.h" + +#include "base/no_destructor.h" +#include "base/strings/strcat.h" +#include "ios/components/webui/web_ui_url_constants.h" + +namespace { + +// A chrome-untrusted data source's name starts with chrome-untrusted://. +bool IsChromeUntrustedDataSource(const web::URLDataSourceIOS* source) { + static const base::NoDestructor kChromeUntrustedSourceNamePrefix( + base::StrCat({kChromeUIUntrustedScheme, url::kStandardSchemeSeparator})); + + return base::StartsWith(source->GetSource(), + *kChromeUntrustedSourceNamePrefix, + base::CompareCase::SENSITIVE); +} + +} // namespace + +BraveURLDataSourceIOS::BraveURLDataSourceIOS() {} +BraveURLDataSourceIOS::~BraveURLDataSourceIOS() = default; + +std::string BraveURLDataSourceIOS::GetContentSecurityPolicyObjectSrc() const { + std::string csp_header; + + // Same as on Desktop + // content/browser/webui/url_data_manager_backend.cc + 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)); + } + + // Add the iOS default frame-src + csp_header.append(GetContentSecurityPolicyFrameSrc()); + + return csp_header; +} + +std::string BraveURLDataSourceIOS::GetContentSecurityPolicyFrameSrc() const { + std::string frame_src = + GetContentSecurityPolicy(network::mojom::CSPDirectiveName::FrameSrc); + if (!frame_src.empty()) { + return frame_src; + } + + // The default for iOS in url_data_manager_ios_backend.mm + return "frame-src 'none';"; +} + +std::string BraveURLDataSourceIOS::GetContentSecurityPolicy( + network::mojom::CSPDirectiveName directive) const { + // Default policies matching Chromium Desktop + // content/public/browser/url_data_source.cc + switch (directive) { + case network::mojom::CSPDirectiveName::ChildSrc: + return "child-src 'none';"; + case network::mojom::CSPDirectiveName::DefaultSrc: + return IsChromeUntrustedDataSource(this) ? "default-src 'self';" + : std::string(); + case network::mojom::CSPDirectiveName::ObjectSrc: + return "object-src 'none';"; + case network::mojom::CSPDirectiveName::ScriptSrc: + // Note: Do not add 'unsafe-eval' here. Instead override CSP for the + // specific pages that need it, see context http://crbug.com/525224. + return IsChromeUntrustedDataSource(this) + ? base::StrCat({"script-src", kChromeUIUntrustedScheme, + url::kStandardSchemeSeparator, + "resources 'self';"}) + : "script-src chrome://resources 'self';"; + case network::mojom::CSPDirectiveName::FrameAncestors: + return "frame-ancestors 'none';"; + case network::mojom::CSPDirectiveName::RequireTrustedTypesFor: + return "require-trusted-types-for 'script';"; + case network::mojom::CSPDirectiveName::TrustedTypes: + return "trusted-types;"; + case network::mojom::CSPDirectiveName::BaseURI: + return IsChromeUntrustedDataSource(this) ? "base-uri 'none';" + : std::string(); + case network::mojom::CSPDirectiveName::FormAction: + return IsChromeUntrustedDataSource(this) ? "form-action 'none';" + : std::string(); + case network::mojom::CSPDirectiveName::BlockAllMixedContent: + case network::mojom::CSPDirectiveName::ConnectSrc: + case network::mojom::CSPDirectiveName::FencedFrameSrc: + case network::mojom::CSPDirectiveName::FrameSrc: + case network::mojom::CSPDirectiveName::FontSrc: + case network::mojom::CSPDirectiveName::ImgSrc: + case network::mojom::CSPDirectiveName::ManifestSrc: + case network::mojom::CSPDirectiveName::MediaSrc: + case network::mojom::CSPDirectiveName::ReportURI: + case network::mojom::CSPDirectiveName::Sandbox: + case network::mojom::CSPDirectiveName::ScriptSrcAttr: + case network::mojom::CSPDirectiveName::ScriptSrcElem: + case network::mojom::CSPDirectiveName::StyleSrc: + case network::mojom::CSPDirectiveName::StyleSrcAttr: + case network::mojom::CSPDirectiveName::StyleSrcElem: + case network::mojom::CSPDirectiveName::UpgradeInsecureRequests: + case network::mojom::CSPDirectiveName::TreatAsPublicAddress: + case network::mojom::CSPDirectiveName::WorkerSrc: + case network::mojom::CSPDirectiveName::ReportTo: + case network::mojom::CSPDirectiveName::Unknown: + return std::string(); + } +} 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()); +}