// Copyright 2015 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. #ifndef COMPONENTS_PERMISSIONS_PERMISSION_MANAGER_H_ #define COMPONENTS_PERMISSIONS_PERMISSION_MANAGER_H_ #include #include "base/callback_forward.h" #include "base/containers/id_map.h" #include "base/macros.h" #include "components/content_settings/core/browser/content_settings_observer.h" #include "components/content_settings/core/common/content_settings.h" #include "components/keyed_service/core/keyed_service.h" #include "components/permissions/permission_util.h" #include "content/public/browser/permission_controller_delegate.h" #include "content/public/browser/permission_type.h" #include "url/origin.h" namespace content { class BrowserContext; } namespace permissions { class PermissionContextBase; struct PermissionResult; class PermissionManager : public KeyedService, public content::PermissionControllerDelegate, public content_settings::Observer { public: using PermissionContextMap = std::unordered_map, ContentSettingsTypeHash>; PermissionManager(content::BrowserContext* browser_context, PermissionContextMap permission_contexts); ~PermissionManager() override; // Converts from |url|'s actual origin to the "canonical origin" that should // be used for the purpose of requesting/storing permissions. For example, the // origin of the local NTP gets mapped to the Google base URL instead. With // Permission Delegation it will transform the requesting origin into // the embedding origin because all permission checks happen on the top level // origin. // // All the public methods below, such as RequestPermission or // GetPermissionStatus, take the actual origin and do the canonicalization // internally. You only need to call this directly if you do something else // with the origin, such as display it in the UI. GURL GetCanonicalOrigin(ContentSettingsType permission, const GURL& requesting_origin, const GURL& embedding_origin) const; // Callers from within chrome/ should use the methods which take the // ContentSettingsType enum. The methods which take PermissionType values // are for the content::PermissionControllerDelegate overrides and shouldn't // be used from chrome/. int RequestPermission(ContentSettingsType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, bool user_gesture, base::OnceCallback callback); int RequestPermissions( const std::vector& permissions, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, bool user_gesture, base::OnceCallback&)> callback); PermissionResult GetPermissionStatus(ContentSettingsType permission, const GURL& requesting_origin, const GURL& embedding_origin); // Returns the permission status for a given frame. This should be preferred // over GetPermissionStatus as additional checks can be performed when we know // the exact context the request is coming from. // TODO(raymes): Currently we still pass the |requesting_origin| as a separate // parameter because we can't yet guarantee that it matches the last committed // origin of the RenderFrameHost. See crbug.com/698985. PermissionResult GetPermissionStatusForFrame( ContentSettingsType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin); // content::PermissionControllerDelegate implementation. int RequestPermission(content::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, bool user_gesture, base::OnceCallback callback) override; int RequestPermissions( const std::vector& permissions, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, bool user_gesture, base::OnceCallback< void(const std::vector&)> callback) override; void ResetPermission(content::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) override; blink::mojom::PermissionStatus GetPermissionStatus( content::PermissionType permission, const GURL& requesting_origin, const GURL& embedding_origin) override; blink::mojom::PermissionStatus GetPermissionStatusForFrame( content::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin) override; bool IsPermissionOverridableByDevTools( content::PermissionType permission, const base::Optional& origin) override; SubscriptionId SubscribePermissionStatusChange( content::PermissionType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, base::RepeatingCallback callback) override; void UnsubscribePermissionStatusChange(SubscriptionId subscription_id) override; // TODO(raymes): Rather than exposing this, use the denial reason from // GetPermissionStatus in callers to determine whether a permission is // denied due to the kill switch. bool IsPermissionKillSwitchOn(ContentSettingsType); // For the given |origin|, overrides permissions that belong to |overrides|. // These permissions are in-sync with the PermissionController. void SetPermissionOverridesForDevTools( const base::Optional& origin, const PermissionOverrides& overrides) override; void ResetPermissionOverridesForDevTools() override; // KeyedService implementation void Shutdown() override; // Helper method to convert PermissionType to ContentSettingType. static ContentSettingsType PermissionTypeToContentSetting( content::PermissionType permission); PermissionContextBase* GetPermissionContextForTesting( ContentSettingsType type); private: friend class PermissionManagerTest; class PendingRequest; using PendingRequestsMap = base::IDMap>; class PermissionResponseCallback; struct Subscription; using SubscriptionsMap = base::IDMap, SubscriptionId>; PermissionContextBase* GetPermissionContext(ContentSettingsType type); // Called when a permission was decided for a given PendingRequest. The // PendingRequest is identified by its |request_id| and the permission is // identified by its |permission_id|. If the PendingRequest contains more than // one permission, it will wait for the remaining permissions to be resolved. // When all the permissions have been resolved, the PendingRequest's callback // is run. void OnPermissionsRequestResponseStatus(int request_id, int permission_id, ContentSetting status); // content_settings::Observer implementation. void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern, const ContentSettingsPattern& secondary_pattern, ContentSettingsType content_type) override; PermissionResult GetPermissionStatusHelper( ContentSettingsType permission, content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, const GURL& embedding_origin); ContentSetting GetPermissionOverrideForDevTools( const url::Origin& origin, ContentSettingsType permission); content::BrowserContext* browser_context_; PendingRequestsMap pending_requests_; SubscriptionsMap subscriptions_; SubscriptionId::Generator subscription_id_generator_; PermissionContextMap permission_contexts_; using ContentSettingsTypeOverrides = base::flat_map; std::map devtools_permission_overrides_; url::Origin devtools_global_overrides_origin_; bool is_shutting_down_ = false; DISALLOW_COPY_AND_ASSIGN(PermissionManager); }; } // namespace permissions #endif // COMPONENTS_PERMISSIONS_PERMISSION_MANAGER_H_