// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/ui/webui/about_ui.h" #include #include #include #include #include #include #include #include "base/bind.h" #include "base/callback.h" #include "base/callback_helpers.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/format_macros.h" #include "base/memory/ref_counted_memory.h" #include "base/strings/escape.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/task/thread_pool.h" #include "base/threading/scoped_blocking_call.h" #include "base/threading/thread.h" #include "base/values.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/about_flags.h" #include "chrome/browser/ash/borealis/borealis_credits.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/url_constants.h" #include "chrome/grit/browser_resources.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "components/about_ui/credit_utils.h" #include "components/grit/components_resources.h" #include "components/strings/grit/components_locale_settings.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/url_data_source.h" #include "content/public/browser/web_contents.h" #include "net/base/filename_util.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/webui/web_ui_util.h" #include "url/gurl.h" #if !BUILDFLAG(IS_ANDROID) #include "chrome/browser/ui/webui/theme_source.h" #endif #if BUILDFLAG(IS_CHROMEOS_ASH) #include #include "base/base64.h" #include "base/cxx17_backports.h" #include "base/strings/strcat.h" #include "chrome/browser/ash/crosapi/browser_manager.h" #include "chrome/browser/ash/crosapi/browser_util.h" #include "chrome/browser/ash/crostini/crostini_features.h" #include "chrome/browser/ash/crostini/crostini_manager.h" #include "chrome/browser/ash/customization/customization_document.h" #include "chrome/browser/ash/login/demo_mode/demo_setup_controller.h" #include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/browser_process_platform_part_ash.h" #include "chrome/browser/component_updater/cros_component_manager.h" #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" #include "chrome/common/webui_url_constants.h" #include "chromeos/system/statistics_provider.h" #include "components/language/core/common/locale_util.h" #include "third_party/cros_system_api/dbus/service_constants.h" #endif #if BUILDFLAG(IS_CHROMEOS_LACROS) #include "chrome/browser/lacros/lacros_url_handling.h" #endif // BUILDFLAG(IS_CHROMEOS_LACROS) #if BUILDFLAG(IS_CHROMEOS) #include "chrome/common/webui_url_constants.h" #include "ui/base/l10n/l10n_util.h" #endif // BUILDFLAG(IS_CHROMEOS) using content::BrowserThread; namespace { constexpr char kCreditsJsPath[] = "credits.js"; constexpr char kCreditsCssPath[] = "credits.css"; constexpr char kStatsJsPath[] = "stats.js"; constexpr char kStringsJsPath[] = "strings.js"; #if BUILDFLAG(IS_CHROMEOS_ASH) constexpr char kKeyboardUtilsPath[] = "keyboard_utils.js"; constexpr char kTerminaCreditsPath[] = "about_os_credits.html"; // APAC region name. constexpr char kApac[] = "apac"; // EMEA region name. constexpr char kEmea[] = "emea"; // EU region name. constexpr char kEu[] = "eu"; // List of countries that belong to APAC. const char* const kApacCountries[] = {"au", "bd", "cn", "hk", "id", "in", "jp", "kh", "la", "lk", "mm", "mn", "my", "nz", "np", "ph", "sg", "th", "tw", "vn"}; // List of countries that belong to EMEA. const char* const kEmeaCountries[] = {"na", "za", "am", "az", "ch", "eg", "ge", "il", "is", "ke", "kg", "li", "mk", "no", "rs", "ru", "tr", "tz", "ua", "ug", "za"}; // List of countries that belong to EU. const char* const kEuCountries[] = { "at", "be", "bg", "cz", "dk", "es", "fi", "fr", "gb", "gr", "hr", "hu", "ie", "it", "lt", "lu", "lv", "nl", "pl", "pt", "ro", "se", "si", "sk"}; // Maps country to one of 3 regions: APAC, EMEA, EU. typedef std::map CountryRegionMap; // Returns country to region map with EU, EMEA and APAC countries. CountryRegionMap CreateCountryRegionMap() { CountryRegionMap region_map; for (size_t i = 0; i < std::size(kApacCountries); ++i) { region_map.emplace(kApacCountries[i], kApac); } for (size_t i = 0; i < std::size(kEmeaCountries); ++i) { region_map.emplace(kEmeaCountries[i], kEmea); } for (size_t i = 0; i < std::size(kEuCountries); ++i) { region_map.emplace(kEuCountries[i], kEu); } return region_map; } // Reads device region from VPD. Returns "us" in case of read or parsing errors. std::string ReadDeviceRegionFromVpd() { std::string region = "us"; chromeos::system::StatisticsProvider* provider = chromeos::system::StatisticsProvider::GetInstance(); bool region_found = provider->GetMachineStatistic(chromeos::system::kRegionKey, ®ion); if (region_found) { // We only need the first part of the complex region codes like ca.ansi. std::vector region_pieces = base::SplitString( region, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); if (!region_pieces.empty()) region = region_pieces[0]; } else { LOG(WARNING) << "Device region for Play Store ToS not found in VPD - " "defaulting to US."; } return base::ToLowerASCII(region); } // Loads bundled terms of service contents (Eula, OEM Eula, Play Store Terms). // The online version of terms is fetched in OOBE screen javascript. This is // intentional because chrome://terms runs in a privileged webui context and // should never load from untrusted places. class ChromeOSTermsHandler : public base::RefCountedThreadSafe { public: ChromeOSTermsHandler(const ChromeOSTermsHandler&) = delete; ChromeOSTermsHandler& operator=(const ChromeOSTermsHandler&) = delete; static void Start(const std::string& path, content::URLDataSource::GotDataCallback callback) { scoped_refptr handler( new ChromeOSTermsHandler(path, std::move(callback))); handler->StartOnUIThread(); } private: friend class base::RefCountedThreadSafe; ChromeOSTermsHandler(const std::string& path, content::URLDataSource::GotDataCallback callback) : path_(path), callback_(std::move(callback)), // Previously we were using "initial locale" http://crbug.com/145142 locale_(g_browser_process->GetApplicationLocale()) {} virtual ~ChromeOSTermsHandler() {} void StartOnUIThread() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (path_ == chrome::kOemEulaURLPath) { // Load local OEM EULA from the disk. base::ThreadPool::PostTaskAndReply( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, base::BindOnce(&ChromeOSTermsHandler::LoadOemEulaFileAsync, this), base::BindOnce(&ChromeOSTermsHandler::ResponseOnUIThread, this)); } else if (path_ == chrome::kArcTermsURLPath) { LOG(WARNING) << "Could not load offline Play Store ToS."; } else if (path_ == chrome::kArcPrivacyPolicyURLPath) { LOG(WARNING) << "Could not load offline Play Store privacy policy."; } else { NOTREACHED(); ResponseOnUIThread(); } } void LoadOemEulaFileAsync() { base::ScopedBlockingCall scoped_blocking_call( FROM_HERE, base::BlockingType::MAY_BLOCK); const ash::StartupCustomizationDocument* customization = ash::StartupCustomizationDocument::GetInstance(); if (!customization->IsReady()) return; base::FilePath oem_eula_file_path; if (net::FileURLToFilePath(GURL(customization->GetEULAPage(locale_)), &oem_eula_file_path)) { if (!base::ReadFileToString(oem_eula_file_path, &contents_)) { contents_.clear(); } } } std::vector CreateArcLocaleLookupArray() { // To get Play Store asset we look for the first locale match in the // following order: // * language and device region combination // * default region (APAC, EMEA, EU) // * en-US // Note: AMERICAS region defaults to en-US and to simplify it is not // included in the country region map. std::vector locale_lookup_array; const std::string device_region = ReadDeviceRegionFromVpd(); locale_lookup_array.push_back(base::StrCat( {base::ToLowerASCII(language::ExtractBaseLanguage(locale_)), "-", device_region})); const CountryRegionMap country_region_map = CreateCountryRegionMap(); const auto region = country_region_map.find(device_region); if (region != country_region_map.end()) { locale_lookup_array.push_back(region->second.c_str()); } locale_lookup_array.push_back("en-us"); return locale_lookup_array; } void ResponseOnUIThread() { DCHECK_CURRENTLY_ON(BrowserThread::UI); // If we fail to load Chrome OS EULA from disk, load it from resources. // Do nothing if OEM EULA or Play Store ToS load failed. if (contents_.empty() && path_.empty()) { contents_ = ui::ResourceBundle::GetSharedInstance().LoadLocalizedResourceString( IDS_TERMS_HTML); } std::move(callback_).Run( base::RefCountedString::TakeString(std::move(contents_))); } // Path in the URL. const std::string path_; // Callback to run with the response. content::URLDataSource::GotDataCallback callback_; // Locale of the EULA. const std::string locale_; // EULA contents that was loaded from file. std::string contents_; }; class ChromeOSCreditsHandler : public base::RefCountedThreadSafe { public: ChromeOSCreditsHandler(const ChromeOSCreditsHandler&) = delete; ChromeOSCreditsHandler& operator=(const ChromeOSCreditsHandler&) = delete; static void Start(const std::string& path, content::URLDataSource::GotDataCallback callback) { scoped_refptr handler( new ChromeOSCreditsHandler(path, std::move(callback))); handler->StartOnUIThread(); } private: friend class base::RefCountedThreadSafe; ChromeOSCreditsHandler(const std::string& path, content::URLDataSource::GotDataCallback callback) : path_(path), callback_(std::move(callback)) {} virtual ~ChromeOSCreditsHandler() {} void StartOnUIThread() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (path_ == kKeyboardUtilsPath) { contents_ = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( IDR_KEYBOARD_UTILS_JS); ResponseOnUIThread(); return; } // Load local Chrome OS credits from the disk. base::ThreadPool::PostTaskAndReply( FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, base::BindOnce(&ChromeOSCreditsHandler::LoadCreditsFileAsync, this), base::BindOnce(&ChromeOSCreditsHandler::ResponseOnUIThread, this)); } void LoadCreditsFileAsync() { base::FilePath credits_file_path(chrome::kChromeOSCreditsPath); if (!base::ReadFileToString(credits_file_path, &contents_)) { // File with credits not found, ResponseOnUIThread will load credits // from resources if contents_ is empty. contents_.clear(); } } void ResponseOnUIThread() { DCHECK_CURRENTLY_ON(BrowserThread::UI); // If we fail to load Chrome OS credits from disk, load it from resources. if (contents_.empty() && path_ != kKeyboardUtilsPath) { contents_ = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( IDR_OS_CREDITS_HTML); } std::move(callback_).Run( base::RefCountedString::TakeString(std::move(contents_))); } // Path in the URL. const std::string path_; // Callback to run with the response. content::URLDataSource::GotDataCallback callback_; // Chrome OS credits contents that was loaded from file. std::string contents_; }; void OnBorealisCreditsLoaded(content::URLDataSource::GotDataCallback callback, std::string credits_html) { if (credits_html.empty()) { credits_html = l10n_util::GetStringUTF8(IDS_BOREALIS_CREDITS_PLACEHOLDER); } std::move(callback).Run( base::RefCountedString::TakeString(std::move(credits_html))); } void HandleBorealisCredits(Profile* profile, content::URLDataSource::GotDataCallback callback) { borealis::LoadBorealisCredits( profile, base::BindOnce(&OnBorealisCreditsLoaded, std::move(callback))); } class CrostiniCreditsHandler : public base::RefCountedThreadSafe { public: CrostiniCreditsHandler(const CrostiniCreditsHandler&) = delete; CrostiniCreditsHandler& operator=(const CrostiniCreditsHandler&) = delete; static void Start(Profile* profile, const std::string& path, content::URLDataSource::GotDataCallback callback) { scoped_refptr handler( new CrostiniCreditsHandler(profile, path, std::move(callback))); handler->StartOnUIThread(); } private: friend class base::RefCountedThreadSafe; CrostiniCreditsHandler(Profile* profile, const std::string& path, content::URLDataSource::GotDataCallback callback) : path_(path), callback_(std::move(callback)), profile_(profile) {} virtual ~CrostiniCreditsHandler() {} void StartOnUIThread() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (path_ == kKeyboardUtilsPath) { contents_ = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( IDR_KEYBOARD_UTILS_JS); RespondOnUIThread(); return; } if (crostini::CrostiniFeatures::Get()->IsAllowedNow(profile_)) { crostini::CrostiniManager::GetForProfile(profile_)->GetInstallLocation( base::BindOnce(&CrostiniCreditsHandler::LoadCredits, this)); } else { RespondWithPlaceholder(); } } void LoadCredits(base::FilePath path) { if (path.empty()) { RespondWithPlaceholder(); return; } // Load crostini credits from the disk. base::ThreadPool::PostTaskAndReply( FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, base::BindOnce(&CrostiniCreditsHandler::LoadCrostiniCreditsFileAsync, this, path.Append(kTerminaCreditsPath)), base::BindOnce(&CrostiniCreditsHandler::RespondOnUIThread, this)); } void LoadCrostiniCreditsFileAsync(base::FilePath credits_file_path) { if (!base::ReadFileToString(credits_file_path, &contents_)) { // File with credits not found, RespondOnUIThread will load a placeholder // if contents_ is empty. contents_.clear(); } } void RespondWithPlaceholder() { contents_.clear(); RespondOnUIThread(); } void RespondOnUIThread() { DCHECK_CURRENTLY_ON(BrowserThread::UI); // If we fail to load Linux credits from disk, use the placeholder. if (contents_.empty() && path_ != kKeyboardUtilsPath) { contents_ = l10n_util::GetStringUTF8(IDS_CROSTINI_CREDITS_PLACEHOLDER); } std::move(callback_).Run( base::RefCountedString::TakeString(std::move(contents_))); } // Path in the URL. const std::string path_; // Callback to run with the response. content::URLDataSource::GotDataCallback callback_; // Linux credits contents that was loaded from file. std::string contents_; Profile* profile_; }; #endif } // namespace // Individual about handlers --------------------------------------------------- namespace about_ui { void AppendHeader(std::string* output, const std::string& unescaped_title) { output->append("\n\n\n"); output->append("\n"); output->append("\n"); if (!unescaped_title.empty()) { output->append(""); output->append(base::EscapeForHTML(unescaped_title)); output->append("\n"); } } #if BUILDFLAG(IS_CHROMEOS) // This function returns true if Lacros is the primary browser - or if the // calling browser is Lacros. bool isLacrosPrimaryOrCurrentBrowser() { #if BUILDFLAG(IS_CHROMEOS_ASH) return crosapi::browser_util::IsLacrosPrimaryBrowser(); #else return true; #endif } void AppendBody(std::string* output) { if (isLacrosPrimaryOrCurrentBrowser()) { output->append( "\n" "\n\n" "\n"); } else { output->append("\n\n"); } } void AppendFooter(std::string* output) { if (isLacrosPrimaryOrCurrentBrowser()) { output->append( "\n"); } output->append("\n\n"); } #else // BUILDFLAG(IS_CHROMEOS) void AppendBody(std::string *output) { output->append("\n\n"); } void AppendFooter(std::string *output) { output->append("\n\n"); } #endif // BUILDFLAG(IS_CHROMEOS) } // namespace about_ui using about_ui::AppendHeader; using about_ui::AppendBody; using about_ui::AppendFooter; namespace { std::string ChromeURLs() { std::string html; AppendHeader(&html, "Chrome URLs"); AppendBody(&html); html += "

