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.
5 #include "chrome/browser/extensions/permissions_updater.h"
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/browser/extension_system.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_messages.h"
23 #include "extensions/common/permissions/permissions_data.h"
25 using content::RenderProcessHost
;
26 using extensions::permissions_api_helpers::PackPermissionSet
;
28 namespace extensions
{
30 namespace permissions
= api::permissions
;
32 PermissionsUpdater::PermissionsUpdater(Profile
* profile
)
33 : profile_(profile
) {}
35 PermissionsUpdater::~PermissionsUpdater() {}
37 void 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()));
46 UpdateActivePermissions(extension
, total
.get());
48 // Update the granted permissions so we don't auto-disable the extension.
49 GrantActivePermissions(extension
);
51 NotifyPermissionsUpdated(ADDED
, extension
, added
.get());
54 void 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()));
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());
68 NotifyPermissionsUpdated(REMOVED
, extension
, removed
.get());
71 void PermissionsUpdater::GrantActivePermissions(const Extension
* extension
) {
74 // We only maintain the granted permissions prefs for INTERNAL and LOAD
76 if (!Manifest::IsUnpackedLocation(extension
->location()) &&
77 extension
->location() != Manifest::INTERNAL
)
80 ExtensionPrefs::Get(profile_
)->AddGrantedPermissions(
81 extension
->id(), extension
->GetActivePermissions().get());
84 void PermissionsUpdater::UpdateActivePermissions(
85 const Extension
* extension
, const PermissionSet
* permissions
) {
86 ExtensionPrefs::Get(profile_
)->SetActivePermissions(
87 extension
->id(), permissions
);
88 PermissionsData::SetActivePermissions(extension
, permissions
);
91 void PermissionsUpdater::DispatchEvent(
92 const std::string
& extension_id
,
93 const char* event_name
,
94 const PermissionSet
* changed_permissions
) {
96 !ExtensionSystem::Get(profile_
)->event_router())
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_browser_context
= profile_
;
105 ExtensionSystem::Get(profile_
)->event_router()->
106 DispatchEventToExtension(extension_id
, event
.Pass());
109 void PermissionsUpdater::NotifyPermissionsUpdated(
110 EventType event_type
,
111 const Extension
* extension
,
112 const PermissionSet
* changed
) {
113 if (!changed
|| changed
->IsEmpty())
116 UpdatedExtensionPermissionsInfo::Reason reason
;
117 const char* event_name
= NULL
;
119 if (event_type
== REMOVED
) {
120 reason
= UpdatedExtensionPermissionsInfo::REMOVED
;
121 event_name
= permissions::OnRemoved::kEventName
;
123 CHECK_EQ(ADDED
, event_type
);
124 reason
= UpdatedExtensionPermissionsInfo::ADDED
;
125 event_name
= permissions::OnAdded::kEventName
;
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
));
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 ExtensionMsg_UpdatePermissions_Params info
;
143 info
.reason_id
= static_cast<int>(reason
);
144 info
.extension_id
= extension
->id();
145 info
.apis
= changed
->apis();
146 info
.manifest_permissions
= changed
->manifest_permissions();
147 info
.explicit_hosts
= changed
->explicit_hosts();
148 info
.scriptable_hosts
= changed
->scriptable_hosts();
149 host
->Send(new ExtensionMsg_UpdatePermissions(info
));
153 // Trigger the onAdded and onRemoved events in the extension.
154 DispatchEvent(extension
->id(), event_name
, changed
);
157 } // namespace extensions