1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/features/simple_feature.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <map>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <vector>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/bind.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/debug/alias.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/sha1.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/extension_api.h"
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/features/feature_provider.h"
20e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "extensions/common/switches.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26116680a4aac90f2aa7413d9095a592090648e557Ben MurdochFeature::Availability IsAvailableToManifestForBind(
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::string& extension_id,
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Manifest::Type type,
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Manifest::Location location,
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int manifest_version,
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Feature::Platform platform,
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const Feature* feature) {
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return feature->IsAvailableToManifest(
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extension_id, type, location, manifest_version, platform);
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
37116680a4aac90f2aa7413d9095a592090648e557Ben MurdochFeature::Availability IsAvailableToContextForBind(const Extension* extension,
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                  Feature::Context context,
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                  const GURL& url,
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                  Feature::Platform platform,
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                  const Feature* feature) {
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return feature->IsAvailableToContext(extension, context, url, platform);
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct Mappings {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Mappings() {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extension_types["extension"] = Manifest::TYPE_EXTENSION;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extension_types["theme"] = Manifest::TYPE_THEME;
49424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    extension_types["legacy_packaged_app"] = Manifest::TYPE_LEGACY_PACKAGED_APP;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extension_types["hosted_app"] = Manifest::TYPE_HOSTED_APP;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extension_types["platform_app"] = Manifest::TYPE_PLATFORM_APP;
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    extension_types["shared_module"] = Manifest::TYPE_SHARED_MODULE;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    contexts["blessed_extension"] = Feature::BLESSED_EXTENSION_CONTEXT;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT;
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    contexts["web_page"] = Feature::WEB_PAGE_CONTEXT;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT;
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    contexts["webui"] = Feature::WEBUI_CONTEXT;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    locations["component"] = SimpleFeature::COMPONENT_LOCATION;
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    locations["policy"] = SimpleFeature::POLICY_LOCATION;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    platforms["chromeos"] = Feature::CHROMEOS_PLATFORM;
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    platforms["linux"] = Feature::LINUX_PLATFORM;
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    platforms["mac"] = Feature::MACOSX_PLATFORM;
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    platforms["win"] = Feature::WIN_PLATFORM;
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::map<std::string, Manifest::Type> extension_types;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::map<std::string, Feature::Context> contexts;
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::map<std::string, SimpleFeature::Location> locations;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::map<std::string, Feature::Platform> platforms;
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::LazyInstance<Mappings> g_mappings = LAZY_INSTANCE_INITIALIZER;
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(aa): Can we replace all this manual parsing with JSON schema stuff?
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void ParseSet(const base::DictionaryValue* value,
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              const std::string& property,
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              std::set<std::string>* set) {
837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::ListValue* list_value = NULL;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!value->GetList(property, &list_value))
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set->clear();
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < list_value->GetSize(); ++i) {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string str_val;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK(list_value->GetString(i, &str_val)) << property << " " << i;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    set->insert(str_val);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ParseEnum(const std::string& string_value,
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               T* enum_value,
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               const std::map<std::string, T>& mapping) {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typename std::map<std::string, T>::const_iterator iter =
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      mapping.find(string_value);
1010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (iter == mapping.end()) {
1020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // For http://crbug.com/365192.
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    char minidump[256];
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::debug::Alias(&minidump);
1050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::snprintf(minidump, arraysize(minidump),
1060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        "e::simple_feature.cc:%d:\"%s\"", __LINE__, string_value.c_str());
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    CHECK(false) << string_value;
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *enum_value = iter->second;
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
1137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void ParseEnum(const base::DictionaryValue* value,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               const std::string& property,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               T* enum_value,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               const std::map<std::string, T>& mapping) {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string string_value;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!value->GetString(property, &string_value))
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ParseEnum(string_value, enum_value, mapping);
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<typename T>
1257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void ParseEnumSet(const base::DictionaryValue* value,
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  const std::string& property,
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  std::set<T>* enum_set,
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  const std::map<std::string, T>& mapping) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!value->HasKey(property))
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enum_set->clear();
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string property_string;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (value->GetString(property, &property_string)) {
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (property_string == "all") {
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (typename std::map<std::string, T>::const_iterator j =
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               mapping.begin(); j != mapping.end(); ++j) {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        enum_set->insert(j->second);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<std::string> string_set;
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ParseSet(value, property, &string_set);
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::set<std::string>::iterator iter = string_set.begin();
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != string_set.end(); ++iter) {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    T enum_value = static_cast<T>(0);
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ParseEnum(*iter, &enum_value, mapping);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    enum_set->insert(enum_value);
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void ParseURLPatterns(const base::DictionaryValue* value,
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      const std::string& key,
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      URLPatternSet* set) {
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::ListValue* matches = NULL;
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (value->GetList(key, &matches)) {
1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    set->ClearPatterns();
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < matches->GetSize(); ++i) {
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string pattern;
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CHECK(matches->GetString(i, &pattern));
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      set->AddPattern(URLPattern(URLPattern::SCHEME_ALL, pattern));
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Gets a human-readable name for the given extension type, suitable for giving
1708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// to developers in an error message.
1718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)std::string GetDisplayName(Manifest::Type type) {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (type) {
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Manifest::TYPE_UNKNOWN:
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "unknown";
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Manifest::TYPE_EXTENSION:
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "extension";
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Manifest::TYPE_HOSTED_APP:
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "hosted app";
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Manifest::TYPE_LEGACY_PACKAGED_APP:
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "legacy packaged app";
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Manifest::TYPE_PLATFORM_APP:
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "packaged app";
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Manifest::TYPE_THEME:
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "theme";
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case Manifest::TYPE_USER_SCRIPT:
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "user script";
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case Manifest::TYPE_SHARED_MODULE:
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return "shared module";
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case Manifest::NUM_LOAD_TYPES:
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      NOTREACHED();
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  NOTREACHED();
1938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return "";
1948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Gets a human-readable name for the given context type, suitable for giving
1978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// to developers in an error message.
1988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)std::string GetDisplayName(Feature::Context context) {
1998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  switch (context) {
2008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    case Feature::UNSPECIFIED_CONTEXT:
2018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return "unknown";
2028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    case Feature::BLESSED_EXTENSION_CONTEXT:
2038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      // "privileged" is vague but hopefully the developer will understand that
2048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      // means background or app window.
2058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return "privileged page";
2068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    case Feature::UNBLESSED_EXTENSION_CONTEXT:
2078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      // "iframe" is a bit of a lie/oversimplification, but that's the most
2088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      // common unblessed context.
2098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return "extension iframe";
2108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    case Feature::CONTENT_SCRIPT_CONTEXT:
2118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return "content script";
2128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    case Feature::WEB_PAGE_CONTEXT:
2138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return "web page";
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case Feature::BLESSED_WEB_PAGE_CONTEXT:
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return "hosted app";
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case Feature::WEBUI_CONTEXT:
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return "webui";
2188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED();
2208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return "";
2218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Gets a human-readable list of the display names (pluralized, comma separated
2248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// with the "and" in the correct place) for each of |enum_types|.
2258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)template <typename EnumType>
2268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)std::string ListDisplayNames(const std::vector<EnumType> enum_types) {
2278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::string display_name_list;
2288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  for (size_t i = 0; i < enum_types.size(); ++i) {
2298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // Pluralize type name.
2308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    display_name_list += GetDisplayName(enum_types[i]) + "s";
2318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // Comma-separate entries, with an Oxford comma if there is more than 2
2328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    // total entries.
2338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (enum_types.size() > 2) {
2348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      if (i < enum_types.size() - 2)
2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        display_name_list += ", ";
2368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      else if (i == enum_types.size() - 2)
2378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        display_name_list += ", and ";
2388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    } else if (enum_types.size() == 2 && i == 0) {
2398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      display_name_list += " and ";
2408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
2418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
2428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return display_name_list;
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string HashExtensionId(const std::string& extension_id) {
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const std::string id_hash = base::SHA1HashString(extension_id);
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(id_hash.length() == base::kSHA1Length);
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::HexEncode(id_hash.c_str(), id_hash.length());
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SimpleFeature::SimpleFeature()
254e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    : location_(UNSPECIFIED_LOCATION),
255e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      min_manifest_version_(0),
256e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      max_manifest_version_(0),
257010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      has_parent_(false),
258010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      component_extensions_auto_granted_(true) {}
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
260e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochSimpleFeature::~SimpleFeature() {}
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SimpleFeature::HasDependencies() {
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return !dependencies_.empty();
264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
266e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) {
267e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  filters_.push_back(make_linked_ptr(filter.release()));
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)std::string SimpleFeature::Parse(const base::DictionaryValue* value) {
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ParseURLPatterns(value, "matches", &matches_);
272010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ParseSet(value, "blacklist", &blacklist_);
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ParseSet(value, "whitelist", &whitelist_);
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ParseSet(value, "dependencies", &dependencies_);
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ParseEnumSet<Manifest::Type>(value, "extension_types", &extension_types_,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                g_mappings.Get().extension_types);
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ParseEnumSet<Context>(value, "contexts", &contexts_,
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        g_mappings.Get().contexts);
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ParseEnum<Location>(value, "location", &location_,
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      g_mappings.Get().locations);
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ParseEnumSet<Platform>(value, "platforms", &platforms_,
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                         g_mappings.Get().platforms);
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  value->GetInteger("min_manifest_version", &min_manifest_version_);
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  value->GetInteger("max_manifest_version", &max_manifest_version_);
2857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  no_parent_ = false;
2877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  value->GetBoolean("noparent", &no_parent_);
2887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
289010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  component_extensions_auto_granted_ = true;
290010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  value->GetBoolean("component_extensions_auto_granted",
291010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    &component_extensions_auto_granted_);
292010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // NOTE: ideally we'd sanity check that "matches" can be specified if and
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // only if there's a "web_page" or "webui" context, but without
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // (Simple)Features being aware of their own heirarchy this is impossible.
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  //
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // For example, we might have feature "foo" available to "web_page" context
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // and "matches" google.com/*. Then a sub-feature "foo.bar" might override
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // "matches" to be chromium.org/*. That sub-feature doesn't need to specify
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // "web_page" context because it's inherited, but we don't know that here.
3017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
302e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (FilterList::iterator filter_iter = filters_.begin();
303e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       filter_iter != filters_.end();
304e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       ++filter_iter) {
305e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    std::string result = (*filter_iter)->Parse(value);
306e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (!result.empty()) {
307e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return result;
308e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
309e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
310e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::string();
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Feature::Availability SimpleFeature::IsAvailableToManifest(
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& extension_id,
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Manifest::Type type,
3170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    Manifest::Location location,
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int manifest_version,
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Platform platform) const {
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Check extension type first to avoid granting platform app permissions
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // to component extensions.
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // HACK(kalman): user script -> extension. Solve this in a more generic way
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // when we compile feature files.
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ?
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Manifest::TYPE_EXTENSION : type;
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!extension_types_.empty() &&
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extension_types_.find(type_to_check) == extension_types_.end()) {
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CreateAvailability(INVALID_TYPE, type);
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
331010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (IsIdInBlacklist(extension_id))
332010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return CreateAvailability(FOUND_IN_BLACKLIST, type);
333010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
334010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // TODO(benwells): don't grant all component extensions.
335010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // See http://crbug.com/370375 for more details.
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Component extensions can access any feature.
337010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // NOTE: Deliberately does not match EXTERNAL_COMPONENT.
338010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (component_extensions_auto_granted_ && location == Manifest::COMPONENT)
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return CreateAvailability(IS_AVAILABLE, type);
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!whitelist_.empty()) {
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!IsIdInWhitelist(extension_id)) {
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(aa): This is gross. There should be a better way to test the
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // whitelist.
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CommandLine* command_line = CommandLine::ForCurrentProcess();
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!command_line->HasSwitch(switches::kWhitelistedExtensionID))
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return CreateAvailability(NOT_FOUND_IN_WHITELIST, type);
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string whitelist_switch_value =
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              switches::kWhitelistedExtensionID);
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extension_id != whitelist_switch_value)
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return CreateAvailability(NOT_FOUND_IN_WHITELIST, type);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!MatchesManifestLocation(location))
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return CreateAvailability(INVALID_LOCATION, type);
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!platforms_.empty() &&
3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      platforms_.find(platform) == platforms_.end())
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return CreateAvailability(INVALID_PLATFORM, type);
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_)
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return CreateAvailability(INVALID_MIN_MANIFEST_VERSION, type);
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (max_manifest_version_ != 0 && manifest_version > max_manifest_version_)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return CreateAvailability(INVALID_MAX_MANIFEST_VERSION, type);
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
370e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (FilterList::const_iterator filter_iter = filters_.begin();
371e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       filter_iter != filters_.end();
372e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       ++filter_iter) {
373e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    Availability availability = (*filter_iter)->IsAvailableToManifest(
374e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        extension_id, type, location, manifest_version, platform);
375e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (!availability.is_available())
376e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return availability;
377e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return CheckDependencies(base::Bind(&IsAvailableToManifestForBind,
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      extension_id,
381116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      type,
382116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      location,
383116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      manifest_version,
384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      platform));
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Feature::Availability SimpleFeature::IsAvailableToContext(
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Extension* extension,
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SimpleFeature::Context context,
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& url,
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SimpleFeature::Platform platform) const {
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (extension) {
3930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    Availability result = IsAvailableToManifest(extension->id(),
3940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                extension->GetType(),
3950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                extension->location(),
3960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                extension->manifest_version(),
3970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                platform);
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!result.is_available())
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return result;
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!contexts_.empty() && contexts_.find(context) == contexts_.end())
4038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return CreateAvailability(INVALID_CONTEXT, context);
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(kalman): Consider checking |matches_| regardless of context type.
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Fewer surprises, and if the feature configuration wants to isolate
4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // "matches" from say "blessed_extension" then they can use complex features.
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if ((context == WEB_PAGE_CONTEXT || context == WEBUI_CONTEXT) &&
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      !matches_.MatchesURL(url)) {
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return CreateAvailability(INVALID_URL, url);
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
413e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (FilterList::const_iterator filter_iter = filters_.begin();
414e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       filter_iter != filters_.end();
415e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       ++filter_iter) {
416e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    Availability availability =
417e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        (*filter_iter)->IsAvailableToContext(extension, context, url, platform);
418e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (!availability.is_available())
419e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return availability;
420e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
421e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(kalman): Assert that if the context was a webpage or WebUI context
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // then at some point a "matches" restriction was checked.
424116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return CheckDependencies(base::Bind(
425116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &IsAvailableToContextForBind, extension, context, url, platform));
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string SimpleFeature::GetAvailabilityMessage(
4298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    AvailabilityResult result,
4308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    Manifest::Type type,
4318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const GURL& url,
4328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    Context context) const {
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (result) {
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case IS_AVAILABLE:
435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return std::string();
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOT_FOUND_IN_WHITELIST:
437010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case FOUND_IN_BLACKLIST:
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf(
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "'%s' is not allowed for specified extension ID.",
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          name().c_str());
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case INVALID_URL:
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf("'%s' is not allowed on %s.",
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                name().c_str(), url.spec().c_str());
4448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    case INVALID_TYPE:
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf(
4468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          "'%s' is only allowed for %s, but this is a %s.",
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          name().c_str(),
4488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          ListDisplayNames(std::vector<Manifest::Type>(
4498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)              extension_types_.begin(), extension_types_.end())).c_str(),
4508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          GetDisplayName(type).c_str());
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case INVALID_CONTEXT:
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf(
4538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          "'%s' is only allowed to run in %s, but this is a %s",
4548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          name().c_str(),
4558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          ListDisplayNames(std::vector<Context>(
4568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)              contexts_.begin(), contexts_.end())).c_str(),
4578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          GetDisplayName(context).c_str());
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case INVALID_LOCATION:
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf(
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "'%s' is not allowed for specified install location.",
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          name().c_str());
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case INVALID_PLATFORM:
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf(
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "'%s' is not allowed for specified platform.",
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          name().c_str());
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case INVALID_MIN_MANIFEST_VERSION:
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf(
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "'%s' requires manifest version of at least %d.",
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          name().c_str(),
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          min_manifest_version_);
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case INVALID_MAX_MANIFEST_VERSION:
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf(
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "'%s' requires manifest version of %d or lower.",
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          name().c_str(),
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          max_manifest_version_);
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOT_PRESENT:
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf(
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "'%s' requires a different Feature that is not present.",
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          name().c_str());
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case UNSUPPORTED_CHANNEL:
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return base::StringPrintf(
482e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          "'%s' is unsupported in this version of the platform.",
483e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          name().c_str());
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED();
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::string();
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Feature::Availability SimpleFeature::CreateAvailability(
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AvailabilityResult result) const {
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Availability(
4938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(),
4948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                     UNSPECIFIED_CONTEXT));
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Feature::Availability SimpleFeature::CreateAvailability(
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AvailabilityResult result, Manifest::Type type) const {
4998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return Availability(result, GetAvailabilityMessage(result, type, GURL(),
5008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                                     UNSPECIFIED_CONTEXT));
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Feature::Availability SimpleFeature::CreateAvailability(
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AvailabilityResult result,
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& url) const {
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Availability(
5078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, url,
5088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                     UNSPECIFIED_CONTEXT));
5098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
5108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)Feature::Availability SimpleFeature::CreateAvailability(
5128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    AvailabilityResult result,
5138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    Context context) const {
5148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return Availability(
5158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(),
5168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                     context));
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool SimpleFeature::IsInternal() const {
520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
523010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool SimpleFeature::IsIdInBlacklist(const std::string& extension_id) const {
524010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return IsIdInList(extension_id, blacklist_);
525010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
526010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const {
528010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return IsIdInList(extension_id, whitelist_);
529d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
530d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
531d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// static
532010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool SimpleFeature::IsIdInList(const std::string& extension_id,
533010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                               const std::set<std::string>& list) {
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Belt-and-suspenders philosophy here. We should be pretty confident by this
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // point that we've validated the extension ID format, but in case something
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // slips through, we avoid a class of attack where creative ID manipulation
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // leads to hash collisions.
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (extension_id.length() != 32)  // 128 bits / 4 = 32 mpdecimal characters
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
541010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (list.find(extension_id) != list.end() ||
542010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      list.find(HashExtensionId(extension_id)) != list.end()) {
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
544d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool SimpleFeature::MatchesManifestLocation(
5500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    Manifest::Location manifest_location) const {
5510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  switch (location_) {
5520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case SimpleFeature::UNSPECIFIED_LOCATION:
5530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return true;
5540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case SimpleFeature::COMPONENT_LOCATION:
5550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // TODO(kalman/asargent): Should this include EXTERNAL_COMPONENT too?
5560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return manifest_location == Manifest::COMPONENT;
5570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case SimpleFeature::POLICY_LOCATION:
5580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return manifest_location == Manifest::EXTERNAL_POLICY ||
5590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch             manifest_location == Manifest::EXTERNAL_POLICY_DOWNLOAD;
5600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
5610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  NOTREACHED();
5620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return false;
5630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
5640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
565116680a4aac90f2aa7413d9095a592090648e557Ben MurdochFeature::Availability SimpleFeature::CheckDependencies(
566116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::Callback<Availability(const Feature*)>& checker) const {
567116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (std::set<std::string>::const_iterator it = dependencies_.begin();
568116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       it != dependencies_.end();
569116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++it) {
570116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Feature* dependency =
571116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        ExtensionAPI::GetSharedInstance()->GetFeatureDependency(*it);
572116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!dependency)
573116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return CreateAvailability(NOT_PRESENT);
574116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Availability dependency_availability = checker.Run(dependency);
575116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!dependency_availability.is_available())
576116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return dependency_availability;
577116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
578116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return CreateAvailability(IS_AVAILABLE);
579116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
580116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
582