blob: c6c82b38b189e87e418d21d73478c815946f7d51 [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.
#ifndef CHROME_BROWSER_UI_SAFETY_HUB_UNUSED_SITE_PERMISSIONS_SERVICE_H_
#define CHROME_BROWSER_UI_SAFETY_HUB_UNUSED_SITE_PERMISSIONS_SERVICE_H_
#include <list>
#include <map>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/ui/safety_hub/safety_hub_service.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
constexpr char kUnusedSitePermissionsResultKey[] = "permissions";
constexpr char kUnusedSitePermissionsResultPermissionTypesKey[] =
"permissionTypes";
constexpr char kUnusedSitePermissionsResultOriginKey[] = "origin";
constexpr char kUnusedSitePermissionsResultExpirationKey[] = "expiration";
namespace url {
class Origin;
}
namespace content {
class Page;
} // namespace content
// This class keeps track of unused permissions, updates their last_visit date
// on navigations and clears them periodically.
class UnusedSitePermissionsService : public SafetyHubService,
public content_settings::Observer {
public:
struct RevokedPermission {
public:
RevokedPermission(ContentSettingsPattern origin,
std::set<ContentSettingsType> permission_types,
base::Time expiration);
RevokedPermission(const RevokedPermission&);
RevokedPermission& operator=(const RevokedPermission&) = delete;
~RevokedPermission();
ContentSettingsPattern origin;
std::set<ContentSettingsType> permission_types;
base::Time expiration;
};
struct ContentSettingEntry {
ContentSettingsType type;
ContentSettingPatternSource source;
};
// The result of the periodic update of unused site permissions contains
// the permissions that have been revoked. These revoked permissions will be
// stored until the clean-up threshold has been reached.
class UnusedSitePermissionsResult : public SafetyHubService::Result {
public:
UnusedSitePermissionsResult();
explicit UnusedSitePermissionsResult(const base::Value::Dict& dict);
UnusedSitePermissionsResult(const UnusedSitePermissionsResult&) = delete;
UnusedSitePermissionsResult& operator=(const UnusedSitePermissionsResult&) =
delete;
~UnusedSitePermissionsResult() override;
using UnusedPermissionMap =
std::map<std::string, std::list<ContentSettingEntry>>;
void AddRevokedPermission(ContentSettingsPattern origin,
std::set<ContentSettingsType> permission_types,
base::Time expiration);
void SetRecentlyUnusedPermissions(UnusedPermissionMap map) {
recently_unused_permissions_ = map;
}
UnusedPermissionMap GetRecentlyUnusedPermissions() {
return recently_unused_permissions_;
}
std::list<RevokedPermission> GetRevokedPermissions();
std::set<ContentSettingsPattern> GetRevokedOrigins() const;
// SafetyHubService::Result implementation
base::Value::Dict ToDictValue() override;
bool IsTriggerForMenuNotification() override;
bool WarrantsNewMenuNotification(const Result& previousResult) override;
private:
std::list<RevokedPermission> revoked_permissions_;
UnusedPermissionMap recently_unused_permissions_;
};
class TabHelper : public content::WebContentsObserver,
public content::WebContentsUserData<TabHelper> {
public:
TabHelper(const TabHelper&) = delete;
TabHelper& operator=(const TabHelper&) = delete;
~TabHelper() override;
// WebContentsObserver:
void PrimaryPageChanged(content::Page& page) override;
private:
explicit TabHelper(
content::WebContents* web_contents,
UnusedSitePermissionsService* unused_site_permission_service);
base::WeakPtr<UnusedSitePermissionsService> unused_site_permission_service_;
friend class content::WebContentsUserData<TabHelper>;
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
explicit UnusedSitePermissionsService(HostContentSettingsMap* hcsm);
UnusedSitePermissionsService(const UnusedSitePermissionsService&) = delete;
UnusedSitePermissionsService& operator=(const UnusedSitePermissionsService&) =
delete;
~UnusedSitePermissionsService() override;
// content_settings::Observer implementation.
void OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsTypeSet content_type_set) override;
// KeyedService implementation.
void Shutdown() override;
// If the user clicked "Allow again" for an auto-revoked origin, the
// permissions for that site should not be auto-revoked again by the service.
void IgnoreOriginForAutoRevocation(const url::Origin& origin);
// Re-grants permissions that are auto-revoked ones and removes the origin
// from revoked permissions list.
void RegrantPermissionsForOrigin(const url::Origin& origin);
// Reverse changes made by |RegrantPermissionsForOrigin|. Adds this origin to
// the removed permissions list and resets its permissions.
void UndoRegrantPermissionsForOrigin(
const std::set<ContentSettingsType> permissions,
const absl::optional<content_settings::ContentSettingConstraints>
constraint,
const url::Origin origin);
// Clear the list of revoked permissions so they will no longer be shown to
// the user. Does not change permissions themselves.
void ClearRevokedPermissionsList();
// Stores revoked permissions data on HCSM.
void StorePermissionInRevokedPermissionSetting(
const std::set<ContentSettingsType> permissions,
const absl::optional<content_settings::ContentSettingConstraints>
constraint,
const url::Origin origin);
// Returns the list of all permissions that have been revoked.
std::unique_ptr<Result> GetRevokedPermissions();
// Does most of the heavy lifting of the update process: for each permission,
// it determines whether it should be considered as recently unused (i.e. one
// week). This list will be further filtered in the UI task to determine which
// permissions should be revoked.
static std::unique_ptr<Result> UpdateOnBackgroundThread(
base::Clock* clock,
const scoped_refptr<HostContentSettingsMap> hcsm);
// SafetyHubService implementation
// Returns a weak pointer to the service.
base::WeakPtr<SafetyHubService> GetAsWeakRef() override;
// Test support:
void SetClockForTesting(base::Clock* clock);
std::vector<ContentSettingEntry> GetTrackedUnusedPermissionsForTesting();
using UnusedPermissionMap =
std::map<std::string, std::list<ContentSettingEntry>>;
private:
// Called by TabHelper when a URL was visited.
void OnPageVisited(const url::Origin& origin);
// Removes a pattern from the list of revoked permissions so that the entry is
// no longer shown to the user. Does not affect permissions themselves.
void DeletePatternFromRevokedPermissionList(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern);
// Revokes permissions that belong to sites that were last visited over 60
// days ago.
void RevokeUnusedPermissions();
// Stores revoked permissions data on HCSM.
void StorePermissionInRevokedPermissionSetting(
const std::set<ContentSettingsType> permissions,
const absl::optional<content_settings::ContentSettingConstraints>
constraint,
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern);
// SafetyHubService implementation
void InitializeLatestResult() override;
// Returns the interval at which the repeated updates will be run.
base::TimeDelta GetRepeatedUpdateInterval() override;
// Returns a reference to the static |UpdateOnBackgroundThread| function,
// bound with a |Result| containing a reference to the clock and
// host content settings map.
base::OnceCallback<std::unique_ptr<Result>()> GetBackgroundTask() override;
// Uses the |UnusedPermissionMap| from the background task to determine which
// permissions should be revoked, revokes them and returns the list of revoked
// permissions.
std::unique_ptr<Result> UpdateOnUIThread(
std::unique_ptr<Result> result) override;
// Set of permissions that haven't been used for at least a week.
UnusedPermissionMap recently_unused_permissions_;
// Repeating timer that updates the recently_unused_permissions_ map.
base::RepeatingTimer update_timer_;
const scoped_refptr<HostContentSettingsMap> hcsm_;
// Observer to watch for content settings changed.
base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
content_settings_observation_{this};
raw_ptr<base::Clock> clock_;
base::WeakPtrFactory<UnusedSitePermissionsService> weak_factory_{this};
};
#endif // CHROME_BROWSER_UI_SAFETY_HUB_UNUSED_SITE_PERMISSIONS_SERVICE_H_