blob: a61ab87b1c52652afc066b020ceb4456dc668121 [file] [log] [blame]
// Copyright 2020 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/chromeos/extensions/extensions_permissions_tracker.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chromeos/login/login_state/login_state.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/device_local_account_util.h"
#include "extensions/browser/pref_names.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/manifest_permission_set.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
namespace extensions {
ExtensionsPermissionsTracker::ExtensionsPermissionsTracker(
ExtensionRegistry* registry,
content::BrowserContext* browser_context)
: registry_(registry),
pref_service_(Profile::FromBrowserContext(browser_context)->GetPrefs()) {
observation_.Observe(registry_);
pref_change_registrar_.Init(pref_service_);
pref_change_registrar_.Add(
pref_names::kInstallForceList,
base::BindRepeating(
&ExtensionsPermissionsTracker::OnForcedExtensionsPrefChanged,
base::Unretained(
this))); // Safe as ExtensionsPermissionsTracker
// owns pref_change_registrar_ & outlives it
// Try to load list now.
OnForcedExtensionsPrefChanged();
}
ExtensionsPermissionsTracker::~ExtensionsPermissionsTracker() = default;
void ExtensionsPermissionsTracker::OnForcedExtensionsPrefChanged() {
// TODO(crbug.com/1015378): handle pref_names::kExtensionManagement with
// installation_mode: forced.
const base::Value* value = pref_service_->Get(pref_names::kInstallForceList);
if (!value || value->type() != base::Value::Type::DICTIONARY) {
return;
}
extension_safety_ratings_.clear();
pending_forced_extensions_.clear();
for (const auto entry : value->DictItems()) {
const ExtensionId& extension_id = entry.first;
// By default the extension permissions are assumed to trigger full warning
// (false). When the extension is loaded, if all of its permissions is safe,
// it'll be marked safe (true)
extension_safety_ratings_.insert(make_pair(extension_id, false));
const Extension* extension =
registry_->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
if (extension)
ParseExtensionPermissions(extension);
else
pending_forced_extensions_.insert(extension_id);
}
if (pending_forced_extensions_.empty())
UpdateLocalState();
}
bool ExtensionsPermissionsTracker::IsSafePerms(
const PermissionsData* perms_data) const {
const PermissionSet& active_permissions = perms_data->active_permissions();
const APIPermissionSet& api_permissions = active_permissions.apis();
for (auto* permission : api_permissions) {
if (permission->info()->requires_managed_session_full_login_warning()) {
return false;
}
}
const ManifestPermissionSet& manifest_permissions =
active_permissions.manifest_permissions();
for (const auto* permission : manifest_permissions) {
if (permission->RequiresManagedSessionFullLoginWarning()) {
return false;
}
}
if (active_permissions.ShouldWarnAllHosts() ||
!active_permissions.effective_hosts().is_empty()) {
return false;
}
return true;
}
void ExtensionsPermissionsTracker::OnExtensionLoaded(
content::BrowserContext* browser_context,
const Extension* extension) {
auto itr = extension_safety_ratings_.find(extension->id());
if (itr == extension_safety_ratings_.end())
return;
pending_forced_extensions_.erase(extension->id());
ParseExtensionPermissions(extension);
// If the extension isn't safe or all extensions are loaded, update the local
// state.
if (!itr->second || pending_forced_extensions_.empty())
UpdateLocalState();
}
void ExtensionsPermissionsTracker::UpdateLocalState() {
bool any_unsafe = std::any_of(
extension_safety_ratings_.begin(), extension_safety_ratings_.end(),
[](const auto& key_value) { return !key_value.second; });
DCHECK(pending_forced_extensions_.empty() || any_unsafe);
g_browser_process->local_state()->SetBoolean(
prefs::kManagedSessionUseFullLoginWarning, any_unsafe);
}
// static
void ExtensionsPermissionsTracker::RegisterLocalStatePrefs(
PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(prefs::kManagedSessionUseFullLoginWarning,
true);
}
void ExtensionsPermissionsTracker::ParseExtensionPermissions(
const Extension* extension) {
bool is_safe = IsWhitelistedForPublicSession(extension->id()) ||
IsSafePerms(extension->permissions_data());
extension_safety_ratings_[extension->id()] = is_safe;
}
} // namespace extensions