// Copyright 2024 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef EXTENSIONS_BROWSER_HOST_ACCESS_REQUEST_HELPER_H_ #define EXTENSIONS_BROWSER_HOST_ACCESS_REQUEST_HELPER_H_ #include "base/scoped_observation.h" #include "content/public/browser/web_contents_observer.h" #include "extensions/browser/extension_registry_observer.h" #include "extensions/common/extension.h" #include "extensions/common/extension_id.h" #include "extensions/common/url_pattern.h" namespace content { class WebContents; } // namespace content namespace extensions { class PermissionsManager; // Per-tab helper that stores extension's site access requests and restores // them on cross-origin navigations. // This class should only be used by PermissionsManager since it's an // implementation detail that was pulled out for legibility. class HostAccessRequestsHelper : public ExtensionRegistryObserver, public content::WebContentsObserver { public: using PassKey = base::PassKey<PermissionsManager>; HostAccessRequestsHelper(PassKey pass_key, PermissionsManager* permissions_manager, content::WebContents* web_contents, int tab_id); HostAccessRequestsHelper(const HostAccessRequestsHelper&) = delete; const HostAccessRequestsHelper& operator=(const HostAccessRequestsHelper&) = delete; ~HostAccessRequestsHelper() override; // Adds `extension` to the set of extensions with site access requests. // Request will be matched to `filter`, if existent. Extension must not have // granted access to the current site. void AddRequest(const Extension& extension, const std::optional<URLPattern>& filter); // Updates the site access request entry for `extension`. Request will be // matched to `filter, if existent. void UpdateRequest(const Extension& extension, const std::optional<URLPattern>& filter); // Removes `extension_id` from the set of extensions with site access // requests. Request will be matches to `filter`, if existent. Returns whether // request was removed. bool RemoveRequest(const ExtensionId& extension_id, const std::optional<URLPattern>& filter); // Removes `extension` from the set of extensions with site access requests // iff extension has granted access to the current site. Returns whether // request was removed. bool RemoveRequestIfGrantedAccess(const Extension& extension); // Adds `extension_id` to the set of extension with site access requests that // have been dismissed by the user. Request must be existent in // `extensions_with_requests_` for user to be able to dismiss it. // An extension's request cannot be undismissed by the user. Requests will be // reset on cross-origin navigation, along with their dismissals if existent. void UserDismissedRequest(const ExtensionId& extension_id); // Returns whether `extension_id` has a site access request for this tab. bool HasRequest(const ExtensionId& extension_id) const; // Returns whether `extension_id` has a site access request that has not been // dismissed by the user and matches the URLPattern filter, if existent. bool HasActiveRequest(const ExtensionId& extension_id) const; // Returns whether helper has any site access requests. bool HasRequests(); private: // ExtensionRegistryObserver: void OnExtensionUnloaded(content::BrowserContext* browser_context, const Extension* extension, UnloadedExtensionReason reason) override; // content::WebContentsObserver: void DidFinishNavigation( content::NavigationHandle* navigation_handle) override; void WebContentsDestroyed() override; // PermissionsManager owns this object, thus `permissions_manager_` will // always be valid. raw_ptr<PermissionsManager> permissions_manager_; raw_ptr<content::WebContents> web_contents_; int tab_id_; // Extensions that have a site access request on this tab's origin. If pattern // is provided, request will only be shown for URLs that match it. std::map<ExtensionId, std::optional<URLPattern>> extensions_with_requests_; // Extensions that have a site access request for this tab's origin which was // dismissed by the user. std::set<ExtensionId> extensions_with_requests_dismissed_; base::ScopedObservation<extensions::ExtensionRegistry, extensions::ExtensionRegistryObserver> extension_registry_observation_{this}; }; } // namespace extensions #endif // EXTENSIONS_BROWSER_HOST_ACCESS_REQUEST_HELPER_H_