146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// found in the LICENSE file.
446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/manifest_handlers/permissions_parser.h"
646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/command_line.h"
846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/memory/ref_counted.h"
946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/values.h"
1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "content/public/common/url_constants.h"
1246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/error_utils.h"
1346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/extension.h"
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/extensions_client.h"
1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/features/feature.h"
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/features/feature_provider.h"
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/manifest.h"
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/manifest_constants.h"
1946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/manifest_handler.h"
2046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/permissions/api_permission_set.h"
2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/permissions/permission_set.h"
2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/permissions/permissions_data.h"
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/switches.h"
2446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/url_pattern_set.h"
2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "url/url_constants.h"
2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace extensions {
2846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
2946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace {
3046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace keys = manifest_keys;
3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace errors = manifest_errors;
3346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)struct ManifestPermissions : public Extension::ManifestData {
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ManifestPermissions(scoped_refptr<const PermissionSet> permissions);
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual ~ManifestPermissions();
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_refptr<const PermissionSet> permissions;
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)ManifestPermissions::ManifestPermissions(
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scoped_refptr<const PermissionSet> permissions)
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : permissions(permissions) {
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)ManifestPermissions::~ManifestPermissions() {
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Custom checks for the experimental permission that can't be expressed in
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// _permission_features.json.
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool CanSpecifyExperimentalPermission(const Extension* extension) {
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (extension->location() == Manifest::COMPONENT)
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return true;
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (CommandLine::ForCurrentProcess()->HasSwitch(
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          switches::kEnableExperimentalExtensionApis)) {
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return true;
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // We rely on the webstore to check access to experimental. This way we can
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // whitelist extensions to have access to experimental in just the store, and
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // not have to push a new version of the client.
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (extension->from_webstore())
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return true;
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return false;
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Checks whether the host |pattern| is allowed for the given |extension|,
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// given API permissions |permissions|.
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool CanSpecifyHostPermission(const Extension* extension,
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                              const URLPattern& pattern,
7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                              const APIPermissionSet& permissions) {
7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!pattern.match_all_urls() &&
7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      pattern.MatchesScheme(content::kChromeUIScheme)) {
7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    URLPatternSet chrome_scheme_hosts =
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(extension,
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                                               permissions);
7946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (chrome_scheme_hosts.ContainsPattern(pattern))
8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return true;
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // Component extensions can have access to all of chrome://*.
8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (PermissionsData::CanExecuteScriptEverywhere(extension))
8446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return true;
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (CommandLine::ForCurrentProcess()->HasSwitch(
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            switches::kExtensionsOnChromeURLs)) {
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return true;
8946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
9046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // TODO(aboxhall): return from_webstore() when webstore handles blocking
9246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // extensions which request chrome:// urls
9346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
9446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
9546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Otherwise, the valid schemes were handled by URLPattern.
9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return true;
9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Parses the host and api permissions from the specified permission |key|
10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// from |extension|'s manifest.
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool ParseHelper(Extension* extension,
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 const char* key,
10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 APIPermissionSet* api_permissions,
10546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 URLPatternSet* host_permissions,
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 base::string16* error) {
10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!extension->manifest()->HasKey(key))
10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return true;
10946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
11046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const base::ListValue* permissions = NULL;
11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!extension->manifest()->GetList(key, &permissions)) {
11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidPermissions,
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                                 std::string());
11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // NOTE: We need to get the APIPermission before we check if features
11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // associated with them are available because the feature system does not
11946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // know about aliases.
12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::vector<std::string> host_data;
12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!APIPermissionSet::ParseFromJSON(
12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          permissions,
12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          APIPermissionSet::kDisallowInternalPermissions,
12546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          api_permissions,
12646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          error,
12746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          &host_data)) {
12846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
12946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
13146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Verify feature availability of permissions.
13246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  std::vector<APIPermission::ID> to_remove;
13346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const FeatureProvider* permission_features =
13446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      FeatureProvider::GetPermissionFeatures();
13546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (APIPermissionSet::const_iterator iter = api_permissions->begin();
13646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       iter != api_permissions->end();
13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       ++iter) {
13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    Feature* feature = permission_features->GetFeature(iter->name());
13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // The feature should exist since we just got an APIPermission for it. The
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // two systems should be updated together whenever a permission is added.
14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DCHECK(feature) << "Could not find feature for " << iter->name();
14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // http://crbug.com/176381
14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!feature) {
14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      to_remove.push_back(iter->id());
14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    Feature::Availability availability =
15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        feature->IsAvailableToExtension(extension);
15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!availability.is_available()) {
15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // Don't fail, but warn the developer that the manifest contains
15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // unrecognized permissions. This may happen legitimately if the
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // extensions requests platform- or channel-specific permissions.
15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension->AddInstallWarning(
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          InstallWarning(availability.message(), feature->name()));
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      to_remove.push_back(iter->id());
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (iter->id() == APIPermission::kExperimental) {
16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (!CanSpecifyExperimentalPermission(extension)) {
16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        *error = base::ASCIIToUTF16(errors::kExperimentalFlagRequired);
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return false;
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      }
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  api_permissions->AddImpliedPermissions();
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Remove permissions that are not available to this extension.
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (std::vector<APIPermission::ID>::const_iterator iter = to_remove.begin();
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       iter != to_remove.end();
17446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       ++iter) {
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    api_permissions->erase(*iter);
17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
17746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Parse host pattern permissions.
17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const int kAllowedSchemes =
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      PermissionsData::CanExecuteScriptEverywhere(extension)
18146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          ? URLPattern::SCHEME_ALL
18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          : Extension::kValidHostPermissionSchemes;
18346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
18446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (std::vector<std::string>::const_iterator iter = host_data.begin();
18546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       iter != host_data.end();
18646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       ++iter) {
18746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& permission_str = *iter;
18846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
18946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // Check if it's a host pattern permission.
19046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    URLPattern pattern = URLPattern(kAllowedSchemes);
19146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
19246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (parse_result == URLPattern::PARSE_SUCCESS) {
19346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // The path component is not used for host permissions, so we force it
19446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // to match all paths.
19546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      pattern.SetPath("/*");
19646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      int valid_schemes = pattern.valid_schemes();
19746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (pattern.MatchesScheme(url::kFileScheme) &&
19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          !PermissionsData::CanExecuteScriptEverywhere(extension)) {
19946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        extension->set_wants_file_access(true);
20046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS))
20146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          valid_schemes &= ~URLPattern::SCHEME_FILE;
20246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      }
20346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
20446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (pattern.scheme() != content::kChromeUIScheme &&
20546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          !PermissionsData::CanExecuteScriptEverywhere(extension)) {
20646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        // Keep chrome:// in allowed schemes only if it's explicitly requested
20746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        // or CanExecuteScriptEverywhere is true. If the
20846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        // extensions_on_chrome_urls flag is not set, CanSpecifyHostPermission
20946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        // will fail, so don't check the flag here.
21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
21146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      }
21246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      pattern.SetValidSchemes(valid_schemes);
21346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
21446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (!CanSpecifyHostPermission(extension, pattern, *api_permissions)) {
21546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        // TODO(aboxhall): make a warning (see pattern.match_all_urls() block
21646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        // below).
21746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        extension->AddInstallWarning(InstallWarning(
21846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            ErrorUtils::FormatErrorMessage(errors::kInvalidPermissionScheme,
21946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                           permission_str),
22046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            key,
22146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            permission_str));
22246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        continue;
22346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      }
22446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
22546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      host_permissions->AddPattern(pattern);
22646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // We need to make sure all_urls matches chrome://favicon and (maybe)
22746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      // chrome://thumbnail, so add them back in to host_permissions separately.
22846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (pattern.match_all_urls()) {
22946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        host_permissions->AddPatterns(
23046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(
23146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                extension, *api_permissions));
23246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      }
23346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
23446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
23546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
23646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // It's probably an unknown API permission. Do not throw an error so
23746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // extensions can retain backwards compatability (http://crbug.com/42742).
23846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    extension->AddInstallWarning(InstallWarning(
23946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        ErrorUtils::FormatErrorMessage(
24046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            manifest_errors::kPermissionUnknownOrMalformed, permission_str),
24146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        key,
24246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        permission_str));
24346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
24446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
24546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return true;
24646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
24746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
24846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace
24946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)struct PermissionsParser::InitialPermissions {
25146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  APIPermissionSet api_permissions;
25246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ManifestPermissionSet manifest_permissions;
25346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  URLPatternSet host_permissions;
25446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  URLPatternSet scriptable_hosts;
25546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
25646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
25746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)PermissionsParser::PermissionsParser() {
25846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
25946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
26046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)PermissionsParser::~PermissionsParser() {
26146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
26246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
26346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool PermissionsParser::Parse(Extension* extension, base::string16* error) {
26446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  initial_required_permissions_.reset(new InitialPermissions);
26546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!ParseHelper(extension,
26646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   keys::kPermissions,
26746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   &initial_required_permissions_->api_permissions,
26846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   &initial_required_permissions_->host_permissions,
26946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   error)) {
27046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
27146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
27246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
27346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  initial_optional_permissions_.reset(new InitialPermissions);
27446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!ParseHelper(extension,
27546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   keys::kOptionalPermissions,
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   &initial_optional_permissions_->api_permissions,
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   &initial_optional_permissions_->host_permissions,
27846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   error)) {
27946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
28046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
28146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return true;
28346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
28446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void PermissionsParser::Finalize(Extension* extension) {
28646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ManifestHandler::AddExtensionInitialRequiredPermissions(
28746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      extension, &initial_required_permissions_->manifest_permissions);
28846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_refptr<const PermissionSet> required_permissions(
29046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      new PermissionSet(initial_required_permissions_->api_permissions,
29146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        initial_required_permissions_->manifest_permissions,
29246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        initial_required_permissions_->host_permissions,
29346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        initial_required_permissions_->scriptable_hosts));
29446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  extension->SetManifestData(keys::kPermissions,
29546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                             new ManifestPermissions(required_permissions));
29646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
29746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_refptr<const PermissionSet> optional_permissions(
29846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      new PermissionSet(initial_optional_permissions_->api_permissions,
29946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        initial_optional_permissions_->manifest_permissions,
30046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        initial_optional_permissions_->host_permissions,
30146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        URLPatternSet()));
30246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  extension->SetManifestData(keys::kOptionalPermissions,
30346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                             new ManifestPermissions(optional_permissions));
30446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
30546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
30646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// static
30746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void PermissionsParser::AddAPIPermission(Extension* extension,
30846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                         APIPermission::ID permission) {
30946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(extension->permissions_parser());
31046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  extension->permissions_parser()
31146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ->initial_required_permissions_->api_permissions.insert(permission);
31246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
31346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
31446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// static
31546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void PermissionsParser::AddAPIPermission(Extension* extension,
31646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                         APIPermission* permission) {
31746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(extension->permissions_parser());
31846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  extension->permissions_parser()
31946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ->initial_required_permissions_->api_permissions.insert(permission);
32046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
32146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
32246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// static
32346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool PermissionsParser::HasAPIPermission(const Extension* extension,
32446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                         APIPermission::ID permission) {
32546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(extension->permissions_parser());
32646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return extension->permissions_parser()
32746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)             ->initial_required_permissions_->api_permissions.count(
32846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 permission) > 0;
32946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
33046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
33146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// static
33246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void PermissionsParser::SetScriptableHosts(
33346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    Extension* extension,
33446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const URLPatternSet& scriptable_hosts) {
33546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(extension->permissions_parser());
33646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  extension->permissions_parser()
33746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ->initial_required_permissions_->scriptable_hosts = scriptable_hosts;
33846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
33946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
34046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// static
34146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)scoped_refptr<const PermissionSet> PermissionsParser::GetRequiredPermissions(
34246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const Extension* extension) {
34346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(extension->GetManifestData(keys::kPermissions));
34446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return static_cast<const ManifestPermissions*>(
34546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)             extension->GetManifestData(keys::kPermissions))->permissions;
34646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
34746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
34846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// static
34946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)scoped_refptr<const PermissionSet> PermissionsParser::GetOptionalPermissions(
35046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const Extension* extension) {
35146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(extension->GetManifestData(keys::kOptionalPermissions));
35246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return static_cast<const ManifestPermissions*>(
35346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)             extension->GetManifestData(keys::kOptionalPermissions))
35446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ->permissions;
35546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
35646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
35746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace extensions
358