OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |