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 26using content::RenderProcessHost; 27using extensions::permissions_api_helpers::PackPermissionSet; 28 29namespace extensions { 30 31namespace permissions = api::permissions; 32 33PermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context) 34 : browser_context_(browser_context) { 35} 36 37PermissionsUpdater::~PermissionsUpdater() {} 38 39void 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 56void 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 73void 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 87void 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 118void 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 125void 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 142void 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