Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / extensions / install_verifier.cc
blobd035436ddd0b34ff46a6527ae09a8c930df8d0d2
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_service.h"
17 #include "chrome/browser/extensions/install_signer.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/extensions/manifest_url_handler.h"
20 #include "chrome/common/pref_names.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/one_shot_event.h"
30 #include "grit/generated_resources.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.
42 // This is used in histograms - do not remove or reorder entries above! Also
43 // the "MAX" item below should always be the last element.
45 VERIFY_STATUS_MAX
48 #if defined(GOOGLE_CHROME_BUILD)
49 const char kExperimentName[] = "ExtensionInstallVerification";
50 #endif // defined(GOOGLE_CHROME_BUILD)
52 VerifyStatus GetExperimentStatus() {
53 #if defined(GOOGLE_CHROME_BUILD)
54 const std::string group = base::FieldTrialList::FindFullName(
55 kExperimentName);
57 std::string forced_trials = CommandLine::ForCurrentProcess()->
58 GetSwitchValueASCII(switches::kForceFieldTrials);
59 if (forced_trials.find(kExperimentName) != std::string::npos) {
60 // We don't want to allow turning off enforcement by forcing the field
61 // trial group to something other than enforcement.
62 return ENFORCE;
65 VerifyStatus default_status = NONE;
67 if (group == "Enforce")
68 return ENFORCE;
69 else if (group == "Bootstrap")
70 return BOOTSTRAP;
71 else if (group == "None" || group == "Control")
72 return NONE;
73 else
74 return default_status;
75 #endif // defined(GOOGLE_CHROME_BUILD)
77 return NONE;
80 VerifyStatus GetCommandLineStatus() {
81 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
82 if (!InstallSigner::GetForcedNotFromWebstore().empty())
83 return ENFORCE;
85 if (cmdline->HasSwitch(switches::kExtensionsInstallVerification)) {
86 std::string value = cmdline->GetSwitchValueASCII(
87 switches::kExtensionsInstallVerification);
88 if (value == "bootstrap")
89 return BOOTSTRAP;
90 else
91 return ENFORCE;
94 return NONE;
97 VerifyStatus GetStatus() {
98 return std::max(GetExperimentStatus(), GetCommandLineStatus());
101 bool ShouldFetchSignature() {
102 VerifyStatus status = GetStatus();
103 return (status == BOOTSTRAP || status == ENFORCE);
106 bool ShouldEnforce() {
107 return GetStatus() == ENFORCE;
110 enum InitResult {
111 INIT_NO_PREF = 0,
112 INIT_UNPARSEABLE_PREF,
113 INIT_INVALID_SIGNATURE,
114 INIT_VALID_SIGNATURE,
116 // This is used in histograms - do not remove or reorder entries above! Also
117 // the "MAX" item below should always be the last element.
119 INIT_RESULT_MAX
122 void LogInitResultHistogram(InitResult result) {
123 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult",
124 result, INIT_RESULT_MAX);
127 bool FromStore(const Extension& extension) {
128 if (extension.from_webstore() || ManifestURL::UpdatesFromGallery(&extension))
129 return true;
131 // If an extension has no update url, our autoupdate code will ask the
132 // webstore about it (to aid in migrating to the webstore from self-hosting
133 // or sideloading based installs). So we want to do verification checks on
134 // such extensions too so that we don't accidentally disable old installs of
135 // extensions that did migrate to the webstore.
136 return (ManifestURL::GetUpdateURL(&extension).is_empty() &&
137 Manifest::IsAutoUpdateableLocation(extension.location()));
140 bool CanUseExtensionApis(const Extension& extension) {
141 return extension.is_extension() || extension.is_legacy_packaged_app();
144 enum VerifyAllSuccess {
145 VERIFY_ALL_BOOTSTRAP_SUCCESS = 0,
146 VERIFY_ALL_BOOTSTRAP_FAILURE,
147 VERIFY_ALL_NON_BOOTSTRAP_SUCCESS,
148 VERIFY_ALL_NON_BOOTSTRAP_FAILURE,
150 // Used in histograms. Do not remove/reorder any entries above, and the below
151 // MAX entry should always come last.
152 VERIFY_ALL_SUCCESS_MAX
155 // Record the success or failure of verifying all extensions, and whether or
156 // not it was a bootstrapping.
157 void LogVerifyAllSuccessHistogram(bool bootstrap, bool success) {
158 VerifyAllSuccess result;
159 if (bootstrap && success)
160 result = VERIFY_ALL_BOOTSTRAP_SUCCESS;
161 else if (bootstrap && !success)
162 result = VERIFY_ALL_BOOTSTRAP_FAILURE;
163 else if (!bootstrap && success)
164 result = VERIFY_ALL_NON_BOOTSTRAP_SUCCESS;
165 else
166 result = VERIFY_ALL_NON_BOOTSTRAP_FAILURE;
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_ENUMERATION(
171 "ExtensionService.VerifyAllSuccess", result, VERIFY_ALL_SUCCESS_MAX);
174 // Record the success or failure of a single verification.
175 void LogAddVerifiedSuccess(bool success) {
176 // This used to be part of ExtensionService, but moved here. In order to keep
177 // our histograms accurate, the name is unchanged.
178 UMA_HISTOGRAM_BOOLEAN("ExtensionService.AddVerified", success);
181 } // namespace
183 InstallVerifier::InstallVerifier(ExtensionPrefs* prefs,
184 content::BrowserContext* context)
185 : prefs_(prefs), context_(context), weak_factory_(this) {}
187 InstallVerifier::~InstallVerifier() {}
189 // static
190 bool InstallVerifier::NeedsVerification(const Extension& extension) {
191 return FromStore(extension) && CanUseExtensionApis(extension);
194 void InstallVerifier::Init() {
195 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ExperimentStatus",
196 GetExperimentStatus(), VERIFY_STATUS_MAX);
197 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.ActualStatus",
198 GetStatus(), VERIFY_STATUS_MAX);
200 const base::DictionaryValue* pref = prefs_->GetInstallSignature();
201 if (pref) {
202 scoped_ptr<InstallSignature> signature_from_prefs =
203 InstallSignature::FromValue(*pref);
204 if (!signature_from_prefs.get()) {
205 LogInitResultHistogram(INIT_UNPARSEABLE_PREF);
206 } else if (!InstallSigner::VerifySignature(*signature_from_prefs.get())) {
207 LogInitResultHistogram(INIT_INVALID_SIGNATURE);
208 DVLOG(1) << "Init - ignoring invalid signature";
209 } else {
210 signature_ = signature_from_prefs.Pass();
211 LogInitResultHistogram(INIT_VALID_SIGNATURE);
212 UMA_HISTOGRAM_COUNTS_100("ExtensionInstallVerifier.InitSignatureCount",
213 signature_->ids.size());
214 GarbageCollect();
216 } else {
217 LogInitResultHistogram(INIT_NO_PREF);
220 ExtensionSystem::Get(context_)->ready().Post(
221 FROM_HERE,
222 base::Bind(&InstallVerifier::MaybeBootstrapSelf,
223 weak_factory_.GetWeakPtr()));
226 void InstallVerifier::VerifyAllExtensions() {
227 AddMany(GetExtensionsToVerify(), ADD_ALL);
230 base::Time InstallVerifier::SignatureTimestamp() {
231 if (signature_.get())
232 return signature_->timestamp;
233 else
234 return base::Time();
237 bool InstallVerifier::IsKnownId(const std::string& id) {
238 return signature_.get() && (ContainsKey(signature_->ids, id) ||
239 ContainsKey(signature_->invalid_ids, id));
242 void InstallVerifier::VerifyExtension(const std::string& extension_id) {
243 ExtensionIdSet ids;
244 ids.insert(extension_id);
245 AddMany(ids, ADD_SINGLE);
248 void InstallVerifier::AddMany(const ExtensionIdSet& ids, OperationType type) {
249 if (!ShouldFetchSignature()) {
250 OnVerificationComplete(true, type); // considered successful.
251 return;
254 if (signature_.get()) {
255 ExtensionIdSet not_allowed_yet =
256 base::STLSetDifference<ExtensionIdSet>(ids, signature_->ids);
257 if (not_allowed_yet.empty()) {
258 OnVerificationComplete(true, type); // considered successful.
259 return;
263 InstallVerifier::PendingOperation* operation =
264 new InstallVerifier::PendingOperation(type);
265 operation->ids.insert(ids.begin(), ids.end());
267 operation_queue_.push(linked_ptr<PendingOperation>(operation));
269 // If there are no ongoing pending requests, we need to kick one off.
270 if (operation_queue_.size() == 1)
271 BeginFetch();
274 void InstallVerifier::AddProvisional(const ExtensionIdSet& ids) {
275 provisional_.insert(ids.begin(), ids.end());
276 AddMany(ids, ADD_PROVISIONAL);
279 void InstallVerifier::Remove(const std::string& id) {
280 ExtensionIdSet ids;
281 ids.insert(id);
282 RemoveMany(ids);
285 void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) {
286 if (!signature_.get() || !ShouldFetchSignature())
287 return;
289 bool found_any = false;
290 for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) {
291 if (ContainsKey(signature_->ids, *i) ||
292 ContainsKey(signature_->invalid_ids, *i)) {
293 found_any = true;
294 break;
297 if (!found_any)
298 return;
300 InstallVerifier::PendingOperation* operation =
301 new InstallVerifier::PendingOperation(InstallVerifier::REMOVE);
302 operation->ids = ids;
304 operation_queue_.push(linked_ptr<PendingOperation>(operation));
305 if (operation_queue_.size() == 1)
306 BeginFetch();
309 std::string InstallVerifier::GetDebugPolicyProviderName() const {
310 return std::string("InstallVerifier");
313 namespace {
315 enum MustRemainDisabledOutcome {
316 VERIFIED = 0,
317 NOT_EXTENSION,
318 UNPACKED,
319 ENTERPRISE_POLICY_ALLOWED,
320 FORCED_NOT_VERIFIED,
321 NOT_FROM_STORE,
322 NO_SIGNATURE,
323 NOT_VERIFIED_BUT_NOT_ENFORCING,
324 NOT_VERIFIED,
325 NOT_VERIFIED_BUT_INSTALL_TIME_NEWER_THAN_SIGNATURE,
326 NOT_VERIFIED_BUT_UNKNOWN_ID,
327 COMPONENT,
329 // This is used in histograms - do not remove or reorder entries above! Also
330 // the "MAX" item below should always be the last element.
331 MUST_REMAIN_DISABLED_OUTCOME_MAX
334 void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) {
335 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled",
336 outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX);
339 } // namespace
341 bool InstallVerifier::MustRemainDisabled(const Extension* extension,
342 Extension::DisableReason* reason,
343 base::string16* error) const {
344 CHECK(extension);
345 if (!CanUseExtensionApis(*extension)) {
346 MustRemainDisabledHistogram(NOT_EXTENSION);
347 return false;
349 if (Manifest::IsUnpackedLocation(extension->location())) {
350 MustRemainDisabledHistogram(UNPACKED);
351 return false;
353 if (extension->location() == Manifest::COMPONENT) {
354 MustRemainDisabledHistogram(COMPONENT);
355 return false;
357 if (AllowedByEnterprisePolicy(extension->id())) {
358 MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED);
359 return false;
362 bool verified = true;
363 MustRemainDisabledOutcome outcome = VERIFIED;
364 if (ContainsKey(InstallSigner::GetForcedNotFromWebstore(), extension->id())) {
365 verified = false;
366 outcome = FORCED_NOT_VERIFIED;
367 } else if (!FromStore(*extension)) {
368 verified = false;
369 outcome = NOT_FROM_STORE;
370 } else if (signature_.get() == NULL) {
371 // If we don't have a signature yet, we'll temporarily consider every
372 // extension from the webstore verified to avoid false positives on existing
373 // profiles hitting this code for the first time. The InstallVerifier
374 // will bootstrap itself once the ExtensionsSystem is ready.
375 outcome = NO_SIGNATURE;
376 } else if (!IsVerified(extension->id())) {
377 if (!ContainsKey(signature_->invalid_ids, extension->id())) {
378 outcome = NOT_VERIFIED_BUT_UNKNOWN_ID;
379 } else {
380 verified = false;
381 outcome = NOT_VERIFIED;
384 if (!verified && !ShouldEnforce()) {
385 verified = true;
386 outcome = NOT_VERIFIED_BUT_NOT_ENFORCING;
388 MustRemainDisabledHistogram(outcome);
390 if (!verified) {
391 if (reason)
392 *reason = Extension::DISABLE_NOT_VERIFIED;
393 if (error)
394 *error = l10n_util::GetStringFUTF16(
395 IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE,
396 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
398 return !verified;
401 InstallVerifier::PendingOperation::PendingOperation(OperationType type)
402 : type(type) {}
404 InstallVerifier::PendingOperation::~PendingOperation() {
407 ExtensionIdSet InstallVerifier::GetExtensionsToVerify() const {
408 ExtensionIdSet result;
409 scoped_ptr<ExtensionSet> extensions =
410 ExtensionRegistry::Get(context_)->GenerateInstalledExtensionsSet();
411 for (ExtensionSet::const_iterator iter = extensions->begin();
412 iter != extensions->end();
413 ++iter) {
414 if (NeedsVerification(**iter))
415 result.insert((*iter)->id());
417 return result;
420 void InstallVerifier::MaybeBootstrapSelf() {
421 bool needs_bootstrap = false;
423 ExtensionIdSet extension_ids = GetExtensionsToVerify();
424 if (signature_.get() == NULL && ShouldFetchSignature()) {
425 needs_bootstrap = true;
426 } else {
427 for (ExtensionIdSet::const_iterator iter = extension_ids.begin();
428 iter != extension_ids.end();
429 ++iter) {
430 if (!IsKnownId(*iter)) {
431 needs_bootstrap = true;
432 break;
437 if (needs_bootstrap)
438 AddMany(extension_ids, ADD_ALL_BOOTSTRAP);
441 void InstallVerifier::OnVerificationComplete(bool success,
442 OperationType type) const {
443 switch (type) {
444 case ADD_SINGLE:
445 LogAddVerifiedSuccess(success);
446 break;
447 case ADD_ALL:
448 case ADD_ALL_BOOTSTRAP:
449 LogVerifyAllSuccessHistogram(type == ADD_ALL_BOOTSTRAP, success);
450 if (success) {
451 // Iterate through the extensions and, if any are newly-verified and
452 // should have the DISABLE_NOT_VERIFIED reason lifted, do so.
453 const ExtensionSet& disabled_extensions =
454 ExtensionRegistry::Get(context_)->disabled_extensions();
455 for (ExtensionSet::const_iterator iter = disabled_extensions.begin();
456 iter != disabled_extensions.end();
457 ++iter) {
458 int disable_reasons = prefs_->GetDisableReasons((*iter)->id());
459 if (disable_reasons & Extension::DISABLE_NOT_VERIFIED &&
460 !MustRemainDisabled(*iter, NULL, NULL)) {
461 prefs_->RemoveDisableReason((*iter)->id(),
462 Extension::DISABLE_NOT_VERIFIED);
466 ExtensionSystem::Get(context_)
467 ->extension_service()
468 ->CheckManagementPolicy();
470 break;
471 // We don't need to check disable reasons or report UMA stats for
472 // provisional adds or removals.
473 case ADD_PROVISIONAL:
474 case REMOVE:
475 break;
479 void InstallVerifier::GarbageCollect() {
480 if (!ShouldFetchSignature()) {
481 return;
483 CHECK(signature_.get());
484 ExtensionIdSet leftovers = signature_->ids;
485 leftovers.insert(signature_->invalid_ids.begin(),
486 signature_->invalid_ids.end());
487 ExtensionIdList all_ids;
488 prefs_->GetExtensions(&all_ids);
489 for (ExtensionIdList::const_iterator i = all_ids.begin();
490 i != all_ids.end(); ++i) {
491 ExtensionIdSet::iterator found = leftovers.find(*i);
492 if (found != leftovers.end())
493 leftovers.erase(found);
495 if (!leftovers.empty()) {
496 RemoveMany(leftovers);
500 bool InstallVerifier::AllowedByEnterprisePolicy(const std::string& id) const {
501 PrefService* pref_service = prefs_->pref_service();
502 if (pref_service->IsManagedPreference(pref_names::kInstallAllowList)) {
503 const base::ListValue* whitelist =
504 pref_service->GetList(pref_names::kInstallAllowList);
505 base::StringValue id_value(id);
506 if (whitelist && whitelist->Find(id_value) != whitelist->end())
507 return true;
509 if (pref_service->IsManagedPreference(pref_names::kInstallForceList)) {
510 const base::DictionaryValue* forcelist =
511 pref_service->GetDictionary(pref_names::kInstallForceList);
512 if (forcelist && forcelist->HasKey(id))
513 return true;
515 return false;
518 bool InstallVerifier::IsVerified(const std::string& id) const {
519 return ((signature_.get() && ContainsKey(signature_->ids, id)) ||
520 ContainsKey(provisional_, id));
523 void InstallVerifier::BeginFetch() {
524 DCHECK(ShouldFetchSignature());
526 // TODO(asargent) - It would be possible to coalesce all operations in the
527 // queue into one fetch - we'd probably just need to change the queue to
528 // hold (set of ids, list of operation type) pairs.
529 CHECK(!operation_queue_.empty());
530 const PendingOperation& operation = *operation_queue_.front();
532 ExtensionIdSet ids_to_sign;
533 if (signature_.get()) {
534 ids_to_sign.insert(signature_->ids.begin(), signature_->ids.end());
536 if (operation.type == InstallVerifier::REMOVE) {
537 for (ExtensionIdSet::const_iterator i = operation.ids.begin();
538 i != operation.ids.end(); ++i) {
539 if (ContainsKey(ids_to_sign, *i))
540 ids_to_sign.erase(*i);
542 } else { // All other operation types are some form of "ADD".
543 ids_to_sign.insert(operation.ids.begin(), operation.ids.end());
546 signer_.reset(new InstallSigner(context_->GetRequestContext(), ids_to_sign));
547 signer_->GetSignature(base::Bind(&InstallVerifier::SignatureCallback,
548 weak_factory_.GetWeakPtr()));
551 void InstallVerifier::SaveToPrefs() {
552 if (signature_.get())
553 DCHECK(InstallSigner::VerifySignature(*signature_));
555 if (!signature_.get() || signature_->ids.empty()) {
556 DVLOG(1) << "SaveToPrefs - saving NULL";
557 prefs_->SetInstallSignature(NULL);
558 } else {
559 base::DictionaryValue pref;
560 signature_->ToValue(&pref);
561 if (VLOG_IS_ON(1)) {
562 DVLOG(1) << "SaveToPrefs - saving";
564 DCHECK(InstallSigner::VerifySignature(*signature_.get()));
565 scoped_ptr<InstallSignature> rehydrated =
566 InstallSignature::FromValue(pref);
567 DCHECK(InstallSigner::VerifySignature(*rehydrated.get()));
569 prefs_->SetInstallSignature(&pref);
573 namespace {
575 enum CallbackResult {
576 CALLBACK_NO_SIGNATURE = 0,
577 CALLBACK_INVALID_SIGNATURE,
578 CALLBACK_VALID_SIGNATURE,
580 // This is used in histograms - do not remove or reorder entries above! Also
581 // the "MAX" item below should always be the last element.
583 CALLBACK_RESULT_MAX
586 void GetSignatureResultHistogram(CallbackResult result) {
587 UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.GetSignatureResult",
588 result, CALLBACK_RESULT_MAX);
591 } // namespace
593 void InstallVerifier::SignatureCallback(
594 scoped_ptr<InstallSignature> signature) {
596 linked_ptr<PendingOperation> operation = operation_queue_.front();
597 operation_queue_.pop();
599 bool success = false;
600 if (!signature.get()) {
601 GetSignatureResultHistogram(CALLBACK_NO_SIGNATURE);
602 } else if (!InstallSigner::VerifySignature(*signature)) {
603 GetSignatureResultHistogram(CALLBACK_INVALID_SIGNATURE);
604 } else {
605 GetSignatureResultHistogram(CALLBACK_VALID_SIGNATURE);
606 success = true;
609 if (!success) {
610 OnVerificationComplete(false, operation->type);
612 // TODO(asargent) - if this was something like a network error, we need to
613 // do retries with exponential back off.
614 } else {
615 signature_ = signature.Pass();
616 SaveToPrefs();
618 if (!provisional_.empty()) {
619 // Update |provisional_| to remove ids that were successfully signed.
620 provisional_ = base::STLSetDifference<ExtensionIdSet>(
621 provisional_, signature_->ids);
624 OnVerificationComplete(success, operation->type);
627 if (!operation_queue_.empty())
628 BeginFetch();
631 } // namespace extensions