15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/permissions_updater.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h"
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/extensions/extension_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/api/permissions.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_observer.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_registrar.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/common/extension_messages.h"
236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/common/manifest_handlers/permissions_parser.h"
246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/common/permissions/permission_set.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/permissions/permissions_data.h"
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/url_pattern.h"
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/url_pattern_set.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderProcessHost;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using extensions::permissions_api_helpers::PackPermissionSet;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace permissions = api::permissions;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Returns a set of single origin permissions from |permissions| that match
396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// |bounds|. This is necessary for two reasons:
406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)//   a) single origin active permissions can get filtered out in
416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)//      GetBoundedActivePermissions because they are not recognized as a subset
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)//      of all-host permissions
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)//   b) active permissions that do not match any manifest permissions can
446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)//      exist if a manifest permission is dropped
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)URLPatternSet FilterSingleOriginPermissions(const URLPatternSet& permissions,
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                            const URLPatternSet& bounds) {
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  URLPatternSet single_origin_permissions;
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (URLPatternSet::const_iterator iter = permissions.begin();
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       iter != permissions.end();
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       ++iter) {
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (iter->MatchesSingleOrigin() &&
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        bounds.MatchesURL(GURL(iter->GetAsString()))) {
536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      single_origin_permissions.AddPattern(*iter);
546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return single_origin_permissions;
576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Returns a PermissionSet that has the active permissions of the extension,
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// bounded to its current manifest.
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdochscoped_refptr<const PermissionSet> GetBoundedActivePermissions(
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const Extension* extension,
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    const scoped_refptr<const PermissionSet>& active_permissions) {
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If the extension has used the optional permissions API, it will have a
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // custom set of active permissions defined in the extension prefs. Here,
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // we update the extension's active permissions based on the prefs.
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!active_permissions.get())
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return extension->permissions_data()->active_permissions();
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<const PermissionSet> required_permissions =
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      PermissionsParser::GetRequiredPermissions(extension);
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // We restrict the active permissions to be within the bounds defined in the
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // extension's manifest.
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  //  a) active permissions must be a subset of optional + default permissions
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  //  b) active permissions must contains all default permissions
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<PermissionSet> total_permissions = PermissionSet::CreateUnion(
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      required_permissions.get(),
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      PermissionsParser::GetOptionalPermissions(extension).get());
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Make sure the active permissions contain no more than optional + default.
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<PermissionSet> adjusted_active =
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      PermissionSet::CreateIntersection(total_permissions.get(),
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                        active_permissions.get());
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Make sure the active permissions contain the default permissions.
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  adjusted_active = PermissionSet::CreateUnion(required_permissions.get(),
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                               adjusted_active.get());
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return adjusted_active;
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Divvy up the |url patterns| between those we grant and those we do not. If
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// |withhold_permissions| is false (because the requisite feature is not
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// enabled), no permissions are withheld.
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SegregateUrlPermissions(const URLPatternSet& url_patterns,
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             bool withhold_permissions,
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             URLPatternSet* granted,
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             URLPatternSet* withheld) {
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (URLPatternSet::const_iterator iter = url_patterns.begin();
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != url_patterns.end();
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++iter) {
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (withhold_permissions && iter->ImpliesAllHosts())
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      withheld->AddPattern(*iter);
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    else
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      granted->AddPattern(*iter);
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)PermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context)
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : browser_context_(browser_context), init_flag_(INIT_FLAG_NONE) {
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciPermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context,
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       InitFlag init_flag)
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : browser_context_(browser_context), init_flag_(init_flag) {
1196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PermissionsUpdater::~PermissionsUpdater() {}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PermissionsUpdater::AddPermissions(
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension, const PermissionSet* permissions) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<const PermissionSet> existing(
12646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension->permissions_data()->active_permissions());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<PermissionSet> total(
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PermissionSet::CreateUnion(existing.get(), permissions));
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<PermissionSet> added(
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PermissionSet::CreateDifference(total.get(), existing.get()));
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetPermissions(extension, total, NULL);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the granted permissions so we don't auto-disable the extension.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GrantActivePermissions(extension);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyPermissionsUpdated(ADDED, extension, added.get());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PermissionsUpdater::RemovePermissions(
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension, const PermissionSet* permissions) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<const PermissionSet> existing(
14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension->permissions_data()->active_permissions());
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<PermissionSet> total(
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PermissionSet::CreateDifference(existing.get(), permissions));
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<PermissionSet> removed(
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PermissionSet::CreateDifference(existing.get(), total.get()));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We update the active permissions, and not the granted permissions, because
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the extension, not the user, removed the permissions. This allows the
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // extension to add them again without prompting the user.
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetPermissions(extension, total, NULL);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyPermissionsUpdated(REMOVED, extension, removed.get());
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PermissionsUpdater::GrantActivePermissions(const Extension* extension) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(extension);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only maintain the granted permissions prefs for INTERNAL and LOAD
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // extensions.
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!Manifest::IsUnpackedLocation(extension->location()) &&
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension->location() != Manifest::INTERNAL)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ExtensionPrefs::Get(browser_context_)->AddGrantedPermissions(
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension->id(),
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension->permissions_data()->active_permissions().get());
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PermissionsUpdater::InitializePermissions(const Extension* extension) {
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<const PermissionSet> active_permissions(NULL);
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<const PermissionSet> bounded_active(NULL);
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If |extension| is a transient dummy extension, we do not want to look for
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // it in preferences.
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (init_flag_ & INIT_FLAG_TRANSIENT) {
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bounded_active = active_permissions =
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        extension->permissions_data()->active_permissions();
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    active_permissions = ExtensionPrefs::Get(browser_context_)
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             ->GetActivePermissions(extension->id());
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bounded_active = GetBoundedActivePermissions(extension, active_permissions);
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Withhold permissions if the switch applies to this extension.
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Non-transient extensions also must not have the preference to allow
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // scripting on all urls.
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool should_withhold_permissions =
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      util::ScriptsMayRequireActionForExtension(extension);
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if ((init_flag_ & INIT_FLAG_TRANSIENT) == 0) {
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    should_withhold_permissions &=
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        !util::AllowedScriptingOnAllUrls(extension->id(), browser_context_);
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet granted_explicit_hosts;
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet withheld_explicit_hosts;
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SegregateUrlPermissions(bounded_active->explicit_hosts(),
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          should_withhold_permissions,
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          &granted_explicit_hosts,
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          &withheld_explicit_hosts);
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet granted_scriptable_hosts;
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet withheld_scriptable_hosts;
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SegregateUrlPermissions(bounded_active->scriptable_hosts(),
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          should_withhold_permissions,
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          &granted_scriptable_hosts,
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          &withheld_scriptable_hosts);
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // After withholding permissions, add back any origins to the active set that
2106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // may have been lost during the set operations that would have dropped them.
2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // For example, the union of <all_urls> and "example.com" is <all_urls>, so
2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // we may lose "example.com". However, "example.com" is important once
2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // <all_urls> is stripped during withholding.
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (active_permissions.get()) {
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    granted_explicit_hosts.AddPatterns(
2166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        FilterSingleOriginPermissions(active_permissions->explicit_hosts(),
2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                      bounded_active->explicit_hosts()));
2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    granted_scriptable_hosts.AddPatterns(
2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        FilterSingleOriginPermissions(active_permissions->scriptable_hosts(),
2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                      bounded_active->scriptable_hosts()));
2216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bounded_active = new PermissionSet(bounded_active->apis(),
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     bounded_active->manifest_permissions(),
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     granted_explicit_hosts,
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     granted_scriptable_hosts);
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<const PermissionSet> withheld =
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new PermissionSet(APIPermissionSet(),
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        ManifestPermissionSet(),
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        withheld_explicit_hosts,
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        withheld_scriptable_hosts);
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetPermissions(extension, bounded_active, withheld);
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
2356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PermissionsUpdater::WithholdImpliedAllHosts(const Extension* extension) {
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<const PermissionSet> active =
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension->permissions_data()->active_permissions();
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<const PermissionSet> withheld =
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension->permissions_data()->withheld_permissions();
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet withheld_scriptable = withheld->scriptable_hosts();
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet active_scriptable;
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SegregateUrlPermissions(active->scriptable_hosts(),
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          true,  // withhold permissions
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          &active_scriptable,
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          &withheld_scriptable);
248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet withheld_explicit = withheld->explicit_hosts();
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet active_explicit;
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SegregateUrlPermissions(active->explicit_hosts(),
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          true,  // withhold permissions
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          &active_explicit,
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          &withheld_explicit);
255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
256116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetPermissions(extension,
257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 new PermissionSet(active->apis(),
258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   active->manifest_permissions(),
259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   active_explicit,
260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   active_scriptable),
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                  new PermissionSet(withheld->apis(),
262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                    withheld->manifest_permissions(),
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                    withheld_explicit,
264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                    withheld_scriptable));
265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // TODO(rdevlin.cronin) We should notify the observers/renderer.
266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
2676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PermissionsUpdater::GrantWithheldImpliedAllHosts(
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const Extension* extension) {
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<const PermissionSet> active =
271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension->permissions_data()->active_permissions();
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<const PermissionSet> withheld =
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension->permissions_data()->withheld_permissions();
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Move the all-hosts permission from withheld to active.
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // We can cheat a bit here since we know that the only host permission we
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // withhold is allhosts (or something similar enough to it), so we can just
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // grant all withheld host permissions.
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet explicit_hosts;
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet::CreateUnion(
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      active->explicit_hosts(), withheld->explicit_hosts(), &explicit_hosts);
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet scriptable_hosts;
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  URLPatternSet::CreateUnion(active->scriptable_hosts(),
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             withheld->scriptable_hosts(),
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             &scriptable_hosts);
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Since we only withhold host permissions (so far), we know that withheld
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // permissions will be empty.
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetPermissions(extension,
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 new PermissionSet(active->apis(),
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   active->manifest_permissions(),
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   explicit_hosts,
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   scriptable_hosts),
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 new PermissionSet());
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // TODO(rdevlin.cronin) We should notify the observers/renderer.
2966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
2976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PermissionsUpdater::SetPermissions(
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const Extension* extension,
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const scoped_refptr<const PermissionSet>& active,
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<const PermissionSet> withheld) {
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  withheld = withheld.get() ? withheld
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 : extension->permissions_data()->withheld_permissions();
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  extension->permissions_data()->SetPermissions(active, withheld);
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if ((init_flag_ & INIT_FLAG_TRANSIENT) == 0) {
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ExtensionPrefs::Get(browser_context_)
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ->SetActivePermissions(extension->id(), active.get());
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PermissionsUpdater::DispatchEvent(
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& extension_id,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* event_name,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PermissionSet* changed_permissions) {
3156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  EventRouter* event_router = EventRouter::Get(browser_context_);
3166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!event_router)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::ListValue> value(new base::ListValue());
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<api::permissions::Permissions> permissions =
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PackPermissionSet(changed_permissions);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->Append(permissions->ToValue().release());
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<Event> event(new Event(event_name, value.Pass()));
3246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  event->restrict_to_browser_context = browser_context_;
3256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  event_router->DispatchEventToExtension(extension_id, event.Pass());
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PermissionsUpdater::NotifyPermissionsUpdated(
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EventType event_type,
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension,
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PermissionSet* changed) {
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK((init_flag_ & INIT_FLAG_TRANSIENT) == 0);
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!changed || changed->IsEmpty())
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatedExtensionPermissionsInfo::Reason reason;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* event_name = NULL;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event_type == REMOVED) {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reason = UpdatedExtensionPermissionsInfo::REMOVED;
3413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    event_name = permissions::OnRemoved::kEventName;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_EQ(ADDED, event_type);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reason = UpdatedExtensionPermissionsInfo::ADDED;
3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    event_name = permissions::OnAdded::kEventName;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notify other APIs or interested parties.
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo(
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension, changed, reason);
3516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(browser_context_);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationService::current()->Notify(
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
3546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      content::Source<Profile>(profile),
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Details<UpdatedExtensionPermissionsInfo>(&info));
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ExtensionMsg_UpdatePermissions_Params params;
3586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  params.extension_id = extension->id();
359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  params.active_permissions = ExtensionMsg_PermissionSetStruct(
3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      *extension->permissions_data()->active_permissions());
361116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  params.withheld_permissions = ExtensionMsg_PermissionSetStruct(
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      *extension->permissions_data()->withheld_permissions());
3636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send the new permissions to the renderers.
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !i.IsAtEnd(); i.Advance()) {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RenderProcessHost* host = i.GetCurrentValue();
3686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (profile->IsSameProfile(
3696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)            Profile::FromBrowserContext(host->GetBrowserContext()))) {
3706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      host->Send(new ExtensionMsg_UpdatePermissions(params));
371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Trigger the onAdded and onRemoved events in the extension.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DispatchEvent(extension->id(), event_name, changed);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
379