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 <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <map> |
9 #include <utility> | 9 #include <utility> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/macros.h" | 14 #include "base/macros.h" |
15 #include "base/sha1.h" | 15 #include "base/sha1.h" |
16 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
18 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
19 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
20 #include "components/crx_file/id_util.h" | 20 #include "components/crx_file/id_util.h" |
21 #include "extensions/common/extension_api.h" | 21 #include "extensions/common/extension_api.h" |
| 22 #include "extensions/common/features/feature_channel.h" |
22 #include "extensions/common/features/feature_provider.h" | 23 #include "extensions/common/features/feature_provider.h" |
23 #include "extensions/common/features/feature_util.h" | 24 #include "extensions/common/features/feature_util.h" |
24 #include "extensions/common/switches.h" | 25 #include "extensions/common/switches.h" |
25 | 26 |
26 using crx_file::id_util::HashedIdInHex; | 27 using crx_file::id_util::HashedIdInHex; |
27 | 28 |
28 namespace extensions { | 29 namespace extensions { |
29 | 30 |
30 namespace { | 31 namespace { |
31 | 32 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 template<typename T> | 75 template<typename T> |
75 void ParseEnum(const std::string& string_value, | 76 void ParseEnum(const std::string& string_value, |
76 T* enum_value, | 77 T* enum_value, |
77 const std::map<std::string, T>& mapping) { | 78 const std::map<std::string, T>& mapping) { |
78 const auto& iter = mapping.find(string_value); | 79 const auto& iter = mapping.find(string_value); |
79 if (iter == mapping.end()) | 80 if (iter == mapping.end()) |
80 CRASH_WITH_MINIDUMP("Enum value not found: " + string_value); | 81 CRASH_WITH_MINIDUMP("Enum value not found: " + string_value); |
81 *enum_value = iter->second; | 82 *enum_value = iter->second; |
82 } | 83 } |
83 | 84 |
84 template<typename T> | 85 template <typename T> |
85 void ParseEnum(const base::DictionaryValue* value, | 86 void ParseEnum(const base::Value* value, |
86 const std::string& property, | |
87 T* enum_value, | 87 T* enum_value, |
88 const std::map<std::string, T>& mapping) { | 88 const std::map<std::string, T>& mapping) { |
89 std::string string_value; | 89 std::string string_value; |
90 if (!value->GetString(property, &string_value)) | 90 if (!value->GetAsString(&string_value)) |
91 return; | 91 return; |
92 | 92 |
93 ParseEnum(string_value, enum_value, mapping); | 93 ParseEnum(string_value, enum_value, mapping); |
94 } | 94 } |
95 | 95 |
96 template<typename T> | 96 template<typename T> |
97 void ParseEnumVector(const base::Value* value, | 97 void ParseEnumVector(const base::Value* value, |
98 std::vector<T>* enum_vector, | 98 std::vector<T>* enum_vector, |
99 const std::map<std::string, T>& mapping) { | 99 const std::map<std::string, T>& mapping) { |
100 enum_vector->clear(); | 100 enum_vector->clear(); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 return "hosted app"; | 183 return "hosted app"; |
184 case Feature::WEBUI_CONTEXT: | 184 case Feature::WEBUI_CONTEXT: |
185 return "webui"; | 185 return "webui"; |
186 case Feature::SERVICE_WORKER_CONTEXT: | 186 case Feature::SERVICE_WORKER_CONTEXT: |
187 return "service worker"; | 187 return "service worker"; |
188 } | 188 } |
189 NOTREACHED(); | 189 NOTREACHED(); |
190 return ""; | 190 return ""; |
191 } | 191 } |
192 | 192 |
| 193 std::string GetDisplayName(version_info::Channel channel) { |
| 194 switch (channel) { |
| 195 case version_info::Channel::UNKNOWN: |
| 196 return "trunk"; |
| 197 case version_info::Channel::CANARY: |
| 198 return "canary"; |
| 199 case version_info::Channel::DEV: |
| 200 return "dev"; |
| 201 case version_info::Channel::BETA: |
| 202 return "beta"; |
| 203 case version_info::Channel::STABLE: |
| 204 return "stable"; |
| 205 } |
| 206 NOTREACHED(); |
| 207 return ""; |
| 208 } |
| 209 |
193 // Gets a human-readable list of the display names (pluralized, comma separated | 210 // Gets a human-readable list of the display names (pluralized, comma separated |
194 // with the "and" in the correct place) for each of |enum_types|. | 211 // with the "and" in the correct place) for each of |enum_types|. |
195 template <typename EnumType> | 212 template <typename EnumType> |
196 std::string ListDisplayNames(const std::vector<EnumType>& enum_types) { | 213 std::string ListDisplayNames(const std::vector<EnumType>& enum_types) { |
197 std::string display_name_list; | 214 std::string display_name_list; |
198 for (size_t i = 0; i < enum_types.size(); ++i) { | 215 for (size_t i = 0; i < enum_types.size(); ++i) { |
199 // Pluralize type name. | 216 // Pluralize type name. |
200 display_name_list += GetDisplayName(enum_types[i]) + "s"; | 217 display_name_list += GetDisplayName(enum_types[i]) + "s"; |
201 // Comma-separate entries, with an Oxford comma if there is more than 2 | 218 // Comma-separate entries, with an Oxford comma if there is more than 2 |
202 // total entries. | 219 // total entries. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 | 284 |
268 locations["component"] = SimpleFeature::COMPONENT_LOCATION; | 285 locations["component"] = SimpleFeature::COMPONENT_LOCATION; |
269 locations["external_component"] = | 286 locations["external_component"] = |
270 SimpleFeature::EXTERNAL_COMPONENT_LOCATION; | 287 SimpleFeature::EXTERNAL_COMPONENT_LOCATION; |
271 locations["policy"] = SimpleFeature::POLICY_LOCATION; | 288 locations["policy"] = SimpleFeature::POLICY_LOCATION; |
272 | 289 |
273 platforms["chromeos"] = Feature::CHROMEOS_PLATFORM; | 290 platforms["chromeos"] = Feature::CHROMEOS_PLATFORM; |
274 platforms["linux"] = Feature::LINUX_PLATFORM; | 291 platforms["linux"] = Feature::LINUX_PLATFORM; |
275 platforms["mac"] = Feature::MACOSX_PLATFORM; | 292 platforms["mac"] = Feature::MACOSX_PLATFORM; |
276 platforms["win"] = Feature::WIN_PLATFORM; | 293 platforms["win"] = Feature::WIN_PLATFORM; |
| 294 |
| 295 channels["trunk"] = version_info::Channel::UNKNOWN; |
| 296 channels["canary"] = version_info::Channel::CANARY; |
| 297 channels["dev"] = version_info::Channel::DEV; |
| 298 channels["beta"] = version_info::Channel::BETA; |
| 299 channels["stable"] = version_info::Channel::STABLE; |
277 } | 300 } |
278 | 301 |
279 std::map<std::string, Manifest::Type> extension_types; | 302 std::map<std::string, Manifest::Type> extension_types; |
280 std::map<std::string, Feature::Context> contexts; | 303 std::map<std::string, Feature::Context> contexts; |
281 std::map<std::string, SimpleFeature::Location> locations; | 304 std::map<std::string, SimpleFeature::Location> locations; |
282 std::map<std::string, Feature::Platform> platforms; | 305 std::map<std::string, Feature::Platform> platforms; |
| 306 std::map<std::string, version_info::Channel> channels; |
283 }; | 307 }; |
284 | 308 |
285 SimpleFeature::SimpleFeature() | 309 SimpleFeature::SimpleFeature() |
286 : location_(UNSPECIFIED_LOCATION), | 310 : location_(UNSPECIFIED_LOCATION), |
287 min_manifest_version_(0), | 311 min_manifest_version_(0), |
288 max_manifest_version_(0), | 312 max_manifest_version_(0), |
289 component_extensions_auto_granted_(true) {} | 313 component_extensions_auto_granted_(true) {} |
290 | 314 |
291 SimpleFeature::~SimpleFeature() {} | 315 SimpleFeature::~SimpleFeature() {} |
292 | 316 |
293 bool SimpleFeature::HasDependencies() const { | |
294 return !dependencies_.empty(); | |
295 } | |
296 | |
297 void SimpleFeature::AddFilter(std::unique_ptr<SimpleFeatureFilter> filter) { | |
298 filters_.push_back(std::move(filter)); | |
299 } | |
300 | |
301 std::string SimpleFeature::Parse(const base::DictionaryValue* dictionary) { | 317 std::string SimpleFeature::Parse(const base::DictionaryValue* dictionary) { |
302 static base::LazyInstance<SimpleFeature::Mappings> mappings = | 318 static base::LazyInstance<SimpleFeature::Mappings> mappings = |
303 LAZY_INSTANCE_INITIALIZER; | 319 LAZY_INSTANCE_INITIALIZER; |
304 | 320 |
305 no_parent_ = false; | 321 no_parent_ = false; |
306 for (base::DictionaryValue::Iterator it(*dictionary); | 322 for (base::DictionaryValue::Iterator it(*dictionary); |
307 !it.IsAtEnd(); | 323 !it.IsAtEnd(); |
308 it.Advance()) { | 324 it.Advance()) { |
309 const std::string& key = it.key(); | 325 const std::string& key = it.key(); |
310 const base::Value* value = &it.value(); | 326 const base::Value* value = &it.value(); |
311 if (key == "matches") { | 327 if (key == "matches") { |
312 ParseURLPatterns(dictionary, "matches", &matches_); | 328 ParseURLPatterns(dictionary, "matches", &matches_); |
313 } else if (key == "blacklist") { | 329 } else if (key == "blacklist") { |
314 ParseVector(value, &blacklist_); | 330 ParseVector(value, &blacklist_); |
315 } else if (key == "whitelist") { | 331 } else if (key == "whitelist") { |
316 ParseVector(value, &whitelist_); | 332 ParseVector(value, &whitelist_); |
317 } else if (key == "dependencies") { | 333 } else if (key == "dependencies") { |
318 ParseVector(value, &dependencies_); | 334 ParseVector(value, &dependencies_); |
319 } else if (key == "extension_types") { | 335 } else if (key == "extension_types") { |
320 ParseEnumVector<Manifest::Type>(value, &extension_types_, | 336 ParseEnumVector<Manifest::Type>(value, &extension_types_, |
321 mappings.Get().extension_types); | 337 mappings.Get().extension_types); |
322 } else if (key == "contexts") { | 338 } else if (key == "contexts") { |
323 ParseEnumVector<Context>(value, &contexts_, | 339 ParseEnumVector<Context>(value, &contexts_, |
324 mappings.Get().contexts); | 340 mappings.Get().contexts); |
325 } else if (key == "location") { | 341 } else if (key == "location") { |
326 ParseEnum<Location>(dictionary, "location", &location_, | 342 ParseEnum<Location>(value, &location_, mappings.Get().locations); |
327 mappings.Get().locations); | |
328 } else if (key == "platforms") { | 343 } else if (key == "platforms") { |
329 ParseEnumVector<Platform>(value, &platforms_, | 344 ParseEnumVector<Platform>(value, &platforms_, |
330 mappings.Get().platforms); | 345 mappings.Get().platforms); |
331 } else if (key == "min_manifest_version") { | 346 } else if (key == "min_manifest_version") { |
332 dictionary->GetInteger("min_manifest_version", &min_manifest_version_); | 347 dictionary->GetInteger("min_manifest_version", &min_manifest_version_); |
333 } else if (key == "max_manifest_version") { | 348 } else if (key == "max_manifest_version") { |
334 dictionary->GetInteger("max_manifest_version", &max_manifest_version_); | 349 dictionary->GetInteger("max_manifest_version", &max_manifest_version_); |
335 } else if (key == "noparent") { | 350 } else if (key == "noparent") { |
336 dictionary->GetBoolean("noparent", &no_parent_); | 351 dictionary->GetBoolean("noparent", &no_parent_); |
337 } else if (key == "component_extensions_auto_granted") { | 352 } else if (key == "component_extensions_auto_granted") { |
338 dictionary->GetBoolean("component_extensions_auto_granted", | 353 dictionary->GetBoolean("component_extensions_auto_granted", |
339 &component_extensions_auto_granted_); | 354 &component_extensions_auto_granted_); |
340 } else if (key == "command_line_switch") { | 355 } else if (key == "command_line_switch") { |
341 dictionary->GetString("command_line_switch", &command_line_switch_); | 356 dictionary->GetString("command_line_switch", &command_line_switch_); |
| 357 } else if (key == "channel") { |
| 358 channel_.reset(new version_info::Channel(version_info::Channel::UNKNOWN)); |
| 359 ParseEnum<version_info::Channel>(value, channel_.get(), |
| 360 mappings.Get().channels); |
342 } | 361 } |
343 } | 362 } |
344 | 363 |
345 // NOTE: ideally we'd sanity check that "matches" can be specified if and | 364 // NOTE: ideally we'd sanity check that "matches" can be specified if and |
346 // only if there's a "web_page" or "webui" context, but without | 365 // only if there's a "web_page" or "webui" context, but without |
347 // (Simple)Features being aware of their own heirarchy this is impossible. | 366 // (Simple)Features being aware of their own heirarchy this is impossible. |
348 // | 367 // |
349 // For example, we might have feature "foo" available to "web_page" context | 368 // For example, we might have feature "foo" available to "web_page" context |
350 // and "matches" google.com/*. Then a sub-feature "foo.bar" might override | 369 // and "matches" google.com/*. Then a sub-feature "foo.bar" might override |
351 // "matches" to be chromium.org/*. That sub-feature doesn't need to specify | 370 // "matches" to be chromium.org/*. That sub-feature doesn't need to specify |
352 // "web_page" context because it's inherited, but we don't know that here. | 371 // "web_page" context because it's inherited, but we don't know that here. |
353 | 372 |
354 std::string result; | 373 // All features must be channel-restricted, either directly or through |
355 for (const auto& filter : filters_) { | 374 // dependents. |
356 result = filter->Parse(dictionary); | 375 if (!channel_ && dependencies_.empty()) |
357 if (!result.empty()) | 376 return name() + ": Must supply a value for channel or dependencies."; |
358 break; | |
359 } | |
360 | 377 |
361 return result; | 378 return std::string(); |
362 } | 379 } |
363 | 380 |
364 Feature::Availability SimpleFeature::IsAvailableToManifest( | 381 Feature::Availability SimpleFeature::IsAvailableToManifest( |
365 const std::string& extension_id, | 382 const std::string& extension_id, |
366 Manifest::Type type, | 383 Manifest::Type type, |
367 Manifest::Location location, | 384 Manifest::Location location, |
368 int manifest_version, | 385 int manifest_version, |
369 Platform platform) const { | 386 Platform platform) const { |
370 // Check extension type first to avoid granting platform app permissions | 387 // Check extension type first to avoid granting platform app permissions |
371 // to component extensions. | 388 // to component extensions. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 return CreateAvailability(INVALID_MIN_MANIFEST_VERSION, type); | 420 return CreateAvailability(INVALID_MIN_MANIFEST_VERSION, type); |
404 | 421 |
405 if (max_manifest_version_ != 0 && manifest_version > max_manifest_version_) | 422 if (max_manifest_version_ != 0 && manifest_version > max_manifest_version_) |
406 return CreateAvailability(INVALID_MAX_MANIFEST_VERSION, type); | 423 return CreateAvailability(INVALID_MAX_MANIFEST_VERSION, type); |
407 | 424 |
408 if (!command_line_switch_.empty() && | 425 if (!command_line_switch_.empty() && |
409 !IsCommandLineSwitchEnabled(command_line_switch_)) { | 426 !IsCommandLineSwitchEnabled(command_line_switch_)) { |
410 return CreateAvailability(MISSING_COMMAND_LINE_SWITCH, type); | 427 return CreateAvailability(MISSING_COMMAND_LINE_SWITCH, type); |
411 } | 428 } |
412 | 429 |
413 for (const auto& filter : filters_) { | 430 if (channel_ && check_channel_ && *channel_ < GetCurrentChannel()) |
414 Availability availability = filter->IsAvailableToManifest( | 431 return CreateAvailability(UNSUPPORTED_CHANNEL, *channel_); |
415 extension_id, type, location, manifest_version, platform); | |
416 if (!availability.is_available()) | |
417 return availability; | |
418 } | |
419 | 432 |
420 return CheckDependencies(base::Bind(&IsAvailableToManifestForBind, | 433 return CheckDependencies(base::Bind(&IsAvailableToManifestForBind, |
421 extension_id, | 434 extension_id, |
422 type, | 435 type, |
423 location, | 436 location, |
424 manifest_version, | 437 manifest_version, |
425 platform)); | 438 platform)); |
426 } | 439 } |
427 | 440 |
428 Feature::Availability SimpleFeature::IsAvailableToContext( | 441 Feature::Availability SimpleFeature::IsAvailableToContext( |
(...skipping 19 matching lines...) Expand all Loading... |
448 return CreateAvailability(INVALID_CONTEXT, context); | 461 return CreateAvailability(INVALID_CONTEXT, context); |
449 | 462 |
450 // TODO(kalman): Consider checking |matches_| regardless of context type. | 463 // TODO(kalman): Consider checking |matches_| regardless of context type. |
451 // Fewer surprises, and if the feature configuration wants to isolate | 464 // Fewer surprises, and if the feature configuration wants to isolate |
452 // "matches" from say "blessed_extension" then they can use complex features. | 465 // "matches" from say "blessed_extension" then they can use complex features. |
453 if ((context == WEB_PAGE_CONTEXT || context == WEBUI_CONTEXT) && | 466 if ((context == WEB_PAGE_CONTEXT || context == WEBUI_CONTEXT) && |
454 !matches_.MatchesURL(url)) { | 467 !matches_.MatchesURL(url)) { |
455 return CreateAvailability(INVALID_URL, url); | 468 return CreateAvailability(INVALID_URL, url); |
456 } | 469 } |
457 | 470 |
458 for (const auto& filter : filters_) { | |
459 Availability availability = | |
460 filter->IsAvailableToContext(extension, context, url, platform); | |
461 if (!availability.is_available()) | |
462 return availability; | |
463 } | |
464 | |
465 // TODO(kalman): Assert that if the context was a webpage or WebUI context | 471 // TODO(kalman): Assert that if the context was a webpage or WebUI context |
466 // then at some point a "matches" restriction was checked. | 472 // then at some point a "matches" restriction was checked. |
467 return CheckDependencies(base::Bind( | 473 return CheckDependencies(base::Bind( |
468 &IsAvailableToContextForBind, extension, context, url, platform)); | 474 &IsAvailableToContextForBind, extension, context, url, platform)); |
469 } | 475 } |
470 | 476 |
471 std::string SimpleFeature::GetAvailabilityMessage( | 477 std::string SimpleFeature::GetAvailabilityMessage( |
472 AvailabilityResult result, | 478 AvailabilityResult result, |
473 Manifest::Type type, | 479 Manifest::Type type, |
474 const GURL& url, | 480 const GURL& url, |
475 Context context) const { | 481 Context context, |
| 482 version_info::Channel channel) const { |
476 switch (result) { | 483 switch (result) { |
477 case IS_AVAILABLE: | 484 case IS_AVAILABLE: |
478 return std::string(); | 485 return std::string(); |
479 case NOT_FOUND_IN_WHITELIST: | 486 case NOT_FOUND_IN_WHITELIST: |
480 case FOUND_IN_BLACKLIST: | 487 case FOUND_IN_BLACKLIST: |
481 return base::StringPrintf( | 488 return base::StringPrintf( |
482 "'%s' is not allowed for specified extension ID.", | 489 "'%s' is not allowed for specified extension ID.", |
483 name().c_str()); | 490 name().c_str()); |
484 case INVALID_URL: | 491 case INVALID_URL: |
485 return base::StringPrintf("'%s' is not allowed on %s.", | 492 return base::StringPrintf("'%s' is not allowed on %s.", |
(...skipping 29 matching lines...) Expand all Loading... |
515 return base::StringPrintf( | 522 return base::StringPrintf( |
516 "'%s' requires manifest version of %d or lower.", | 523 "'%s' requires manifest version of %d or lower.", |
517 name().c_str(), | 524 name().c_str(), |
518 max_manifest_version_); | 525 max_manifest_version_); |
519 case NOT_PRESENT: | 526 case NOT_PRESENT: |
520 return base::StringPrintf( | 527 return base::StringPrintf( |
521 "'%s' requires a different Feature that is not present.", | 528 "'%s' requires a different Feature that is not present.", |
522 name().c_str()); | 529 name().c_str()); |
523 case UNSUPPORTED_CHANNEL: | 530 case UNSUPPORTED_CHANNEL: |
524 return base::StringPrintf( | 531 return base::StringPrintf( |
525 "'%s' is unsupported in this version of the platform.", | 532 "'%s' requires %s channel or newer, but this is the %s channel.", |
526 name().c_str()); | 533 name().c_str(), GetDisplayName(channel).c_str(), |
| 534 GetDisplayName(GetCurrentChannel()).c_str()); |
527 case MISSING_COMMAND_LINE_SWITCH: | 535 case MISSING_COMMAND_LINE_SWITCH: |
528 return base::StringPrintf( | 536 return base::StringPrintf( |
529 "'%s' requires the '%s' command line switch to be enabled.", | 537 "'%s' requires the '%s' command line switch to be enabled.", |
530 name().c_str(), command_line_switch_.c_str()); | 538 name().c_str(), command_line_switch_.c_str()); |
531 } | 539 } |
532 | 540 |
533 NOTREACHED(); | 541 NOTREACHED(); |
534 return std::string(); | 542 return std::string(); |
535 } | 543 } |
536 | 544 |
537 Feature::Availability SimpleFeature::CreateAvailability( | 545 Feature::Availability SimpleFeature::CreateAvailability( |
538 AvailabilityResult result) const { | 546 AvailabilityResult result) const { |
539 return Availability( | 547 return Availability( |
540 result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(), | 548 result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(), |
541 UNSPECIFIED_CONTEXT)); | 549 UNSPECIFIED_CONTEXT, |
| 550 version_info::Channel::UNKNOWN)); |
542 } | 551 } |
543 | 552 |
544 Feature::Availability SimpleFeature::CreateAvailability( | 553 Feature::Availability SimpleFeature::CreateAvailability( |
545 AvailabilityResult result, Manifest::Type type) const { | 554 AvailabilityResult result, Manifest::Type type) const { |
546 return Availability(result, GetAvailabilityMessage(result, type, GURL(), | 555 return Availability( |
547 UNSPECIFIED_CONTEXT)); | 556 result, GetAvailabilityMessage(result, type, GURL(), UNSPECIFIED_CONTEXT, |
| 557 version_info::Channel::UNKNOWN)); |
548 } | 558 } |
549 | 559 |
550 Feature::Availability SimpleFeature::CreateAvailability( | 560 Feature::Availability SimpleFeature::CreateAvailability( |
551 AvailabilityResult result, | 561 AvailabilityResult result, |
552 const GURL& url) const { | 562 const GURL& url) const { |
553 return Availability( | 563 return Availability( |
554 result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, url, | 564 result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, url, |
555 UNSPECIFIED_CONTEXT)); | 565 UNSPECIFIED_CONTEXT, |
| 566 version_info::Channel::UNKNOWN)); |
556 } | 567 } |
557 | 568 |
558 Feature::Availability SimpleFeature::CreateAvailability( | 569 Feature::Availability SimpleFeature::CreateAvailability( |
559 AvailabilityResult result, | 570 AvailabilityResult result, |
560 Context context) const { | 571 Context context) const { |
561 return Availability( | 572 return Availability( |
562 result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(), | 573 result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(), |
563 context)); | 574 context, version_info::Channel::UNKNOWN)); |
| 575 } |
| 576 |
| 577 Feature::Availability SimpleFeature::CreateAvailability( |
| 578 AvailabilityResult result, |
| 579 version_info::Channel channel) const { |
| 580 return Availability( |
| 581 result, GetAvailabilityMessage(result, Manifest::TYPE_UNKNOWN, GURL(), |
| 582 UNSPECIFIED_CONTEXT, channel)); |
564 } | 583 } |
565 | 584 |
566 bool SimpleFeature::IsInternal() const { | 585 bool SimpleFeature::IsInternal() const { |
567 return false; | 586 return false; |
568 } | 587 } |
569 | 588 |
570 bool SimpleFeature::IsIdInBlacklist(const std::string& extension_id) const { | 589 bool SimpleFeature::IsIdInBlacklist(const std::string& extension_id) const { |
571 return IsIdInList(extension_id, blacklist_); | 590 return IsIdInList(extension_id, blacklist_); |
572 } | 591 } |
573 | 592 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 bool SimpleFeature::IsValidExtensionId(const std::string& extension_id) { | 653 bool SimpleFeature::IsValidExtensionId(const std::string& extension_id) { |
635 // Belt-and-suspenders philosophy here. We should be pretty confident by this | 654 // Belt-and-suspenders philosophy here. We should be pretty confident by this |
636 // point that we've validated the extension ID format, but in case something | 655 // point that we've validated the extension ID format, but in case something |
637 // slips through, we avoid a class of attack where creative ID manipulation | 656 // slips through, we avoid a class of attack where creative ID manipulation |
638 // leads to hash collisions. | 657 // leads to hash collisions. |
639 // 128 bits / 4 = 32 mpdecimal characters | 658 // 128 bits / 4 = 32 mpdecimal characters |
640 return (extension_id.length() == 32); | 659 return (extension_id.length() == 32); |
641 } | 660 } |
642 | 661 |
643 } // namespace extensions | 662 } // namespace extensions |
OLD | NEW |