List of Chrome URLs

\n
    \n"; std::vector hosts( chrome::kChromeHostURLs, chrome::kChromeHostURLs + chrome::kNumberOfChromeHostURLs); std::sort(hosts.begin(), hosts.end()); #if BUILDFLAG(IS_CHROMEOS_ASH) const bool is_lacros_primary = about_ui::isLacrosPrimaryOrCurrentBrowser(); // If Lacros is active, the user can navigate by hand to os:// URL's but // internally we will still navigate to chrome:// URL's. Note also that // only a subset of URLs might be available in this mode - so we have to // make sure that only allowed URLs are being presented. if (is_lacros_primary) { auto* WebUiControllerFactory = ChromeWebUIControllerFactory::GetInstance(); for (const std::string& host : hosts) { // TODO(crbug/1271718): The refactor should make sure that the provided // list can be shown as is without filtering. if (WebUiControllerFactory->CanHandleUrl(GURL("os://" + host)) || WebUiControllerFactory->CanHandleUrl(GURL("chrome://" + host))) { html += "
  • os://" + host + "
  • \n"; } } } else { #else { #endif // BUILDFLAG(IS_CHROMEOS_ASH) for (const std::string& host : hosts) { html += "
  • chrome://" + host + "
  • \n"; } html += "

List of chrome://internals " "pages

