ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / extensions / install_verifier.cc
blob2f23209a7ed05603450f24c464f7b558bbebfe33
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/install_verifier.h"
7 #include <algorithm>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/metrics/histogram.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/stl_util.h"
16 #include "chrome/browser/extensions/extension_management.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/install_signer.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/grit/generated_resources.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/common/content_switches.h"
23 #include "extensions/browser/extension_prefs.h"
24 #include "extensions/browser/extension_registry.h"
25 #include "extensions/browser/extension_system.h"
26 #include "extensions/browser/pref_names.h"
27 #include "extensions/common/extension_set.h"
28 #include "extensions/common/manifest.h"
29 #include "extensions/common/manifest_url_handlers.h"
30 #include "extensions/common/one_shot_event.h"
31 #include "ui/base/l10n/l10n_util.h"
33 namespace extensions {
35 namespace {
37 enum VerifyStatus {
38 NONE = 0, // Do not request install signatures, and do not enforce them.
39 BOOTSTRAP, // Request install signatures, but do not enforce them.
40 ENFORCE, // Request install signatures, and enforce them.
41 ENFORCE_STRICT, // Same as ENFORCE, but hard fail if we can't fetch
42 // signatures.
44 // This is used in histograms - do not remove or reorder entries above! Also
45 // the "MAX" item below should always be the last element.
46 VERIFY_STATUS_MAX
49 #if defined(GOOGLE_CHROME_BUILD)
50 const char kExperimentName[] = "ExtensionInstallVerification";
51 #endif // defined(GOOGLE_CHROME_BUILD)
53 VerifyStatus GetExperimentStatus() {
54 #if defined(GOOGLE_CHROME_BUILD)
55 const std::string group = base::FieldTrialList::FindFullName(
56 kExperimentName);
58 std::string forced_trials =
59 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
60 switches::kForceFieldTrials);
61 if (forced_trials.find(kExperimentName) != std::string::npos) {
62 // We don't want to allow turning off enforcement by forcing the field
63 // trial group to something other than enforcement.
64 return ENFORCE_STRICT;
67 VerifyStatus default_status = NONE;
69 if (group == "EnforceStrict")
70 return ENFORCE_STRICT;
71 else if (group == "Enforce")
72 return ENFORCE;
73 else if (group == "Bootstrap")
74 return BOOTSTRAP;
75 else if (group == "None" || group == "Control")
76 return NONE;
77 else
78 return default_status;
79 #endif // defined(GOOGLE_CHROME_BUILD)
81 return NONE;
84 VerifyStatus GetCommandLineStatus() {
85 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
86 if (!InstallSigner::GetForcedNotFromWebstore().empty())
87 return ENFORCE;
89 if (cmdline->HasSwitch(switches::kExtensionsInstallVerification)) {
90 std::string value = cmdline->GetSwitchValueASCII(
91 switches::kExtensionsInstallVerification);
92 if (value == "bootstrap")
93 return BOOTSTRAP;
94 else if (value == "enforce_strict")
95 return ENFORCE_STRICT;
96 else
97 return ENFORCE;
100 return NONE;
103 VerifyStatus GetStatus() {
104 return std::max(GetExperimentStatus(), GetCommandLineStatus());
107 bool ShouldFetchSignature() {
108 return GetStatus() >= BOOTSTRAP;
111 bool ShouldEnforce() {
112 return GetStatus() >= ENFORCE;
115 enum InitResult {
116 INIT_NO_PREF = 0,
117 INIT_UNPARSEABLE_PREF,
118 INIT_INVALID_SIGNATURE,
119 INIT_VALID_SIGNATURE,
121 // This is used in histograms - do not remove or reorder entries above! Also
122 // the "MAX" item below should always be the last element.
124 INIT_RESULT_MAX
127 void LogInitResultHistogram(InitResult result) {
128 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult",
129 result, INIT_RESULT_MAX);
132 bool CanUseExtensionApis(const Extension& extension) {
133 return extension.is_extension() || extension.is_legacy_packaged_app();
136 enum VerifyAllSuccess {
137 VERIFY_ALL_BOOTSTRAP_SUCCESS = 0,
138 VERIFY_ALL_BOOTSTRAP_FAILURE,
139 VERIFY_ALL_NON_BOOTSTRAP_SUCCESS,
140 VERIFY_ALL_NON_BOOTSTRAP_FAILURE,
142 // Used in histograms. Do not remove/reorder any entries above, and the below
143 // MAX entry should always come last.
144 VERIFY_ALL_SUCCESS_MAX
147 // Record the success or failure of verifying all extensions, and whether or
148 // not it was a bootstrapping.
149 void LogVerifyAllSuccessHistogram(bool bootstrap, bool success) {
150 VerifyAllSuccess result;
151 if (bootstrap && success)
152 result = VERIFY_ALL_BOOTSTRAP_SUCCESS;
153 else if (bootstrap && !success)
154 result = VERIFY_ALL_BOOTSTRAP_FAILURE;
155 else if (!bootstrap && success)
156 result = VERIFY_ALL_NON_BOOTSTRAP_SUCCESS;
157 else
158 result = VERIFY_ALL_NON_BOOTSTRAP_FAILURE;
160 // This used to be part of ExtensionService, but moved here. In order to keep
161 // our histograms accurate, the name is unchanged.
162 UMA_HISTOGRAM_ENUMERATION(
163 "ExtensionService.VerifyAllSuccess", result, VERIFY_ALL_SUCCESS_MAX);
166 // Record the success or failure of a single verification.
167 void LogAddVerifiedSuccess(bool success) {
168 // This used to be part of ExtensionService, but moved here. In order to keep
169 // our histograms accurate, the name is unchanged.
170 UMA_HISTOGRAM_BOOLEAN("ExtensionService.AddVerified", success);
173 } // namespace
175 InstallVerifier::InstallVerifier(ExtensionPrefs* prefs,
176 content::BrowserContext* context)
177 : prefs_(prefs),
178 context_(context),
179 bootstrap_check_complete_(false),
180 weak_factory_(this) {
183 InstallVerifier::~InstallVerifier() {}
185 // static
186 bool InstallVerifier::NeedsVerification(const Extension& extension) {
187 return IsFromStore(extension) && CanUseExtensionApis(extension);
192 // static
193 bool InstallVerifier::IsFromStore(const Extension& extension) {
194 if (extension.from_webstore() || ManifestURL::UpdatesFromGallery(&extension))
195 return true;
197 // If an extension has no update url, our autoupdate code will ask the
198 // webstore about it (to aid in migrating to the webstore from self-hosting
199 // or sideloading based installs). So we want to do verification checks on
200 // such extensions too so that we don't accidentally disable old installs of
201 // extensions that did migrate to the webstore.
202 return (ManifestURL::GetUpdateURL(&extension).is_empty() &&
203 Manifest::IsAutoUpdateableLocation(extension.location()));
206 void InstallVerifier::Init() {
207 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ExperimentStatus",
208 GetExperimentStatus(), VERIFY_STATUS_MAX);
209 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ActualStatus",
210 GetStatus(), VERIFY_STATUS_MAX);
212 const base::DictionaryValue* pref = prefs_->GetInstallSignature();
213 if (pref) {
214 scoped_ptr<InstallSignature> signature_from_prefs =
215 InstallSignature::FromValue(*pref);
216 if (!signature_from_prefs.get()) {
217 LogInitResultHistogram(INIT_UNPARSEABLE_PREF);
218 } else if (!InstallSigner::VerifySignature(*signature_from_prefs.get())) {
219 LogInitResultHistogram(INIT_INVALID_SIGNATURE);
220 DVLOG(1) << "Init - ignoring invalid signature";
221 } else {
222 signature_ = signature_from_prefs.Pass();
223 LogInitResultHistogram(INIT_VALID_SIGNATURE);
224 UMA_HISTOGRAM_COUNTS_100("ExtensionInstallVerifier.InitSignatureCount",
225 signature_->ids.size());
226 GarbageCollect();
228 } else {
229 LogInitResultHistogram(INIT_NO_PREF);
232 ExtensionSystem::Get(context_)->ready().Post(
233 FROM_HERE,
234 base::Bind(&InstallVerifier::MaybeBootstrapSelf,
235 weak_factory_.GetWeakPtr()));
238 void InstallVerifier::VerifyAllExtensions() {
239 AddMany(GetExtensionsToVerify(), ADD_ALL);
242 base::Time InstallVerifier::SignatureTimestamp() {
243 if (signature_.get())
244 return signature_->timestamp;
245 else
246 return base::Time();
249 bool InstallVerifier::IsKnownId(const std::string& id) const {
250 return signature_.get() && (ContainsKey(signature_->ids, id) ||
251 ContainsKey(signature_->invalid_ids, id));
254 bool InstallVerifier::IsInvalid(const std::string& id) const {
255 return ((signature_.get() && ContainsKey(signature_->invalid_ids, id)));
258 void InstallVerifier::VerifyExtension(const std::string& extension_id) {
259 ExtensionIdSet ids;
260 ids.insert(extension_id);
261 AddMany(ids, ADD_SINGLE);
264 void InstallVerifier::AddMany(const ExtensionIdSet& ids, OperationType type) {
265 if (!ShouldFetchSignature()) {
266 OnVerificationComplete(true, type); // considered successful.
267 return;
270 if (signature_.get()) {
271 ExtensionIdSet not_allowed_yet =
272 base::STLSetDifference<ExtensionIdSet>(ids, signature_->ids);
273 if (not_allowed_yet.empty()) {
274 OnVerificationComplete(true, type); // considered successful.
275 return;
279 InstallVerifier::PendingOperation* operation =
280 new InstallVerifier::PendingOperation(type);
281 operation->ids.insert(ids.begin(), ids.end());
283 operation_queue_.push(linked_ptr<PendingOperation>(operation));
285 // If there are no ongoing pending requests, we need to kick one off.
286 if (operation_queue_.size() == 1)
287 BeginFetch();
290 void InstallVerifier::AddProvisional(const ExtensionIdSet& ids) {
291 provisional_.insert(ids.begin(), ids.end());
292 AddMany(ids, ADD_PROVISIONAL);
295 void InstallVerifier::Remove(const std::string& id) {
296 ExtensionIdSet ids;
297 ids.insert(id);
298 RemoveMany(ids);
301 void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) {
302 if (!signature_.get() || !ShouldFetchSignature())
303 return;
305 bool found_any = false;
306 for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) {
307 if (ContainsKey(signature_->ids, *i) ||
308 ContainsKey(signature_->invalid_ids, *i)) {
309 found_any = true;
310 break;
313 if (!found_any)
314 return;
316 InstallVerifier::PendingOperation* operation =
317 new InstallVerifier::PendingOperation(InstallVerifier::REMOVE);
318 operation->ids = ids;
320 operation_queue_.push(linked_ptr<PendingOperation>(operation));
321 if (operation_queue_.size() == 1)
322 BeginFetch();
325 bool InstallVerifier::AllowedByEnterprisePolicy(const std::string& id) const {
326 return ExtensionManagementFactory::GetForBrowserContext(context_)
327 ->IsInstallationExplicitlyAllowed(id);
330 std::string InstallVerifier::GetDebugPolicyProviderName() const {
331 return std::string("InstallVerifier");
334 namespace {
336 enum MustRemainDisabledOutcome {
337 VERIFIED = 0,
338 NOT_EXTENSION,
339 UNPACKED,
340 ENTERPRISE_POLICY_ALLOWED,
341 FORCED_NOT_VERIFIED,
342 NOT_FROM_STORE,
343 NO_SIGNATURE,
344 NOT_VERIFIED_BUT_NOT_ENFORCING,
345 NOT_VERIFIED,
346 NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE,
347 NOT_VERIFIED_BUT_UNKNOWN_ID,
348 COMPONENT,
350 // This is used in histograms - do not remove or reorder entries above! Also
351 // the "MAX" item below should always be the last element.
352 MUST_REMAIN_DISABLED_OUTCOME_MAX
355 void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) {
356 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled",
357 outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX);
360 } // namespace
362 bool InstallVerifier::MustRemainDisabled(const Extension* extension,
363 Extension::DisableReason* reason,
364 base::string16* error) const {
365 CHECK(extension);
366 if (!CanUseExtensionApis(*extension)) {
367 MustRemainDisabledHistogram(NOT_EXTENSION);
368 return false;
370 if (Manifest::IsUnpackedLocation(extension->location())) {
371 MustRemainDisabledHistogram(UNPACKED);
372 return false;
374 if (extension->location() == Manifest::COMPONENT) {
375 MustRemainDisabledHistogram(COMPONENT);
376 return false;
378 if (AllowedByEnterprisePolicy(extension->id())) {
379 MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED);
380 return false;
383 bool verified = true;
384 MustRemainDisabledOutcome outcome = VERIFIED;
385 if (ContainsKey(InstallSigner::GetForcedNotFromWebstore(), extension->id())) {
386 verified = false;
387 outcome = FORCED_NOT_VERIFIED;
388 } else if (!IsFromStore(*extension)) {
389 verified = false;
390 outcome = NOT_FROM_STORE;
391 } else if (signature_.get() == NULL &&
392 (!bootstrap_check_complete_ || GetStatus() < ENFORCE_STRICT)) {
393 // If we don't have a signature yet, we'll temporarily consider every
394 // extension from the webstore verified to avoid false positives on existing
395 // profiles hitting this code for the first time. The InstallVerifier
396 // will bootstrap itself once the ExtensionsSystem is ready.
397 outcome = NO_SIGNATURE;
398 } else if (!IsVerified(extension->id())) {
399 if (signature_.get() &&
400 !ContainsKey(signature_->invalid_ids, extension->id())) {
401 outcome = NOT_VERIFIED_BUT_UNKNOWN_ID;
402 } else {
403 verified = false;
404 outcome = NOT_VERIFIED;
407 if (!verified && !ShouldEnforce()) {
408 verified = true;
409 outcome = NOT_VERIFIED_BUT_NOT_ENFORCING;
411 MustRemainDisabledHistogram(outcome);
413 if (!verified) {
414 if (reason)
415 *reason = Extension::DISABLE_NOT_VERIFIED;
416 if (error)
417 *error = l10n_util::GetStringFUTF16(
418 IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE,
419 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
421 return !verified;
424 InstallVerifier::PendingOperation::PendingOperation(OperationType type)
425 : type(type) {}
427 InstallVerifier::PendingOperation::~PendingOperation() {
430 ExtensionIdSet InstallVerifier::GetExtensionsToVerify() const {
431 ExtensionIdSet result;
432 scoped_ptr<ExtensionSet> extensions =
433 ExtensionRegistry::Get(context_)->GenerateInstalledExtensionsSet();
434 for (ExtensionSet::const_iterator iter = extensions->begin();
435 iter != extensions->end();
436 ++iter) {
437 if (NeedsVerification(*iter->get()))
438 result.insert((*iter)->id());
440 return result;
443 void InstallVerifier::MaybeBootstrapSelf() {
444 bool needs_bootstrap = false;
446 ExtensionIdSet extension_ids = GetExtensionsToVerify();
447 if (signature_.get() == NULL && ShouldFetchSignature()) {
448 needs_bootstrap = true;
449 } else {
450 for (ExtensionIdSet::const_iterator iter = extension_ids.begin();
451 iter != extension_ids.end();
452 ++iter) {
453 if (!IsKnownId(*iter)) {
454 needs_bootstrap = true;
455 break;
460 if (needs_bootstrap)
461 AddMany(extension_ids, ADD_ALL_BOOTSTRAP);
462 else
463 bootstrap_check_complete_ = true;
466 void InstallVerifier::OnVerificationComplete(bool success, OperationType type) {
467 switch (type) {
468 case ADD_SINGLE:
469 LogAddVerifiedSuccess(success);
470 break;
471 case ADD_ALL:
472 case ADD_ALL_BOOTSTRAP:
473 LogVerifyAllSuccessHistogram(type == ADD_ALL_BOOTSTRAP, success);
474 bootstrap_check_complete_ = true;
475 if (success) {
476 // Iterate through the extensions and, if any are newly-verified and
477 // should have the DISABLE_NOT_VERIFIED reason lifted, do so.
478 const ExtensionSet& disabled_extensions =
479 ExtensionRegistry::Get(context_)->disabled_extensions();
480 for (ExtensionSet::const_iterator iter = disabled_extensions.begin();
481 iter != disabled_extensions.end();
482 ++iter) {
483 int disable_reasons = prefs_->GetDisableReasons((*iter)->id());
484 if (disable_reasons & Extension::DISABLE_NOT_VERIFIED &&
485 !MustRemainDisabled(iter->get(), NULL, NULL)) {
486 prefs_->RemoveDisableReason((*iter)->id(),
487 Extension::DISABLE_NOT_VERIFIED);
491 if (success || GetStatus() == ENFORCE_STRICT) {
492 ExtensionSystem::Get(context_)
493 ->extension_service()
494 ->CheckManagementPolicy();
496 break;
497 // We don't need to check disable reasons or report UMA stats for
498 // provisional adds or removals.
499 case ADD_PROVISIONAL:
500 case REMOVE:
501 break;
505 void InstallVerifier::GarbageCollect() {
506 if (!ShouldFetchSignature()) {
507 return;
509 CHECK(signature_.get());
510 ExtensionIdSet leftovers = signature_->ids;
511 leftovers.insert(signature_->invalid_ids.begin(),
512 signature_->invalid_ids.end());
513 ExtensionIdList all_ids;
514 prefs_->GetExtensions(&all_ids);
515 for (ExtensionIdList::const_iterator i = all_ids.begin();
516 i != all_ids.end(); ++i) {
517 ExtensionIdSet::iterator found = leftovers.find(*i);
518 if (found != leftovers.end())
519 leftovers.erase(found);
521 if (!leftovers.empty()) {
522 RemoveMany(leftovers);
526 bool InstallVerifier::IsVerified(const std::string& id) const {
527 return ((signature_.get() && ContainsKey(signature_->ids, id)) ||
528 ContainsKey(provisional_, id));
531 void InstallVerifier::BeginFetch() {
532 DCHECK(ShouldFetchSignature());
534 // TODO(asargent) - It would be possible to coalesce all operations in the
535 // queue into one fetch - we'd probably just need to change the queue to
536 // hold (set of ids, list of operation type) pairs.
537 CHECK(!operation_queue_.empty());
538 const PendingOperation& operation = *operation_queue_.front();
540 ExtensionIdSet ids_to_sign;
541 if (signature_.get()) {
542 ids_to_sign.insert(signature_->ids.begin(), signature_->ids.end());
544 if (operation.type == InstallVerifier::REMOVE) {
545 for (ExtensionIdSet::const_iterator i = operation.ids.begin();
546 i != operation.ids.end(); ++i) {
547 if (ContainsKey(ids_to_sign, *i))
548 ids_to_sign.erase(*i);
550 } else { // All other operation types are some form of "ADD".
551 ids_to_sign.insert(operation.ids.begin(), operation.ids.end());
554 signer_.reset(new InstallSigner(context_->GetRequestContext(), ids_to_sign));
555 signer_->GetSignature(base::Bind(&InstallVerifier::SignatureCallback,
556 weak_factory_.GetWeakPtr()));
559 void InstallVerifier::SaveToPrefs() {
560 if (signature_.get())
561 DCHECK(InstallSigner::VerifySignature(*signature_));
563 if (!signature_.get() || signature_->ids.empty()) {
564 DVLOG(1) << "SaveToPrefs - saving NULL";
565 prefs_->SetInstallSignature(NULL);
566 } else {
567 base::DictionaryValue pref;
568 signature_->ToValue(&pref);
569 if (VLOG_IS_ON(1)) {
570 DVLOG(1) << "SaveToPrefs - saving";
572 DCHECK(InstallSigner::VerifySignature(*signature_.get()));
573 scoped_ptr<InstallSignature> rehydrated =
574 InstallSignature::FromValue(pref);
575 DCHECK(InstallSigner::VerifySignature(*rehydrated.get()));
577 prefs_->SetInstallSignature(&pref);
581 namespace {
583 enum CallbackResult {
584 CALLBACK_NO_SIGNATURE = 0,
585 CALLBACK_INVALID_SIGNATURE,
586 CALLBACK_VALID_SIGNATURE,
588 // This is used in histograms - do not remove or reorder entries above! Also
589 // the "MAX" item below should always be the last element.
591 CALLBACK_RESULT_MAX
594 void GetSignatureResultHistogram(CallbackResult result) {
595 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.GetSignatureResult",
596 result, CALLBACK_RESULT_MAX);
599 } // namespace
601 void InstallVerifier::SignatureCallback(
602 scoped_ptr<InstallSignature> signature) {
604 linked_ptr<PendingOperation> operation = operation_queue_.front();
605 operation_queue_.pop();
607 bool success = false;
608 if (!signature.get()) {
609 GetSignatureResultHistogram(CALLBACK_NO_SIGNATURE);
610 } else if (!InstallSigner::VerifySignature(*signature)) {
611 GetSignatureResultHistogram(CALLBACK_INVALID_SIGNATURE);
612 } else {
613 GetSignatureResultHistogram(CALLBACK_VALID_SIGNATURE);
614 success = true;
617 if (!success) {
618 OnVerificationComplete(false, operation->type);
620 // TODO(asargent) - if this was something like a network error, we need to
621 // do retries with exponential back off.
622 } else {
623 signature_ = signature.Pass();
624 SaveToPrefs();
626 if (!provisional_.empty()) {
627 // Update |provisional_| to remove ids that were successfully signed.
628 provisional_ = base::STLSetDifference<ExtensionIdSet>(
629 provisional_, signature_->ids);
632 OnVerificationComplete(success, operation->type);
635 if (!operation_queue_.empty())
636 BeginFetch();
639 } // namespace extensions