blob: 1f4d0b39f916fadef0491ecd8e2053860bf5be5d [file] [log] [blame]
// 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/ui/safety_hub/extensions_result.h"
#include <algorithm>
#include <memory>
#include <optional>
#include "base/notreached.h"
#include "base/values.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/extensions/extension_management.h"
#include "chrome/browser/extensions/extension_safety_check_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/safety_hub/safety_hub_constants.h"
#include "chrome/browser/ui/safety_hub/safety_hub_result.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/blocklist_extension_prefs.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_prefs_factory.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension_set.h"
#include "ui/base/l10n/l10n_util.h"
namespace developer = extensions::api::developer_private;
SafetyHubExtensionsResult::SafetyHubExtensionsResult(
std::set<extensions::ExtensionId> triggering_extensions,
bool is_unpublished_extensions_only)
: triggering_extensions_(triggering_extensions),
is_unpublished_extensions_only_(is_unpublished_extensions_only) {}
SafetyHubExtensionsResult::SafetyHubExtensionsResult(
const SafetyHubExtensionsResult&) = default;
SafetyHubExtensionsResult& SafetyHubExtensionsResult::operator=(
const SafetyHubExtensionsResult&) = default;
SafetyHubExtensionsResult::~SafetyHubExtensionsResult() = default;
// static
std::optional<std::unique_ptr<SafetyHubResult>>
SafetyHubExtensionsResult::GetResult(Profile* profile,
bool only_unpublished_extensions = false) {
extensions::ExtensionRegistry* extension_registry =
extensions::ExtensionRegistry::Get(profile);
std::set<extensions::ExtensionId> triggering_extensions;
const extensions::ExtensionSet all_installed_extensions =
extension_registry->GenerateInstalledExtensionsSet();
// If `only_unpublished_extensions` is true, GetSafetyCheckWarningReason
// will ignore other extension warning types and only consider
// unpublished extensions.
for (const auto& extension : all_installed_extensions) {
developer::SafetyCheckWarningReason warning_reason =
extensions::ExtensionSafetyCheckUtils::GetSafetyCheckWarningReason(
*extension.get(), profile, only_unpublished_extensions);
if (warning_reason != developer::SafetyCheckWarningReason::kNone) {
triggering_extensions.insert(std::move(extension->id()));
}
}
return std::make_unique<SafetyHubExtensionsResult>(
triggering_extensions, only_unpublished_extensions);
}
std::unique_ptr<SafetyHubResult> SafetyHubExtensionsResult::Clone() const {
return std::make_unique<SafetyHubExtensionsResult>(*this);
}
void SafetyHubExtensionsResult::OnExtensionPrefsUpdated(
const std::string& extension_id,
Profile* profile) {
auto extension_ptr = triggering_extensions_.find(extension_id);
if (extension_ptr != triggering_extensions_.end()) {
extensions::ExtensionRegistry* extension_registry =
extensions::ExtensionRegistry::Get(profile);
const extensions::Extension* extension =
extension_registry->GetExtensionById(
extension_id, extensions::ExtensionRegistry::EVERYTHING);
// If the extension is NULL it has been uninstalled and should be
// removed from `triggering_extensions_`.
if (!extension) {
triggering_extensions_.erase(extension_ptr);
return;
}
developer::SafetyCheckWarningReason warning_reason =
extensions::ExtensionSafetyCheckUtils::GetSafetyCheckWarningReason(
*extension, profile);
if (warning_reason == developer::SafetyCheckWarningReason::kNone) {
triggering_extensions_.erase(extension_ptr);
}
}
}
void SafetyHubExtensionsResult::OnExtensionUninstalled(
content::BrowserContext* browser_context,
const extensions::Extension* extension,
extensions::UninstallReason reason) {
auto extension_ptr = triggering_extensions_.find(extension->id());
if (extension_ptr != triggering_extensions_.end()) {
triggering_extensions_.erase(extension_ptr);
}
}
base::Value::Dict SafetyHubExtensionsResult::ToDictValue() const {
// Only results that contain extensions that have been unpublished for a long
// time should be serialized.
CHECK(is_unpublished_extensions_only_);
base::Value::Dict result = BaseToDictValue();
base::Value::List extensions_list;
for (const auto& triggering_extension : triggering_extensions_) {
extensions_list.Append(triggering_extension);
}
result.Set(safety_hub::kSafetyHubTriggeringExtensionIdsKey,
std::move(extensions_list));
return result;
}
bool SafetyHubExtensionsResult::IsTriggerForMenuNotification() const {
// Only results that have unpublished extensions can result in a menu
// notification.
return is_unpublished_extensions_only_ && !triggering_extensions_.empty();
}
unsigned int SafetyHubExtensionsResult::GetNumTriggeringExtensions() const {
return triggering_extensions_.size();
}
bool SafetyHubExtensionsResult::WarrantsNewMenuNotification(
const base::Value::Dict& previous_result_dict) const {
std::set<extensions::ExtensionId> previous_triggering_extensions;
for (const base::Value& extension_id : *previous_result_dict.FindList(
safety_hub::kSafetyHubTriggeringExtensionIdsKey)) {
previous_triggering_extensions.insert(extension_id.GetString());
}
// Only results that are for unpublished extensions can result in a menu
// notification.
if (!is_unpublished_extensions_only_) {
return false;
}
return !std::ranges::includes(previous_triggering_extensions,
triggering_extensions_);
}
std::u16string SafetyHubExtensionsResult::GetNotificationString() const {
CHECK(is_unpublished_extensions_only_);
return l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_HUB_EXTENSIONS_MENU_NOTIFICATION,
triggering_extensions_.size());
}
int SafetyHubExtensionsResult::GetNotificationCommandId() const {
CHECK(is_unpublished_extensions_only_);
return IDC_SAFETY_HUB_MANAGE_EXTENSIONS;
}
void SafetyHubExtensionsResult::ClearTriggeringExtensionsForTesting() {
triggering_extensions_.clear();
}
void SafetyHubExtensionsResult::SetTriggeringExtensionForTesting(
std::string extension_id) {
triggering_extensions_.insert(extension_id);
}