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/extension_prefs.h" 13 #include "chrome/browser/extensions/extension_system.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/common/extensions/api/permissions.h" 16 #include "chrome/common/extensions/extension_messages.h" 17 #include "content/public/browser/notification_observer.h" 18 #include "content/public/browser/notification_registrar.h" 19 #include "content/public/browser/notification_service.h" 20 #include "content/public/browser/render_process_host.h" 21 #include "extensions/browser/event_router.h" 22 #include "extensions/common/extension.h" 23 #include "extensions/common/permissions/permissions_data.h" 24 25 using content::RenderProcessHost; 26 using extensions::permissions_api_helpers::PackPermissionSet; 27 28 namespace extensions { 29 30 namespace permissions = api::permissions; 31 32 PermissionsUpdater::PermissionsUpdater(Profile* profile) 33 : profile_(profile) {} 34 35 PermissionsUpdater::~PermissionsUpdater() {} 36 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())); 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 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())); 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 71 void 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 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); 89 } 90 91 void 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_browser_context = profile_; 105 ExtensionSystem::Get(profile_)->event_router()-> 106 DispatchEventToExtension(extension_id, event.Pass()); 107 } 108 109 void 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 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)); 150 } 151 } 152 153 // Trigger the onAdded and onRemoved events in the extension. 154 DispatchEvent(extension->id(), event_name, changed); 155 } 156 157 } // namespace extensions 158