\n
    \n"; std::vector internals_paths( chrome::kChromeInternalsPathURLs, chrome::kChromeInternalsPathURLs + chrome::kNumberOfChromeInternalsPathURLs); std::sort(internals_paths.begin(), internals_paths.end()); for (const std::string& path : internals_paths) { html += "
  • chrome://internals/" + path + "
  • \n"; } } html += "
\n

For Debug

\n" "

The following pages are for debugging purposes only. Because they " "crash or hang the renderer, they're not linked directly; you can type " "them into the address bar if you need them.

\n
    "; #if BUILDFLAG(IS_CHROMEOS_ASH) // If Lacros is active, the user can navigate by hand to os:// URL's but // internally we will still navigate to chrome:// URL's. Note also that // only a subset of URLs might be available in this mode - so we have to // make sure that only allowed URLs are being presented. if (is_lacros_primary) { auto* WebUiControllerFactory = ChromeWebUIControllerFactory::GetInstance(); for (size_t i = 0; i < chrome::kNumberOfChromeDebugURLs; i++) { // TODO(crbug/1271718): The refactor should make sure that the provided // list can be shown as is without filtering. const std::string host = GURL(chrome::kChromeDebugURLs[i]).host(); if (WebUiControllerFactory->CanHandleUrl(GURL("os://" + host)) || WebUiControllerFactory->CanHandleUrl(GURL("chrome://" + host))) { html += "
  • os://" + host + "
  • \n"; } } } else { #else { #endif // BUILDFLAG(IS_CHROMEOS_ASH) for (size_t i = 0; i < chrome::kNumberOfChromeDebugURLs; i++) html += "
  • " + std::string(chrome::kChromeDebugURLs[i]) + "
  • \n"; } html += "
