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