blob: fd872c28c2deab33f1920ff5e5886e7c57b4a5d4 [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.
#ifndef CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_EXTENSIONS_MANAGER_H_
#define CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_EXTENSIONS_MANAGER_H_
#include <set>
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "components/prefs/pref_change_registrar.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/management_policy.h"
namespace content {
class BrowserContext;
} // namespace content
namespace extensions {
class Extension;
class ExtensionPrefs;
class ExtensionSystem;
class ExtensionRegistry;
// UMA metrics for auto-approved extensions.
inline constexpr char
kInitialLocallyApprovedExtensionCountWinLinuxMacHistogramName[] =
"SupervisedUsers.InitialLocallyApprovedExtensionsCountOnWinLinuxMac";
inline constexpr char kExtensionApprovalsCountOnExtensionToggleHistogramName[] =
"SupervisedUsers.ExtensionApprovalsCountOnExtensionToggle";
// This class groups all the functionality to handle extensions
// for supervised users.
class SupervisedUserExtensionsManager : public ExtensionRegistryObserver,
public ManagementPolicy::Provider {
public:
explicit SupervisedUserExtensionsManager(content::BrowserContext* context);
SupervisedUserExtensionsManager(const SupervisedUserExtensionsManager&) =
delete;
SupervisedUserExtensionsManager& operator=(
const SupervisedUserExtensionsManager&) = delete;
~SupervisedUserExtensionsManager() override;
// Updates registration of this class as a management policy provider
// for supervised users. It needs to be called after
// extension::ManagementPolicy has been set.
void UpdateManagementPolicyRegistration();
// Updates the set of approved extensions to add approval for `extension`.
void AddExtensionApproval(const Extension& extension);
// Checks if the extension escalated permissions during an upgrade
// and records the corresponding metrics.
void MaybeRecordPermissionsIncreaseMetrics(const extensions::Extension& extension);
// Updates the set of approved extensions to remove approval for `extension`.
void RemoveExtensionApproval(const Extension& extension);
// Returns whether the extension is allowed by the parent.
bool IsExtensionAllowed(const Extension& extension) const;
// Returns whether the supervised user can install extensions.
// If the feature that allows skipping parent approval is enabled, supervised
// user are always allowed to install extensions.
// If the feature is disabled, the permission to install is based on existing
// Family Link parental controls ("Permissions" switch).
bool CanInstallExtensions() const;
// Records the state of extension approvals.
void RecordExtensionEnablementUmaMetrics(bool enabled) const;
// extensions::ManagementPolicy::Provider implementation:
std::string GetDebugPolicyProviderName() const override;
bool UserMayLoad(const Extension* extension,
std::u16string* error) const override;
bool MustRemainDisabled(const Extension* extension,
disable_reason::DisableReason* reason) const override;
// extensions::ExtensionRegistryObserver overrides:
void OnExtensionInstalled(content::BrowserContext* browser_context,
const Extension* extension,
bool is_update) override;
void OnExtensionUninstalled(content::BrowserContext* browser_context,
const Extension* extension,
UninstallReason reason) override;
private:
// These enum values represent operations to manage the
// kSupervisedUserApprovedExtensions user pref, which stores parent approved
// extension ids.
enum class ApprovedExtensionChange {
// Adds a new approved extension to the pref.
kAdd,
// Removes extension approval.
kRemove
};
// An extension can be in one of the following states:
//
// BLOCKED: if kSupervisedUserExtensionsMayRequestPermissions is false and the
// child user is attempting to install a new extension or an existing
// extension is asking for additional permissions.
// ALLOWED: Components, Themes, Default extensions ..etc
// are generally allowed. Extensions that have been approved by the
// custodian are also allowed.
// REQUIRE_APPROVAL: if it is installed by the child user and
// hasn't been approved by the custodian yet.
enum class ExtensionState { BLOCKED, ALLOWED, REQUIRE_APPROVAL };
// Returns the state of an extension whether being BLOCKED, ALLOWED or
// REQUIRE_APPROVAL from the Supervised User service's point of view.
ExtensionState GetExtensionState(const Extension& extension) const;
// Updates the set of approved extensions when the preference is changed.
void RefreshApprovedExtensionsFromPrefs();
// Activates the extension manager for supervised users.
void SetActiveForSupervisedUsers();
// Marks the class as active manegment policy provider for supervised users
// and updates management policy registration.
void ActivateManagementPolicyAndUpdateRegistration();
// Updates the synced set of approved extension ids.
// Use AddExtensionApproval() or RemoveExtensionApproval() for public access.
// If `type` is kAdd, then add approval.
// If `type` is kRemove, then remove approval.
// Triggers a call to RefreshApprovedExtensionsFromPrefs() via a listener.
// TODO(crbug.com/40685974): We don't need the extension version information.
// It's only included for backwards compatibility with previous versions of
// Chrome. Remove the version information once a sufficient number of users
// have migrated away from M83.
void UpdateApprovedExtension(const std::string& extension_id,
const std::string& version,
ApprovedExtensionChange type);
// Returns a message saying that extensions can only be modified by the
// custodian.
std::u16string GetExtensionsLockedMessage() const;
// Enables/Disables extensions upon change in approvals. This function is
// idempotent.
void ChangeExtensionStateIfNecessary(const std::string& extension_id);
// Returns whether we should block an extension.
// If the toggle "Permissions for sites, apps and extensions" toggle
// is used to manage supervised user extensions, the result depends on the
// value of the toggle.
// If the new toggle "Extensions" is used to manage supervised user
// extensions, this method return always false.
// TODO(b/321239324): De-release when the "Extensions" toggle-management is
// launched.
bool ShouldBlockExtension(const std::string& extension_id) const;
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
// Triggers an one-time migration of the present extensions as parent-approved
// when the feature
// `kEnableSupervisedUserSkipParentApprovalToInstallExtensions` becomes
// enabled.
void MaybeMarkExtensionsLocallyParentApproved();
// Marks the extensions available to the child user as locally parent-approved
// on a preference on this device.
void DoExtensionsMigrationToParentApproved();
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
// Returns true if the given `extension_id` has been marked locally parent
// approved.
bool IsLocallyParentApprovedExtension(const std::string& extension_id) const;
// Removes from the locally approved extension preference the given
// `extension_ids`. The input `extension_ids` doesn't have to be a subset of
// the locally approved extensions: the method will remove those that are
// locally approved and ignore the rest.
void RemoveLocalParentalApproval(const std::set<std::string>& extension_ids);
// Handles the parent-approval state of the present extensions,
// whenever the parent changes the value of the FL "Extension" switch.
void OnSkipParentApprovalToInstallExtensionsChanged();
// The current state of registration of this class as a management policy.
bool is_active_policy_for_supervised_users_ = false;
const raw_ptr<content::BrowserContext> context_;
raw_ptr<ExtensionPrefs> extension_prefs_;
raw_ptr<ExtensionSystem> extension_system_;
raw_ptr<ExtensionRegistry> extension_registry_;
raw_ptr<PrefService> user_prefs_;
PrefChangeRegistrar pref_change_registrar_;
// Store a set of extension ids approved by the custodian.
// It is only relevant for SU-initiated installs.
std::set<std::string> approved_extensions_set_;
base::ScopedObservation<ExtensionRegistry, ExtensionRegistryObserver>
registry_observation_{this};
};
} // namespace extensions
#endif // CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_EXTENSIONS_MANAGER_H_