1656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// Use of this source code is governed by a BSD-style license that can be
3656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project// found in the LICENSE file.
4656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
5656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "chrome/browser/extensions/active_tab_permission_granter.h"
6656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
7656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "chrome/browser/extensions/active_script_controller.h"
8656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "chrome/browser/profiles/profile.h"
9656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "content/public/browser/navigation_details.h"
10656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "content/public/browser/navigation_entry.h"
11656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "content/public/browser/web_contents.h"
12656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "extensions/browser/extension_registry.h"
13656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "extensions/common/extension_messages.h"
14656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "extensions/common/feature_switch.h"
15656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "extensions/common/permissions/permission_set.h"
16656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "extensions/common/permissions/permissions_data.h"
17656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "extensions/common/user_script.h"
18656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project#include "url/gurl.h"
19656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
20656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectusing content::RenderProcessHost;
21656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectusing content::WebContentsObserver;
22656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
23656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectnamespace extensions {
24656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
25656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source ProjectActiveTabPermissionGranter::ActiveTabPermissionGranter(
26656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    content::WebContents* web_contents,
27656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    int tab_id,
28656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    Profile* profile)
29656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    : WebContentsObserver(web_contents),
30656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      tab_id_(tab_id),
31656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      extension_registry_observer_(this) {
32656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
33656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}
34656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
35656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source ProjectActiveTabPermissionGranter::~ActiveTabPermissionGranter() {}
36656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
37656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectvoid ActiveTabPermissionGranter::GrantIfRequested(const Extension* extension) {
38656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (granted_extensions_.Contains(extension->id()))
39656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    return;
40656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
41656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  APIPermissionSet new_apis;
42656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  URLPatternSet new_hosts;
43656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
44656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  const PermissionsData* permissions_data = extension->permissions_data();
45656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
46656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // If the extension requested all-hosts but has had it withheld, we grant it
47656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // active tab-style permissions, even if it doesn't have the activeTab
48656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // permission in the manifest.
49656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (permissions_data->HasAPIPermission(APIPermission::kActiveTab) ||
50656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      permissions_data->HasWithheldImpliedAllHosts()) {
51656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    new_hosts.AddOrigin(UserScript::ValidUserScriptSchemes(),
52656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                        web_contents()->GetVisibleURL().GetOrigin());
53656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    new_apis.insert(APIPermission::kTab);
54656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
55656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
56656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (permissions_data->HasAPIPermission(APIPermission::kTabCapture))
57656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    new_apis.insert(APIPermission::kTabCaptureForTab);
58656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
59656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (!new_apis.empty() || !new_hosts.is_empty()) {
60656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    granted_extensions_.Insert(extension);
61656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    scoped_refptr<const PermissionSet> new_permissions =
62656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project        new PermissionSet(new_apis, ManifestPermissionSet(),
63656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                          new_hosts, URLPatternSet());
64656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    permissions_data->UpdateTabSpecificPermissions(tab_id_, new_permissions);
65656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    const content::NavigationEntry* navigation_entry =
66656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project        web_contents()->GetController().GetVisibleEntry();
67656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    if (navigation_entry) {
68656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      Send(new ExtensionMsg_UpdateTabSpecificPermissions(
69656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project          navigation_entry->GetURL(),
70656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project          tab_id_,
71656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project          extension->id(),
72656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project          new_hosts));
73656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      // If more things ever need to know about this, we should consider making
74656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      // an observer class.
75656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      // It's important that this comes after the IPC is sent to the renderer,
76656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      // so that any tasks executing in the renderer occur after it has the
77656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      // updated permissions.
78656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      ActiveScriptController::GetForWebContents(web_contents())
79656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project          ->OnActiveTabPermissionGranted(extension);
80656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    }
81656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
82656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}
83656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
84656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectvoid ActiveTabPermissionGranter::DidNavigateMainFrame(
85656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    const content::LoadCommittedDetails& details,
86656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    const content::FrameNavigateParams& params) {
87656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (details.is_in_page)
88656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    return;
89656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  DCHECK(details.is_main_frame);  // important: sub-frames don't get granted!
90656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
91656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // Only clear the granted permissions for cross-origin navigations.
92656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  //
93656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // See http://crbug.com/404243 for why. Currently we only differentiate
94656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // between same-origin and cross-origin navigations when the
95656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // script-require-action flag is on. It's not clear it's good for general
96656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // activeTab consumption (we likely need to build some UI around it first).
97656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // However, the scripts-require-action feature is all-but unusable without
98656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // this behaviour.
99656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (FeatureSwitch::scripts_require_action()->IsEnabled()) {
100656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    const content::NavigationEntry* navigation_entry =
101656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project        web_contents()->GetController().GetVisibleEntry();
102656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    if (!navigation_entry || (navigation_entry->GetURL().GetOrigin() !=
103656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project                              details.previous_url.GetOrigin())) {
104656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project      ClearActiveExtensionsAndNotify();
105656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    }
106656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  } else {
107656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    ClearActiveExtensionsAndNotify();
108656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
109656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}
110656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
111656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectvoid ActiveTabPermissionGranter::WebContentsDestroyed() {
112656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  ClearActiveExtensionsAndNotify();
113656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}
114656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
115656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectvoid ActiveTabPermissionGranter::OnExtensionUnloaded(
116656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    content::BrowserContext* browser_context,
117656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    const Extension* extension,
118656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    UnloadedExtensionInfo::Reason reason) {
119656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // Note: don't need to clear the permissions (nor tell the renderer about it)
120656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  // because it's being unloaded anyway.
121656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  granted_extensions_.Remove(extension->id());
122656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}
123656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
124656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Projectvoid ActiveTabPermissionGranter::ClearActiveExtensionsAndNotify() {
125656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  if (granted_extensions_.is_empty())
126656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    return;
127656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
128656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  std::vector<std::string> extension_ids;
129656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
130656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  for (ExtensionSet::const_iterator it = granted_extensions_.begin();
131656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project       it != granted_extensions_.end(); ++it) {
132656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    it->get()->permissions_data()->ClearTabSpecificPermissions(tab_id_);
133656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project    extension_ids.push_back((*it)->id());
134656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  }
135656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
136656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  Send(new ExtensionMsg_ClearTabSpecificPermissions(tab_id_, extension_ids));
137656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project  granted_extensions_.Clear();
138656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}
139656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project
140656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project}  // namespace extensions
141656d9c7f52f88b3a3daccafa7655dec086c4756eThe Android Open Source Project