| 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 18 matching lines...) Expand all Loading... |
| 155 } | 173 } |
| 156 } | 174 } |
| 157 | 175 |
| 158 return blocked_actions; | 176 return blocked_actions; |
| 159 } | 177 } |
| 160 | 178 |
| 161 bool ExtensionActionRunner::WantsToRun(const Extension* extension) { | 179 bool ExtensionActionRunner::WantsToRun(const Extension* extension) { |
| 162 return GetBlockedActions(extension) != BLOCKED_ACTION_NONE; | 180 return GetBlockedActions(extension) != BLOCKED_ACTION_NONE; |
| 163 } | 181 } |
| 164 | 182 |
| 183 void ExtensionActionRunner::RunForTesting(const Extension* extension) { |
| 184 if (WantsToRun(extension)) { |
| 185 TabHelper::FromWebContents(web_contents()) |
| 186 ->active_tab_permission_granter() |
| 187 ->GrantIfRequested(extension); |
| 188 } |
| 189 } |
| 190 |
| 165 PermissionsData::AccessType | 191 PermissionsData::AccessType |
| 166 ExtensionActionRunner::RequiresUserConsentForScriptInjection( | 192 ExtensionActionRunner::RequiresUserConsentForScriptInjection( |
| 167 const Extension* extension, | 193 const Extension* extension, |
| 168 UserScript::InjectionType type) { | 194 UserScript::InjectionType type) { |
| 169 CHECK(extension); | 195 CHECK(extension); |
| 170 | 196 |
| 171 // Allow the extension if it's been explicitly granted permission. | 197 // Allow the extension if it's been explicitly granted permission. |
| 172 if (permitted_extensions_.count(extension->id()) > 0) | 198 if (permitted_extensions_.count(extension->id()) > 0) |
| 173 return PermissionsData::ACCESS_ALLOWED; | 199 return PermissionsData::ACCESS_ALLOWED; |
| 174 | 200 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 if (was_used_on_page_) { | 331 if (was_used_on_page_) { |
| 306 UMA_HISTOGRAM_COUNTS_100( | 332 UMA_HISTOGRAM_COUNTS_100( |
| 307 "Extensions.ActiveScriptController.PermittedExtensions", | 333 "Extensions.ActiveScriptController.PermittedExtensions", |
| 308 permitted_extensions_.size()); | 334 permitted_extensions_.size()); |
| 309 UMA_HISTOGRAM_COUNTS_100( | 335 UMA_HISTOGRAM_COUNTS_100( |
| 310 "Extensions.ActiveScriptController.DeniedExtensions", | 336 "Extensions.ActiveScriptController.DeniedExtensions", |
| 311 pending_scripts_.size()); | 337 pending_scripts_.size()); |
| 312 } | 338 } |
| 313 } | 339 } |
| 314 | 340 |
| 341 void ExtensionActionRunner::ShowBlockedActionBubble( |
| 342 const Extension* extension) { |
| 343 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| 344 ToolbarActionsBar* toolbar_actions_bar = |
| 345 browser ? browser->window()->GetToolbarActionsBar() : nullptr; |
| 346 if (toolbar_actions_bar) { |
| 347 auto callback = |
| 348 base::Bind(&ExtensionActionRunner::OnBlockedActionBubbleClosed, |
| 349 weak_factory_.GetWeakPtr(), extension->id()); |
| 350 if (default_bubble_close_action_for_testing_) { |
| 351 base::MessageLoop::current()->PostTask( |
| 352 FROM_HERE, |
| 353 base::Bind(callback, *default_bubble_close_action_for_testing_)); |
| 354 } else { |
| 355 toolbar_actions_bar->ShowToolbarActionBubble(make_scoped_ptr( |
| 356 new BlockedActionBubbleDelegate(callback, extension->id()))); |
| 357 } |
| 358 } |
| 359 } |
| 360 |
| 361 void ExtensionActionRunner::OnBlockedActionBubbleClosed( |
| 362 const std::string& extension_id, |
| 363 ToolbarActionsBarBubbleDelegate::CloseAction action) { |
| 364 // If the user agreed to refresh the page, do so. |
| 365 if (action == ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE) { |
| 366 const Extension* extension = ExtensionRegistry::Get(browser_context_) |
| 367 ->enabled_extensions() |
| 368 .GetByID(extension_id); |
| 369 if (!extension) |
| 370 return; |
| 371 { |
| 372 // Ignore the active tab permission being granted because we don't want |
| 373 // to run scripts right before we refresh the page. |
| 374 base::AutoReset<bool> ignore_active_tab(&ignore_active_tab_granted_, |
| 375 true); |
| 376 TabHelper::FromWebContents(web_contents()) |
| 377 ->active_tab_permission_granter() |
| 378 ->GrantIfRequested(extension); |
| 379 } |
| 380 web_contents()->GetController().Reload(false); |
| 381 } |
| 382 } |
| 383 |
| 315 bool ExtensionActionRunner::OnMessageReceived( | 384 bool ExtensionActionRunner::OnMessageReceived( |
| 316 const IPC::Message& message, | 385 const IPC::Message& message, |
| 317 content::RenderFrameHost* render_frame_host) { | 386 content::RenderFrameHost* render_frame_host) { |
| 318 bool handled = true; | 387 bool handled = true; |
| 319 IPC_BEGIN_MESSAGE_MAP(ExtensionActionRunner, message) | 388 IPC_BEGIN_MESSAGE_MAP(ExtensionActionRunner, message) |
| 320 IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestScriptInjectionPermission, | 389 IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestScriptInjectionPermission, |
| 321 OnRequestScriptInjectionPermission) | 390 OnRequestScriptInjectionPermission) |
| 322 IPC_MESSAGE_UNHANDLED(handled = false) | 391 IPC_MESSAGE_UNHANDLED(handled = false) |
| 323 IPC_END_MESSAGE_MAP() | 392 IPC_END_MESSAGE_MAP() |
| 324 return handled; | 393 return handled; |
| 325 } | 394 } |
| 326 | 395 |
| 327 void ExtensionActionRunner::DidNavigateMainFrame( | 396 void ExtensionActionRunner::DidNavigateMainFrame( |
| 328 const content::LoadCommittedDetails& details, | 397 const content::LoadCommittedDetails& details, |
| 329 const content::FrameNavigateParams& params) { | 398 const content::FrameNavigateParams& params) { |
| 330 if (details.is_in_page) | 399 if (details.is_in_page) |
| 331 return; | 400 return; |
| 332 | 401 |
| 333 LogUMA(); | 402 LogUMA(); |
| 334 num_page_requests_ = 0; | 403 num_page_requests_ = 0; |
| 335 permitted_extensions_.clear(); | 404 permitted_extensions_.clear(); |
| 336 pending_scripts_.clear(); | 405 pending_scripts_.clear(); |
| 337 web_request_blocked_.clear(); | 406 web_request_blocked_.clear(); |
| 338 was_used_on_page_ = false; | 407 was_used_on_page_ = false; |
| 408 weak_factory_.InvalidateWeakPtrs(); |
| 339 } | 409 } |
| 340 | 410 |
| 341 void ExtensionActionRunner::OnExtensionUnloaded( | 411 void ExtensionActionRunner::OnExtensionUnloaded( |
| 342 content::BrowserContext* browser_context, | 412 content::BrowserContext* browser_context, |
| 343 const Extension* extension, | 413 const Extension* extension, |
| 344 UnloadedExtensionInfo::Reason reason) { | 414 UnloadedExtensionInfo::Reason reason) { |
| 345 PendingScriptMap::iterator iter = pending_scripts_.find(extension->id()); | 415 PendingScriptMap::iterator iter = pending_scripts_.find(extension->id()); |
| 346 if (iter != pending_scripts_.end()) { | 416 if (iter != pending_scripts_.end()) { |
| 347 pending_scripts_.erase(iter); | 417 pending_scripts_.erase(iter); |
| 348 ExtensionActionAPI::Get(browser_context_) | 418 ExtensionActionAPI::Get(browser_context_) |
| 349 ->NotifyPageActionsChanged(web_contents()); | 419 ->NotifyPageActionsChanged(web_contents()); |
| 350 } | 420 } |
| 351 } | 421 } |
| 352 | 422 |
| 353 } // namespace extensions | 423 } // namespace extensions |
| OLD | NEW |