• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/profiles/profile.h"
13 #include "chrome/common/extensions/api/permissions.h"
14 #include "content/public/browser/notification_observer.h"
15 #include "content/public/browser/notification_registrar.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "extensions/browser/event_router.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/common/extension.h"
21 #include "extensions/common/extension_messages.h"
22 #include "extensions/common/manifest_handlers/permissions_parser.h"
23 #include "extensions/common/permissions/permission_set.h"
24 #include "extensions/common/permissions/permissions_data.h"
25 
26 using content::RenderProcessHost;
27 using extensions::permissions_api_helpers::PackPermissionSet;
28 
29 namespace extensions {
30 
31 namespace permissions = api::permissions;
32 
PermissionsUpdater(content::BrowserContext * browser_context)33 PermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context)
34     : browser_context_(browser_context) {
35 }
36 
~PermissionsUpdater()37 PermissionsUpdater::~PermissionsUpdater() {}
38 
AddPermissions(const Extension * extension,const PermissionSet * permissions)39 void PermissionsUpdater::AddPermissions(
40     const Extension* extension, const PermissionSet* permissions) {
41   scoped_refptr<const PermissionSet> existing(
42       extension->permissions_data()->active_permissions());
43   scoped_refptr<PermissionSet> total(
44       PermissionSet::CreateUnion(existing.get(), permissions));
45   scoped_refptr<PermissionSet> added(
46       PermissionSet::CreateDifference(total.get(), existing.get()));
47 
48   SetActivePermissions(extension, total.get());
49 
50   // Update the granted permissions so we don't auto-disable the extension.
51   GrantActivePermissions(extension);
52 
53   NotifyPermissionsUpdated(ADDED, extension, added.get());
54 }
55 
RemovePermissions(const Extension * extension,const PermissionSet * permissions)56 void PermissionsUpdater::RemovePermissions(
57     const Extension* extension, const PermissionSet* permissions) {
58   scoped_refptr<const PermissionSet> existing(
59       extension->permissions_data()->active_permissions());
60   scoped_refptr<PermissionSet> total(
61       PermissionSet::CreateDifference(existing.get(), permissions));
62   scoped_refptr<PermissionSet> removed(
63       PermissionSet::CreateDifference(existing.get(), total.get()));
64 
65   // We update the active permissions, and not the granted permissions, because
66   // the extension, not the user, removed the permissions. This allows the
67   // extension to add them again without prompting the user.
68   SetActivePermissions(extension, total.get());
69 
70   NotifyPermissionsUpdated(REMOVED, extension, removed.get());
71 }
72 
GrantActivePermissions(const Extension * extension)73 void PermissionsUpdater::GrantActivePermissions(const Extension* extension) {
74   CHECK(extension);
75 
76   // We only maintain the granted permissions prefs for INTERNAL and LOAD
77   // extensions.
78   if (!Manifest::IsUnpackedLocation(extension->location()) &&
79       extension->location() != Manifest::INTERNAL)
80     return;
81 
82   ExtensionPrefs::Get(browser_context_)->AddGrantedPermissions(
83       extension->id(),
84       extension->permissions_data()->active_permissions().get());
85 }
86 
InitializeActivePermissions(const Extension * extension)87 void PermissionsUpdater::InitializeActivePermissions(
88     const Extension* extension) {
89   // If the extension has used the optional permissions API, it will have a
90   // custom set of active permissions defined in the extension prefs. Here,
91   // we update the extension's active permissions based on the prefs.
92   scoped_refptr<PermissionSet> active_permissions =
93       ExtensionPrefs::Get(browser_context_)->GetActivePermissions(
94           extension->id());
95   if (!active_permissions)
96     return;
97 
98   // We restrict the active permissions to be within the bounds defined in the
99   // extension's manifest.
100   //  a) active permissions must be a subset of optional + default permissions
101   //  b) active permissions must contains all default permissions
102   scoped_refptr<PermissionSet> total_permissions = PermissionSet::CreateUnion(
103       PermissionsParser::GetRequiredPermissions(extension),
104       PermissionsParser::GetOptionalPermissions(extension));
105 
106   // Make sure the active permissions contain no more than optional + default.
107   scoped_refptr<PermissionSet> adjusted_active =
108       PermissionSet::CreateIntersection(total_permissions, active_permissions);
109 
110   // Make sure the active permissions contain the default permissions.
111   adjusted_active = PermissionSet::CreateUnion(
112       PermissionsParser::GetRequiredPermissions(extension),
113       adjusted_active);
114 
115   SetActivePermissions(extension, adjusted_active);
116 }
117 
SetActivePermissions(const Extension * extension,const PermissionSet * permissions)118 void PermissionsUpdater::SetActivePermissions(
119     const Extension* extension, const PermissionSet* permissions) {
120   ExtensionPrefs::Get(browser_context_)->SetActivePermissions(
121       extension->id(), permissions);
122   extension->permissions_data()->SetActivePermissions(permissions);
123 }
124 
DispatchEvent(const std::string & extension_id,const char * event_name,const PermissionSet * changed_permissions)125 void PermissionsUpdater::DispatchEvent(
126     const std::string& extension_id,
127     const char* event_name,
128     const PermissionSet* changed_permissions) {
129   EventRouter* event_router = EventRouter::Get(browser_context_);
130   if (!event_router)
131     return;
132 
133   scoped_ptr<base::ListValue> value(new base::ListValue());
134   scoped_ptr<api::permissions::Permissions> permissions =
135       PackPermissionSet(changed_permissions);
136   value->Append(permissions->ToValue().release());
137   scoped_ptr<Event> event(new Event(event_name, value.Pass()));
138   event->restrict_to_browser_context = browser_context_;
139   event_router->DispatchEventToExtension(extension_id, event.Pass());
140 }
141 
NotifyPermissionsUpdated(EventType event_type,const Extension * extension,const PermissionSet * changed)142 void PermissionsUpdater::NotifyPermissionsUpdated(
143     EventType event_type,
144     const Extension* extension,
145     const PermissionSet* changed) {
146   if (!changed || changed->IsEmpty())
147     return;
148 
149   UpdatedExtensionPermissionsInfo::Reason reason;
150   const char* event_name = NULL;
151 
152   if (event_type == REMOVED) {
153     reason = UpdatedExtensionPermissionsInfo::REMOVED;
154     event_name = permissions::OnRemoved::kEventName;
155   } else {
156     CHECK_EQ(ADDED, event_type);
157     reason = UpdatedExtensionPermissionsInfo::ADDED;
158     event_name = permissions::OnAdded::kEventName;
159   }
160 
161   // Notify other APIs or interested parties.
162   UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo(
163       extension, changed, reason);
164   Profile* profile = Profile::FromBrowserContext(browser_context_);
165   content::NotificationService::current()->Notify(
166       chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
167       content::Source<Profile>(profile),
168       content::Details<UpdatedExtensionPermissionsInfo>(&info));
169 
170   ExtensionMsg_UpdatePermissions_Params params;
171   params.reason_id = static_cast<int>(reason);
172   params.extension_id = extension->id();
173   params.apis = changed->apis();
174   params.manifest_permissions = changed->manifest_permissions();
175   params.explicit_hosts = changed->explicit_hosts();
176   params.scriptable_hosts = changed->scriptable_hosts();
177 
178   // Send the new permissions to the renderers.
179   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
180        !i.IsAtEnd(); i.Advance()) {
181     RenderProcessHost* host = i.GetCurrentValue();
182     if (profile->IsSameProfile(
183             Profile::FromBrowserContext(host->GetBrowserContext()))) {
184       host->Send(new ExtensionMsg_UpdatePermissions(params));
185     }
186   }
187 
188   // Trigger the onAdded and onRemoved events in the extension.
189   DispatchEvent(extension->id(), event_name, changed);
190 }
191 
192 }  // namespace extensions
193