d9cbee6ca88885358268c582bff539657e544a3d
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / install_verifier.cc
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.
4
5 #include "chrome/browser/extensions/install_verifier.h"
6
7 #include <algorithm>
8 #include <string>
9
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/common/extensions/manifest_url_handler.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "content/public/browser/browser_context.h"
24 #include "content/public/common/content_switches.h"
25 #include "extensions/browser/extension_prefs.h"
26 #include "extensions/browser/extension_registry.h"
27 #include "extensions/browser/extension_system.h"
28 #include "extensions/browser/pref_names.h"
29 #include "extensions/common/extension_set.h"
30 #include "extensions/common/manifest.h"
31 #include "extensions/common/one_shot_event.h"
32 #include "ui/base/l10n/l10n_util.h"
33
34 namespace extensions {
35
36 namespace {
37
38 enum VerifyStatus {
39   NONE = 0,   // Do not request install signatures, and do not enforce them.
40   BOOTSTRAP,  // Request install signatures, but do not enforce them.
41   ENFORCE,    // Request install signatures, and enforce them.
42   ENFORCE_STRICT,  // Same as ENFORCE, but hard fail if we can't fetch
43                    // signatures.
44
45   // This is used in histograms - do not remove or reorder entries above! Also
46   // the "MAX" item below should always be the last element.
47   VERIFY_STATUS_MAX
48 };
49
50 #if defined(GOOGLE_CHROME_BUILD)
51 const char kExperimentName[] = "ExtensionInstallVerification";
52 #endif  // defined(GOOGLE_CHROME_BUILD)
53
54 VerifyStatus GetExperimentStatus() {
55 #if defined(GOOGLE_CHROME_BUILD)
56   const std::string group = base::FieldTrialList::FindFullName(
57       kExperimentName);
58
59   std::string forced_trials = CommandLine::ForCurrentProcess()->
60       GetSwitchValueASCII(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;
65   }
66
67   VerifyStatus default_status = NONE;
68
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)
80
81   return NONE;
82 }
83
84 VerifyStatus GetCommandLineStatus() {
85   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
86   if (!InstallSigner::GetForcedNotFromWebstore().empty())
87     return ENFORCE;
88
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;
98   }
99
100   return NONE;
101 }
102
103 VerifyStatus GetStatus() {
104   return std::max(GetExperimentStatus(), GetCommandLineStatus());
105 }
106
107 bool ShouldFetchSignature() {
108   return GetStatus() >= BOOTSTRAP;
109 }
110
111 bool ShouldEnforce() {
112   return GetStatus() >= ENFORCE;
113 }
114
115 enum InitResult {
116   INIT_NO_PREF = 0,
117   INIT_UNPARSEABLE_PREF,
118   INIT_INVALID_SIGNATURE,
119   INIT_VALID_SIGNATURE,
120
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.
123
124   INIT_RESULT_MAX
125 };
126
127 void LogInitResultHistogram(InitResult result) {
128   UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.InitResult",
129                             result, INIT_RESULT_MAX);
130 }
131
132 bool CanUseExtensionApis(const Extension& extension) {
133   return extension.is_extension() || extension.is_legacy_packaged_app();
134 }
135
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,
141
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
145 };
146
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;
159
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);
164 }
165
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);
171 }
172
173 }  // namespace
174
175 InstallVerifier::InstallVerifier(ExtensionPrefs* prefs,
176                                  content::BrowserContext* context)
177     : prefs_(prefs),
178       context_(context),
179       bootstrap_check_complete_(false),
180       weak_factory_(this) {
181 }
182
183 InstallVerifier::~InstallVerifier() {}
184
185 // static
186 bool InstallVerifier::NeedsVerification(const Extension& extension) {
187   return IsFromStore(extension) && CanUseExtensionApis(extension);
188 }
189
190
191
192 // static
193 bool InstallVerifier::IsFromStore(const Extension& extension) {
194   if (extension.from_webstore() || ManifestURL::UpdatesFromGallery(&extension))
195     return true;
196
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()));
204 }
205
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);
211
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();
227     }
228   } else {
229     LogInitResultHistogram(INIT_NO_PREF);
230   }
231
232   ExtensionSystem::Get(context_)->ready().Post(
233       FROM_HERE,
234       base::Bind(&InstallVerifier::MaybeBootstrapSelf,
235                  weak_factory_.GetWeakPtr()));
236 }
237
238 void InstallVerifier::VerifyAllExtensions() {
239   AddMany(GetExtensionsToVerify(), ADD_ALL);
240 }
241
242 base::Time InstallVerifier::SignatureTimestamp() {
243   if (signature_.get())
244     return signature_->timestamp;
245   else
246     return base::Time();
247 }
248
249 bool InstallVerifier::IsKnownId(const std::string& id) const {
250   return signature_.get() && (ContainsKey(signature_->ids, id) ||
251                               ContainsKey(signature_->invalid_ids, id));
252 }
253
254 bool InstallVerifier::IsInvalid(const std::string& id) const {
255   return ((signature_.get() && ContainsKey(signature_->invalid_ids, id)));
256 }
257
258 void InstallVerifier::VerifyExtension(const std::string& extension_id) {
259   ExtensionIdSet ids;
260   ids.insert(extension_id);
261   AddMany(ids, ADD_SINGLE);
262 }
263
264 void InstallVerifier::AddMany(const ExtensionIdSet& ids, OperationType type) {
265   if (!ShouldFetchSignature()) {
266     OnVerificationComplete(true, type);  // considered successful.
267     return;
268   }
269
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;
276     }
277   }
278
279   InstallVerifier::PendingOperation* operation =
280       new InstallVerifier::PendingOperation(type);
281   operation->ids.insert(ids.begin(), ids.end());
282
283   operation_queue_.push(linked_ptr<PendingOperation>(operation));
284
285   // If there are no ongoing pending requests, we need to kick one off.
286   if (operation_queue_.size() == 1)
287     BeginFetch();
288 }
289
290 void InstallVerifier::AddProvisional(const ExtensionIdSet& ids) {
291   provisional_.insert(ids.begin(), ids.end());
292   AddMany(ids, ADD_PROVISIONAL);
293 }
294
295 void InstallVerifier::Remove(const std::string& id) {
296   ExtensionIdSet ids;
297   ids.insert(id);
298   RemoveMany(ids);
299 }
300
301 void InstallVerifier::RemoveMany(const ExtensionIdSet& ids) {
302   if (!signature_.get() || !ShouldFetchSignature())
303     return;
304
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;
311     }
312   }
313   if (!found_any)
314     return;
315
316   InstallVerifier::PendingOperation* operation =
317       new InstallVerifier::PendingOperation(InstallVerifier::REMOVE);
318   operation->ids = ids;
319
320   operation_queue_.push(linked_ptr<PendingOperation>(operation));
321   if (operation_queue_.size() == 1)
322     BeginFetch();
323 }
324
325 bool InstallVerifier::AllowedByEnterprisePolicy(const std::string& id) const {
326   return ExtensionManagementFactory::GetForBrowserContext(context_)
327       ->IsInstallationAllowed(id);
328 }
329
330 std::string InstallVerifier::GetDebugPolicyProviderName() const {
331   return std::string("InstallVerifier");
332 }
333
334 namespace {
335
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,
349
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
353 };
354
355 void MustRemainDisabledHistogram(MustRemainDisabledOutcome outcome) {
356   UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.MustRemainDisabled",
357                             outcome, MUST_REMAIN_DISABLED_OUTCOME_MAX);
358 }
359
360 }  // namespace
361
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;
369   }
370   if (Manifest::IsUnpackedLocation(extension->location())) {
371     MustRemainDisabledHistogram(UNPACKED);
372     return false;
373   }
374   if (extension->location() == Manifest::COMPONENT) {
375     MustRemainDisabledHistogram(COMPONENT);
376     return false;
377   }
378   if (AllowedByEnterprisePolicy(extension->id())) {
379     MustRemainDisabledHistogram(ENTERPRISE_POLICY_ALLOWED);
380     return false;
381   }
382
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;
405     }
406   }
407   if (!verified && !ShouldEnforce()) {
408     verified = true;
409     outcome = NOT_VERIFIED_BUT_NOT_ENFORCING;
410   }
411   MustRemainDisabledHistogram(outcome);
412
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));
420   }
421   return !verified;
422 }
423
424 InstallVerifier::PendingOperation::PendingOperation(OperationType type)
425     : type(type) {}
426
427 InstallVerifier::PendingOperation::~PendingOperation() {
428 }
429
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());
439   }
440   return result;
441 }
442
443 void InstallVerifier::MaybeBootstrapSelf() {
444   bool needs_bootstrap = false;
445
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;
456       }
457     }
458   }
459
460   if (needs_bootstrap)
461     AddMany(extension_ids, ADD_ALL_BOOTSTRAP);
462   else
463     bootstrap_check_complete_ = true;
464 }
465
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);
488           }
489         }
490       }
491       if (success || GetStatus() == ENFORCE_STRICT) {
492         ExtensionSystem::Get(context_)
493             ->extension_service()
494             ->CheckManagementPolicy();
495       }
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;
502   }
503 }
504
505 void InstallVerifier::GarbageCollect() {
506   if (!ShouldFetchSignature()) {
507     return;
508   }
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);
520   }
521   if (!leftovers.empty()) {
522     RemoveMany(leftovers);
523   }
524 }
525
526 bool InstallVerifier::IsVerified(const std::string& id) const {
527   return ((signature_.get() && ContainsKey(signature_->ids, id)) ||
528           ContainsKey(provisional_, id));
529 }
530
531 void InstallVerifier::BeginFetch() {
532   DCHECK(ShouldFetchSignature());
533
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();
539
540   ExtensionIdSet ids_to_sign;
541   if (signature_.get()) {
542     ids_to_sign.insert(signature_->ids.begin(), signature_->ids.end());
543   }
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);
549     }
550   } else {  // All other operation types are some form of "ADD".
551     ids_to_sign.insert(operation.ids.begin(), operation.ids.end());
552   }
553
554   signer_.reset(new InstallSigner(context_->GetRequestContext(), ids_to_sign));
555   signer_->GetSignature(base::Bind(&InstallVerifier::SignatureCallback,
556                                    weak_factory_.GetWeakPtr()));
557 }
558
559 void InstallVerifier::SaveToPrefs() {
560   if (signature_.get())
561     DCHECK(InstallSigner::VerifySignature(*signature_));
562
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";
571
572       DCHECK(InstallSigner::VerifySignature(*signature_.get()));
573       scoped_ptr<InstallSignature> rehydrated =
574           InstallSignature::FromValue(pref);
575       DCHECK(InstallSigner::VerifySignature(*rehydrated.get()));
576     }
577     prefs_->SetInstallSignature(&pref);
578   }
579 }
580
581 namespace {
582
583 enum CallbackResult {
584   CALLBACK_NO_SIGNATURE = 0,
585   CALLBACK_INVALID_SIGNATURE,
586   CALLBACK_VALID_SIGNATURE,
587
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.
590
591   CALLBACK_RESULT_MAX
592 };
593
594 void GetSignatureResultHistogram(CallbackResult result) {
595   UMA_HISTOGRAM_ENUMERATION("ExtensionInstallVerifier.GetSignatureResult",
596                             result, CALLBACK_RESULT_MAX);
597 }
598
599 }  // namespace
600
601 void InstallVerifier::SignatureCallback(
602     scoped_ptr<InstallSignature> signature) {
603
604   linked_ptr<PendingOperation> operation = operation_queue_.front();
605   operation_queue_.pop();
606
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;
615   }
616
617   if (!success) {
618     OnVerificationComplete(false, operation->type);
619
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();
625
626     if (!provisional_.empty()) {
627       // Update |provisional_| to remove ids that were successfully signed.
628       provisional_ = base::STLSetDifference<ExtensionIdSet>(
629           provisional_, signature_->ids);
630     }
631
632     OnVerificationComplete(success, operation->type);
633   }
634
635   if (!operation_queue_.empty())
636     BeginFetch();
637 }
638
639 }  // namespace extensions