blob: 1845cf5ade6fd638bc5f4364e03bd679c0170b97 [file] [log] [blame]
// Copyright 2022 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/policy/value_provider/extension_policies_value_provider.h"
#include <memory>
#include "base/memory/scoped_refptr.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/policy/chrome_policy_conversions_client.h"
#include "chrome/browser/policy/schema_registry_service.h"
#include "chrome/browser/policy/value_provider/value_provider_util.h"
#include "chrome/browser/profiles/profile.h"
#include "components/policy/core/browser/policy_conversions.h"
#include "components/policy/core/common/policy_namespace.h"
#include "components/policy/core/common/policy_service.h"
#include "components/policy/core/common/schema.h"
#include "components/policy/core/common/schema_map.h"
#include "components/policy/core/common/schema_registry.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/ash/profiles/profile_helper.h"
#endif // BUILDFLAG(IS_CHROMEOS)
namespace {
bool ContainsStorageManagedSchema(const extensions::Extension* extension) {
return extension->manifest()->FindPath(
extensions::manifest_keys::kStorageManagedSchema);
}
// Looks for policy::kIdKey in `policy` dictionary and adds it to
// `extension_policies` with the ID value as a key. Moves `policy` when adding.
void AddExtensionPolicyValueToDict(base::Value& policy,
base::Value::Dict& extension_policies) {
base::Value::Dict* policy_dict = policy.GetIfDict();
if (!policy_dict)
return;
std::string* id = policy_dict->FindString(policy::kIdKey);
if (!id)
return;
policy_dict->Remove(*id);
extension_policies.Set(*id, std::move(policy));
}
} // namespace
ExtensionPoliciesValueProvider::ExtensionPoliciesValueProvider(Profile* profile)
: profile_(profile) {
extension_registry_observation_.Observe(
extensions::ExtensionRegistry::Get(profile_));
policy::PolicyService* policy_service = GetPolicyService(profile_);
policy_service->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
#if BUILDFLAG(IS_CHROMEOS)
policy_service->AddObserver(policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS, this);
#endif // BUILDFLAG(IS_CHROMEOS)
}
ExtensionPoliciesValueProvider::~ExtensionPoliciesValueProvider() {
policy::PolicyService* policy_service = GetPolicyService(profile_);
policy_service->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
#if BUILDFLAG(IS_CHROMEOS)
policy_service->RemoveObserver(policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS, this);
#endif // BUILDFLAG(IS_CHROMEOS)
}
base::Value::Dict ExtensionPoliciesValueProvider::GetValues() {
base::Value::Dict extension_policies;
auto client =
std::make_unique<policy::ChromePolicyConversionsClient>(profile_);
if (client->HasUserPolicies()) {
for (auto& policy :
client->GetExtensionPolicies(policy::POLICY_DOMAIN_EXTENSIONS)) {
AddExtensionPolicyValueToDict(policy, extension_policies);
}
}
#if BUILDFLAG(IS_CHROMEOS)
for (auto& policy :
client->GetExtensionPolicies(policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS)) {
AddExtensionPolicyValueToDict(policy, extension_policies);
}
#endif // BUILDFLAG(IS_CHROMEOS)
return extension_policies;
}
base::Value::Dict ExtensionPoliciesValueProvider::GetNames() {
base::Value::Dict extension_policy_names =
GetExtensionPolicyNames(policy::POLICY_DOMAIN_EXTENSIONS);
#if BUILDFLAG(IS_CHROMEOS)
extension_policy_names.Merge(
GetExtensionPolicyNames(policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS));
#endif // BUILDFLAG(IS_CHROMEOS)
return extension_policy_names;
}
base::Value::Dict ExtensionPoliciesValueProvider::GetExtensionPolicyNames(
policy::PolicyDomain policy_domain) {
base::Value::Dict names;
#if BUILDFLAG(IS_CHROMEOS)
Profile* extension_profile =
policy_domain == policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS
? ash::ProfileHelper::GetSigninProfile()
: profile_.get();
#else // BUILDFLAG(IS_CHROMEOS)
Profile* extension_profile = profile_.get();
#endif // BUILDFLAG(IS_CHROMEOS)
scoped_refptr<policy::SchemaMap> schema_map =
extension_profile->GetOriginalProfile()
->GetPolicySchemaRegistryService()
->registry()
->schema_map();
const extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(extension_profile);
const extensions::ExtensionSet extension_set =
registry->GenerateInstalledExtensionsSet();
for (const auto& extension : extension_set) {
// Skip this extension if it's not an enterprise extension.
if (!ContainsStorageManagedSchema(extension.get())) {
continue;
}
base::Value::Dict extension_value;
extension_value.Set(policy::kNameKey, extension->name());
const policy::Schema* schema = schema_map->GetSchema(
policy::PolicyNamespace(policy_domain, extension->id()));
base::Value::List policy_names;
if (schema && schema->valid()) {
// Get policy names from the extension's policy schema.
for (auto prop = schema->GetPropertiesIterator(); !prop.IsAtEnd();
prop.Advance()) {
policy_names.Append(prop.key());
}
}
extension_value.Set(policy::kPolicyNamesKey, std::move(policy_names));
names.Set(extension->id(), std::move(extension_value));
}
return names;
}
void ExtensionPoliciesValueProvider::OnExtensionLoaded(
content::BrowserContext* browser_context,
const extensions::Extension* extension) {
// Notify value change if the loaded extension has policy.
if (ContainsStorageManagedSchema(extension)) {
NotifyValueChange();
}
}
void ExtensionPoliciesValueProvider::OnExtensionUnloaded(
content::BrowserContext* browser_context,
const extensions::Extension* extension,
extensions::UnloadedExtensionReason reason) {
// Notify value change if the unloaded extension has policy.
if (ContainsStorageManagedSchema(extension)) {
NotifyValueChange();
}
}
void ExtensionPoliciesValueProvider::OnPolicyUpdated(
const policy::PolicyNamespace& ns,
const policy::PolicyMap& previous,
const policy::PolicyMap& current) {
NotifyValueChange();
}