| OLD | NEW |
| 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/extension_action_runner.h" | 5 #include "chrome/browser/extensions/extension_action_runner.h" |
| 6 | 6 |
| 7 #include "base/auto_reset.h" |
| 7 #include "base/bind.h" | 8 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
| 9 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 11 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
| 12 #include "chrome/browser/extensions/active_tab_permission_granter.h" | 13 #include "chrome/browser/extensions/active_tab_permission_granter.h" |
| 13 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" | 14 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" |
| 14 #include "chrome/browser/extensions/extension_action.h" | 15 #include "chrome/browser/extensions/extension_action.h" |
| 15 #include "chrome/browser/extensions/extension_action_manager.h" | 16 #include "chrome/browser/extensions/extension_action_manager.h" |
| 16 #include "chrome/browser/extensions/permissions_updater.h" | 17 #include "chrome/browser/extensions/permissions_updater.h" |
| 17 #include "chrome/browser/extensions/tab_helper.h" | 18 #include "chrome/browser/extensions/tab_helper.h" |
| 18 #include "chrome/browser/profiles/profile.h" | 19 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/browser/sessions/session_tab_helper.h" | 20 #include "chrome/browser/sessions/session_tab_helper.h" |
| 21 #include "chrome/browser/ui/browser_finder.h" |
| 22 #include "chrome/browser/ui/browser_window.h" |
| 23 #include "chrome/browser/ui/extensions/blocked_action_bubble_delegate.h" |
| 24 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h" |
| 20 #include "chrome/common/extensions/api/extension_action/action_info.h" | 25 #include "chrome/common/extensions/api/extension_action/action_info.h" |
| 21 #include "components/crx_file/id_util.h" | 26 #include "components/crx_file/id_util.h" |
| 22 #include "content/public/browser/navigation_controller.h" | 27 #include "content/public/browser/navigation_controller.h" |
| 23 #include "content/public/browser/navigation_details.h" | 28 #include "content/public/browser/navigation_details.h" |
| 24 #include "content/public/browser/navigation_entry.h" | 29 #include "content/public/browser/navigation_entry.h" |
| 25 #include "content/public/browser/render_view_host.h" | 30 #include "content/public/browser/render_view_host.h" |
| 26 #include "content/public/browser/web_contents.h" | 31 #include "content/public/browser/web_contents.h" |
| 27 #include "extensions/browser/extension_registry.h" | 32 #include "extensions/browser/extension_registry.h" |
| 28 #include "extensions/common/extension.h" | 33 #include "extensions/common/extension.h" |
| 29 #include "extensions/common/extension_messages.h" | 34 #include "extensions/common/extension_messages.h" |
| 30 #include "extensions/common/extension_set.h" | 35 #include "extensions/common/extension_set.h" |
| 31 #include "extensions/common/manifest.h" | 36 #include "extensions/common/manifest.h" |
| 32 #include "extensions/common/permissions/permission_set.h" | 37 #include "extensions/common/permissions/permission_set.h" |
| 33 #include "extensions/common/permissions/permissions_data.h" | 38 #include "extensions/common/permissions/permissions_data.h" |
| 34 #include "ipc/ipc_message_macros.h" | 39 #include "ipc/ipc_message_macros.h" |
| 35 | 40 |
| 36 namespace extensions { | 41 namespace extensions { |
| 37 | 42 |
| 43 namespace { |
| 44 |
| 45 // The blocked actions that require a page refresh to run. |
| 46 const int kRefreshRequiredActionsMask = |
| 47 BLOCKED_ACTION_WEB_REQUEST | BLOCKED_ACTION_SCRIPT_AT_START; |
| 48 } |
| 49 |
| 38 ExtensionActionRunner::PendingScript::PendingScript( | 50 ExtensionActionRunner::PendingScript::PendingScript( |
| 39 UserScript::RunLocation run_location, | 51 UserScript::RunLocation run_location, |
| 40 const base::Closure& permit_script) | 52 const base::Closure& permit_script) |
| 41 : run_location(run_location), permit_script(permit_script) {} | 53 : run_location(run_location), permit_script(permit_script) {} |
| 42 | 54 |
| 43 ExtensionActionRunner::PendingScript::PendingScript( | 55 ExtensionActionRunner::PendingScript::PendingScript( |
| 44 const PendingScript& other) = default; | 56 const PendingScript& other) = default; |
| 45 | 57 |
| 46 ExtensionActionRunner::PendingScript::~PendingScript() {} | 58 ExtensionActionRunner::PendingScript::~PendingScript() {} |
| 47 | 59 |
| 48 ExtensionActionRunner::ExtensionActionRunner(content::WebContents* web_contents) | 60 ExtensionActionRunner::ExtensionActionRunner(content::WebContents* web_contents) |
| 49 : content::WebContentsObserver(web_contents), | 61 : content::WebContentsObserver(web_contents), |
| 50 num_page_requests_(0), | 62 num_page_requests_(0), |
| 51 browser_context_(web_contents->GetBrowserContext()), | 63 browser_context_(web_contents->GetBrowserContext()), |
| 52 was_used_on_page_(false), | 64 was_used_on_page_(false), |
| 53 extension_registry_observer_(this) { | 65 ignore_active_tab_granted_(false), |
| 66 extension_registry_observer_(this), |
| 67 weak_factory_(this) { |
| 54 CHECK(web_contents); | 68 CHECK(web_contents); |
| 55 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); | 69 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); |
| 56 } | 70 } |
| 57 | 71 |
| 58 ExtensionActionRunner::~ExtensionActionRunner() { | 72 ExtensionActionRunner::~ExtensionActionRunner() { |
| 59 LogUMA(); | 73 LogUMA(); |
| 60 } | 74 } |
| 61 | 75 |
| 62 // static | 76 // static |
| 63 ExtensionActionRunner* ExtensionActionRunner::GetForWebContents( | 77 ExtensionActionRunner* ExtensionActionRunner::GetForWebContents( |
| 64 content::WebContents* web_contents) { | 78 content::WebContents* web_contents) { |
| 65 if (!web_contents) | 79 if (!web_contents) |
| 66 return NULL; | 80 return NULL; |
| 67 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents); | 81 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents); |
| 68 return tab_helper ? tab_helper->extension_action_runner() : NULL; | 82 return tab_helper ? tab_helper->extension_action_runner() : NULL; |
| 69 } | 83 } |
| 70 | 84 |
| 71 ExtensionAction::ShowAction ExtensionActionRunner::RunAction( | 85 ExtensionAction::ShowAction ExtensionActionRunner::RunAction( |
| 72 const Extension* extension, | 86 const Extension* extension, |
| 73 bool grant_tab_permissions) { | 87 bool grant_tab_permissions) { |
| 74 bool has_pending_scripts = WantsToRun(extension); | |
| 75 if (grant_tab_permissions) { | 88 if (grant_tab_permissions) { |
| 89 int blocked = GetBlockedActions(extension); |
| 90 if ((blocked & kRefreshRequiredActionsMask) != 0) { |
| 91 ShowBlockedActionBubble(extension); |
| 92 return ExtensionAction::ACTION_NONE; |
| 93 } |
| 76 TabHelper::FromWebContents(web_contents()) | 94 TabHelper::FromWebContents(web_contents()) |
| 77 ->active_tab_permission_granter() | 95 ->active_tab_permission_granter() |
| 78 ->GrantIfRequested(extension); | 96 ->GrantIfRequested(extension); |
| 79 // If the extension had blocked actions, granting active tab will have | 97 // If the extension had blocked actions, granting active tab will have |
| 80 // run the extension. Don't execute further since clicking should run | 98 // run the extension. Don't execute further since clicking should run |
| 81 // blocked actions *or* the normal extension action, not both. | 99 // blocked actions *or* the normal extension action, not both. |
| 82 if (has_pending_scripts) | 100 if (blocked != BLOCKED_ACTION_NONE) |
| 83 return ExtensionAction::ACTION_NONE; | 101 return ExtensionAction::ACTION_NONE; |
| 84 } | 102 } |
| 85 | 103 |
| 86 ExtensionAction* extension_action = | 104 ExtensionAction* extension_action = |
| 87 ExtensionActionManager::Get(browser_context_) | 105 ExtensionActionManager::Get(browser_context_) |
| 88 ->GetExtensionAction(*extension); | 106 ->GetExtensionAction(*extension); |
| 89 | 107 |
| 90 // Anything that gets here should have a page or browser action. | 108 // Anything that gets here should have a page or browser action. |
| 91 DCHECK(extension_action); | 109 DCHECK(extension_action); |
| 92 int tab_id = SessionTabHelper::IdForTab(web_contents()); | 110 int tab_id = SessionTabHelper::IdForTab(web_contents()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 116 RunPendingScriptsForExtension(extension); | 134 RunPendingScriptsForExtension(extension); |
| 117 web_request_blocked_.erase(extension->id()); | 135 web_request_blocked_.erase(extension->id()); |
| 118 | 136 |
| 119 // The extension ran, so we need to tell the ExtensionActionAPI that we no | 137 // The extension ran, so we need to tell the ExtensionActionAPI that we no |
| 120 // longer want to act. | 138 // longer want to act. |
| 121 NotifyChange(extension); | 139 NotifyChange(extension); |
| 122 } | 140 } |
| 123 | 141 |
| 124 void ExtensionActionRunner::OnActiveTabPermissionGranted( | 142 void ExtensionActionRunner::OnActiveTabPermissionGranted( |
| 125 const Extension* extension) { | 143 const Extension* extension) { |
| 126 if (WantsToRun(extension)) | 144 if (!ignore_active_tab_granted_ && WantsToRun(extension)) |
| 127 RunBlockedActions(extension); | 145 RunBlockedActions(extension); |
| 128 } | 146 } |
| 129 | 147 |
| 130 void ExtensionActionRunner::OnWebRequestBlocked(const Extension* extension) { | 148 void ExtensionActionRunner::OnWebRequestBlocked(const Extension* extension) { |
| 131 web_request_blocked_.insert(extension->id()); | 149 web_request_blocked_.insert(extension->id()); |
| 132 } | 150 } |
| 133 | 151 |
| 134 int ExtensionActionRunner::GetBlockedActions(const Extension* extension) { | 152 int ExtensionActionRunner::GetBlockedActions(const Extension* extension) { |
| 135 int blocked_actions = BLOCKED_ACTION_NONE; | 153 int blocked_actions = BLOCKED_ACTION_NONE; |
| 136 if (web_request_blocked_.count(extension->id()) != 0) | 154 if (web_request_blocked_.count(extension->id()) != 0) |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 if (was_used_on_page_) { | 323 if (was_used_on_page_) { |
| 306 UMA_HISTOGRAM_COUNTS_100( | 324 UMA_HISTOGRAM_COUNTS_100( |
| 307 "Extensions.ActiveScriptController.PermittedExtensions", | 325 "Extensions.ActiveScriptController.PermittedExtensions", |
| 308 permitted_extensions_.size()); | 326 permitted_extensions_.size()); |
| 309 UMA_HISTOGRAM_COUNTS_100( | 327 UMA_HISTOGRAM_COUNTS_100( |
| 310 "Extensions.ActiveScriptController.DeniedExtensions", | 328 "Extensions.ActiveScriptController.DeniedExtensions", |
| 311 pending_scripts_.size()); | 329 pending_scripts_.size()); |
| 312 } | 330 } |
| 313 } | 331 } |
| 314 | 332 |
| 333 void ExtensionActionRunner::ShowBlockedActionBubble( |
| 334 const Extension* extension) { |
| 335 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| 336 ToolbarActionsBar* toolbar_actions_bar = |
| 337 browser ? browser->window()->GetToolbarActionsBar() : nullptr; |
| 338 if (toolbar_actions_bar) { |
| 339 auto callback = |
| 340 base::Bind(&ExtensionActionRunner::OnBlockedActionBubbleClosed, |
| 341 weak_factory_.GetWeakPtr(), extension->id()); |
| 342 if (default_bubble_close_action_for_testing_) { |
| 343 base::MessageLoop::current()->PostTask( |
| 344 FROM_HERE, |
| 345 base::Bind(callback, *default_bubble_close_action_for_testing_)); |
| 346 } else { |
| 347 toolbar_actions_bar->ShowToolbarActionBubble(make_scoped_ptr( |
| 348 new BlockedActionBubbleDelegate(callback, extension->id()))); |
| 349 } |
| 350 } |
| 351 } |
| 352 |
| 353 void ExtensionActionRunner::OnBlockedActionBubbleClosed( |
| 354 const std::string& extension_id, |
| 355 ToolbarActionsBarBubbleDelegate::CloseAction action) { |
| 356 // If the user agreed to refresh the page, do so. |
| 357 if (action == ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE) { |
| 358 const Extension* extension = ExtensionRegistry::Get(browser_context_) |
| 359 ->enabled_extensions() |
| 360 .GetByID(extension_id); |
| 361 if (!extension) |
| 362 return; |
| 363 { |
| 364 // Ignore the active tab permission being granted because we don't want |
| 365 // to run scripts right before we refresh the page. |
| 366 base::AutoReset<bool> ignore_active_tab(&ignore_active_tab_granted_, |
| 367 true); |
| 368 TabHelper::FromWebContents(web_contents()) |
| 369 ->active_tab_permission_granter() |
| 370 ->GrantIfRequested(extension); |
| 371 } |
| 372 web_contents()->GetController().Reload(false); |
| 373 } |
| 374 } |
| 375 |
| 315 bool ExtensionActionRunner::OnMessageReceived( | 376 bool ExtensionActionRunner::OnMessageReceived( |
| 316 const IPC::Message& message, | 377 const IPC::Message& message, |
| 317 content::RenderFrameHost* render_frame_host) { | 378 content::RenderFrameHost* render_frame_host) { |
| 318 bool handled = true; | 379 bool handled = true; |
| 319 IPC_BEGIN_MESSAGE_MAP(ExtensionActionRunner, message) | 380 IPC_BEGIN_MESSAGE_MAP(ExtensionActionRunner, message) |
| 320 IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestScriptInjectionPermission, | 381 IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestScriptInjectionPermission, |
| 321 OnRequestScriptInjectionPermission) | 382 OnRequestScriptInjectionPermission) |
| 322 IPC_MESSAGE_UNHANDLED(handled = false) | 383 IPC_MESSAGE_UNHANDLED(handled = false) |
| 323 IPC_END_MESSAGE_MAP() | 384 IPC_END_MESSAGE_MAP() |
| 324 return handled; | 385 return handled; |
| 325 } | 386 } |
| 326 | 387 |
| 327 void ExtensionActionRunner::DidNavigateMainFrame( | 388 void ExtensionActionRunner::DidNavigateMainFrame( |
| 328 const content::LoadCommittedDetails& details, | 389 const content::LoadCommittedDetails& details, |
| 329 const content::FrameNavigateParams& params) { | 390 const content::FrameNavigateParams& params) { |
| 330 if (details.is_in_page) | 391 if (details.is_in_page) |
| 331 return; | 392 return; |
| 332 | 393 |
| 333 LogUMA(); | 394 LogUMA(); |
| 334 num_page_requests_ = 0; | 395 num_page_requests_ = 0; |
| 335 permitted_extensions_.clear(); | 396 permitted_extensions_.clear(); |
| 336 pending_scripts_.clear(); | 397 pending_scripts_.clear(); |
| 337 web_request_blocked_.clear(); | 398 web_request_blocked_.clear(); |
| 338 was_used_on_page_ = false; | 399 was_used_on_page_ = false; |
| 400 weak_factory_.InvalidateWeakPtrs(); |
| 339 } | 401 } |
| 340 | 402 |
| 341 void ExtensionActionRunner::OnExtensionUnloaded( | 403 void ExtensionActionRunner::OnExtensionUnloaded( |
| 342 content::BrowserContext* browser_context, | 404 content::BrowserContext* browser_context, |
| 343 const Extension* extension, | 405 const Extension* extension, |
| 344 UnloadedExtensionInfo::Reason reason) { | 406 UnloadedExtensionInfo::Reason reason) { |
| 345 PendingScriptMap::iterator iter = pending_scripts_.find(extension->id()); | 407 PendingScriptMap::iterator iter = pending_scripts_.find(extension->id()); |
| 346 if (iter != pending_scripts_.end()) { | 408 if (iter != pending_scripts_.end()) { |
| 347 pending_scripts_.erase(iter); | 409 pending_scripts_.erase(iter); |
| 348 ExtensionActionAPI::Get(browser_context_) | 410 ExtensionActionAPI::Get(browser_context_) |
| 349 ->NotifyPageActionsChanged(web_contents()); | 411 ->NotifyPageActionsChanged(web_contents()); |
| 350 } | 412 } |
| 351 } | 413 } |
| 352 | 414 |
| 353 } // namespace extensions | 415 } // namespace extensions |
| OLD | NEW |