permissions_updater.cc revision 3551c9c881056c480085172ff9840cab31610854
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/permissions_updater.h"
6
7#include "base/json/json_writer.h"
8#include "base/memory/ref_counted.h"
9#include "base/values.h"
10#include "chrome/browser/chrome_notification_types.h"
11#include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h"
12#include "chrome/browser/extensions/event_router.h"
13#include "chrome/browser/extensions/extension_prefs.h"
14#include "chrome/browser/extensions/extension_system.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/common/extensions/api/permissions.h"
17#include "chrome/common/extensions/extension.h"
18#include "chrome/common/extensions/extension_messages.h"
19#include "chrome/common/extensions/permissions/permissions_data.h"
20#include "content/public/browser/notification_observer.h"
21#include "content/public/browser/notification_registrar.h"
22#include "content/public/browser/notification_service.h"
23#include "content/public/browser/render_process_host.h"
24
25using content::RenderProcessHost;
26using extensions::permissions_api_helpers::PackPermissionSet;
27
28namespace extensions {
29
30namespace permissions = api::permissions;
31
32PermissionsUpdater::PermissionsUpdater(Profile* profile)
33    : profile_(profile) {}
34
35PermissionsUpdater::~PermissionsUpdater() {}
36
37void PermissionsUpdater::AddPermissions(
38    const Extension* extension, const PermissionSet* permissions) {
39  scoped_refptr<const PermissionSet> existing(
40      extension->GetActivePermissions());
41  scoped_refptr<PermissionSet> total(
42      PermissionSet::CreateUnion(existing.get(), permissions));
43  scoped_refptr<PermissionSet> added(
44      PermissionSet::CreateDifference(total.get(), existing.get()));
45
46  UpdateActivePermissions(extension, total.get());
47
48  // Update the granted permissions so we don't auto-disable the extension.
49  GrantActivePermissions(extension);
50
51  NotifyPermissionsUpdated(ADDED, extension, added.get());
52}
53
54void PermissionsUpdater::RemovePermissions(
55    const Extension* extension, const PermissionSet* permissions) {
56  scoped_refptr<const PermissionSet> existing(
57      extension->GetActivePermissions());
58  scoped_refptr<PermissionSet> total(
59      PermissionSet::CreateDifference(existing.get(), permissions));
60  scoped_refptr<PermissionSet> removed(
61      PermissionSet::CreateDifference(existing.get(), total.get()));
62
63  // We update the active permissions, and not the granted permissions, because
64  // the extension, not the user, removed the permissions. This allows the
65  // extension to add them again without prompting the user.
66  UpdateActivePermissions(extension, total.get());
67
68  NotifyPermissionsUpdated(REMOVED, extension, removed.get());
69}
70
71void PermissionsUpdater::GrantActivePermissions(const Extension* extension) {
72  CHECK(extension);
73
74  // We only maintain the granted permissions prefs for INTERNAL and LOAD
75  // extensions.
76  if (!Manifest::IsUnpackedLocation(extension->location()) &&
77      extension->location() != Manifest::INTERNAL)
78    return;
79
80  ExtensionPrefs::Get(profile_)->AddGrantedPermissions(
81      extension->id(), extension->GetActivePermissions().get());
82}
83
84void PermissionsUpdater::UpdateActivePermissions(
85    const Extension* extension, const PermissionSet* permissions) {
86  ExtensionPrefs::Get(profile_)->SetActivePermissions(
87      extension->id(), permissions);
88  PermissionsData::SetActivePermissions(extension, permissions);
89}
90
91void PermissionsUpdater::DispatchEvent(
92    const std::string& extension_id,
93    const char* event_name,
94    const PermissionSet* changed_permissions) {
95  if (!profile_ ||
96      !ExtensionSystem::Get(profile_)->event_router())
97    return;
98
99  scoped_ptr<base::ListValue> value(new base::ListValue());
100  scoped_ptr<api::permissions::Permissions> permissions =
101      PackPermissionSet(changed_permissions);
102  value->Append(permissions->ToValue().release());
103  scoped_ptr<Event> event(new Event(event_name, value.Pass()));
104  event->restrict_to_profile = profile_;
105  ExtensionSystem::Get(profile_)->event_router()->
106      DispatchEventToExtension(extension_id, event.Pass());
107}
108
109void PermissionsUpdater::NotifyPermissionsUpdated(
110    EventType event_type,
111    const Extension* extension,
112    const PermissionSet* changed) {
113  if (!changed || changed->IsEmpty())
114    return;
115
116  UpdatedExtensionPermissionsInfo::Reason reason;
117  const char* event_name = NULL;
118
119  if (event_type == REMOVED) {
120    reason = UpdatedExtensionPermissionsInfo::REMOVED;
121    event_name = permissions::OnRemoved::kEventName;
122  } else {
123    CHECK_EQ(ADDED, event_type);
124    reason = UpdatedExtensionPermissionsInfo::ADDED;
125    event_name = permissions::OnAdded::kEventName;
126  }
127
128  // Notify other APIs or interested parties.
129  UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo(
130      extension, changed, reason);
131  content::NotificationService::current()->Notify(
132      chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
133      content::Source<Profile>(profile_),
134      content::Details<UpdatedExtensionPermissionsInfo>(&info));
135
136  // Send the new permissions to the renderers.
137  for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
138       !i.IsAtEnd(); i.Advance()) {
139    RenderProcessHost* host = i.GetCurrentValue();
140    Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
141    if (profile_->IsSameProfile(profile))
142      host->Send(new ExtensionMsg_UpdatePermissions(
143          static_cast<int>(reason),
144          extension->id(),
145          changed->apis(),
146          changed->explicit_hosts(),
147          changed->scriptable_hosts()));
148  }
149
150  // Trigger the onAdded and onRemoved events in the extension.
151  DispatchEvent(extension->id(), event_name, changed);
152}
153
154}  // namespace extensions
155