1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/active_tab_permission_granter.h"
6
7 #include "chrome/browser/extensions/active_script_controller.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "content/public/browser/navigation_details.h"
10 #include "content/public/browser/navigation_entry.h"
11 #include "content/public/browser/web_contents.h"
12 #include "extensions/browser/extension_registry.h"
13 #include "extensions/common/extension_messages.h"
14 #include "extensions/common/permissions/permission_set.h"
15 #include "extensions/common/permissions/permissions_data.h"
16 #include "extensions/common/user_script.h"
17 #include "url/gurl.h"
18
19 using content::RenderProcessHost;
20 using content::WebContentsObserver;
21
22 namespace extensions {
23
ActiveTabPermissionGranter(content::WebContents * web_contents,int tab_id,Profile * profile)24 ActiveTabPermissionGranter::ActiveTabPermissionGranter(
25 content::WebContents* web_contents,
26 int tab_id,
27 Profile* profile)
28 : WebContentsObserver(web_contents),
29 tab_id_(tab_id),
30 extension_registry_observer_(this) {
31 extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
32 }
33
~ActiveTabPermissionGranter()34 ActiveTabPermissionGranter::~ActiveTabPermissionGranter() {}
35
GrantIfRequested(const Extension * extension)36 void ActiveTabPermissionGranter::GrantIfRequested(const Extension* extension) {
37 if (granted_extensions_.Contains(extension->id()))
38 return;
39
40 APIPermissionSet new_apis;
41 URLPatternSet new_hosts;
42
43 const PermissionsData* permissions_data = extension->permissions_data();
44
45 // If the extension requires action for script execution, we grant it
46 // active tab-style permissions, even if it doesn't have the activeTab
47 // permission in the manifest.
48 // We don't take tab id into account, because we want to know if the extension
49 // should require active tab in general (not for the current tab).
50 bool requires_action_for_script_execution =
51 permissions_data->RequiresActionForScriptExecution(extension,
52 -1, // No tab id.
53 GURL());
54
55 if (extension->permissions_data()->HasAPIPermission(
56 APIPermission::kActiveTab) ||
57 requires_action_for_script_execution) {
58 URLPattern pattern(UserScript::ValidUserScriptSchemes());
59 // Pattern parsing could fail if this is an unsupported URL e.g. chrome://.
60 if (pattern.Parse(web_contents()->GetURL().spec()) ==
61 URLPattern::PARSE_SUCCESS) {
62 new_hosts.AddPattern(pattern);
63 }
64 new_apis.insert(APIPermission::kTab);
65 }
66
67 if (extension->permissions_data()->HasAPIPermission(
68 APIPermission::kTabCapture))
69 new_apis.insert(APIPermission::kTabCaptureForTab);
70
71 if (!new_apis.empty() || !new_hosts.is_empty()) {
72 granted_extensions_.Insert(extension);
73 scoped_refptr<const PermissionSet> new_permissions =
74 new PermissionSet(new_apis, ManifestPermissionSet(),
75 new_hosts, URLPatternSet());
76 permissions_data->UpdateTabSpecificPermissions(tab_id_, new_permissions);
77 const content::NavigationEntry* navigation_entry =
78 web_contents()->GetController().GetVisibleEntry();
79 if (navigation_entry) {
80 Send(new ExtensionMsg_UpdateTabSpecificPermissions(
81 navigation_entry->GetPageID(),
82 tab_id_,
83 extension->id(),
84 new_hosts));
85 // If more things ever need to know about this, we should consider making
86 // an observer class.
87 // It's important that this comes after the IPC is sent to the renderer,
88 // so that any tasks executing in the renderer occur after it has the
89 // updated permissions.
90 ActiveScriptController::GetForWebContents(web_contents())
91 ->OnActiveTabPermissionGranted(extension);
92 }
93 }
94 }
95
DidNavigateMainFrame(const content::LoadCommittedDetails & details,const content::FrameNavigateParams & params)96 void ActiveTabPermissionGranter::DidNavigateMainFrame(
97 const content::LoadCommittedDetails& details,
98 const content::FrameNavigateParams& params) {
99 if (details.is_in_page)
100 return;
101 DCHECK(details.is_main_frame); // important: sub-frames don't get granted!
102 ClearActiveExtensionsAndNotify();
103 }
104
WebContentsDestroyed()105 void ActiveTabPermissionGranter::WebContentsDestroyed() {
106 ClearActiveExtensionsAndNotify();
107 }
108
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,UnloadedExtensionInfo::Reason reason)109 void ActiveTabPermissionGranter::OnExtensionUnloaded(
110 content::BrowserContext* browser_context,
111 const Extension* extension,
112 UnloadedExtensionInfo::Reason reason) {
113 // Note: don't need to clear the permissions (nor tell the renderer about it)
114 // because it's being unloaded anyway.
115 granted_extensions_.Remove(extension->id());
116 }
117
ClearActiveExtensionsAndNotify()118 void ActiveTabPermissionGranter::ClearActiveExtensionsAndNotify() {
119 if (granted_extensions_.is_empty())
120 return;
121
122 std::vector<std::string> extension_ids;
123
124 for (ExtensionSet::const_iterator it = granted_extensions_.begin();
125 it != granted_extensions_.end(); ++it) {
126 it->get()->permissions_data()->ClearTabSpecificPermissions(tab_id_);
127 extension_ids.push_back((*it)->id());
128 }
129
130 Send(new ExtensionMsg_ClearTabSpecificPermissions(tab_id_, extension_ids));
131 granted_extensions_.Clear();
132 }
133
134 } // namespace extensions
135