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" |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 DCHECK(id_hash.length() == base::kSHA1Length); | 220 DCHECK(id_hash.length() == base::kSHA1Length); |
221 return base::HexEncode(id_hash.c_str(), id_hash.length()); | 221 return base::HexEncode(id_hash.c_str(), id_hash.length()); |
222 } | 222 } |
223 | 223 |
224 } // namespace | 224 } // namespace |
225 | 225 |
226 SimpleFeature::SimpleFeature() | 226 SimpleFeature::SimpleFeature() |
227 : location_(UNSPECIFIED_LOCATION), | 227 : location_(UNSPECIFIED_LOCATION), |
228 min_manifest_version_(0), | 228 min_manifest_version_(0), |
229 max_manifest_version_(0), | 229 max_manifest_version_(0), |
230 has_parent_(false) {} | 230 has_parent_(false), |
231 component_extensions_auto_whitelisted_(true) {} | |
231 | 232 |
232 SimpleFeature::~SimpleFeature() {} | 233 SimpleFeature::~SimpleFeature() {} |
233 | 234 |
234 void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) { | 235 void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) { |
235 filters_.push_back(make_linked_ptr(filter.release())); | 236 filters_.push_back(make_linked_ptr(filter.release())); |
236 } | 237 } |
237 | 238 |
238 std::string SimpleFeature::Parse(const base::DictionaryValue* value) { | 239 std::string SimpleFeature::Parse(const base::DictionaryValue* value) { |
239 ParseURLPatterns(value, "matches", &matches_); | 240 ParseURLPatterns(value, "matches", &matches_); |
241 ParseSet(value, "blacklist", &blacklist_); | |
240 ParseSet(value, "whitelist", &whitelist_); | 242 ParseSet(value, "whitelist", &whitelist_); |
241 ParseSet(value, "dependencies", &dependencies_); | 243 ParseSet(value, "dependencies", &dependencies_); |
242 ParseEnumSet<Manifest::Type>(value, "extension_types", &extension_types_, | 244 ParseEnumSet<Manifest::Type>(value, "extension_types", &extension_types_, |
243 g_mappings.Get().extension_types); | 245 g_mappings.Get().extension_types); |
244 ParseEnumSet<Context>(value, "contexts", &contexts_, | 246 ParseEnumSet<Context>(value, "contexts", &contexts_, |
245 g_mappings.Get().contexts); | 247 g_mappings.Get().contexts); |
246 ParseEnum<Location>(value, "location", &location_, | 248 ParseEnum<Location>(value, "location", &location_, |
247 g_mappings.Get().locations); | 249 g_mappings.Get().locations); |
248 ParseEnumSet<Platform>(value, "platforms", &platforms_, | 250 ParseEnumSet<Platform>(value, "platforms", &platforms_, |
249 g_mappings.Get().platforms); | 251 g_mappings.Get().platforms); |
250 value->GetInteger("min_manifest_version", &min_manifest_version_); | 252 value->GetInteger("min_manifest_version", &min_manifest_version_); |
251 value->GetInteger("max_manifest_version", &max_manifest_version_); | 253 value->GetInteger("max_manifest_version", &max_manifest_version_); |
252 | 254 |
253 no_parent_ = false; | 255 no_parent_ = false; |
254 value->GetBoolean("noparent", &no_parent_); | 256 value->GetBoolean("noparent", &no_parent_); |
255 | 257 |
258 component_extensions_auto_whitelisted_ = true; | |
259 value->GetBoolean("component_extensions_auto_whitelisted", | |
260 &component_extensions_auto_whitelisted_); | |
261 | |
256 if (matches_.is_empty() && contexts_.count(WEB_PAGE_CONTEXT) != 0) { | 262 if (matches_.is_empty() && contexts_.count(WEB_PAGE_CONTEXT) != 0) { |
257 return name() + ": Allowing web_page contexts requires supplying a value " + | 263 return name() + ": Allowing web_page contexts requires supplying a value " + |
258 "for matches."; | 264 "for matches."; |
259 } | 265 } |
260 | 266 |
261 for (FilterList::iterator filter_iter = filters_.begin(); | 267 for (FilterList::iterator filter_iter = filters_.begin(); |
262 filter_iter != filters_.end(); | 268 filter_iter != filters_.end(); |
263 ++filter_iter) { | 269 ++filter_iter) { |
264 std::string result = (*filter_iter)->Parse(value); | 270 std::string result = (*filter_iter)->Parse(value); |
265 if (!result.empty()) { | 271 if (!result.empty()) { |
(...skipping 14 matching lines...) Expand all Loading... | |
280 // to component extensions. | 286 // to component extensions. |
281 // HACK(kalman): user script -> extension. Solve this in a more generic way | 287 // HACK(kalman): user script -> extension. Solve this in a more generic way |
282 // when we compile feature files. | 288 // when we compile feature files. |
283 Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ? | 289 Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ? |
284 Manifest::TYPE_EXTENSION : type; | 290 Manifest::TYPE_EXTENSION : type; |
285 if (!extension_types_.empty() && | 291 if (!extension_types_.empty() && |
286 extension_types_.find(type_to_check) == extension_types_.end()) { | 292 extension_types_.find(type_to_check) == extension_types_.end()) { |
287 return CreateAvailability(INVALID_TYPE, type); | 293 return CreateAvailability(INVALID_TYPE, type); |
288 } | 294 } |
289 | 295 |
290 // Component extensions can access any feature. | 296 if (IsIdInBlacklist(extension_id)) |
291 // TODO(kalman/asargent): Should this match EXTERNAL_COMPONENT too? | 297 return CreateAvailability(FOUND_IN_BLACKLIST, type); |
292 if (location == Manifest::COMPONENT) | 298 |
299 // TODO(benwells): don't auto whitelist all component extensions. | |
300 // See http://crbug.com/370375 for more details. | |
not at google - send to devlin
2014/05/06 23:04:03
this is pretty hacky. I've been working on trying
| |
301 if (component_extensions_auto_whitelisted_ && location == Manifest::COMPONENT) | |
293 return CreateAvailability(IS_AVAILABLE, type); | 302 return CreateAvailability(IS_AVAILABLE, type); |
294 | 303 |
295 if (!whitelist_.empty()) { | 304 if (!whitelist_.empty()) { |
296 if (!IsIdInWhitelist(extension_id)) { | 305 if (!IsIdInWhitelist(extension_id)) { |
297 // TODO(aa): This is gross. There should be a better way to test the | 306 // TODO(aa): This is gross. There should be a better way to test the |
298 // whitelist. | 307 // whitelist. |
299 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 308 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
300 if (!command_line->HasSwitch(switches::kWhitelistedExtensionID)) | 309 if (!command_line->HasSwitch(switches::kWhitelistedExtensionID)) |
301 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); | 310 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); |
302 | 311 |
303 std::string whitelist_switch_value = | 312 std::string whitelist_switch_value = |
304 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 313 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
305 switches::kWhitelistedExtensionID); | 314 switches::kWhitelistedExtensionID); |
306 if (extension_id != whitelist_switch_value) | 315 if (extension_id != whitelist_switch_value) |
307 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); | 316 return CreateAvailability(NOT_FOUND_IN_WHITELIST, type); |
308 } | 317 } |
309 } | 318 } |
310 | 319 |
320 // Component extensions can access any feature. | |
321 // TODO(kalman/asargent): Should this match EXTERNAL_COMPONENT too? | |
not at google - send to devlin
2014/05/06 23:04:03
hey could you change this TODO to be instead:
NOT
| |
322 if (location == Manifest::COMPONENT) | |
323 return CreateAvailability(IS_AVAILABLE, type); | |
324 | |
311 if (!MatchesManifestLocation(location)) | 325 if (!MatchesManifestLocation(location)) |
312 return CreateAvailability(INVALID_LOCATION, type); | 326 return CreateAvailability(INVALID_LOCATION, type); |
313 | 327 |
314 if (!platforms_.empty() && | 328 if (!platforms_.empty() && |
315 platforms_.find(platform) == platforms_.end()) | 329 platforms_.find(platform) == platforms_.end()) |
316 return CreateAvailability(INVALID_PLATFORM, type); | 330 return CreateAvailability(INVALID_PLATFORM, type); |
317 | 331 |
318 if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_) | 332 if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_) |
319 return CreateAvailability(INVALID_MIN_MANIFEST_VERSION, type); | 333 return CreateAvailability(INVALID_MIN_MANIFEST_VERSION, type); |
320 | 334 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
368 | 382 |
369 std::string SimpleFeature::GetAvailabilityMessage( | 383 std::string SimpleFeature::GetAvailabilityMessage( |
370 AvailabilityResult result, | 384 AvailabilityResult result, |
371 Manifest::Type type, | 385 Manifest::Type type, |
372 const GURL& url, | 386 const GURL& url, |
373 Context context) const { | 387 Context context) const { |
374 switch (result) { | 388 switch (result) { |
375 case IS_AVAILABLE: | 389 case IS_AVAILABLE: |
376 return std::string(); | 390 return std::string(); |
377 case NOT_FOUND_IN_WHITELIST: | 391 case NOT_FOUND_IN_WHITELIST: |
392 case FOUND_IN_BLACKLIST: | |
378 return base::StringPrintf( | 393 return base::StringPrintf( |
379 "'%s' is not allowed for specified extension ID.", | 394 "'%s' is not allowed for specified extension ID.", |
380 name().c_str()); | 395 name().c_str()); |
381 case INVALID_URL: | 396 case INVALID_URL: |
382 return base::StringPrintf("'%s' is not allowed on %s.", | 397 return base::StringPrintf("'%s' is not allowed on %s.", |
383 name().c_str(), url.spec().c_str()); | 398 name().c_str(), url.spec().c_str()); |
384 case INVALID_TYPE: | 399 case INVALID_TYPE: |
385 return base::StringPrintf( | 400 return base::StringPrintf( |
386 "'%s' is only allowed for %s, but this is a %s.", | 401 "'%s' is only allowed for %s, but this is a %s.", |
387 name().c_str(), | 402 name().c_str(), |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
459 std::set<Feature::Context>* SimpleFeature::GetContexts() { | 474 std::set<Feature::Context>* SimpleFeature::GetContexts() { |
460 return &contexts_; | 475 return &contexts_; |
461 } | 476 } |
462 | 477 |
463 bool SimpleFeature::IsInternal() const { | 478 bool SimpleFeature::IsInternal() const { |
464 return false; | 479 return false; |
465 } | 480 } |
466 | 481 |
467 bool SimpleFeature::IsBlockedInServiceWorker() const { return false; } | 482 bool SimpleFeature::IsBlockedInServiceWorker() const { return false; } |
468 | 483 |
484 bool SimpleFeature::IsIdInBlacklist(const std::string& extension_id) const { | |
485 return IsIdInList(extension_id, blacklist_); | |
486 } | |
487 | |
469 bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const { | 488 bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const { |
470 return IsIdInWhitelist(extension_id, whitelist_); | 489 return IsIdInList(extension_id, whitelist_); |
471 } | 490 } |
472 | 491 |
473 // static | 492 // static |
474 bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id, | 493 bool SimpleFeature::IsIdInList(const std::string& extension_id, |
475 const std::set<std::string>& whitelist) { | 494 const std::set<std::string>& list) { |
476 // Belt-and-suspenders philosophy here. We should be pretty confident by this | 495 // Belt-and-suspenders philosophy here. We should be pretty confident by this |
477 // point that we've validated the extension ID format, but in case something | 496 // point that we've validated the extension ID format, but in case something |
478 // slips through, we avoid a class of attack where creative ID manipulation | 497 // slips through, we avoid a class of attack where creative ID manipulation |
479 // leads to hash collisions. | 498 // leads to hash collisions. |
480 if (extension_id.length() != 32) // 128 bits / 4 = 32 mpdecimal characters | 499 if (extension_id.length() != 32) // 128 bits / 4 = 32 mpdecimal characters |
481 return false; | 500 return false; |
482 | 501 |
483 if (whitelist.find(extension_id) != whitelist.end() || | 502 if (list.find(extension_id) != list.end() || |
484 whitelist.find(HashExtensionId(extension_id)) != whitelist.end()) { | 503 list.find(HashExtensionId(extension_id)) != list.end()) { |
485 return true; | 504 return true; |
486 } | 505 } |
487 | 506 |
488 return false; | 507 return false; |
489 } | 508 } |
490 | 509 |
491 bool SimpleFeature::MatchesManifestLocation( | 510 bool SimpleFeature::MatchesManifestLocation( |
492 Manifest::Location manifest_location) const { | 511 Manifest::Location manifest_location) const { |
493 switch (location_) { | 512 switch (location_) { |
494 case SimpleFeature::UNSPECIFIED_LOCATION: | 513 case SimpleFeature::UNSPECIFIED_LOCATION: |
495 return true; | 514 return true; |
496 case SimpleFeature::COMPONENT_LOCATION: | 515 case SimpleFeature::COMPONENT_LOCATION: |
497 // TODO(kalman/asargent): Should this include EXTERNAL_COMPONENT too? | 516 // TODO(kalman/asargent): Should this include EXTERNAL_COMPONENT too? |
498 return manifest_location == Manifest::COMPONENT; | 517 return manifest_location == Manifest::COMPONENT; |
499 case SimpleFeature::POLICY_LOCATION: | 518 case SimpleFeature::POLICY_LOCATION: |
500 return manifest_location == Manifest::EXTERNAL_POLICY || | 519 return manifest_location == Manifest::EXTERNAL_POLICY || |
501 manifest_location == Manifest::EXTERNAL_POLICY_DOWNLOAD; | 520 manifest_location == Manifest::EXTERNAL_POLICY_DOWNLOAD; |
502 } | 521 } |
503 NOTREACHED(); | 522 NOTREACHED(); |
504 return false; | 523 return false; |
505 } | 524 } |
506 | 525 |
507 } // namespace extensions | 526 } // namespace extensions |
OLD | NEW |