blob: 26730a999aaa4510a01500c6c3bab92db4b18f12 [file] [log] [blame]
[email protected]c333e792012-01-06 16:57:391// 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/permissions_updater.h"
6
dcheng1fc00f12015-12-26 22:18:037#include <utility>
8
[email protected]c333e792012-01-06 16:57:399#include "base/memory/ref_counted.h"
10#include "base/values.h"
[email protected]76aeb1772012-01-20 22:14:1611#include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h"
rdevlin.cronincb9f86e2015-10-15 15:13:4212#include "chrome/browser/extensions/scripting_permissions_modifier.h"
[email protected]c333e792012-01-06 16:57:3913#include "chrome/browser/profiles/profile.h"
[email protected]6386cf52012-09-07 04:26:3714#include "chrome/common/extensions/api/permissions.h"
[email protected]c97496b2012-10-01 16:20:1915#include "content/public/browser/notification_observer.h"
16#include "content/public/browser/notification_registrar.h"
[email protected]c333e792012-01-06 16:57:3917#include "content/public/browser/notification_service.h"
18#include "content/public/browser/render_process_host.h"
[email protected]34423532013-11-21 18:13:1019#include "extensions/browser/event_router.h"
[email protected]489db0842014-01-22 18:20:0320#include "extensions/browser/extension_prefs.h"
limasdfd0069922015-10-20 17:07:1521#include "extensions/browser/notification_types.h"
[email protected]e4452d32013-11-15 23:07:4122#include "extensions/common/extension.h"
[email protected]fb820c02014-03-13 15:07:0823#include "extensions/common/extension_messages.h"
[email protected]8d42db52014-06-20 21:50:5024#include "extensions/common/manifest_handlers/permissions_parser.h"
25#include "extensions/common/permissions/permission_set.h"
[email protected]e4452d32013-11-15 23:07:4126#include "extensions/common/permissions/permissions_data.h"
[email protected]c333e792012-01-06 16:57:3927
28using content::RenderProcessHost;
[email protected]15f08dd2012-01-27 07:29:4829using extensions::permissions_api_helpers::PackPermissionSet;
[email protected]c333e792012-01-06 16:57:3930
31namespace extensions {
32
[email protected]e054ea12013-08-20 00:41:5733namespace permissions = api::permissions;
[email protected]c333e792012-01-06 16:57:3934
[email protected]23a85362014-07-07 23:26:1935namespace {
36
37// Returns a PermissionSet that has the active permissions of the extension,
38// bounded to its current manifest.
dchengc963c7142016-04-08 03:55:2239std::unique_ptr<const PermissionSet> GetBoundedActivePermissions(
[email protected]e1670582014-08-15 23:05:4140 const Extension* extension,
rdevlin.cronine2d0fd02015-09-24 22:35:4941 const PermissionSet* active_permissions) {
[email protected]23a85362014-07-07 23:26:1942 // If the extension has used the optional permissions API, it will have a
43 // custom set of active permissions defined in the extension prefs. Here,
44 // we update the extension's active permissions based on the prefs.
rdevlin.cronine2d0fd02015-09-24 22:35:4945 if (!active_permissions)
rdevlin.cronind630c302015-09-30 20:19:3346 return extension->permissions_data()->active_permissions().Clone();
[email protected]23a85362014-07-07 23:26:1947
rdevlin.cronind630c302015-09-30 20:19:3348 const PermissionSet& required_permissions =
[email protected]23a85362014-07-07 23:26:1949 PermissionsParser::GetRequiredPermissions(extension);
50
51 // We restrict the active permissions to be within the bounds defined in the
52 // extension's manifest.
53 // a) active permissions must be a subset of optional + default permissions
54 // b) active permissions must contains all default permissions
dchengc963c7142016-04-08 03:55:2255 std::unique_ptr<const PermissionSet> total_permissions =
rdevlin.cronine01ec2c2015-09-17 21:27:2856 PermissionSet::CreateUnion(
rdevlin.cronind630c302015-09-30 20:19:3357 required_permissions,
58 PermissionsParser::GetOptionalPermissions(extension));
[email protected]23a85362014-07-07 23:26:1959
60 // Make sure the active permissions contain no more than optional + default.
dchengc963c7142016-04-08 03:55:2261 std::unique_ptr<const PermissionSet> adjusted_active =
rdevlin.cronine01ec2c2015-09-17 21:27:2862 PermissionSet::CreateIntersection(*total_permissions,
63 *active_permissions);
[email protected]23a85362014-07-07 23:26:1964
65 // Make sure the active permissions contain the default permissions.
rdevlin.cronine01ec2c2015-09-17 21:27:2866 adjusted_active =
rdevlin.cronind630c302015-09-30 20:19:3367 PermissionSet::CreateUnion(required_permissions, *adjusted_active);
[email protected]23a85362014-07-07 23:26:1968
69 return adjusted_active;
70}
71
[email protected]23a85362014-07-07 23:26:1972} // namespace
73
[email protected]8d42db52014-06-20 21:50:5074PermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context)
gpdavis.chromium0fbac4d2014-09-19 20:57:5475 : browser_context_(browser_context), init_flag_(INIT_FLAG_NONE) {
76}
77
78PermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context,
79 InitFlag init_flag)
80 : browser_context_(browser_context), init_flag_(init_flag) {
[email protected]8d42db52014-06-20 21:50:5081}
[email protected]c333e792012-01-06 16:57:3982
83PermissionsUpdater::~PermissionsUpdater() {}
84
rdevlin.cronind630c302015-09-30 20:19:3385void PermissionsUpdater::AddPermissions(const Extension* extension,
86 const PermissionSet& permissions) {
87 const PermissionSet& active =
88 extension->permissions_data()->active_permissions();
dchengc963c7142016-04-08 03:55:2289 std::unique_ptr<const PermissionSet> total =
rdevlin.cronind630c302015-09-30 20:19:3390 PermissionSet::CreateUnion(active, permissions);
dchengc963c7142016-04-08 03:55:2291 std::unique_ptr<const PermissionSet> added =
rdevlin.cronind630c302015-09-30 20:19:3392 PermissionSet::CreateDifference(*total, active);
[email protected]c333e792012-01-06 16:57:3993
dchengc963c7142016-04-08 03:55:2294 std::unique_ptr<const PermissionSet> new_withheld =
rdevlin.cronincb9f86e2015-10-15 15:13:4295 PermissionSet::CreateDifference(
96 extension->permissions_data()->withheld_permissions(), permissions);
dcheng1fc00f12015-12-26 22:18:0397 SetPermissions(extension, std::move(total), std::move(new_withheld));
[email protected]c333e792012-01-06 16:57:3998
99 // Update the granted permissions so we don't auto-disable the extension.
[email protected]009633c2013-03-07 22:08:28100 GrantActivePermissions(extension);
[email protected]c333e792012-01-06 16:57:39101
rdevlin.cronine2d0fd02015-09-24 22:35:49102 NotifyPermissionsUpdated(ADDED, extension, *added);
[email protected]c333e792012-01-06 16:57:39103}
104
rdevlin.cronin77cb0ef2015-09-16 17:03:48105void PermissionsUpdater::RemovePermissions(const Extension* extension,
rdevlin.cronind630c302015-09-30 20:19:33106 const PermissionSet& to_remove,
rdevlin.cronin77cb0ef2015-09-16 17:03:48107 RemoveType remove_type) {
108 // We should only be revoking revokable permissions.
rdevlin.cronind630c302015-09-30 20:19:33109 CHECK(GetRevokablePermissions(extension)->Contains(to_remove));
rdevlin.cronin77cb0ef2015-09-16 17:03:48110
rdevlin.cronind630c302015-09-30 20:19:33111 const PermissionSet& active =
rdevlin.cronine2d0fd02015-09-24 22:35:49112 extension->permissions_data()->active_permissions();
dchengc963c7142016-04-08 03:55:22113 std::unique_ptr<const PermissionSet> remaining =
rdevlin.cronind630c302015-09-30 20:19:33114 PermissionSet::CreateDifference(active, to_remove);
rdevlin.cronin77cb0ef2015-09-16 17:03:48115
116 // Move any granted permissions that were in the withheld set back to the
117 // withheld set so they can be added back later.
118 // Any revoked permission that isn't from the optional permissions can only
119 // be a withheld permission.
dchengc963c7142016-04-08 03:55:22120 std::unique_ptr<const PermissionSet> removed_withheld =
rdevlin.cronin77cb0ef2015-09-16 17:03:48121 PermissionSet::CreateDifference(
rdevlin.cronind630c302015-09-30 20:19:33122 to_remove, PermissionsParser::GetOptionalPermissions(extension));
dchengc963c7142016-04-08 03:55:22123 std::unique_ptr<const PermissionSet> withheld = PermissionSet::CreateUnion(
rdevlin.cronind630c302015-09-30 20:19:33124 *removed_withheld, extension->permissions_data()->withheld_permissions());
rdevlin.cronin77cb0ef2015-09-16 17:03:48125
dcheng1fc00f12015-12-26 22:18:03126 SetPermissions(extension, std::move(remaining), std::move(withheld));
rdevlin.cronin77cb0ef2015-09-16 17:03:48127
128 // We might not want to revoke the granted permissions because the extension,
129 // not the user, removed the permissions. This allows the extension to add
130 // them again without prompting the user.
131 if (remove_type == REMOVE_HARD) {
132 ExtensionPrefs::Get(browser_context_)
133 ->RemoveGrantedPermissions(extension->id(), to_remove);
134 }
135
rdevlin.cronind630c302015-09-30 20:19:33136 NotifyPermissionsUpdated(REMOVED, extension, to_remove);
rdevlin.cronin77cb0ef2015-09-16 17:03:48137}
138
139void PermissionsUpdater::RemovePermissionsUnsafe(
140 const Extension* extension,
rdevlin.cronind630c302015-09-30 20:19:33141 const PermissionSet& to_remove) {
142 const PermissionSet& active =
rdevlin.cronine2d0fd02015-09-24 22:35:49143 extension->permissions_data()->active_permissions();
dchengc963c7142016-04-08 03:55:22144 std::unique_ptr<const PermissionSet> total =
rdevlin.cronind630c302015-09-30 20:19:33145 PermissionSet::CreateDifference(active, to_remove);
rdevlin.cronin77cb0ef2015-09-16 17:03:48146 // |successfully_removed| might not equal |to_remove| if |to_remove| contains
147 // permissions the extension didn't have.
dchengc963c7142016-04-08 03:55:22148 std::unique_ptr<const PermissionSet> successfully_removed =
rdevlin.cronind630c302015-09-30 20:19:33149 PermissionSet::CreateDifference(active, *total);
[email protected]c333e792012-01-06 16:57:39150
dcheng1fc00f12015-12-26 22:18:03151 SetPermissions(extension, std::move(total), nullptr);
rdevlin.cronine2d0fd02015-09-24 22:35:49152 NotifyPermissionsUpdated(REMOVED, extension, *successfully_removed);
rdevlin.cronin77cb0ef2015-09-16 17:03:48153}
[email protected]c333e792012-01-06 16:57:39154
dchengc963c7142016-04-08 03:55:22155std::unique_ptr<const PermissionSet>
156PermissionsUpdater::GetRevokablePermissions(const Extension* extension) const {
rdevlin.cronincb9f86e2015-10-15 15:13:42157 // The user can revoke any permissions they granted. In other words, any
158 // permissions the extension didn't start with can be revoked.
159 const PermissionSet& required =
160 PermissionsParser::GetRequiredPermissions(extension);
dchengc963c7142016-04-08 03:55:22161 std::unique_ptr<const PermissionSet> granted;
162 std::unique_ptr<const PermissionSet> withheld;
rdevlin.cronincb9f86e2015-10-15 15:13:42163 ScriptingPermissionsModifier(browser_context_, make_scoped_refptr(extension))
rdevlin.cronin738501d2015-11-05 21:51:36164 .WithholdPermissions(required, &granted, &withheld, true);
rdevlin.cronincb9f86e2015-10-15 15:13:42165 return PermissionSet::CreateDifference(
166 extension->permissions_data()->active_permissions(), *granted);
[email protected]c333e792012-01-06 16:57:39167}
168
[email protected]009633c2013-03-07 22:08:28169void PermissionsUpdater::GrantActivePermissions(const Extension* extension) {
[email protected]c333e792012-01-06 16:57:39170 CHECK(extension);
171
rdevlin.cronine2d0fd02015-09-24 22:35:49172 ExtensionPrefs::Get(browser_context_)
173 ->AddGrantedPermissions(
174 extension->id(), extension->permissions_data()->active_permissions());
[email protected]f746b3f2012-07-03 17:53:37175}
176
[email protected]23a85362014-07-07 23:26:19177void PermissionsUpdater::InitializePermissions(const Extension* extension) {
dchengc963c7142016-04-08 03:55:22178 std::unique_ptr<const PermissionSet> bounded_wrapper;
rdevlin.cronine2d0fd02015-09-24 22:35:49179 const PermissionSet* bounded_active = nullptr;
gpdavis.chromium0fbac4d2014-09-19 20:57:54180 // If |extension| is a transient dummy extension, we do not want to look for
181 // it in preferences.
182 if (init_flag_ & INIT_FLAG_TRANSIENT) {
rdevlin.cronincb9f86e2015-10-15 15:13:42183 bounded_active = &extension->permissions_data()->active_permissions();
gpdavis.chromium0fbac4d2014-09-19 20:57:54184 } else {
dchengc963c7142016-04-08 03:55:22185 std::unique_ptr<const PermissionSet> active_permissions =
rdevlin.cronincb9f86e2015-10-15 15:13:42186 ExtensionPrefs::Get(browser_context_)
187 ->GetActivePermissions(extension->id());
rdevlin.cronine2d0fd02015-09-24 22:35:49188 bounded_wrapper =
rdevlin.cronincb9f86e2015-10-15 15:13:42189 GetBoundedActivePermissions(extension, active_permissions.get());
rdevlin.cronine2d0fd02015-09-24 22:35:49190 bounded_active = bounded_wrapper.get();
gpdavis.chromium0fbac4d2014-09-19 20:57:54191 }
[email protected]8d42db52014-06-20 21:50:50192
dchengc963c7142016-04-08 03:55:22193 std::unique_ptr<const PermissionSet> granted_permissions;
194 std::unique_ptr<const PermissionSet> withheld_permissions;
rdevlin.cronincb9f86e2015-10-15 15:13:42195 ScriptingPermissionsModifier(browser_context_, make_scoped_refptr(extension))
196 .WithholdPermissions(*bounded_active, &granted_permissions,
197 &withheld_permissions,
rdevlin.cronin738501d2015-11-05 21:51:36198 (init_flag_ & INIT_FLAG_TRANSIENT) != 0);
[email protected]8d42db52014-06-20 21:50:50199
dcheng1fc00f12015-12-26 22:18:03200 SetPermissions(extension, std::move(granted_permissions),
201 std::move(withheld_permissions));
[email protected]23a85362014-07-07 23:26:19202}
203
204void PermissionsUpdater::SetPermissions(
205 const Extension* extension,
dchengc963c7142016-04-08 03:55:22206 std::unique_ptr<const PermissionSet> active,
207 std::unique_ptr<const PermissionSet> withheld) {
rdevlin.cronine2d0fd02015-09-24 22:35:49208 DCHECK(active);
rdevlin.cronind630c302015-09-30 20:19:33209 const PermissionSet& active_weak = *active;
rdevlin.cronine2d0fd02015-09-24 22:35:49210 if (withheld) {
dcheng1fc00f12015-12-26 22:18:03211 extension->permissions_data()->SetPermissions(std::move(active),
212 std::move(withheld));
rdevlin.cronine2d0fd02015-09-24 22:35:49213 } else {
dcheng1fc00f12015-12-26 22:18:03214 extension->permissions_data()->SetActivePermissions(std::move(active));
rdevlin.cronine2d0fd02015-09-24 22:35:49215 }
216
gpdavis.chromium0fbac4d2014-09-19 20:57:54217 if ((init_flag_ & INIT_FLAG_TRANSIENT) == 0) {
218 ExtensionPrefs::Get(browser_context_)
rdevlin.cronine2d0fd02015-09-24 22:35:49219 ->SetActivePermissions(extension->id(), active_weak);
gpdavis.chromium0fbac4d2014-09-19 20:57:54220 }
[email protected]c333e792012-01-06 16:57:39221}
222
223void PermissionsUpdater::DispatchEvent(
224 const std::string& extension_id,
kalmanef20c652015-07-06 22:18:33225 events::HistogramValue histogram_value,
[email protected]c333e792012-01-06 16:57:39226 const char* event_name,
rdevlin.cronine2d0fd02015-09-24 22:35:49227 const PermissionSet& changed_permissions) {
[email protected]8d42db52014-06-20 21:50:50228 EventRouter* event_router = EventRouter::Get(browser_context_);
229 if (!event_router)
[email protected]c333e792012-01-06 16:57:39230 return;
231
dchengc963c7142016-04-08 03:55:22232 std::unique_ptr<base::ListValue> value(new base::ListValue());
233 std::unique_ptr<api::permissions::Permissions> permissions =
rdevlin.cronind630c302015-09-30 20:19:33234 PackPermissionSet(changed_permissions);
dcheng5d090492016-06-09 17:53:34235 value->Append(permissions->ToValue());
dchengc963c7142016-04-08 03:55:22236 std::unique_ptr<Event> event(
dcheng1fc00f12015-12-26 22:18:03237 new Event(histogram_value, event_name, std::move(value)));
[email protected]8d42db52014-06-20 21:50:50238 event->restrict_to_browser_context = browser_context_;
dcheng1fc00f12015-12-26 22:18:03239 event_router->DispatchEventToExtension(extension_id, std::move(event));
[email protected]c333e792012-01-06 16:57:39240}
241
242void PermissionsUpdater::NotifyPermissionsUpdated(
243 EventType event_type,
244 const Extension* extension,
rdevlin.cronine2d0fd02015-09-24 22:35:49245 const PermissionSet& changed) {
gpdavis.chromium0fbac4d2014-09-19 20:57:54246 DCHECK((init_flag_ & INIT_FLAG_TRANSIENT) == 0);
rdevlin.cronine2d0fd02015-09-24 22:35:49247 if (changed.IsEmpty())
[email protected]c333e792012-01-06 16:57:39248 return;
249
250 UpdatedExtensionPermissionsInfo::Reason reason;
kalmanef20c652015-07-06 22:18:33251 events::HistogramValue histogram_value;
[email protected]c333e792012-01-06 16:57:39252 const char* event_name = NULL;
253
254 if (event_type == REMOVED) {
255 reason = UpdatedExtensionPermissionsInfo::REMOVED;
kalmanef20c652015-07-06 22:18:33256 histogram_value = events::PERMISSIONS_ON_REMOVED;
[email protected]e054ea12013-08-20 00:41:57257 event_name = permissions::OnRemoved::kEventName;
[email protected]c333e792012-01-06 16:57:39258 } else {
259 CHECK_EQ(ADDED, event_type);
260 reason = UpdatedExtensionPermissionsInfo::ADDED;
kalmanef20c652015-07-06 22:18:33261 histogram_value = events::PERMISSIONS_ON_ADDED;
[email protected]e054ea12013-08-20 00:41:57262 event_name = permissions::OnAdded::kEventName;
[email protected]c333e792012-01-06 16:57:39263 }
264
265 // Notify other APIs or interested parties.
266 UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo(
267 extension, changed, reason);
[email protected]8d42db52014-06-20 21:50:50268 Profile* profile = Profile::FromBrowserContext(browser_context_);
[email protected]c333e792012-01-06 16:57:39269 content::NotificationService::current()->Notify(
[email protected]adf5a102014-07-31 12:44:06270 extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
[email protected]8d42db52014-06-20 21:50:50271 content::Source<Profile>(profile),
[email protected]c333e792012-01-06 16:57:39272 content::Details<UpdatedExtensionPermissionsInfo>(&info));
273
[email protected]8d42db52014-06-20 21:50:50274 ExtensionMsg_UpdatePermissions_Params params;
[email protected]8d42db52014-06-20 21:50:50275 params.extension_id = extension->id();
[email protected]23a85362014-07-07 23:26:19276 params.active_permissions = ExtensionMsg_PermissionSetStruct(
rdevlin.cronind630c302015-09-30 20:19:33277 extension->permissions_data()->active_permissions());
[email protected]23a85362014-07-07 23:26:19278 params.withheld_permissions = ExtensionMsg_PermissionSetStruct(
rdevlin.cronind630c302015-09-30 20:19:33279 extension->permissions_data()->withheld_permissions());
[email protected]8d42db52014-06-20 21:50:50280
[email protected]c333e792012-01-06 16:57:39281 // Send the new permissions to the renderers.
282 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
283 !i.IsAtEnd(); i.Advance()) {
284 RenderProcessHost* host = i.GetCurrentValue();
[email protected]8d42db52014-06-20 21:50:50285 if (profile->IsSameProfile(
286 Profile::FromBrowserContext(host->GetBrowserContext()))) {
287 host->Send(new ExtensionMsg_UpdatePermissions(params));
[email protected]e737c442013-11-15 15:55:24288 }
[email protected]c333e792012-01-06 16:57:39289 }
290
291 // Trigger the onAdded and onRemoved events in the extension.
kalmanef20c652015-07-06 22:18:33292 DispatchEvent(extension->id(), histogram_value, event_name, changed);
[email protected]c333e792012-01-06 16:57:39293}
294
[email protected]c333e792012-01-06 16:57:39295} // namespace extensions