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