\n"; AppendFooter(&html); return html; } #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OPENBSD) std::string AboutLinuxProxyConfig() { std::string data; AppendHeader(&data, l10n_util::GetStringUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE)); data.append(""); AppendBody(&data); base::FilePath binary = base::CommandLine::ForCurrentProcess()->GetProgram(); data.append( l10n_util::GetStringFUTF8(IDS_ABOUT_LINUX_PROXY_CONFIG_BODY, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), base::ASCIIToUTF16(binary.BaseName().value()))); AppendFooter(&data); return data; } #endif } // namespace // AboutUIHTMLSource ---------------------------------------------------------- AboutUIHTMLSource::AboutUIHTMLSource(const std::string& source_name, Profile* profile) : source_name_(source_name), profile_(profile) {} AboutUIHTMLSource::~AboutUIHTMLSource() {} std::string AboutUIHTMLSource::GetSource() { return source_name_; } void AboutUIHTMLSource::StartDataRequest( const GURL& url, const content::WebContents::Getter& wc_getter, content::URLDataSource::GotDataCallback callback) { // TODO(crbug/1009127): Simplify usages of |path| since |url| is available. const std::string path = content::URLDataSource::URLToRequestPath(url); std::string response; // Add your data source here, in alphabetical order. if (source_name_ == chrome::kChromeUIChromeURLsHost) { response = ChromeURLs(); } else if (source_name_ == chrome::kChromeUICreditsHost) { int idr = IDR_ABOUT_UI_CREDITS_HTML; if (path == kCreditsJsPath) idr = IDR_ABOUT_UI_CREDITS_JS; else if (path == kCreditsCssPath) idr = IDR_ABOUT_UI_CREDITS_CSS; #if BUILDFLAG(IS_CHROMEOS_ASH) else if (path == kKeyboardUtilsPath) idr = IDR_KEYBOARD_UTILS_JS; #endif if (idr == IDR_ABOUT_UI_CREDITS_HTML) { response = about_ui::GetCredits(true /*include_scripts*/); } else { response = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(idr); } #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OPENBSD) } else if (source_name_ == chrome::kChromeUILinuxProxyConfigHost) { response = AboutLinuxProxyConfig(); #endif #if BUILDFLAG(IS_CHROMEOS_ASH) } else if (source_name_ == chrome::kChromeUIOSCreditsHost) { ChromeOSCreditsHandler::Start(path, std::move(callback)); return; } else if (source_name_ == chrome::kChromeUICrostiniCreditsHost) { CrostiniCreditsHandler::Start(profile(), path, std::move(callback)); return; } else if (source_name_ == chrome::kChromeUIBorealisCreditsHost) { HandleBorealisCredits(profile(), std::move(callback)); return; #endif #if !BUILDFLAG(IS_ANDROID) } else if (source_name_ == chrome::kChromeUITermsHost) { #if BUILDFLAG(IS_CHROMEOS_ASH) if (!path.empty()) { ChromeOSTermsHandler::Start(path, std::move(callback)); return; } #endif response = ui::ResourceBundle::GetSharedInstance().LoadLocalizedResourceString( IDS_TERMS_HTML); #endif } FinishDataRequest(response, std::move(callback)); } void AboutUIHTMLSource::FinishDataRequest( const std::string& html, content::URLDataSource::GotDataCallback callback) { std::string html_copy(html); std::move(callback).Run( base::RefCountedString::TakeString(std::move(html_copy))); } std::string AboutUIHTMLSource::GetMimeType(const std::string& path) { if (path == kCreditsJsPath || #if BUILDFLAG(IS_CHROMEOS_ASH) path == kKeyboardUtilsPath || #endif path == kStatsJsPath || path == kStringsJsPath) { return "application/javascript"; } if (path == kCreditsCssPath) { return "text/css"; } return "text/html"; } bool AboutUIHTMLSource::ShouldAddContentSecurityPolicy() { #if BUILDFLAG(IS_CHROMEOS_ASH) if (source_name_ == chrome::kChromeUIOSCreditsHost || source_name_ == chrome::kChromeUICrostiniCreditsHost || source_name_ == chrome::kChromeUIBorealisCreditsHost) { return false; } #endif return content::URLDataSource::ShouldAddContentSecurityPolicy(); } std::string AboutUIHTMLSource::GetAccessControlAllowOriginForOrigin( const std::string& origin) { #if BUILDFLAG(IS_CHROMEOS_ASH) // Allow chrome://oobe to load chrome://terms via XHR. if (source_name_ == chrome::kChromeUITermsHost && base::StartsWith(chrome::kChromeUIOobeURL, origin, base::CompareCase::SENSITIVE)) { return origin; } #endif return content::URLDataSource::GetAccessControlAllowOriginForOrigin(origin); } AboutUI::AboutUI(content::WebUI* web_ui, const std::string& name) : WebUIController(web_ui) { Profile* profile = Profile::FromWebUI(web_ui); #if !BUILDFLAG(IS_ANDROID) // Set up the chrome://theme/ source. content::URLDataSource::Add(profile, std::make_unique(profile)); #endif content::URLDataSource::Add( profile, std::make_unique(name, profile)); } #if BUILDFLAG(IS_CHROMEOS) bool AboutUI::OverrideHandleWebUIMessage(const GURL& source_url, const std::string& message, const base::Value::List& args) { if (message != "crosUrlAboutRedirect") return false; #if BUILDFLAG(IS_CHROMEOS_LACROS) lacros_url_handling::NavigateInAsh(GURL(chrome::kOsUIAboutURL)); #else // Note: This will only be called by the UI when Lacros is available. DCHECK(crosapi::BrowserManager::Get()); crosapi::BrowserManager::Get()->SwitchToTab( GURL(chrome::kChromeUIAboutURL), /*path_behavior=*/NavigateParams::RESPECT); #endif return true; } #endif // BUILDFLAG(IS_CHROMEOS)