1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/active_script_controller.h"
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/bind.h"
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/bind_helpers.h"
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/metrics/histogram.h"
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/stl_util.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/active_tab_permission_granter.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/extension_action.h"
156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/extensions/extension_action_manager.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/extension_util.h"
176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/extensions/permissions_updater.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/tab_helper.h"
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/sessions/session_tab_helper.h"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/common/extensions/api/extension_action/action_info.h"
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/crx_file/id_util.h"
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/navigation_controller.h"
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/navigation_details.h"
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/navigation_entry.h"
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/web_contents.h"
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/extension.h"
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/extension_messages.h"
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/extension_set.h"
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/feature_switch.h"
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/manifest.h"
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "extensions/common/permissions/permission_set.h"
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/permissions/permissions_data.h"
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ipc/ipc_message_macros.h"
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace extensions {
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Returns true if the extension should be regarded as a "permitted" extension
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// for the case of metrics. We need this because we only actually withhold
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// permissions if the switch is enabled, but want to record metrics in all
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// cases.
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// "ExtensionWouldHaveHadHostPermissionsWithheldIfSwitchWasOn()" would be
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// more accurate, but too long.
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool ShouldRecordExtension(const Extension* extension) {
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return extension->ShouldDisplayInExtensionSettings() &&
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         !Manifest::IsPolicyLocation(extension->location()) &&
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         !Manifest::IsComponentLocation(extension->location()) &&
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         !PermissionsData::CanExecuteScriptEverywhere(extension) &&
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         extension->permissions_data()
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch             ->active_permissions()
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch             ->ShouldWarnAllHosts();
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ActiveScriptController::ActiveScriptController(
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::WebContents* web_contents)
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : content::WebContentsObserver(web_contents),
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      enabled_(FeatureSwitch::scripts_require_action()->IsEnabled()),
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extension_registry_observer_(this) {
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CHECK(web_contents);
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extension_registry_observer_.Add(
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ExtensionRegistry::Get(web_contents->GetBrowserContext()));
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ActiveScriptController::~ActiveScriptController() {
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LogUMA();
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ActiveScriptController* ActiveScriptController::GetForWebContents(
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::WebContents* web_contents) {
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!web_contents)
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return NULL;
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  TabHelper* tab_helper = TabHelper::FromWebContents(web_contents);
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return tab_helper ? tab_helper->active_script_controller() : NULL;
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ActiveScriptController::OnActiveTabPermissionGranted(
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const Extension* extension) {
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  RunPendingForExtension(extension);
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ActiveScriptController::OnAdInjectionDetected(
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::set<std::string>& ad_injectors) {
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // We're only interested in data if there are ad injectors detected.
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (ad_injectors.empty())
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  size_t num_preventable_ad_injectors =
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::STLSetIntersection<std::set<std::string> >(
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          ad_injectors, permitted_extensions_).size();
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100(
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      "Extensions.ActiveScriptController.PreventableAdInjectors",
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      num_preventable_ad_injectors);
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100(
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      "Extensions.ActiveScriptController.UnpreventableAdInjectors",
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ad_injectors.size() - num_preventable_ad_injectors);
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void ActiveScriptController::AlwaysRunOnVisibleOrigin(
1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const Extension* extension) {
1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  const GURL& url = web_contents()->GetVisibleURL();
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  URLPatternSet new_explicit_hosts;
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  URLPatternSet new_scriptable_hosts;
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_refptr<const PermissionSet> withheld_permissions =
1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      extension->permissions_data()->withheld_permissions();
1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (withheld_permissions->explicit_hosts().MatchesURL(url)) {
1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    new_explicit_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(),
1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                 url.GetOrigin());
1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (withheld_permissions->scriptable_hosts().MatchesURL(url)) {
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    new_scriptable_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(),
1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                   url.GetOrigin());
1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_refptr<PermissionSet> new_permissions =
1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      new PermissionSet(APIPermissionSet(),
1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                        ManifestPermissionSet(),
1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                        new_explicit_hosts,
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                        new_scriptable_hosts);
1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Update permissions for the session. This adds |new_permissions| to active
1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // permissions and granted permissions.
1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // TODO(devlin): Make sure that the permission is removed from
1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // withheld_permissions if appropriate.
1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  PermissionsUpdater(web_contents()->GetBrowserContext())
1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      .AddPermissions(extension, new_permissions.get());
1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Allow current tab to run injection.
1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  OnClicked(extension);
1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ActiveScriptController::OnClicked(const Extension* extension) {
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(ContainsKey(pending_requests_, extension->id()));
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  RunPendingForExtension(extension);
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ActiveScriptController::WantsToRun(const Extension* extension) {
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return enabled_ && pending_requests_.count(extension->id()) > 0;
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
149116680a4aac90f2aa7413d9095a592090648e557Ben MurdochPermissionsData::AccessType
150116680a4aac90f2aa7413d9095a592090648e557Ben MurdochActiveScriptController::RequiresUserConsentForScriptInjection(
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const Extension* extension,
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    UserScript::InjectionType type) {
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK(extension);
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If the feature is not enabled, we automatically allow all extensions to
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // run scripts.
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!enabled_)
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    permitted_extensions_.insert(extension->id());
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Allow the extension if it's been explicitly granted permission.
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (permitted_extensions_.count(extension->id()) > 0)
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return PermissionsData::ACCESS_ALLOWED;
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GURL url = web_contents()->GetVisibleURL();
16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int tab_id = SessionTabHelper::IdForTab(web_contents());
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (type) {
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case UserScript::CONTENT_SCRIPT:
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return extension->permissions_data()->GetContentScriptAccess(
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          extension, url, url, tab_id, -1, NULL);
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case UserScript::PROGRAMMATIC_SCRIPT:
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return extension->permissions_data()->GetPageAccess(
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          extension, url, url, tab_id, -1, NULL);
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  NOTREACHED();
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return PermissionsData::ACCESS_DENIED;
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ActiveScriptController::RequestScriptInjection(
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const Extension* extension,
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::Closure& callback) {
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK(extension);
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  PendingRequestList& list = pending_requests_[extension->id()];
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  list.push_back(callback);
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If this was the first entry, notify the location bar that there's a new
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // icon.
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (list.size() == 1u) {
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ExtensionActionAPI::Get(web_contents()->GetBrowserContext())->
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        NotifyPageActionsChanged(web_contents());
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ActiveScriptController::RunPendingForExtension(
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const Extension* extension) {
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(extension);
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  content::NavigationEntry* visible_entry =
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      web_contents()->GetController().GetVisibleEntry();
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Refuse to run if there's no visible entry, because we have no idea of
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // determining if it's the proper page. This should rarely, if ever, happen.
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!visible_entry)
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // We add this to the list of permitted extensions and erase pending entries
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // *before* running them to guard against the crazy case where running the
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // callbacks adds more entries.
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  permitted_extensions_.insert(extension->id());
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  PendingRequestMap::iterator iter = pending_requests_.find(extension->id());
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (iter == pending_requests_.end())
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PendingRequestList requests;
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  iter->second.swap(requests);
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  pending_requests_.erase(extension->id());
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Clicking to run the extension counts as granting it permission to run on
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // the given tab.
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The extension may already have active tab at this point, but granting
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // it twice is essentially a no-op.
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  TabHelper::FromWebContents(web_contents())->
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      active_tab_permission_granter()->GrantIfRequested(extension);
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Run all pending injections for the given extension.
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (PendingRequestList::iterator request = requests.begin();
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       request != requests.end();
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       ++request) {
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    request->Run();
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Inform the location bar that the action is now gone.
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ExtensionActionAPI::Get(web_contents()->GetBrowserContext())->
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      NotifyPageActionsChanged(web_contents());
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ActiveScriptController::OnRequestScriptInjectionPermission(
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& extension_id,
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    UserScript::InjectionType script_type,
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int64 request_id) {
24103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!crx_file::id_util::IdIsValid(extension_id)) {
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    NOTREACHED() << "'" << extension_id << "' is not a valid id.";
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const Extension* extension =
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExtensionRegistry::Get(web_contents()->GetBrowserContext())
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          ->enabled_extensions().GetByID(extension_id);
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // We shouldn't allow extensions which are no longer enabled to run any
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // scripts. Ignore the request.
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!extension)
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // If the request id is -1, that signals that the content script has already
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // ran (because this feature is not enabled). Add the extension to the list of
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // permitted extensions (for metrics), and return immediately.
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (request_id == -1) {
258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (ShouldRecordExtension(extension)) {
259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      DCHECK(!enabled_);
260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      permitted_extensions_.insert(extension->id());
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (RequiresUserConsentForScriptInjection(extension, script_type)) {
266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case PermissionsData::ACCESS_ALLOWED:
267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      PermitScriptInjection(request_id);
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case PermissionsData::ACCESS_WITHHELD:
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // This base::Unretained() is safe, because the callback is only invoked
271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // by this object.
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      RequestScriptInjection(
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          extension,
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          base::Bind(&ActiveScriptController::PermitScriptInjection,
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     base::Unretained(this),
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     request_id));
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case PermissionsData::ACCESS_DENIED:
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // We should usually only get a "deny access" if the page changed (as the
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // renderer wouldn't have requested permission if the answer was always
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // "no"). Just let the request fizzle and die.
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ActiveScriptController::PermitScriptInjection(int64 request_id) {
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // This only sends the response to the renderer - the process of adding the
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // extension to the list of |permitted_extensions_| is done elsewhere.
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  content::RenderViewHost* render_view_host =
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      web_contents()->GetRenderViewHost();
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (render_view_host) {
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    render_view_host->Send(new ExtensionMsg_PermitScriptInjection(
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        render_view_host->GetRoutingID(), request_id));
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ActiveScriptController::LogUMA() const {
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100(
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      "Extensions.ActiveScriptController.ShownActiveScriptsOnPage",
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      pending_requests_.size());
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // We only log the permitted extensions metric if the feature is enabled,
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // because otherwise the data will be boring (100% allowed).
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (enabled_) {
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS_100(
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "Extensions.ActiveScriptController.PermittedExtensions",
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        permitted_extensions_.size());
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS_100(
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "Extensions.ActiveScriptController.DeniedExtensions",
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        pending_requests_.size());
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ActiveScriptController::OnMessageReceived(const IPC::Message& message) {
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool handled = true;
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  IPC_BEGIN_MESSAGE_MAP(ActiveScriptController, message)
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestScriptInjectionPermission,
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        OnRequestScriptInjectionPermission)
3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    IPC_MESSAGE_UNHANDLED(handled = false)
3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  IPC_END_MESSAGE_MAP()
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return handled;
3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ActiveScriptController::DidNavigateMainFrame(
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const content::LoadCommittedDetails& details,
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const content::FrameNavigateParams& params) {
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (details.is_in_page)
3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LogUMA();
3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  permitted_extensions_.clear();
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pending_requests_.clear();
3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ActiveScriptController::OnExtensionUnloaded(
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::BrowserContext* browser_context,
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const Extension* extension,
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UnloadedExtensionInfo::Reason reason) {
3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PendingRequestMap::iterator iter = pending_requests_.find(extension->id());
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (iter != pending_requests_.end()) {
3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_requests_.erase(iter);
3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ExtensionActionAPI::Get(web_contents()->GetBrowserContext())->
3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        NotifyPageActionsChanged(web_contents());
3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace extensions
348