Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(236)

Side by Side Diff: chrome/browser/extensions/active_script_controller.cc

Issue 286003004: Block tabs.executeScript() from executing until user grants permission (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/active_script_controller.h" 5 #include "chrome/browser/extensions/active_script_controller.h"
6 6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/memory/scoped_ptr.h"
7 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
8 #include "base/stl_util.h" 11 #include "base/stl_util.h"
9 #include "chrome/browser/extensions/extension_action.h" 12 #include "chrome/browser/extensions/extension_action.h"
10 #include "chrome/browser/extensions/location_bar_controller.h" 13 #include "chrome/browser/extensions/location_bar_controller.h"
11 #include "chrome/browser/extensions/tab_helper.h" 14 #include "chrome/browser/extensions/tab_helper.h"
12 #include "chrome/common/extensions/api/extension_action/action_info.h" 15 #include "chrome/common/extensions/api/extension_action/action_info.h"
13 #include "content/public/browser/navigation_controller.h" 16 #include "content/public/browser/navigation_controller.h"
14 #include "content/public/browser/navigation_entry.h" 17 #include "content/public/browser/navigation_entry.h"
18 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/web_contents.h" 19 #include "content/public/browser/web_contents.h"
16 #include "extensions/browser/extension_registry.h" 20 #include "extensions/browser/extension_registry.h"
17 #include "extensions/common/extension.h" 21 #include "extensions/common/extension.h"
18 #include "extensions/common/extension_messages.h" 22 #include "extensions/common/extension_messages.h"
19 #include "extensions/common/extension_set.h" 23 #include "extensions/common/extension_set.h"
20 #include "extensions/common/feature_switch.h" 24 #include "extensions/common/feature_switch.h"
21 #include "extensions/common/permissions/permissions_data.h" 25 #include "extensions/common/permissions/permissions_data.h"
22 #include "ipc/ipc_message_macros.h" 26 #include "ipc/ipc_message_macros.h"
23 27
24 namespace extensions { 28 namespace extensions {
25 29
26 ActiveScriptController::ActiveScriptController( 30 ActiveScriptController::ActiveScriptController(
27 content::WebContents* web_contents) 31 content::WebContents* web_contents)
28 : content::WebContentsObserver(web_contents), 32 : content::WebContentsObserver(web_contents),
29 enabled_(FeatureSwitch::scripts_require_action()->IsEnabled()) { 33 enabled_(FeatureSwitch::scripts_require_action()->IsEnabled()) {
34 CHECK(web_contents);
30 } 35 }
31 36
32 ActiveScriptController::~ActiveScriptController() { 37 ActiveScriptController::~ActiveScriptController() {
33 LogUMA(); 38 LogUMA();
34 } 39 }
35 40
36 // static 41 // static
37 ActiveScriptController* ActiveScriptController::GetForWebContents( 42 ActiveScriptController* ActiveScriptController::GetForWebContents(
38 content::WebContents* web_contents) { 43 content::WebContents* web_contents) {
39 if (!web_contents) 44 if (!web_contents)
40 return NULL; 45 return NULL;
41 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents); 46 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents);
42 if (!tab_helper) 47 if (!tab_helper)
43 return NULL; 48 return NULL;
44 LocationBarController* location_bar_controller = 49 LocationBarController* location_bar_controller =
45 tab_helper->location_bar_controller(); 50 tab_helper->location_bar_controller();
46 // This should never be NULL. 51 // This should never be NULL.
47 DCHECK(location_bar_controller); 52 DCHECK(location_bar_controller);
48 return location_bar_controller->active_script_controller(); 53 return location_bar_controller->active_script_controller();
49 } 54 }
50 55
51 void ActiveScriptController::NotifyScriptExecuting( 56 bool ActiveScriptController::RequiresUserConsentForScriptInjection(
52 const std::string& extension_id, int page_id) { 57 const std::string& extension_id,
58 int page_id) {
53 content::NavigationEntry* visible_entry = 59 content::NavigationEntry* visible_entry =
54 web_contents()->GetController().GetVisibleEntry(); 60 web_contents()->GetController().GetVisibleEntry();
55 if (!visible_entry || 61 if (!visible_entry || visible_entry->GetPageID() != page_id)
56 extensions_executing_scripts_.count(extension_id) || 62 return false;
57 visible_entry->GetPageID() != page_id) {
58 return;
59 }
60 63
61 const Extension* extension = 64 const Extension* extension =
62 ExtensionRegistry::Get(web_contents()->GetBrowserContext()) 65 ExtensionRegistry::Get(web_contents()->GetBrowserContext())
63 ->enabled_extensions().GetByID(extension_id); 66 ->enabled_extensions().GetByID(extension_id);
64 if (extension && 67 if (!extension)
65 PermissionsData::RequiresActionForScriptExecution(extension)) { 68 return false;
66 extensions_executing_scripts_.insert(extension_id); 69
67 LocationBarController::NotifyChange(web_contents()); 70 if (PermissionsData::RequiresActionForScriptExecution(extension)) {
not at google - send to devlin 2014/05/16 00:08:33 extreme nit: can this be if (!PermissionData::...)
Devlin 2014/05/16 16:13:46 Done.
71 // If the feature is not enabled, we automatically allow all extensions to
72 // run scripts.
73 if (!enabled_)
74 permitted_extensions_.insert(extension->id());
75 return permitted_extensions_.count(extension->id()) == 0;
68 } 76 }
77
78 return false;
69 } 79 }
70 80
71 void ActiveScriptController::OnAdInjectionDetected( 81 void ActiveScriptController::OnAdInjectionDetected(
72 const std::vector<std::string> ad_injectors) { 82 const std::vector<std::string> ad_injectors) {
73 size_t num_preventable_ad_injectors = 83 size_t num_preventable_ad_injectors =
74 base::STLSetIntersection<std::set<std::string> >( 84 base::STLSetIntersection<std::set<std::string> >(
75 ad_injectors, extensions_executing_scripts_).size(); 85 ad_injectors, permitted_extensions_).size();
86
87 // We only log the permitted extensions metric if the feature is enabled,
88 // because otherwise the data will be boring (100% allowed).
89 if (enabled_) {
90 UMA_HISTOGRAM_COUNTS_100(
91 "Extensions.ActiveScriptController.PermittedExtensions",
92 permitted_extensions_.size());
93 UMA_HISTOGRAM_COUNTS_100(
94 "Extensions.ActiveScriptController.DeniedExtensions",
not at google - send to devlin 2014/05/16 00:08:33 I think I made this comment earlier... but this st
Devlin 2014/05/16 16:13:46 Done.
95 pending_requests_.size());
96 }
76 97
77 UMA_HISTOGRAM_COUNTS_100( 98 UMA_HISTOGRAM_COUNTS_100(
78 "Extensions.ActiveScriptController.PreventableAdInjectors", 99 "Extensions.ActiveScriptController.PreventableAdInjectors",
79 num_preventable_ad_injectors); 100 num_preventable_ad_injectors);
80 UMA_HISTOGRAM_COUNTS_100( 101 UMA_HISTOGRAM_COUNTS_100(
81 "Extensions.ActiveScriptController.PreventableAdInjectors", 102 "Extensions.ActiveScriptController.UnpreventableAdInjectors",
82 ad_injectors.size() - num_preventable_ad_injectors); 103 ad_injectors.size() - num_preventable_ad_injectors);
not at google - send to devlin 2014/05/16 00:08:33 and this stuff now needs to take into account the
Devlin 2014/05/16 16:13:46 It shouldn't - in fact, that would make it less ac
83 } 104 }
84 105
85 ExtensionAction* ActiveScriptController::GetActionForExtension( 106 ExtensionAction* ActiveScriptController::GetActionForExtension(
86 const Extension* extension) { 107 const Extension* extension) {
87 if (!enabled_ || extensions_executing_scripts_.count(extension->id()) == 0) 108 if (!enabled_ || pending_requests_.count(extension->id()) == 0)
88 return NULL; // No action for this extension. 109 return NULL; // No action for this extension.
89 110
90 ActiveScriptMap::iterator existing = 111 ActiveScriptMap::iterator existing =
91 active_script_actions_.find(extension->id()); 112 active_script_actions_.find(extension->id());
92 if (existing != active_script_actions_.end()) 113 if (existing != active_script_actions_.end())
93 return existing->second.get(); 114 return existing->second.get();
94 115
95 linked_ptr<ExtensionAction> action(new ExtensionAction( 116 linked_ptr<ExtensionAction> action(new ExtensionAction(
96 extension->id(), ActionInfo::TYPE_PAGE, ActionInfo())); 117 extension->id(), ActionInfo::TYPE_PAGE, ActionInfo()));
97 action->SetTitle(ExtensionAction::kDefaultTabId, extension->name()); 118 action->SetTitle(ExtensionAction::kDefaultTabId, extension->name());
98 action->SetIsVisible(ExtensionAction::kDefaultTabId, true); 119 action->SetIsVisible(ExtensionAction::kDefaultTabId, true);
99 120
100 const ActionInfo* action_info = ActionInfo::GetPageActionInfo(extension); 121 const ActionInfo* action_info = ActionInfo::GetPageActionInfo(extension);
101 if (!action_info) 122 if (!action_info)
102 action_info = ActionInfo::GetBrowserActionInfo(extension); 123 action_info = ActionInfo::GetBrowserActionInfo(extension);
103 124
104 if (action_info && !action_info->default_icon.empty()) { 125 if (action_info && !action_info->default_icon.empty()) {
105 action->set_default_icon( 126 action->set_default_icon(
106 make_scoped_ptr(new ExtensionIconSet(action_info->default_icon))); 127 make_scoped_ptr(new ExtensionIconSet(action_info->default_icon)));
107 } 128 }
108 129
109 active_script_actions_[extension->id()] = action; 130 active_script_actions_[extension->id()] = action;
110 return action.get(); 131 return action.get();
111 } 132 }
112 133
113 LocationBarController::Action ActiveScriptController::OnClicked( 134 LocationBarController::Action ActiveScriptController::OnClicked(
114 const Extension* extension) { 135 const Extension* extension) {
115 DCHECK(extensions_executing_scripts_.count(extension->id()) > 0); 136 DCHECK(extension);
137 PendingRequestMap::iterator iter =
138 pending_requests_.find(extension->id());
139 DCHECK(iter != pending_requests_.end());
140
141 // We add this to the list of permitted extensions and erase pending entries
142 // *before* running them to guard against the crazy case where running the
143 // callbacks adds more entries.
144 permitted_extensions_.insert(extension->id());
145 PendingRequestList requests;
146 iter->second.swap(requests);
147 pending_requests_.erase(extension->id());
148
149 // Run all pending injections for the given extension.
150 for (PendingRequestList::iterator request = requests.begin();
151 request != requests.end();
152 ++request) {
153 request->Run();
154 }
155
156 // Inform the location bar that the action is now gone.
157 LocationBarController::NotifyChange(web_contents());
158
116 return LocationBarController::ACTION_NONE; 159 return LocationBarController::ACTION_NONE;
117 } 160 }
118 161
119 void ActiveScriptController::OnNavigated() { 162 void ActiveScriptController::OnNavigated() {
120 LogUMA(); 163 LogUMA();
121 extensions_executing_scripts_.clear(); 164 permitted_extensions_.clear();
165 pending_requests_.clear();
166 }
167
168 void ActiveScriptController::OnNotifyExtensionScriptExecution(
169 const std::string& extension_id,
170 int page_id) {
171 if (!Extension::IdIsValid(extension_id)) {
172 NOTREACHED() << "'" << extension_id << "' is not a valid id.";
173 return;
174 }
175
not at google - send to devlin 2014/05/16 00:08:33 maybe note here for future hapless readers that th
Devlin 2014/05/16 16:13:46 Done.
176 if (RequiresUserConsentForScriptInjection(extension_id, page_id))
177 RequestScriptInjection(extension_id, base::Bind(&base::DoNothing));
178 }
179
180 void ActiveScriptController::RequestScriptInjection(
181 const std::string& extension_id,
182 const base::Closure& request) {
183 PendingRequestList& list = pending_requests_[extension_id];
184 list.push_back(request);
185
186 // If this was the first entry, notify the location bar that there's a new
187 // icon.
188 if (list.size() == 1u)
189 LocationBarController::NotifyChange(web_contents());
122 } 190 }
123 191
124 bool ActiveScriptController::OnMessageReceived(const IPC::Message& message) { 192 bool ActiveScriptController::OnMessageReceived(const IPC::Message& message) {
125 bool handled = true; 193 bool handled = true;
126 IPC_BEGIN_MESSAGE_MAP(ActiveScriptController, message) 194 IPC_BEGIN_MESSAGE_MAP(ActiveScriptController, message)
127 IPC_MESSAGE_HANDLER(ExtensionHostMsg_NotifyExtensionScriptExecution, 195 IPC_MESSAGE_HANDLER(ExtensionHostMsg_NotifyExtensionScriptExecution,
128 OnNotifyExtensionScriptExecution) 196 OnNotifyExtensionScriptExecution)
129 IPC_MESSAGE_UNHANDLED(handled = false) 197 IPC_MESSAGE_UNHANDLED(handled = false)
130 IPC_END_MESSAGE_MAP() 198 IPC_END_MESSAGE_MAP()
131 return handled; 199 return handled;
132 } 200 }
133 201
134 void ActiveScriptController::OnNotifyExtensionScriptExecution(
135 const std::string& extension_id,
136 int page_id) {
137 if (!Extension::IdIsValid(extension_id)) {
138 NOTREACHED() << "'" << extension_id << "' is not a valid id.";
139 return;
140 }
141 NotifyScriptExecuting(extension_id, page_id);
142 }
143
144 void ActiveScriptController::LogUMA() const { 202 void ActiveScriptController::LogUMA() const {
145 UMA_HISTOGRAM_COUNTS_100( 203 UMA_HISTOGRAM_COUNTS_100(
146 "Extensions.ActiveScriptController.ShownActiveScriptsOnPage", 204 "Extensions.ActiveScriptController.ShownActiveScriptsOnPage",
147 extensions_executing_scripts_.size()); 205 pending_requests_.size());
148 } 206 }
149 207
150 } // namespace extensions 208 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698