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/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