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

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

Issue 348313003: Create withheld permissions (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Kalman's Created 6 years, 5 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" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "chrome/browser/extensions/active_tab_permission_granter.h" 12 #include "chrome/browser/extensions/active_tab_permission_granter.h"
13 #include "chrome/browser/extensions/extension_action.h" 13 #include "chrome/browser/extensions/extension_action.h"
14 #include "chrome/browser/extensions/extension_util.h" 14 #include "chrome/browser/extensions/extension_util.h"
15 #include "chrome/browser/extensions/location_bar_controller.h" 15 #include "chrome/browser/extensions/location_bar_controller.h"
16 #include "chrome/browser/extensions/tab_helper.h" 16 #include "chrome/browser/extensions/tab_helper.h"
17 #include "chrome/browser/sessions/session_id.h" 17 #include "chrome/browser/sessions/session_id.h"
18 #include "chrome/common/extensions/api/extension_action/action_info.h" 18 #include "chrome/common/extensions/api/extension_action/action_info.h"
19 #include "content/public/browser/navigation_controller.h" 19 #include "content/public/browser/navigation_controller.h"
20 #include "content/public/browser/navigation_entry.h" 20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/render_view_host.h" 21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/web_contents.h" 22 #include "content/public/browser/web_contents.h"
23 #include "extensions/browser/extension_registry.h" 23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/common/extension.h" 24 #include "extensions/common/extension.h"
25 #include "extensions/common/extension_messages.h" 25 #include "extensions/common/extension_messages.h"
26 #include "extensions/common/extension_set.h" 26 #include "extensions/common/extension_set.h"
27 #include "extensions/common/feature_switch.h" 27 #include "extensions/common/feature_switch.h"
28 #include "extensions/common/manifest.h"
28 #include "extensions/common/permissions/permissions_data.h" 29 #include "extensions/common/permissions/permissions_data.h"
29 #include "ipc/ipc_message_macros.h" 30 #include "ipc/ipc_message_macros.h"
30 31
31 namespace extensions { 32 namespace extensions {
32 33
34 namespace {
35
36 // Returns true if the extension should be regarded as a "permitted" extension
37 // for the case of metrics. We need this because we only actually withhold
38 // permissions if the switch is enabled, but want to record metrics in all
39 // cases.
40 // "ExtensionWouldHaveHadHostPermissionsWithheldIfSwitchWasOn()" would be
41 // more accurate, but too long.
42 bool ShouldRecordExtension(const Extension* extension) {
43 return extension->ShouldDisplayInExtensionSettings() &&
44 !Manifest::IsPolicyLocation(extension->location()) &&
45 !Manifest::IsComponentLocation(extension->location()) &&
46 !PermissionsData::CanExecuteScriptEverywhere(extension) &&
47 extension->permissions_data()
48 ->active_permissions()
49 ->ShouldWarnAllHosts();
50 }
51
52 } // namespace
53
33 ActiveScriptController::PendingRequest::PendingRequest() : 54 ActiveScriptController::PendingRequest::PendingRequest() :
34 page_id(-1) { 55 page_id(-1) {
35 } 56 }
36 57
37 ActiveScriptController::PendingRequest::PendingRequest( 58 ActiveScriptController::PendingRequest::PendingRequest(
38 const base::Closure& closure, 59 const base::Closure& closure,
39 int page_id) 60 int page_id)
40 : closure(closure), 61 : closure(closure),
41 page_id(page_id) { 62 page_id(page_id) {
42 } 63 }
(...skipping 20 matching lines...) Expand all
63 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents); 84 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents);
64 if (!tab_helper) 85 if (!tab_helper)
65 return NULL; 86 return NULL;
66 LocationBarController* location_bar_controller = 87 LocationBarController* location_bar_controller =
67 tab_helper->location_bar_controller(); 88 tab_helper->location_bar_controller();
68 // This should never be NULL. 89 // This should never be NULL.
69 DCHECK(location_bar_controller); 90 DCHECK(location_bar_controller);
70 return location_bar_controller->active_script_controller(); 91 return location_bar_controller->active_script_controller();
71 } 92 }
72 93
73 bool ActiveScriptController::RequiresUserConsentForScriptInjection(
74 const Extension* extension) {
75 CHECK(extension);
76 if (!extension->permissions_data()->RequiresActionForScriptExecution(
77 extension,
78 SessionID::IdForTab(web_contents()),
79 web_contents()->GetVisibleURL()) ||
80 util::AllowedScriptingOnAllUrls(extension->id(),
81 web_contents()->GetBrowserContext())) {
82 return false;
83 }
84
85 // If the feature is not enabled, we automatically allow all extensions to
86 // run scripts.
87 if (!enabled_)
88 permitted_extensions_.insert(extension->id());
89
90 return permitted_extensions_.count(extension->id()) == 0;
91 }
92
93 void ActiveScriptController::RequestScriptInjection(
94 const Extension* extension,
95 int page_id,
96 const base::Closure& callback) {
97 CHECK(extension);
98 PendingRequestList& list = pending_requests_[extension->id()];
99 list.push_back(PendingRequest(callback, page_id));
100
101 // If this was the first entry, notify the location bar that there's a new
102 // icon.
103 if (list.size() == 1u)
104 LocationBarController::NotifyChange(web_contents());
105 }
106
107 void ActiveScriptController::OnActiveTabPermissionGranted( 94 void ActiveScriptController::OnActiveTabPermissionGranted(
108 const Extension* extension) { 95 const Extension* extension) {
109 RunPendingForExtension(extension); 96 RunPendingForExtension(extension);
110 } 97 }
111 98
112 void ActiveScriptController::OnAdInjectionDetected( 99 void ActiveScriptController::OnAdInjectionDetected(
113 const std::set<std::string>& ad_injectors) { 100 const std::set<std::string>& ad_injectors) {
114 // We're only interested in data if there are ad injectors detected. 101 // We're only interested in data if there are ad injectors detected.
115 if (ad_injectors.empty()) 102 if (ad_injectors.empty())
116 return; 103 return;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 permitted_extensions_.clear(); 154 permitted_extensions_.clear();
168 pending_requests_.clear(); 155 pending_requests_.clear();
169 } 156 }
170 157
171 void ActiveScriptController::OnExtensionUnloaded(const Extension* extension) { 158 void ActiveScriptController::OnExtensionUnloaded(const Extension* extension) {
172 PendingRequestMap::iterator iter = pending_requests_.find(extension->id()); 159 PendingRequestMap::iterator iter = pending_requests_.find(extension->id());
173 if (iter != pending_requests_.end()) 160 if (iter != pending_requests_.end())
174 pending_requests_.erase(iter); 161 pending_requests_.erase(iter);
175 } 162 }
176 163
164 PermissionsData::AccessType
165 ActiveScriptController::RequiresUserConsentForScriptInjection(
166 const Extension* extension,
167 UserScript::InjectionType type) {
168 CHECK(extension);
169
170 // If the feature is not enabled, we automatically allow all extensions to
171 // run scripts.
172 if (!enabled_)
173 permitted_extensions_.insert(extension->id());
174
175 // Allow the extension if it's been explicitly granted permission.
176 if (permitted_extensions_.count(extension->id()) > 0)
177 return PermissionsData::ACCESS_ALLOWED;
178
179 GURL url = web_contents()->GetVisibleURL();
180 int tab_id = SessionID::IdForTab(web_contents());
181 switch (type) {
182 case UserScript::CONTENT_SCRIPT:
183 return extension->permissions_data()->GetContentScriptAccess(
184 extension, url, url, tab_id, -1, NULL);
185 case UserScript::PROGRAMMATIC_SCRIPT:
186 return extension->permissions_data()->GetPageAccess(
187 extension, url, url, tab_id, -1, NULL);
188 }
189
190 NOTREACHED();
191 return PermissionsData::ACCESS_DENIED;
192 }
193
194 void ActiveScriptController::RequestScriptInjection(
195 const Extension* extension,
196 int page_id,
197 const base::Closure& callback) {
198 CHECK(extension);
199 PendingRequestList& list = pending_requests_[extension->id()];
200 list.push_back(PendingRequest(callback, page_id));
201
202 // If this was the first entry, notify the location bar that there's a new
203 // icon.
204 if (list.size() == 1u)
205 LocationBarController::NotifyChange(web_contents());
206 }
207
177 void ActiveScriptController::RunPendingForExtension( 208 void ActiveScriptController::RunPendingForExtension(
178 const Extension* extension) { 209 const Extension* extension) {
179 DCHECK(extension); 210 DCHECK(extension);
180 PendingRequestMap::iterator iter =
181 pending_requests_.find(extension->id());
182 if (iter == pending_requests_.end())
183 return;
184 211
185 content::NavigationEntry* visible_entry = 212 content::NavigationEntry* visible_entry =
186 web_contents()->GetController().GetVisibleEntry(); 213 web_contents()->GetController().GetVisibleEntry();
187 // Refuse to run if there's no visible entry, because we have no idea of 214 // Refuse to run if there's no visible entry, because we have no idea of
188 // determining if it's the proper page. This should rarely, if ever, happen. 215 // determining if it's the proper page. This should rarely, if ever, happen.
189 if (!visible_entry) 216 if (!visible_entry)
190 return; 217 return;
191 218
192 int page_id = visible_entry->GetPageID(); 219 int page_id = visible_entry->GetPageID();
193 220
194 // We add this to the list of permitted extensions and erase pending entries 221 // We add this to the list of permitted extensions and erase pending entries
195 // *before* running them to guard against the crazy case where running the 222 // *before* running them to guard against the crazy case where running the
196 // callbacks adds more entries. 223 // callbacks adds more entries.
197 permitted_extensions_.insert(extension->id()); 224 permitted_extensions_.insert(extension->id());
225
226 PendingRequestMap::iterator iter = pending_requests_.find(extension->id());
227 if (iter == pending_requests_.end())
228 return;
229
198 PendingRequestList requests; 230 PendingRequestList requests;
199 iter->second.swap(requests); 231 iter->second.swap(requests);
200 pending_requests_.erase(extension->id()); 232 pending_requests_.erase(extension->id());
201 233
202 // Clicking to run the extension counts as granting it permission to run on 234 // Clicking to run the extension counts as granting it permission to run on
203 // the given tab. 235 // the given tab.
204 // The extension may already have active tab at this point, but granting 236 // The extension may already have active tab at this point, but granting
205 // it twice is essentially a no-op. 237 // it twice is essentially a no-op.
206 TabHelper::FromWebContents(web_contents())-> 238 TabHelper::FromWebContents(web_contents())->
207 active_tab_permission_granter()->GrantIfRequested(extension); 239 active_tab_permission_granter()->GrantIfRequested(extension);
208 240
209 // Run all pending injections for the given extension. 241 // Run all pending injections for the given extension.
210 for (PendingRequestList::iterator request = requests.begin(); 242 for (PendingRequestList::iterator request = requests.begin();
211 request != requests.end(); 243 request != requests.end();
212 ++request) { 244 ++request) {
213 // Only run if it's on the proper page. 245 // Only run if it's on the proper page.
214 if (request->page_id == page_id) 246 if (request->page_id == page_id)
215 request->closure.Run(); 247 request->closure.Run();
216 } 248 }
217 249
218 // Inform the location bar that the action is now gone. 250 // Inform the location bar that the action is now gone.
219 LocationBarController::NotifyChange(web_contents()); 251 LocationBarController::NotifyChange(web_contents());
220 } 252 }
221 253
222 void ActiveScriptController::OnRequestScriptInjectionPermission( 254 void ActiveScriptController::OnRequestScriptInjectionPermission(
223 const std::string& extension_id, 255 const std::string& extension_id,
256 UserScript::InjectionType script_type,
224 int page_id, 257 int page_id,
225 int request_id) { 258 int request_id) {
226 if (!Extension::IdIsValid(extension_id)) { 259 if (!Extension::IdIsValid(extension_id)) {
227 NOTREACHED() << "'" << extension_id << "' is not a valid id."; 260 NOTREACHED() << "'" << extension_id << "' is not a valid id.";
228 return; 261 return;
229 } 262 }
230 263
231 const Extension* extension = 264 const Extension* extension =
232 ExtensionRegistry::Get(web_contents()->GetBrowserContext()) 265 ExtensionRegistry::Get(web_contents()->GetBrowserContext())
233 ->enabled_extensions().GetByID(extension_id); 266 ->enabled_extensions().GetByID(extension_id);
234 // We shouldn't allow extensions which are no longer enabled to run any 267 // We shouldn't allow extensions which are no longer enabled to run any
235 // scripts. Ignore the request. 268 // scripts. Ignore the request.
236 if (!extension) 269 if (!extension)
237 return; 270 return;
238 271
239 // If the request id is -1, that signals that the content script has already 272 // If the request id is -1, that signals that the content script has already
240 // ran (because this feature is not enabled). Add the extension to the list of 273 // ran (because this feature is not enabled). Add the extension to the list of
241 // permitted extensions (for metrics), and return immediately. 274 // permitted extensions (for metrics), and return immediately.
242 if (request_id == -1) { 275 if (request_id == -1) {
243 DCHECK(!enabled_); 276 if (ShouldRecordExtension(extension)) {
244 permitted_extensions_.insert(extension->id()); 277 DCHECK(!enabled_);
278 permitted_extensions_.insert(extension->id());
279 }
245 return; 280 return;
246 } 281 }
247 282
248 if (RequiresUserConsentForScriptInjection(extension)) { 283 switch (RequiresUserConsentForScriptInjection(extension, script_type)) {
249 // This base::Unretained() is safe, because the callback is only invoked by 284 case PermissionsData::ACCESS_ALLOWED:
250 // this object. 285 PermitScriptInjection(request_id);
251 RequestScriptInjection( 286 break;
252 extension, 287 case PermissionsData::ACCESS_WITHHELD:
253 page_id, 288 // This base::Unretained() is safe, because the callback is only invoked
254 base::Bind(&ActiveScriptController::PermitScriptInjection, 289 // by this object.
255 base::Unretained(this), 290 RequestScriptInjection(
256 request_id)); 291 extension,
257 } else { 292 page_id,
258 PermitScriptInjection(request_id); 293 base::Bind(&ActiveScriptController::PermitScriptInjection,
294 base::Unretained(this),
295 request_id));
296 break;
297 case PermissionsData::ACCESS_DENIED:
298 // We should usually only get a "deny access" if the page changed (as the
299 // renderer wouldn't have requested permission if the answer was always
300 // "no"). Just let the request fizzle and die.
301 break;
259 } 302 }
260 } 303 }
261 304
262 void ActiveScriptController::PermitScriptInjection(int request_id) { 305 void ActiveScriptController::PermitScriptInjection(int request_id) {
306 // This only sends the response to the renderer - the process of adding the
307 // extension to the list of |permitted_extensions_| is done elsewhere.
263 content::RenderViewHost* render_view_host = 308 content::RenderViewHost* render_view_host =
264 web_contents()->GetRenderViewHost(); 309 web_contents()->GetRenderViewHost();
265 if (render_view_host) { 310 if (render_view_host) {
266 render_view_host->Send(new ExtensionMsg_PermitScriptInjection( 311 render_view_host->Send(new ExtensionMsg_PermitScriptInjection(
267 render_view_host->GetRoutingID(), request_id)); 312 render_view_host->GetRoutingID(), request_id));
268 } 313 }
269 } 314 }
270 315
271 bool ActiveScriptController::OnMessageReceived(const IPC::Message& message) { 316 bool ActiveScriptController::OnMessageReceived(const IPC::Message& message) {
272 bool handled = true; 317 bool handled = true;
(...skipping 16 matching lines...) Expand all
289 UMA_HISTOGRAM_COUNTS_100( 334 UMA_HISTOGRAM_COUNTS_100(
290 "Extensions.ActiveScriptController.PermittedExtensions", 335 "Extensions.ActiveScriptController.PermittedExtensions",
291 permitted_extensions_.size()); 336 permitted_extensions_.size());
292 UMA_HISTOGRAM_COUNTS_100( 337 UMA_HISTOGRAM_COUNTS_100(
293 "Extensions.ActiveScriptController.DeniedExtensions", 338 "Extensions.ActiveScriptController.DeniedExtensions",
294 pending_requests_.size()); 339 pending_requests_.size());
295 } 340 }
296 } 341 }
297 342
298 } // namespace extensions 343 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698