Home | History | Annotate | Download | only in extensions
      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