Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
|
Aaron Boodman
2011/12/01 21:32:04
This class turned out really tight and clean. Nice
jstritar
2011/12/02 16:26:33
Nice, thanks!
| |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/common/extensions/manifest.h" | |
| 6 | |
| 7 #include "base/basictypes.h" | |
| 8 #include "base/lazy_instance.h" | |
| 9 #include "base/logging.h" | |
| 10 #include "base/string_split.h" | |
| 11 #include "base/values.h" | |
| 12 #include "chrome/common/extensions/extension_constants.h" | |
| 13 #include "chrome/common/extensions/extension_error_utils.h" | |
| 14 | |
| 15 namespace errors = extension_manifest_errors; | |
| 16 namespace keys = extension_manifest_keys; | |
| 17 | |
| 18 namespace extensions { | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 typedef std::map<std::string, int> RestrictionMap; | |
| 23 | |
| 24 struct Restrictions { | |
| 25 Restrictions() { | |
| 26 // Base keys that all manifests can specify. | |
| 27 map[keys::kName] = Manifest::kTypeAll; | |
| 28 map[keys::kVersion] = Manifest::kTypeAll; | |
| 29 map[keys::kManifestVersion] = Manifest::kTypeAll; | |
| 30 map[keys::kDescription] = Manifest::kTypeAll; | |
| 31 map[keys::kIcons] = Manifest::kTypeAll; | |
| 32 map[keys::kCurrentLocale] = Manifest::kTypeAll; | |
| 33 map[keys::kDefaultLocale] = Manifest::kTypeAll; | |
| 34 map[keys::kSignature] = Manifest::kTypeAll; | |
| 35 map[keys::kUpdateURL] = Manifest::kTypeAll; | |
| 36 map[keys::kPublicKey] = Manifest::kTypeAll; | |
| 37 | |
| 38 // Type specific. | |
| 39 map[keys::kApp] = Manifest::kTypeHostedApp | Manifest::kTypePackagedApp | | |
| 40 Manifest::kTypePlatformApp; | |
| 41 map[keys::kTheme] = Manifest::kTypeTheme; | |
| 42 map[keys::kPlatformApp] = Manifest::kTypePlatformApp; | |
| 43 | |
| 44 // Extensions only. | |
| 45 map[keys::kBrowserAction] = Manifest::kTypeExtension; | |
| 46 map[keys::kPageAction] = Manifest::kTypeExtension; | |
| 47 map[keys::kPageActions] = Manifest::kTypeExtension; | |
| 48 map[keys::kChromeURLOverrides] = Manifest::kTypeExtension; | |
| 49 | |
| 50 // Everything except themes. | |
| 51 int all_but_themes = Manifest::kTypeAll - Manifest::kTypeTheme; | |
| 52 map[keys::kPermissions] = all_but_themes; | |
| 53 map[keys::kOptionalPermissions] = all_but_themes; | |
| 54 map[keys::kOptionsPage] = all_but_themes; | |
| 55 map[keys::kBackground] = all_but_themes; | |
| 56 map[keys::kOfflineEnabled] = all_but_themes; | |
| 57 map[keys::kMinimumChromeVersion] = all_but_themes; | |
| 58 map[keys::kRequirements] = all_but_themes; | |
| 59 map[keys::kConvertedFromUserScript] = all_but_themes; | |
| 60 map[keys::kNaClModules] = all_but_themes; | |
| 61 map[keys::kPlugins] = all_but_themes; | |
| 62 | |
| 63 // Extensions and packaged apps. | |
| 64 int ext_and_packaged = | |
| 65 Manifest::kTypeExtension | Manifest::kTypePackagedApp; | |
| 66 map[keys::kContentScripts] = ext_and_packaged; | |
| 67 map[keys::kOmnibox] = ext_and_packaged; | |
| 68 map[keys::kDevToolsPage] = ext_and_packaged; | |
| 69 map[keys::kSidebar] = ext_and_packaged; | |
| 70 map[keys::kHomepageURL] = ext_and_packaged; | |
| 71 | |
| 72 // Extensions, packaged apps and platform apps. | |
| 73 int local_apps_and_ext = ext_and_packaged | Manifest::kTypePlatformApp; | |
| 74 map[keys::kContentSecurityPolicy] = local_apps_and_ext; | |
| 75 map[keys::kFileBrowserHandlers] = local_apps_and_ext; | |
| 76 map[keys::kIncognito] = local_apps_and_ext; | |
| 77 map[keys::kInputComponents] = local_apps_and_ext; | |
| 78 map[keys::kTtsEngine] = local_apps_and_ext; | |
| 79 map[keys::kIntents] = local_apps_and_ext; | |
| 80 } | |
| 81 | |
| 82 // Returns true if the |key| is recognized. | |
| 83 bool IsKnownKey(const std::string& key) const { | |
| 84 RestrictionMap::const_iterator i = map.find(key); | |
| 85 return i != map.end(); | |
| 86 } | |
| 87 | |
| 88 // Returns true if the given |key| can be specified by the manifest |type|. | |
| 89 bool CanAccessKey(const std::string& key, Manifest::Type type) const { | |
| 90 RestrictionMap::const_iterator i = map.find(key); | |
| 91 return (i != map.end() && (type & i->second) != 0); | |
| 92 } | |
| 93 | |
| 94 RestrictionMap map; | |
| 95 }; | |
| 96 | |
| 97 base::LazyInstance<Restrictions> g_restrictions; | |
| 98 | |
| 99 } // namespace | |
| 100 | |
| 101 // static | |
| 102 std::set<std::string> Manifest::GetAllKnownKeys() { | |
| 103 std::set<std::string> keys; | |
| 104 const RestrictionMap& map = g_restrictions.Get().map; | |
| 105 for (RestrictionMap::const_iterator i = map.begin(); i != map.end(); i++) | |
| 106 keys.insert(i->first); | |
| 107 return keys; | |
| 108 } | |
| 109 | |
| 110 Manifest::Manifest(DictionaryValue* value) : value_(value) {} | |
| 111 Manifest::~Manifest() {} | |
| 112 | |
| 113 bool Manifest::ValidateManifest(std::string* error) const { | |
| 114 Restrictions restrictions = g_restrictions.Get(); | |
| 115 Type type = GetType(); | |
| 116 | |
| 117 for (DictionaryValue::key_iterator key = value_->begin_keys(); | |
| 118 key != value_->end_keys(); ++key) { | |
| 119 // When validating the extension manifests, we ignore keys that are not | |
| 120 // recognized for forward compatibility. | |
| 121 if (!restrictions.IsKnownKey(*key)) { | |
| 122 // TODO(aa): Consider having an error here in the case of strict error | |
| 123 // checking to let developers know when they screw up. | |
| 124 continue; | |
| 125 } | |
| 126 | |
| 127 if (!restrictions.CanAccessKey(*key, type)) { | |
| 128 *error = ExtensionErrorUtils::FormatErrorMessage( | |
| 129 errors::kFeatureNotAllowed, *key); | |
| 130 return false; | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 return true; | |
| 135 } | |
| 136 | |
| 137 bool Manifest::HasKey(const std::string& key) const { | |
| 138 Restrictions restrictions = g_restrictions.Get(); | |
| 139 return restrictions.CanAccessKey(key, GetType()) && value_->HasKey(key); | |
| 140 } | |
| 141 | |
| 142 bool Manifest::Get( | |
| 143 const std::string& path, Value** out_value) const { | |
| 144 return CanAccessPath(path) && value_->Get(path, out_value); | |
| 145 } | |
| 146 | |
| 147 bool Manifest::GetBoolean( | |
| 148 const std::string& path, bool* out_value) const { | |
| 149 return CanAccessPath(path) && value_->GetBoolean(path, out_value); | |
| 150 } | |
| 151 | |
| 152 bool Manifest::GetInteger( | |
| 153 const std::string& path, int* out_value) const { | |
| 154 return CanAccessPath(path) && value_->GetInteger(path, out_value); | |
| 155 } | |
| 156 | |
| 157 bool Manifest::GetString( | |
| 158 const std::string& path, std::string* out_value) const { | |
| 159 return CanAccessPath(path) && value_->GetString(path, out_value); | |
| 160 } | |
| 161 | |
| 162 bool Manifest::GetString( | |
| 163 const std::string& path, string16* out_value) const { | |
| 164 return CanAccessPath(path) && value_->GetString(path, out_value); | |
| 165 } | |
| 166 | |
| 167 bool Manifest::GetDictionary( | |
| 168 const std::string& path, DictionaryValue** out_value) const { | |
| 169 return CanAccessPath(path) && value_->GetDictionary(path, out_value); | |
| 170 } | |
| 171 | |
| 172 bool Manifest::GetList( | |
| 173 const std::string& path, ListValue** out_value) const { | |
| 174 return CanAccessPath(path) && value_->GetList(path, out_value); | |
| 175 } | |
| 176 | |
| 177 Manifest* Manifest::DeepCopy() const { | |
| 178 return new Manifest(value_->DeepCopy()); | |
| 179 } | |
| 180 | |
| 181 bool Manifest::Equals(const Manifest* other) const { | |
| 182 return other && value_->Equals(other->value()); | |
| 183 } | |
| 184 | |
| 185 Manifest::Type Manifest::GetType() const { | |
| 186 if (value_->HasKey(keys::kTheme) && value_->GetDictionary(keys::kTheme, NULL)) | |
|
Aaron Boodman
2011/12/01 21:32:04
Why do you test that the value is a dictionary for
jstritar
2011/12/02 16:26:33
I did that to be consistent with the previous beha
| |
| 187 return kTypeTheme; | |
| 188 if (value_->HasKey(keys::kPlatformApp)) | |
| 189 return kTypePlatformApp; | |
| 190 if (value_->HasKey(keys::kApp)) { | |
| 191 if (value_->Get(keys::kWebURLs, NULL) || | |
| 192 value_->Get(keys::kLaunchWebURL, NULL)) | |
| 193 return kTypeHostedApp; | |
| 194 else | |
| 195 return kTypePackagedApp; | |
| 196 } else { | |
| 197 return kTypeExtension; | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 bool Manifest::IsTheme() const { | |
| 202 return GetType() == kTypeTheme; | |
| 203 } | |
| 204 | |
| 205 bool Manifest::IsPlatformApp() const { | |
| 206 return GetType() == kTypePlatformApp; | |
| 207 } | |
| 208 | |
| 209 bool Manifest::IsPackagedApp() const { | |
| 210 return GetType() == kTypePackagedApp; | |
| 211 } | |
| 212 | |
| 213 bool Manifest::IsHostedApp() const { | |
| 214 return GetType() == kTypeHostedApp; | |
| 215 } | |
| 216 | |
| 217 bool Manifest::CanAccessPath(const std::string& path) const { | |
| 218 std::vector<std::string> components; | |
| 219 base::SplitString(path, '.', &components); | |
| 220 | |
| 221 Restrictions restrictions = g_restrictions.Get(); | |
| 222 return restrictions.CanAccessKey(components[0], GetType()); | |
| 223 } | |
| 224 | |
| 225 } // namespace extensions | |
| OLD | NEW |