Home | History | Annotate | Download | only in permissions
      1 // Copyright (c) 2013 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/common/extensions/permissions/permissions_data.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/string16.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/values.h"
     14 #include "chrome/common/extensions/extension.h"
     15 #include "chrome/common/extensions/extension_manifest_constants.h"
     16 #include "chrome/common/extensions/features/base_feature_provider.h"
     17 #include "chrome/common/extensions/features/feature.h"
     18 #include "chrome/common/extensions/manifest.h"
     19 #include "chrome/common/extensions/permissions/api_permission_set.h"
     20 #include "chrome/common/extensions/permissions/chrome_scheme_hosts.h"
     21 #include "chrome/common/extensions/permissions/permission_set.h"
     22 #include "chrome/common/extensions/permissions/permissions_info.h"
     23 #include "content/public/common/url_constants.h"
     24 #include "extensions/common/constants.h"
     25 #include "extensions/common/error_utils.h"
     26 #include "extensions/common/switches.h"
     27 #include "extensions/common/url_pattern_set.h"
     28 #include "extensions/common/user_script.h"
     29 #include "url/gurl.h"
     30 
     31 namespace keys = extension_manifest_keys;
     32 namespace errors = extension_manifest_errors;
     33 
     34 namespace extensions {
     35 
     36 namespace {
     37 
     38 PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
     39 
     40 bool ContainsManifestForbiddenPermission(const APIPermissionSet& apis,
     41                                          string16* error) {
     42   CHECK(error);
     43   for (APIPermissionSet::const_iterator iter = apis.begin();
     44        iter != apis.end(); ++iter) {
     45     if ((*iter)->ManifestEntryForbidden()) {
     46       *error = ErrorUtils::FormatErrorMessageUTF16(
     47           errors::kPermissionNotAllowedInManifest,
     48           (*iter)->info()->name());
     49       return true;
     50     }
     51   }
     52   return false;
     53 }
     54 
     55 // Custom checks for the experimental permission that can't be expressed in
     56 // _permission_features.json.
     57 bool CanSpecifyExperimentalPermission(const Extension* extension) {
     58   if (extension->location() == Manifest::COMPONENT)
     59     return true;
     60 
     61   if (CommandLine::ForCurrentProcess()->HasSwitch(
     62           switches::kEnableExperimentalExtensionApis)) {
     63     return true;
     64   }
     65 
     66   // We rely on the webstore to check access to experimental. This way we can
     67   // whitelist extensions to have access to experimental in just the store, and
     68   // not have to push a new version of the client.
     69   if (extension->from_webstore())
     70     return true;
     71 
     72   return false;
     73 }
     74 
     75 // Checks whether the host |pattern| is allowed for the given |extension|,
     76 // given API permissions |permissions|.
     77 bool CanSpecifyHostPermission(const Extension* extension,
     78                               const URLPattern& pattern,
     79                               const APIPermissionSet& permissions) {
     80   if (!pattern.match_all_urls() &&
     81       pattern.MatchesScheme(chrome::kChromeUIScheme)) {
     82     URLPatternSet chrome_scheme_hosts =
     83         GetPermittedChromeSchemeHosts(extension, permissions);
     84     if (chrome_scheme_hosts.ContainsPattern(pattern))
     85       return true;
     86 
     87     // Component extensions can have access to all of chrome://*.
     88     if (PermissionsData::CanExecuteScriptEverywhere(extension))
     89       return true;
     90 
     91     if (CommandLine::ForCurrentProcess()->HasSwitch(
     92           switches::kExtensionsOnChromeURLs)) {
     93       return true;
     94     }
     95 
     96     // TODO(aboxhall): return from_webstore() when webstore handles blocking
     97     // extensions which request chrome:// urls
     98     return false;
     99   }
    100 
    101   // Otherwise, the valid schemes were handled by URLPattern.
    102   return true;
    103 }
    104 
    105 // Parses the host and api permissions from the specified permission |key|
    106 // from |extension|'s manifest.
    107 bool ParseHelper(Extension* extension,
    108                  const char* key,
    109                  APIPermissionSet* api_permissions,
    110                  URLPatternSet* host_permissions,
    111                  string16* error) {
    112   if (!extension->manifest()->HasKey(key))
    113     return true;
    114 
    115   const base::ListValue* permissions = NULL;
    116   if (!extension->manifest()->GetList(key, &permissions)) {
    117     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidPermissions,
    118                                                  std::string());
    119     return false;
    120   }
    121 
    122   // NOTE: We need to get the APIPermission before we check if features
    123   // associated with them are available because the feature system does not
    124   // know about aliases.
    125 
    126   std::vector<std::string> host_data;
    127   if (!APIPermissionSet::ParseFromJSON(
    128           permissions, APIPermissionSet::kDisallowInternalPermissions,
    129           api_permissions, error, &host_data)) {
    130     return false;
    131   }
    132 
    133   // Verify feature availability of permissions.
    134   std::vector<APIPermission::ID> to_remove;
    135   FeatureProvider* permission_features =
    136       BaseFeatureProvider::GetByName("permission");
    137   for (APIPermissionSet::const_iterator iter = api_permissions->begin();
    138        iter != api_permissions->end(); ++iter) {
    139     Feature* feature = permission_features->GetFeature(iter->name());
    140 
    141     // The feature should exist since we just got an APIPermission for it. The
    142     // two systems should be updated together whenever a permission is added.
    143     DCHECK(feature);
    144     // http://crbug.com/176381
    145     if (!feature) {
    146       to_remove.push_back(iter->id());
    147       continue;
    148     }
    149 
    150     Feature::Availability availability = feature->IsAvailableToManifest(
    151         extension->id(),
    152         extension->GetType(),
    153         Feature::ConvertLocation(extension->location()),
    154         extension->manifest_version());
    155 
    156     if (!availability.is_available()) {
    157       // Don't fail, but warn the developer that the manifest contains
    158       // unrecognized permissions. This may happen legitimately if the
    159       // extensions requests platform- or channel-specific permissions.
    160       extension->AddInstallWarning(InstallWarning(InstallWarning::FORMAT_TEXT,
    161                                                   availability.message()));
    162       to_remove.push_back(iter->id());
    163       continue;
    164     }
    165 
    166     if (iter->id() == APIPermission::kExperimental) {
    167       if (!CanSpecifyExperimentalPermission(extension)) {
    168         *error = ASCIIToUTF16(errors::kExperimentalFlagRequired);
    169         return false;
    170       }
    171     }
    172   }
    173 
    174   // Remove permissions that are not available to this extension.
    175   for (std::vector<APIPermission::ID>::const_iterator iter = to_remove.begin();
    176        iter != to_remove.end(); ++iter) {
    177       api_permissions->erase(*iter);
    178   }
    179 
    180   // Parse host pattern permissions.
    181   const int kAllowedSchemes =
    182       PermissionsData::CanExecuteScriptEverywhere(extension) ?
    183       URLPattern::SCHEME_ALL : Extension::kValidHostPermissionSchemes;
    184 
    185   for (std::vector<std::string>::const_iterator iter = host_data.begin();
    186        iter != host_data.end(); ++iter) {
    187     const std::string& permission_str = *iter;
    188 
    189     // Check if it's a host pattern permission.
    190     URLPattern pattern = URLPattern(kAllowedSchemes);
    191     URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
    192     if (parse_result == URLPattern::PARSE_SUCCESS) {
    193       // The path component is not used for host permissions, so we force it
    194       // to match all paths.
    195       pattern.SetPath("/*");
    196       int valid_schemes = pattern.valid_schemes();
    197       if (pattern.MatchesScheme(chrome::kFileScheme) &&
    198           !PermissionsData::CanExecuteScriptEverywhere(extension)) {
    199         extension->set_wants_file_access(true);
    200         if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS))
    201           valid_schemes &= ~URLPattern::SCHEME_FILE;
    202       }
    203 
    204       if (pattern.scheme() != chrome::kChromeUIScheme &&
    205           !PermissionsData::CanExecuteScriptEverywhere(extension)) {
    206         // Keep chrome:// in allowed schemes only if it's explicitly requested
    207         // or CanExecuteScriptEverywhere is true. If the
    208         // extensions_on_chrome_urls flag is not set, CanSpecifyHostPermission
    209         // will fail, so don't check the flag here.
    210         valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
    211       }
    212       pattern.SetValidSchemes(valid_schemes);
    213 
    214       if (!CanSpecifyHostPermission(extension, pattern, *api_permissions)) {
    215         // TODO(aboxhall): make a warning (see pattern.match_all_urls() block
    216         // below).
    217         *error = ErrorUtils::FormatErrorMessageUTF16(
    218             errors::kInvalidPermissionScheme, permission_str);
    219         return false;
    220       }
    221 
    222       host_permissions->AddPattern(pattern);
    223       // We need to make sure all_urls matches chrome://favicon and (maybe)
    224       // chrome://thumbnail, so add them back in to host_permissions separately.
    225       if (pattern.match_all_urls())
    226         host_permissions->AddPatterns(GetPermittedChromeSchemeHosts(
    227             extension, *api_permissions));
    228       continue;
    229     }
    230 
    231     // It's probably an unknown API permission. Do not throw an error so
    232     // extensions can retain backwards compatability (http://crbug.com/42742).
    233     extension->AddInstallWarning(InstallWarning(
    234         InstallWarning::FORMAT_TEXT,
    235         base::StringPrintf(
    236             "Permission '%s' is unknown or URL pattern is malformed.",
    237             permission_str.c_str())));
    238   }
    239 
    240   return true;
    241 }
    242 
    243 // Returns true if this extension id is from a trusted provider.
    244 bool IsTrustedId(const std::string& extension_id) {
    245   // See http://b/4946060 for more details.
    246   return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
    247 }
    248 
    249 }  // namespace
    250 
    251 struct PermissionsData::InitialPermissions {
    252   APIPermissionSet api_permissions;
    253   URLPatternSet host_permissions;
    254   URLPatternSet scriptable_hosts;
    255 };
    256 
    257 PermissionsData::PermissionsData() {
    258 }
    259 
    260 PermissionsData::~PermissionsData() {
    261 }
    262 
    263 // static
    264 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
    265   g_policy_delegate = delegate;
    266 }
    267 
    268 // static
    269 const PermissionSet* PermissionsData::GetOptionalPermissions(
    270     const Extension* extension) {
    271   return extension->permissions_data()->optional_permission_set_.get();
    272 }
    273 
    274 // static
    275 const PermissionSet* PermissionsData::GetRequiredPermissions(
    276     const Extension* extension) {
    277   return extension->permissions_data()->required_permission_set_.get();
    278 }
    279 
    280 // static
    281 const APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
    282     const Extension* extension) {
    283   return &extension->permissions_data()->
    284       initial_required_permissions_->api_permissions;
    285 }
    286 
    287 // static
    288 APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
    289     Extension* extension) {
    290   return &extension->permissions_data()->
    291       initial_required_permissions_->api_permissions;
    292 }
    293 
    294 // static
    295 void PermissionsData::SetInitialScriptableHosts(
    296     Extension* extension, const URLPatternSet& scriptable_hosts) {
    297   extension->permissions_data()->
    298       initial_required_permissions_->scriptable_hosts = scriptable_hosts;
    299 }
    300 
    301 // static
    302 void PermissionsData::SetActivePermissions(const Extension* extension,
    303                                            const PermissionSet* permissions) {
    304   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    305   extension->permissions_data()->active_permissions_ = permissions;
    306 }
    307 
    308 // static
    309 scoped_refptr<const PermissionSet> PermissionsData::GetActivePermissions(
    310     const Extension* extension) {
    311   return extension->permissions_data()->active_permissions_;
    312 }
    313 
    314 // static
    315 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
    316     const Extension* extension,
    317     int tab_id) {
    318   CHECK_GE(tab_id, 0);
    319   TabPermissionsMap::const_iterator iter =
    320       extension->permissions_data()->tab_specific_permissions_.find(tab_id);
    321   return
    322       (iter != extension->permissions_data()->tab_specific_permissions_.end())
    323           ? iter->second
    324           : NULL;
    325 }
    326 
    327 // static
    328 void PermissionsData::UpdateTabSpecificPermissions(
    329     const Extension* extension,
    330     int tab_id,
    331     scoped_refptr<const PermissionSet> permissions) {
    332   CHECK_GE(tab_id, 0);
    333   TabPermissionsMap* tab_permissions =
    334       &extension->permissions_data()->tab_specific_permissions_;
    335   if (tab_permissions->count(tab_id)) {
    336     (*tab_permissions)[tab_id] = PermissionSet::CreateUnion(
    337         (*tab_permissions)[tab_id].get(), permissions.get());
    338   } else {
    339     (*tab_permissions)[tab_id] = permissions;
    340   }
    341 }
    342 
    343 // static
    344 void PermissionsData::ClearTabSpecificPermissions(
    345     const Extension* extension,
    346     int tab_id) {
    347   CHECK_GE(tab_id, 0);
    348   extension->permissions_data()->tab_specific_permissions_.erase(tab_id);
    349 }
    350 
    351 // static
    352 bool PermissionsData::HasAPIPermission(const Extension* extension,
    353                                        APIPermission::ID permission) {
    354   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    355   return GetActivePermissions(extension)->HasAPIPermission(permission);
    356 }
    357 
    358 // static
    359 bool PermissionsData::HasAPIPermission(
    360     const Extension* extension,
    361     const std::string& permission_name) {
    362   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    363   return GetActivePermissions(extension)->HasAPIPermission(permission_name);
    364 }
    365 
    366 // static
    367 bool PermissionsData::HasAPIPermissionForTab(
    368     const Extension* extension,
    369     int tab_id,
    370     APIPermission::ID permission) {
    371   if (HasAPIPermission(extension, permission))
    372     return true;
    373 
    374   // Place autolock below the HasAPIPermission() check, since HasAPIPermission
    375   // also acquires the lock.
    376   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    377   scoped_refptr<const PermissionSet> tab_permissions =
    378       GetTabSpecificPermissions(extension, tab_id);
    379   return tab_permissions.get() && tab_permissions->HasAPIPermission(permission);
    380 }
    381 
    382 // static
    383 bool PermissionsData::CheckAPIPermissionWithParam(
    384     const Extension* extension,
    385     APIPermission::ID permission,
    386     const APIPermission::CheckParam* param) {
    387   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    388   return GetActivePermissions(extension)->CheckAPIPermissionWithParam(
    389       permission, param);
    390 }
    391 
    392 // static
    393 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions(
    394     const Extension* extension) {
    395   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    396   return GetActivePermissions(extension)->effective_hosts();
    397 }
    398 
    399 // static
    400 bool PermissionsData::CanSilentlyIncreasePermissions(
    401     const Extension* extension) {
    402   return extension->location() != Manifest::INTERNAL;
    403 }
    404 
    405 // static
    406 bool PermissionsData::ShouldSkipPermissionWarnings(const Extension* extension) {
    407   return IsTrustedId(extension->id());
    408 }
    409 
    410 // static
    411 bool PermissionsData::HasHostPermission(const Extension* extension,
    412                                         const GURL& url) {
    413   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    414   return GetActivePermissions(extension)->HasExplicitAccessToOrigin(url);
    415 }
    416 
    417 // static
    418 bool PermissionsData::HasEffectiveAccessToAllHosts(const Extension* extension) {
    419   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    420   return GetActivePermissions(extension)->HasEffectiveAccessToAllHosts();
    421 }
    422 
    423 // static
    424 PermissionMessages PermissionsData::GetPermissionMessages(
    425     const Extension* extension) {
    426   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    427   if (ShouldSkipPermissionWarnings(extension)) {
    428     return PermissionMessages();
    429   } else {
    430     return GetActivePermissions(extension)->GetPermissionMessages(
    431         extension->GetType());
    432   }
    433 }
    434 
    435 // static
    436 std::vector<string16> PermissionsData::GetPermissionMessageStrings(
    437     const Extension* extension) {
    438   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    439   if (ShouldSkipPermissionWarnings(extension)) {
    440     return std::vector<string16>();
    441   } else {
    442     return GetActivePermissions(extension)->GetWarningMessages(
    443         extension->GetType());
    444   }
    445 }
    446 
    447 // static
    448 std::vector<string16> PermissionsData::GetPermissionMessageDetailsStrings(
    449     const Extension* extension) {
    450   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    451   if (ShouldSkipPermissionWarnings(extension)) {
    452     return std::vector<string16>();
    453   } else {
    454     return GetActivePermissions(extension)->GetWarningMessagesDetails(
    455         extension->GetType());
    456   }
    457 }
    458 
    459 // static
    460 bool PermissionsData::CanExecuteScriptOnPage(const Extension* extension,
    461                                              const GURL& document_url,
    462                                              const GURL& top_frame_url,
    463                                              int tab_id,
    464                                              const UserScript* script,
    465                                              int process_id,
    466                                              std::string* error) {
    467   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
    468   // The gallery is special-cased as a restricted URL for scripting to prevent
    469   // access to special JS bindings we expose to the gallery (and avoid things
    470   // like extensions removing the "report abuse" link).
    471   // TODO(erikkay): This seems like the wrong test.  Shouldn't we we testing
    472   // against the store app extent?
    473   GURL store_url(extension_urls::GetWebstoreLaunchURL());
    474   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    475   bool can_execute_everywhere = CanExecuteScriptEverywhere(extension);
    476 
    477   if (g_policy_delegate &&
    478       !g_policy_delegate->CanExecuteScriptOnPage(
    479            extension, document_url, top_frame_url, tab_id,
    480            script, process_id, error))
    481     return false;
    482 
    483   if ((document_url.host() == store_url.host()) &&
    484       !can_execute_everywhere &&
    485       !command_line->HasSwitch(switches::kAllowScriptingGallery)) {
    486     if (error)
    487       *error = errors::kCannotScriptGallery;
    488     return false;
    489   }
    490 
    491   if (!command_line->HasSwitch(switches::kExtensionsOnChromeURLs)) {
    492     if (document_url.SchemeIs(chrome::kChromeUIScheme) &&
    493         !can_execute_everywhere) {
    494       if (error)
    495         *error = errors::kCannotAccessChromeUrl;
    496       return false;
    497     }
    498   }
    499 
    500   if (top_frame_url.SchemeIs(extensions::kExtensionScheme) &&
    501       top_frame_url.GetOrigin() !=
    502           Extension::GetBaseURLFromExtensionId(extension->id()).GetOrigin() &&
    503       !can_execute_everywhere) {
    504     if (error)
    505       *error = errors::kCannotAccessExtensionUrl;
    506     return false;
    507   }
    508 
    509   // If a tab ID is specified, try the tab-specific permissions.
    510   if (tab_id >= 0) {
    511     scoped_refptr<const PermissionSet> tab_permissions =
    512         GetTabSpecificPermissions(extension, tab_id);
    513     if (tab_permissions.get() &&
    514         tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) {
    515       return true;
    516     }
    517   }
    518 
    519   bool can_access = false;
    520 
    521   if (script) {
    522     // If a script is specified, use its matches.
    523     can_access = script->MatchesURL(document_url);
    524   } else {
    525     // Otherwise, see if this extension has permission to execute script
    526     // programmatically on pages.
    527     can_access = GetActivePermissions(extension)->
    528         HasExplicitAccessToOrigin(document_url);
    529   }
    530 
    531   if (!can_access && error) {
    532     *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
    533                                             document_url.spec());
    534   }
    535 
    536   return can_access;
    537 }
    538 
    539 // static
    540 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
    541   if (extension->location() == Manifest::COMPONENT)
    542     return true;
    543 
    544   const Extension::ScriptingWhitelist* whitelist =
    545       Extension::GetScriptingWhitelist();
    546 
    547   for (Extension::ScriptingWhitelist::const_iterator iter = whitelist->begin();
    548        iter != whitelist->end(); ++iter) {
    549     if (extension->id() == *iter)
    550       return true;
    551   }
    552 
    553   return false;
    554 }
    555 
    556 // static
    557 bool PermissionsData::CanCaptureVisiblePage(const Extension* extension,
    558                                             const GURL& page_url,
    559                                             int tab_id,
    560                                             std::string* error) {
    561   if (tab_id >= 0) {
    562     scoped_refptr<const PermissionSet> tab_permissions =
    563         GetTabSpecificPermissions(extension, tab_id);
    564     if (tab_permissions.get() &&
    565         tab_permissions->explicit_hosts().MatchesSecurityOrigin(page_url)) {
    566       return true;
    567     }
    568   }
    569 
    570   if (HasHostPermission(extension, page_url) ||
    571       page_url.GetOrigin() == extension->url()) {
    572     return true;
    573   }
    574 
    575   if (error) {
    576     *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
    577                                             page_url.spec());
    578   }
    579   return false;
    580 }
    581 
    582 bool PermissionsData::ParsePermissions(Extension* extension, string16* error) {
    583   initial_required_permissions_.reset(new InitialPermissions);
    584   if (!ParseHelper(extension,
    585                    keys::kPermissions,
    586                    &initial_required_permissions_->api_permissions,
    587                    &initial_required_permissions_->host_permissions,
    588                    error)) {
    589     return false;
    590   }
    591 
    592   // TODO(jeremya/kalman) do this via the features system by exposing the
    593   // app.window API to platform apps, with no dependency on any permissions.
    594   // See http://crbug.com/120069.
    595   if (extension->is_platform_app()) {
    596     initial_required_permissions_->api_permissions.insert(
    597         APIPermission::kAppCurrentWindowInternal);
    598     initial_required_permissions_->api_permissions.insert(
    599         APIPermission::kAppRuntime);
    600     initial_required_permissions_->api_permissions.insert(
    601         APIPermission::kAppWindow);
    602   }
    603 
    604   initial_optional_permissions_.reset(new InitialPermissions);
    605   if (!ParseHelper(extension,
    606                    keys::kOptionalPermissions,
    607                    &initial_optional_permissions_->api_permissions,
    608                    &initial_optional_permissions_->host_permissions,
    609                    error)) {
    610     return false;
    611   }
    612 
    613   if (ContainsManifestForbiddenPermission(
    614           initial_required_permissions_->api_permissions, error) ||
    615       ContainsManifestForbiddenPermission(
    616           initial_optional_permissions_->api_permissions, error)) {
    617     return false;
    618   }
    619 
    620   return true;
    621 }
    622 
    623 void PermissionsData::FinalizePermissions(Extension* extension) {
    624   active_permissions_ = new PermissionSet(
    625       initial_required_permissions_->api_permissions,
    626       initial_required_permissions_->host_permissions,
    627       initial_required_permissions_->scriptable_hosts);
    628 
    629   required_permission_set_ = new PermissionSet(
    630       initial_required_permissions_->api_permissions,
    631       initial_required_permissions_->host_permissions,
    632       initial_required_permissions_->scriptable_hosts);
    633 
    634   optional_permission_set_ = new PermissionSet(
    635       initial_optional_permissions_->api_permissions,
    636       initial_optional_permissions_->host_permissions,
    637       URLPatternSet());
    638 
    639   initial_required_permissions_.reset();
    640   initial_optional_permissions_.reset();
    641 }
    642 
    643 }  // namespace extensions
    644