// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/enterprise/incognito_navigation_throttle.h"
#include "base/i18n/message_formatter.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/browser_resources.h"
#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/jstemplate_builder.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/chromeos/strings/grit/ui_chromeos_strings.h"
namespace chromeos {
namespace {
std::string GetIncognitoNavigationBlockedErrorPage(
base::Value::List blocking_extension,
base::Value::List missing_extension) {
auto strings =
base::Value::Dict()
.Set("incognitoBlockedPageTitle",
l10n_util::GetPluralStringFUTF16(
IDS_INCOGNITO_NAVIGATION_BLOCKED_PAGE_TITLE,
blocking_extension.size()))
.Set("incognitoBlockedMessage",
l10n_util::GetPluralStringFUTF16(
IDS_INCOGNITO_NAVIGATION_MESSAGE, blocking_extension.size()))
.Set("incognitoBlockedInstructions",
l10n_util::GetStringUTF16(IDS_INCOGNITO_NAVIGATION_INSTRUCTIONS))
.Set("incognitoBlockedInstructionsStep1",
l10n_util::GetStringUTF16(
IDS_INCOGNITO_NAVIGATION_INSTRUCTIONS_STEP_1))
.Set("incognitoBlockedInstructionsStep2",
l10n_util::GetStringUTF16(
IDS_INCOGNITO_NAVIGATION_INSTRUCTIONS_STEP_2))
.Set("incognitoBlockedInstructionsStep3",
l10n_util::GetStringUTF16(
IDS_INCOGNITO_NAVIGATION_INSTRUCTIONS_STEP_3))
.Set("incognitoBlockedInstructionsStep4",
l10n_util::GetStringUTF16(
IDS_INCOGNITO_NAVIGATION_INSTRUCTIONS_STEP_4))
.Set("incognitoBlockedMissingExtensionsTitle",
l10n_util::GetPluralStringFUTF16(
IDS_INCOGNITO_NAVIGATION_MISSING_TITLE,
missing_extension.size()))
.Set("incognitoBlockedMissingExtensionsMessage",
l10n_util::GetPluralStringFUTF16(
IDS_INCOGNITO_NAVIGATION_MISSING_EXTENSIONS,
missing_extension.size()))
.Set("blockingExtensions", std::move(blocking_extension))
.Set("missingExtensions", std::move(missing_extension));
std::string html =
ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
IDR_INCOGNITO_NAVIGATION_BLOCKED_PAGE_HTML);
const std::string& app_locale = g_browser_process->GetApplicationLocale();
webui::SetLoadTimeDataDefaults(app_locale, &strings);
return webui::GetI18nTemplateHtml(html, strings);
}
} // namespace
// static
std::unique_ptr<IncognitoNavigationThrottle>
IncognitoNavigationThrottle::MaybeCreateThrottleFor(
content::NavigationHandle* navigation_handle) {
content::BrowserContext* browser_context =
navigation_handle->GetWebContents()->GetBrowserContext();
Profile* profile = Profile::FromBrowserContext(browser_context);
if (!profile->IsIncognitoProfile()) {
return nullptr;
}
const base::Value::List& mandatory_extensions = profile->GetPrefs()->GetList(
prefs::kMandatoryExtensionsForIncognitoNavigation);
if (mandatory_extensions.empty()) {
return nullptr;
}
return std::make_unique<IncognitoNavigationThrottle>(navigation_handle,
profile);
}
IncognitoNavigationThrottle::IncognitoNavigationThrottle(
content::NavigationHandle* navigation_handle,
Profile* profile)
: content::NavigationThrottle(navigation_handle), profile_(profile) {}
IncognitoNavigationThrottle::~IncognitoNavigationThrottle() = default;
content::NavigationThrottle::ThrottleCheckResult
IncognitoNavigationThrottle::WillStartRequest() {
ReadMandatoryExtensionsStatus();
if (blocking_extensions_.empty() && missing_extensions_.empty()) {
return content::NavigationThrottle::PROCEED;
}
return ThrottleCheckResult(
content::NavigationThrottle::CANCEL, net::ERR_BLOCKED_BY_ADMINISTRATOR,
GetIncognitoNavigationBlockedErrorPage(std::move(blocking_extensions_),
std::move(missing_extensions_)));
}
content::NavigationThrottle::ThrottleCheckResult
IncognitoNavigationThrottle::WillRedirectRequest() {
return WillStartRequest();
}
const char* IncognitoNavigationThrottle::GetNameForLogging() {
return "IncognitoNavigationThrottle";
}
void IncognitoNavigationThrottle::ReadMandatoryExtensionsStatus() {
DCHECK(profile_);
blocking_extensions_.clear();
missing_extensions_.clear();
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(profile_);
const base::Value::List& mandatory_extensions = profile_->GetPrefs()->GetList(
prefs::kMandatoryExtensionsForIncognitoNavigation);
if (mandatory_extensions.empty()) {
return;
}
for (const auto& val : mandatory_extensions) {
if (!val.is_string()) {
continue;
}
const std::string id = val.GetString();
auto* ext = registry->GetInstalledExtension(id);
if (ext) {
if (!extensions::util::IsIncognitoEnabled(id, profile_)) {
blocking_extensions_.Append(ext->name());
}
} else {
missing_extensions_.Append(id);
}
}
}
} // namespace chromeos