blob: ed47821275732135292612652494a09927e6aa8a [file] [log] [blame]
[email protected]39ef0a7c52014-05-11 01:40:001// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_EXTENSIONS_ACTIVE_SCRIPT_CONTROLLER_H_
6#define CHROME_BROWSER_EXTENSIONS_ACTIVE_SCRIPT_CONTROLLER_H_
7
avia2f4804a2015-12-24 23:11:138#include <stdint.h>
9
[email protected]39ef0a7c52014-05-11 01:40:0010#include <map>
11#include <set>
12#include <string>
[email protected]ac02ac52014-05-20 01:11:2613#include <vector>
[email protected]39ef0a7c52014-05-11 01:40:0014
[email protected]ac02ac52014-05-20 01:11:2615#include "base/callback.h"
[email protected]39ef0a7c52014-05-11 01:40:0016#include "base/compiler_specific.h"
avia2f4804a2015-12-24 23:11:1317#include "base/macros.h"
rdevlin.cronin91f162a12014-09-03 16:48:4018#include "base/scoped_observer.h"
[email protected]39ef0a7c52014-05-11 01:40:0019#include "content/public/browser/web_contents_observer.h"
rdevlin.cronin8d034e52016-02-02 22:46:3220#include "extensions/browser/blocked_action_type.h"
rdevlin.cronin6e7e5edc2014-08-29 16:23:2321#include "extensions/browser/extension_registry_observer.h"
[email protected]23a85362014-07-07 23:26:1922#include "extensions/common/permissions/permissions_data.h"
23#include "extensions/common/user_script.h"
[email protected]39ef0a7c52014-05-11 01:40:0024
25namespace content {
rdevlin.cronin699ca6ff2014-09-29 23:59:5726class BrowserContext;
[email protected]39ef0a7c52014-05-11 01:40:0027class WebContents;
28}
29
30namespace IPC {
31class Message;
32}
33
34class ExtensionAction;
35
36namespace extensions {
37class Extension;
rdevlin.cronin6e7e5edc2014-08-29 16:23:2338class ExtensionRegistry;
[email protected]39ef0a7c52014-05-11 01:40:0039
40// The provider for ExtensionActions corresponding to scripts which are actively
41// running or need permission.
42// TODO(rdevlin.cronin): This isn't really a controller, but it has good parity
rdevlin.cronin50942232014-08-27 17:40:5643// with LocationBar"Controller".
rdevlin.cronin6e7e5edc2014-08-29 16:23:2344class ActiveScriptController : public content::WebContentsObserver,
45 public ExtensionRegistryObserver {
[email protected]39ef0a7c52014-05-11 01:40:0046 public:
47 explicit ActiveScriptController(content::WebContents* web_contents);
dchengae36a4a2014-10-21 12:36:3648 ~ActiveScriptController() override;
[email protected]39ef0a7c52014-05-11 01:40:0049
[email protected]eac223a2014-05-13 17:39:5750 // Returns the ActiveScriptController for the given |web_contents|, or NULL
51 // if one does not exist.
52 static ActiveScriptController* GetForWebContents(
53 content::WebContents* web_contents);
54
[email protected]11814f52014-05-23 06:50:3555 // Notifies the ActiveScriptController that an extension has been granted
56 // active tab permissions. This will run any pending injections for that
57 // extension.
58 void OnActiveTabPermissionGranted(const Extension* extension);
59
rdevlin.cronine9c71122014-08-25 23:47:2160 // Notifies the ActiveScriptController that the action for |extension| has
61 // been clicked, running any pending tasks that were previously shelved.
62 void OnClicked(const Extension* extension);
63
rdevlin.cronin8d034e52016-02-02 22:46:3264 // Called when a webRequest event for the given |extension| was blocked.
65 void OnWebRequestBlocked(const Extension* extension);
66
67 // Returns a bitmask of BlockedActionType for the actions that have been
68 // blocked for the given extension.
69 int GetBlockedActions(const Extension* extension);
70
71 // Returns true if the given |extension| has any blocked actions.
rdevlin.cronin91f162a12014-09-03 16:48:4072 bool WantsToRun(const Extension* extension);
rdevlin.cronin50942232014-08-27 17:40:5673
rdevlin.cronin1f877032015-02-20 00:12:4274 int num_page_requests() const { return num_page_requests_; }
75
[email protected]23a85362014-07-07 23:26:1976#if defined(UNIT_TEST)
77 // Only used in tests.
78 PermissionsData::AccessType RequiresUserConsentForScriptInjectionForTesting(
79 const Extension* extension,
80 UserScript::InjectionType type) {
81 return RequiresUserConsentForScriptInjection(extension, type);
82 }
83 void RequestScriptInjectionForTesting(const Extension* extension,
rdevlin.cronin8d034e52016-02-02 22:46:3284 UserScript::RunLocation run_location,
[email protected]23a85362014-07-07 23:26:1985 const base::Closure& callback) {
rdevlin.cronin8d034e52016-02-02 22:46:3286 return RequestScriptInjection(extension, run_location, callback);
[email protected]23a85362014-07-07 23:26:1987 }
88#endif // defined(UNIT_TEST)
89
[email protected]39ef0a7c52014-05-11 01:40:0090 private:
rdevlin.cronin8d034e52016-02-02 22:46:3291 struct PendingScript {
92 PendingScript(UserScript::RunLocation run_location,
93 const base::Closure& permit_script);
94 ~PendingScript();
95
96 // The run location that the script wants to inject at.
97 UserScript::RunLocation run_location;
98
99 // The callback to run when the script is permitted by the user.
100 base::Closure permit_script;
101 };
102
103 using PendingScriptList = std::vector<PendingScript>;
104 using PendingScriptMap = std::map<std::string, PendingScriptList>;
[email protected]ac02ac52014-05-20 01:11:26105
[email protected]23a85362014-07-07 23:26:19106 // Returns true if the extension requesting script injection requires
107 // user consent. If this is true, the caller should then register a request
108 // via RequestScriptInjection().
109 PermissionsData::AccessType RequiresUserConsentForScriptInjection(
110 const Extension* extension,
111 UserScript::InjectionType type);
112
113 // |callback|. The only assumption that can be made about when (or if)
114 // |callback| is run is that, if it is run, it will run on the current page.
115 void RequestScriptInjection(const Extension* extension,
rdevlin.cronin8d034e52016-02-02 22:46:32116 UserScript::RunLocation run_location,
[email protected]23a85362014-07-07 23:26:19117 const base::Closure& callback);
118
[email protected]11814f52014-05-23 06:50:35119 // Runs any pending injections for the corresponding extension.
rdevlin.croninacb745922016-02-17 20:37:44120 void RunPendingScriptsForExtension(const Extension* extension);
[email protected]11814f52014-05-23 06:50:35121
[email protected]ac2f89372014-06-23 21:44:25122 // Handle the RequestScriptInjectionPermission message.
avia2f4804a2015-12-24 23:11:13123 void OnRequestScriptInjectionPermission(const std::string& extension_id,
124 UserScript::InjectionType script_type,
rdevlin.cronin8d034e52016-02-02 22:46:32125 UserScript::RunLocation run_location,
avia2f4804a2015-12-24 23:11:13126 int64_t request_id);
[email protected]0d8d6972014-06-03 22:41:02127
128 // Grants permission for the given request to run.
avia2f4804a2015-12-24 23:11:13129 void PermitScriptInjection(int64_t request_id);
[email protected]39ef0a7c52014-05-11 01:40:00130
rdevlin.cronin699ca6ff2014-09-29 23:59:57131 // Notifies the ExtensionActionAPI of a change (either that an extension now
132 // wants permission to run, or that it has been run).
133 void NotifyChange(const Extension* extension);
134
rdevlin.cronin6e7e5edc2014-08-29 16:23:23135 // Log metrics.
136 void LogUMA() const;
137
[email protected]ac02ac52014-05-20 01:11:26138 // content::WebContentsObserver implementation.
rdevlin.cronin45dca7f2015-06-08 19:47:03139 bool OnMessageReceived(const IPC::Message& message,
140 content::RenderFrameHost* render_frame_host) override;
dchengae36a4a2014-10-21 12:36:36141 void DidNavigateMainFrame(
rdevlin.cronin50942232014-08-27 17:40:56142 const content::LoadCommittedDetails& details,
mostynba15bee12014-10-04 00:40:32143 const content::FrameNavigateParams& params) override;
[email protected]ac02ac52014-05-20 01:11:26144
rdevlin.cronin6e7e5edc2014-08-29 16:23:23145 // ExtensionRegistryObserver:
dchengae36a4a2014-10-21 12:36:36146 void OnExtensionUnloaded(content::BrowserContext* browser_context,
147 const Extension* extension,
148 UnloadedExtensionInfo::Reason reason) override;
[email protected]39ef0a7c52014-05-11 01:40:00149
rdevlin.cronin1f877032015-02-20 00:12:42150 // The total number of requests from the renderer on the current page,
151 // including any that are pending or were immediately granted.
152 // Right now, used only in tests.
153 int num_page_requests_;
154
rdevlin.cronin699ca6ff2014-09-29 23:59:57155 // The associated browser context.
156 content::BrowserContext* browser_context_;
157
rdevlin.croninb8dffe52015-02-07 00:58:01158 // Whether or not the feature was used for any extensions. This may not be the
159 // case if the user never enabled the scripts-require-action flag.
160 bool was_used_on_page_;
[email protected]39ef0a7c52014-05-11 01:40:00161
rdevlin.cronin8d034e52016-02-02 22:46:32162 // The map of extension_id:pending_request of all pending script requests.
163 PendingScriptMap pending_scripts_;
164
165 // A set of ids for which the webRequest API was blocked on the page.
166 std::set<std::string> web_request_blocked_;
[email protected]39ef0a7c52014-05-11 01:40:00167
[email protected]ac02ac52014-05-20 01:11:26168 // The extensions which have been granted permission to run on the given page.
169 // TODO(rdevlin.cronin): Right now, this just keeps track of extensions that
170 // have been permitted to run on the page via this interface. Instead, it
171 // should incorporate more fully with ActiveTab.
172 std::set<std::string> permitted_extensions_;
[email protected]39ef0a7c52014-05-11 01:40:00173
rdevlin.cronin6e7e5edc2014-08-29 16:23:23174 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
175 extension_registry_observer_;
176
[email protected]39ef0a7c52014-05-11 01:40:00177 DISALLOW_COPY_AND_ASSIGN(ActiveScriptController);
178};
179
180} // namespace extensions
181
182#endif // CHROME_BROWSER_EXTENSIONS_ACTIVE_SCRIPT_CONTROLLER_H_