blob: d5d8e39835c736af3d05a2c6f0d8752090ea381c [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_PERMISSIONS_PERMISSION_CONTROLLER_IMPL_H_
#define CONTENT_BROWSER_PERMISSIONS_PERMISSION_CONTROLLER_IMPL_H_
#include <map>
#include <optional>
#include <set>
#include "base/containers/id_map.h"
#include "base/memory/raw_ptr.h"
#include "content/browser/permissions/permission_overrides.h"
#include "content/common/content_export.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_request_description.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace blink {
enum class PermissionType;
}
namespace content {
class BrowserContext;
class PermissionControllerImplTest;
class RenderProcessHost;
class PermissionServiceImpl;
class WebContents;
struct PermissionResult;
using blink::PermissionType;
// Implementation of the PermissionController interface. This
// is used by content/ layer to manage permissions.
// There is one instance of this class per BrowserContext.
class CONTENT_EXPORT PermissionControllerImpl : public PermissionController {
public:
explicit PermissionControllerImpl(BrowserContext* browser_context);
PermissionControllerImpl(const PermissionControllerImpl&) = delete;
PermissionControllerImpl& operator=(const PermissionControllerImpl&) = delete;
~PermissionControllerImpl() override;
static PermissionControllerImpl* FromBrowserContext(
BrowserContext* browser_context);
enum class OverrideStatus { kOverrideNotSet, kOverrideSet };
// For the given |requesting_origin| and |embedding_origin|, grant permissions
// in |overrides| and reject all others. If no |requesting_origin| and
// |embedding_origin| are specified, grant permissions globally for context.
// It is invalid to call these methods with exactly one non-null origin.
OverrideStatus GrantOverridesForDevTools(
base::optional_ref<const url::Origin> requesting_origin,
base::optional_ref<const url::Origin> embedding_origin,
const std::vector<PermissionType>& permissions);
OverrideStatus SetOverrideForDevTools(
base::optional_ref<const url::Origin> requesting_origin,
base::optional_ref<const url::Origin> embedding_origin,
PermissionType permission,
const PermissionStatus& status);
void ResetOverridesForDevTools();
// Sets status for |permissions| to GRANTED for |requesting_origin| and
// |embedding_origin|, and DENIED for all others. Null |requesting_origin| and
// |embedding_origin| grants permissions globally for context.
// It is invalid to call these methods with exactly one non-null origin.
OverrideStatus GrantPermissionOverrides(
base::optional_ref<const url::Origin> requesting_origin,
base::optional_ref<const url::Origin> embedding_origin,
const std::vector<PermissionType>& permissions);
OverrideStatus SetPermissionOverride(
base::optional_ref<const url::Origin> requesting_origin,
base::optional_ref<const url::Origin> embedding_origin,
PermissionType permission,
const PermissionStatus& status);
void ResetPermissionOverrides();
void ResetPermission(PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin);
// Only one of |render_process_host| and |render_frame_host| should be set,
// or neither. RenderProcessHost will be inferred from |render_frame_host|.
SubscriptionId SubscribeToPermissionStatusChange(
PermissionType permission,
RenderProcessHost* render_process_host,
RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
bool should_include_device_status,
const base::RepeatingCallback<void(PermissionStatus)>& callback) override;
void UnsubscribeFromPermissionStatusChange(
SubscriptionId subscription_id) override;
// If there's currently a permission prompt bubble for the given WebContents,
// returns the bounds of the bubble view as exclusion area in screen
// coordinates.
std::optional<gfx::Rect> GetExclusionAreaBoundsInScreen(
WebContents* web_contents) const;
void add_notify_listener_observer_for_tests(base::RepeatingClosure callback) {
onchange_listeners_callback_for_tests_ = std::move(callback);
}
void set_exclusion_area_bounds_for_tests(
const std::optional<gfx::Rect>& bounds) {
exclusion_area_bounds_for_tests_ = bounds;
}
private:
friend class PermissionControllerImplTest;
friend class PermissionServiceImpl;
PermissionStatus GetPermissionStatusInternal(
const blink::mojom::PermissionDescriptorPtr& permission,
const GURL& requesting_origin,
const GURL& embedding_origin);
PermissionStatus GetPermissionStatusForCurrentDocumentInternal(
const blink::mojom::PermissionDescriptorPtr& permission,
RenderFrameHost* render_frame_host,
bool should_include_device_status = false);
// PermissionController implementation.
PermissionStatus GetPermissionStatusForWorker(
const blink::mojom::PermissionDescriptorPtr& permission,
RenderProcessHost* render_process_host,
const url::Origin& worker_origin) override;
PermissionStatus GetPermissionStatusForCurrentDocument(
const blink::mojom::PermissionDescriptorPtr& permission,
RenderFrameHost* render_frame_host) override;
PermissionResult GetPermissionResultForCurrentDocument(
const blink::mojom::PermissionDescriptorPtr& permission,
RenderFrameHost* render_frame_host) override;
PermissionStatus GetCombinedPermissionAndDeviceStatus(
const blink::mojom::PermissionDescriptorPtr& permission,
RenderFrameHost* render_frame_host) override;
PermissionResult GetPermissionResultForOriginWithoutContext(
const blink::mojom::PermissionDescriptorPtr& permission,
const url::Origin& origin) override;
PermissionResult GetPermissionResultForOriginWithoutContext(
const blink::mojom::PermissionDescriptorPtr& permission,
const url::Origin& requesting_origin,
const url::Origin& embedding_origin) override;
// WARNING: Permission requests order is not guaranteed.
// TODO(crbug.com/40864728): Migrate to `std::set`.
// TODO(crbug.com/40275129): `RequestPermissions` and
// `RequestPermissionsFromCurrentDocument` do exactly the same things. Merge
// them together.
void RequestPermissions(
RenderFrameHost* render_frame_host,
PermissionRequestDescription request_description,
base::OnceCallback<void(const std::vector<PermissionStatus>&)> callback);
void RequestPermissionFromCurrentDocument(
RenderFrameHost* render_frame_host,
PermissionRequestDescription request_description,
base::OnceCallback<void(PermissionStatus)> callback) override;
// WARNING: Permission requests order is not guaranteed.
// TODO(crbug.com/40864728): Migrate to `std::set`.
void RequestPermissionsFromCurrentDocument(
RenderFrameHost* render_frame_host,
PermissionRequestDescription request_description,
base::OnceCallback<void(const std::vector<PermissionStatus>&)> callback)
override;
void ResetPermission(blink::PermissionType permission,
const url::Origin& origin) override;
PermissionStatus GetPermissionStatusForEmbeddedRequester(
const blink::mojom::PermissionDescriptorPtr& permission,
RenderFrameHost* render_frame_host,
const url::Origin& requesting_origin);
using SubscriptionsStatusMap =
base::flat_map<SubscriptionsMap::KeyType, PermissionStatus>;
PermissionStatus GetSubscriptionCurrentValue(
const content::PermissionStatusSubscription& subscription);
SubscriptionsStatusMap GetSubscriptionsStatuses(
const std::optional<GURL>& requesting_origin = std::nullopt,
const std::optional<GURL>& embedding_origin = std::nullopt);
void NotifyChangedSubscriptions(const SubscriptionsStatusMap& old_statuses);
// Notifies the callback of the new permission status.
// If `ignore_status_override` is true, the status override is not applied,
// which means that the permission status change will be notified to
// subscribed users even the status has been overridden.
void PermissionStatusChange(
const base::RepeatingCallback<void(PermissionStatus)>& callback,
SubscriptionId subscription_id,
PermissionStatus status,
bool ignore_status_override = false);
bool IsSubscribedToPermissionChangeEvent(
blink::PermissionType permission,
RenderFrameHost* render_frame_host) override;
// Notifies that an onchange event listener was added.
void NotifyEventListener();
PermissionOverrides permission_overrides_;
base::RepeatingClosure onchange_listeners_callback_for_tests_;
std::optional<gfx::Rect> exclusion_area_bounds_for_tests_;
// Note that SubscriptionId is distinct from
// PermissionControllerDelegate::SubscriptionId, and the concrete ID values
// may be different as well.
SubscriptionsMap subscriptions_;
SubscriptionId::Generator subscription_id_generator_;
raw_ptr<BrowserContext> browser_context_;
};
} // namespace content
#endif // CONTENT_BROWSER_PERMISSIONS_PERMISSION_CONTROLLER_IMPL_H_