Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: extensions/common/features/simple_feature.cc

Issue 241673002: Support a "policy" extension location in extension features files. At the same (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: format Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/common/features/simple_feature.h" 5 #include "extensions/common/features/simple_feature.h"
6 6
7 #include <map> 7 #include <map>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/lazy_instance.h" 11 #include "base/lazy_instance.h"
12 #include "base/sha1.h" 12 #include "base/sha1.h"
13 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
16 #include "extensions/common/switches.h" 16 #include "extensions/common/switches.h"
17 17
18 namespace extensions { 18 namespace extensions {
19 19
20 namespace { 20 namespace {
21 21
22 struct Mappings { 22 struct Mappings {
23 Mappings() { 23 Mappings() {
24 extension_types["extension"] = Manifest::TYPE_EXTENSION; 24 extension_types["extension"].push_back(Manifest::TYPE_EXTENSION);
not at google - send to devlin 2014/04/17 21:33:14 I'm not... super happy about these changes.
Yoyo Zhou 2014/04/17 21:53:12 Can you replace Manifest::Location with something
not at google - send to devlin 2014/04/17 21:59:31 I found the old way of doing that a bit awkward; e
Yoyo Zhou 2014/04/17 22:00:30 You don't have to expose it. Just pass in the Mani
25 extension_types["theme"] = Manifest::TYPE_THEME; 25 extension_types["theme"].push_back(Manifest::TYPE_THEME);
26 extension_types["legacy_packaged_app"] = Manifest::TYPE_LEGACY_PACKAGED_APP; 26 extension_types["legacy_packaged_app"].push_back(
27 extension_types["hosted_app"] = Manifest::TYPE_HOSTED_APP; 27 Manifest::TYPE_LEGACY_PACKAGED_APP);
28 extension_types["platform_app"] = Manifest::TYPE_PLATFORM_APP; 28 extension_types["hosted_app"].push_back(Manifest::TYPE_HOSTED_APP);
29 extension_types["shared_module"] = Manifest::TYPE_SHARED_MODULE; 29 extension_types["platform_app"].push_back(Manifest::TYPE_PLATFORM_APP);
30 extension_types["shared_module"].push_back(Manifest::TYPE_SHARED_MODULE);
30 31
31 contexts["blessed_extension"] = Feature::BLESSED_EXTENSION_CONTEXT; 32 contexts["blessed_extension"].push_back(Feature::BLESSED_EXTENSION_CONTEXT);
32 contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT; 33 contexts["unblessed_extension"].push_back(
33 contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT; 34 Feature::UNBLESSED_EXTENSION_CONTEXT);
34 contexts["web_page"] = Feature::WEB_PAGE_CONTEXT; 35 contexts["content_script"].push_back(Feature::CONTENT_SCRIPT_CONTEXT);
35 contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT; 36 contexts["web_page"].push_back(Feature::WEB_PAGE_CONTEXT);
37 contexts["blessed_web_page"].push_back(Feature::BLESSED_WEB_PAGE_CONTEXT);
36 38
37 locations["component"] = Feature::COMPONENT_LOCATION; 39 locations["component"].push_back(Manifest::COMPONENT);
40 locations["component"].push_back(Manifest::EXTERNAL_COMPONENT);
41 locations["policy"].push_back(Manifest::EXTERNAL_POLICY_DOWNLOAD);
42 locations["policy"].push_back(Manifest::EXTERNAL_POLICY);
38 43
39 platforms["chromeos"] = Feature::CHROMEOS_PLATFORM; 44 platforms["chromeos"].push_back(Feature::CHROMEOS_PLATFORM);
40 platforms["linux"] = Feature::LINUX_PLATFORM; 45 platforms["linux"].push_back(Feature::LINUX_PLATFORM);
41 platforms["mac"] = Feature::MACOSX_PLATFORM; 46 platforms["mac"].push_back(Feature::MACOSX_PLATFORM);
42 platforms["win"] = Feature::WIN_PLATFORM; 47 platforms["win"].push_back(Feature::WIN_PLATFORM);
43 } 48 }
44 49
45 std::map<std::string, Manifest::Type> extension_types; 50 std::map<std::string, std::vector<Manifest::Type> > extension_types;
46 std::map<std::string, Feature::Context> contexts; 51 std::map<std::string, std::vector<Feature::Context> > contexts;
47 std::map<std::string, Feature::Location> locations; 52 std::map<std::string, std::vector<Manifest::Location> > locations;
48 std::map<std::string, Feature::Platform> platforms; 53 std::map<std::string, std::vector<Feature::Platform> > platforms;
49 }; 54 };
50 55
51 base::LazyInstance<Mappings> g_mappings = LAZY_INSTANCE_INITIALIZER; 56 base::LazyInstance<Mappings> g_mappings = LAZY_INSTANCE_INITIALIZER;
52 57
53 // TODO(aa): Can we replace all this manual parsing with JSON schema stuff? 58 // TODO(aa): Can we replace all this manual parsing with JSON schema stuff?
54 59
55 void ParseSet(const base::DictionaryValue* value, 60 void ParseSet(const base::DictionaryValue* value,
56 const std::string& property, 61 const std::string& property,
57 std::set<std::string>* set) { 62 std::set<std::string>* set) {
58 const base::ListValue* list_value = NULL; 63 const base::ListValue* list_value = NULL;
59 if (!value->GetList(property, &list_value)) 64 if (!value->GetList(property, &list_value))
60 return; 65 return;
61 66
62 set->clear(); 67 set->clear();
63 for (size_t i = 0; i < list_value->GetSize(); ++i) { 68 for (size_t i = 0; i < list_value->GetSize(); ++i) {
64 std::string str_val; 69 std::string str_val;
65 CHECK(list_value->GetString(i, &str_val)) << property << " " << i; 70 CHECK(list_value->GetString(i, &str_val)) << property << " " << i;
66 set->insert(str_val); 71 set->insert(str_val);
67 } 72 }
68 } 73 }
69 74
70 template<typename T> 75 template <typename T>
71 void ParseEnum(const std::string& string_value, 76 void ParseEnumHelper(const std::string& string_value,
72 T* enum_value, 77 const std::map<std::string, std::vector<T> >& mapping,
73 const std::map<std::string, T>& mapping) { 78 std::set<T>* enum_set) {
74 typename std::map<std::string, T>::const_iterator iter = 79 typename std::map<std::string, std::vector<T> >::const_iterator iter =
75 mapping.find(string_value); 80 mapping.find(string_value);
76 CHECK(iter != mapping.end()) << string_value; 81 CHECK(iter != mapping.end()) << string_value;
77 *enum_value = iter->second; 82 enum_set->insert(iter->second.begin(), iter->second.end());
78 } 83 }
79 84
80 template<typename T> 85 template <typename T>
81 void ParseEnum(const base::DictionaryValue* value, 86 void ParseEnum(const std::string& string_value,
82 const std::string& property, 87 const std::map<std::string, std::vector<T> >& mapping,
83 T* enum_value, 88 std::set<T>* enum_set) {
84 const std::map<std::string, T>& mapping) { 89 enum_set->clear();
85 std::string string_value; 90 ParseEnumHelper(string_value, mapping, enum_set);
86 if (!value->GetString(property, &string_value))
87 return;
88
89 ParseEnum(string_value, enum_value, mapping);
90 } 91 }
91 92
92 template<typename T> 93 template <typename T>
93 void ParseEnumSet(const base::DictionaryValue* value, 94 void ParseEnumSet(const base::DictionaryValue* value,
94 const std::string& property, 95 const std::string& property,
95 std::set<T>* enum_set, 96 const std::map<std::string, std::vector<T> >& mapping,
96 const std::map<std::string, T>& mapping) { 97 std::set<T>* enum_set) {
97 if (!value->HasKey(property)) 98 if (!value->HasKey(property))
98 return; 99 return;
99 100
100 enum_set->clear(); 101 enum_set->clear();
101 102
102 std::string property_string; 103 std::string property_string;
103 if (value->GetString(property, &property_string)) { 104 if (value->GetString(property, &property_string)) {
104 if (property_string == "all") { 105 if (property_string == "all") {
105 for (typename std::map<std::string, T>::const_iterator j = 106 for (typename std::map<std::string, std::vector<T> >::const_iterator j =
106 mapping.begin(); j != mapping.end(); ++j) { 107 mapping.begin();
107 enum_set->insert(j->second); 108 j != mapping.end();
109 ++j) {
110 enum_set->insert(j->second.begin(), j->second.end());
108 } 111 }
109 } 112 }
110 return; 113 return;
111 } 114 }
112 115
113 std::set<std::string> string_set; 116 std::set<std::string> string_set;
114 ParseSet(value, property, &string_set); 117 ParseSet(value, property, &string_set);
115 for (std::set<std::string>::iterator iter = string_set.begin(); 118 for (std::set<std::string>::iterator iter = string_set.begin();
116 iter != string_set.end(); ++iter) { 119 iter != string_set.end(); ++iter) {
117 T enum_value = static_cast<T>(0); 120 ParseEnumHelper(*iter, mapping, enum_set);
118 ParseEnum(*iter, &enum_value, mapping);
119 enum_set->insert(enum_value);
120 } 121 }
121 } 122 }
122 123
123 void ParseURLPatterns(const base::DictionaryValue* value, 124 void ParseURLPatterns(const base::DictionaryValue* value,
124 const std::string& key, 125 const std::string& key,
125 URLPatternSet* set) { 126 URLPatternSet* set) {
126 const base::ListValue* matches = NULL; 127 const base::ListValue* matches = NULL;
127 if (value->GetList(key, &matches)) { 128 if (value->GetList(key, &matches)) {
128 set->ClearPatterns(); 129 set->ClearPatterns();
129 for (size_t i = 0; i < matches->GetSize(); ++i) { 130 for (size_t i = 0; i < matches->GetSize(); ++i) {
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 209
209 std::string HashExtensionId(const std::string& extension_id) { 210 std::string HashExtensionId(const std::string& extension_id) {
210 const std::string id_hash = base::SHA1HashString(extension_id); 211 const std::string id_hash = base::SHA1HashString(extension_id);
211 DCHECK(id_hash.length() == base::kSHA1Length); 212 DCHECK(id_hash.length() == base::kSHA1Length);
212 return base::HexEncode(id_hash.c_str(), id_hash.length()); 213 return base::HexEncode(id_hash.c_str(), id_hash.length());
213 } 214 }
214 215
215 } // namespace 216 } // namespace
216 217
217 SimpleFeature::SimpleFeature() 218 SimpleFeature::SimpleFeature()
218 : location_(UNSPECIFIED_LOCATION), 219 : min_manifest_version_(0), max_manifest_version_(0), has_parent_(false) {
219 min_manifest_version_(0), 220 }
220 max_manifest_version_(0),
221 has_parent_(false) {}
222 221
223 SimpleFeature::~SimpleFeature() {} 222 SimpleFeature::~SimpleFeature() {}
224 223
225 void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) { 224 void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) {
226 filters_.push_back(make_linked_ptr(filter.release())); 225 filters_.push_back(make_linked_ptr(filter.release()));
227 } 226 }
228 227
229 std::string SimpleFeature::Parse(const base::DictionaryValue* value) { 228 std::string SimpleFeature::Parse(const base::DictionaryValue* value) {
230 ParseURLPatterns(value, "matches", &matches_); 229 ParseURLPatterns(value, "matches", &matches_);
231 ParseSet(value, "whitelist", &whitelist_); 230 ParseSet(value, "whitelist", &whitelist_);
232 ParseSet(value, "dependencies", &dependencies_); 231 ParseSet(value, "dependencies", &dependencies_);
233 ParseEnumSet<Manifest::Type>(value, "extension_types", &extension_types_, 232 ParseEnumSet<Manifest::Type>(value,
234 g_mappings.Get().extension_types); 233 "extension_types",
235 ParseEnumSet<Context>(value, "contexts", &contexts_, 234 g_mappings.Get().extension_types,
236 g_mappings.Get().contexts); 235 &extension_types_);
237 ParseEnum<Location>(value, "location", &location_, 236 // Only a single value is supported for "location", but it expands to
238 g_mappings.Get().locations); 237 // multiple possible values.
239 ParseEnumSet<Platform>(value, "platforms", &platforms_, 238 std::string location;
240 g_mappings.Get().platforms); 239 if (value->GetStringWithoutPathExpansion("location", &location)) {
240 ParseEnum<Manifest::Location>(
241 location, g_mappings.Get().locations, &locations_);
242 }
243 ParseEnumSet<Context>(
244 value, "contexts", g_mappings.Get().contexts, &contexts_);
245 ParseEnumSet<Platform>(
246 value, "platforms", g_mappings.Get().platforms, &platforms_);
241 value->GetInteger("min_manifest_version", &min_manifest_version_); 247 value->GetInteger("min_manifest_version", &min_manifest_version_);
242 value->GetInteger("max_manifest_version", &max_manifest_version_); 248 value->GetInteger("max_manifest_version", &max_manifest_version_);
243 249
244 no_parent_ = false; 250 no_parent_ = false;
245 value->GetBoolean("noparent", &no_parent_); 251 value->GetBoolean("noparent", &no_parent_);
246 252
247 if (matches_.is_empty() && contexts_.count(WEB_PAGE_CONTEXT) != 0) { 253 if (matches_.is_empty() && contexts_.count(WEB_PAGE_CONTEXT) != 0) {
248 return name() + ": Allowing web_page contexts requires supplying a value " + 254 return name() + ": Allowing web_page contexts requires supplying a value " +
249 "for matches."; 255 "for matches.";
250 } 256 }
251 257
252 for (FilterList::iterator filter_iter = filters_.begin(); 258 for (FilterList::iterator filter_iter = filters_.begin();
253 filter_iter != filters_.end(); 259 filter_iter != filters_.end();
254 ++filter_iter) { 260 ++filter_iter) {
255 std::string result = (*filter_iter)->Parse(value); 261 std::string result = (*filter_iter)->Parse(value);
256 if (!result.empty()) { 262 if (!result.empty()) {
257 return result; 263 return result;
258 } 264 }
259 } 265 }
260 266
261 return std::string(); 267 return std::string();
262 } 268 }
263 269
264 Feature::Availability SimpleFeature::IsAvailableToManifest( 270 Feature::Availability SimpleFeature::IsAvailableToManifest(
265 const std::string& extension_id, 271 const std::string& extension_id,
266 Manifest::Type type, 272 Manifest::Type type,
267 Location location, 273 Manifest::Location location,
268 int manifest_version, 274 int manifest_version,
269 Platform platform) const { 275 Platform platform) const {
270 // Check extension type first to avoid granting platform app permissions
271 // to component extensions.
272 // HACK(kalman): user script -> extension. Solve this in a more generic way
273 // when we compile feature files.
274 Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ?
275 Manifest::TYPE_EXTENSION : type;
276 if (!extension_types_.empty() && 276 if (!extension_types_.empty() &&
277 extension_types_.find(type_to_check) == extension_types_.end()) { 277 extension_types_.find(type) == extension_types_.end()) {
278 return CreateAvailability(INVALID_TYPE, type); 278 return CreateAvailability(INVALID_TYPE, type);
279 } 279 }
280 280
281 // Component extensions can access any feature. 281 // Component extensions can access any feature.
282 if (location == COMPONENT_LOCATION) 282 if (location == Manifest::COMPONENT ||
283 location == Manifest::EXTERNAL_COMPONENT) {
283 return CreateAvailability(IS_AVAILABLE, type); 284 return CreateAvailability(IS_AVAILABLE, type);
285 }
284 286
285 if (!whitelist_.empty()) { 287 if (!whitelist_.empty()) {
286 if (!IsIdInWhitelist(extension_id)) { 288 if (!IsIdInWhitelist(extension_id)) {
287 // TODO(aa): This is gross. There should be a better way to test the 289 // TODO(aa): This is gross. There should be a better way to test the
288 // whitelist. 290 // whitelist.
289 CommandLine* command_line = CommandLine::ForCurrentProcess(); 291 CommandLine* command_line = CommandLine::ForCurrentProcess();
290 if (!command_line->HasSwitch(switches::kWhitelistedExtensionID)) 292 if (!command_line->HasSwitch(switches::kWhitelistedExtensionID))
291 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); 293 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type);
292 294
293 std::string whitelist_switch_value = 295 std::string whitelist_switch_value =
294 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 296 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
295 switches::kWhitelistedExtensionID); 297 switches::kWhitelistedExtensionID);
296 if (extension_id != whitelist_switch_value) 298 if (extension_id != whitelist_switch_value)
297 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); 299 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type);
298 } 300 }
299 } 301 }
300 302
301 if (location_ != UNSPECIFIED_LOCATION && location_ != location) 303 if (!locations_.empty() && locations_.find(location) == locations_.end())
Yoyo Zhou 2014/04/17 21:53:12 Change this test to be something like location_cla
not at google - send to devlin 2014/04/17 23:18:11 done sort of. I went back to how the code was befo
302 return CreateAvailability(INVALID_LOCATION, type); 304 return CreateAvailability(INVALID_LOCATION, type);
303 305
304 if (!platforms_.empty() && 306 if (!platforms_.empty() &&
305 platforms_.find(platform) == platforms_.end()) 307 platforms_.find(platform) == platforms_.end())
306 return CreateAvailability(INVALID_PLATFORM, type); 308 return CreateAvailability(INVALID_PLATFORM, type);
307 309
308 if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_) 310 if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_)
309 return CreateAvailability(INVALID_MIN_MANIFEST_VERSION, type); 311 return CreateAvailability(INVALID_MIN_MANIFEST_VERSION, type);
310 312
311 if (max_manifest_version_ != 0 && manifest_version > max_manifest_version_) 313 if (max_manifest_version_ != 0 && manifest_version > max_manifest_version_)
(...skipping 10 matching lines...) Expand all
322 324
323 return CreateAvailability(IS_AVAILABLE, type); 325 return CreateAvailability(IS_AVAILABLE, type);
324 } 326 }
325 327
326 Feature::Availability SimpleFeature::IsAvailableToContext( 328 Feature::Availability SimpleFeature::IsAvailableToContext(
327 const Extension* extension, 329 const Extension* extension,
328 SimpleFeature::Context context, 330 SimpleFeature::Context context,
329 const GURL& url, 331 const GURL& url,
330 SimpleFeature::Platform platform) const { 332 SimpleFeature::Platform platform) const {
331 if (extension) { 333 if (extension) {
332 Availability result = IsAvailableToManifest( 334 Availability result = IsAvailableToManifest(extension->id(),
333 extension->id(), 335 extension->GetType(),
334 extension->GetType(), 336 extension->location(),
335 ConvertLocation(extension->location()), 337 extension->manifest_version(),
336 extension->manifest_version(), 338 platform);
337 platform);
338 if (!result.is_available()) 339 if (!result.is_available())
339 return result; 340 return result;
340 } 341 }
341 342
342 if (!contexts_.empty() && contexts_.find(context) == contexts_.end()) 343 if (!contexts_.empty() && contexts_.find(context) == contexts_.end())
343 return CreateAvailability(INVALID_CONTEXT, context); 344 return CreateAvailability(INVALID_CONTEXT, context);
344 345
345 if (!matches_.is_empty() && !matches_.MatchesURL(url)) 346 if (!matches_.is_empty() && !matches_.MatchesURL(url))
346 return CreateAvailability(INVALID_URL, url); 347 return CreateAvailability(INVALID_URL, url);
347 348
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 474
474 if (whitelist.find(extension_id) != whitelist.end() || 475 if (whitelist.find(extension_id) != whitelist.end() ||
475 whitelist.find(HashExtensionId(extension_id)) != whitelist.end()) { 476 whitelist.find(HashExtensionId(extension_id)) != whitelist.end()) {
476 return true; 477 return true;
477 } 478 }
478 479
479 return false; 480 return false;
480 } 481 }
481 482
482 } // namespace extensions 483 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698