Home | History | Annotate | Download | only in extensions
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/extension_install_checker.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "chrome/browser/extensions/blacklist.h"
      9 #include "chrome/browser/extensions/requirements_checker.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "content/public/browser/browser_thread.h"
     12 #include "extensions/browser/extension_system.h"
     13 #include "extensions/browser/management_policy.h"
     14 
     15 namespace extensions {
     16 
     17 ExtensionInstallChecker::ExtensionInstallChecker(Profile* profile)
     18     : profile_(profile),
     19       blacklist_state_(NOT_BLACKLISTED),
     20       policy_allows_load_(true),
     21       current_sequence_number_(0),
     22       running_checks_(0),
     23       fail_fast_(false),
     24       weak_ptr_factory_(this) {
     25 }
     26 
     27 ExtensionInstallChecker::~ExtensionInstallChecker() {
     28 }
     29 
     30 void ExtensionInstallChecker::Start(int enabled_checks,
     31                                     bool fail_fast,
     32                                     const Callback& callback) {
     33   // Profile is null in tests.
     34   if (profile_) {
     35     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     36     if (!extension_.get()) {
     37       NOTREACHED();
     38       return;
     39     }
     40   }
     41 
     42   if (is_running() || !enabled_checks || callback.is_null()) {
     43     NOTREACHED();
     44     return;
     45   }
     46 
     47   running_checks_ = enabled_checks;
     48   fail_fast_ = fail_fast;
     49   callback_ = callback;
     50   ResetResults();
     51 
     52   // Execute the management policy check first as it is synchronous.
     53   if (enabled_checks & CHECK_MANAGEMENT_POLICY) {
     54     CheckManagementPolicy();
     55     if (!is_running())
     56       return;
     57   }
     58 
     59   if (enabled_checks & CHECK_REQUIREMENTS) {
     60     CheckRequirements();
     61     if (!is_running())
     62       return;
     63   }
     64 
     65   if (enabled_checks & CHECK_BLACKLIST)
     66     CheckBlacklistState();
     67 }
     68 
     69 void ExtensionInstallChecker::CheckManagementPolicy() {
     70   DCHECK(extension_.get());
     71 
     72   base::string16 error;
     73   bool allow = ExtensionSystem::Get(profile_)->management_policy()->UserMayLoad(
     74       extension_.get(), &error);
     75   OnManagementPolicyCheckDone(allow, base::UTF16ToUTF8(error));
     76 }
     77 
     78 void ExtensionInstallChecker::OnManagementPolicyCheckDone(
     79     bool allows_load,
     80     const std::string& error) {
     81   policy_allows_load_ = allows_load;
     82   policy_error_ = error;
     83   DCHECK(policy_allows_load_ || !policy_error_.empty());
     84 
     85   running_checks_ &= ~CHECK_MANAGEMENT_POLICY;
     86   MaybeInvokeCallback();
     87 }
     88 
     89 void ExtensionInstallChecker::CheckRequirements() {
     90   DCHECK(extension_.get());
     91 
     92   if (!requirements_checker_.get())
     93     requirements_checker_.reset(new RequirementsChecker());
     94   requirements_checker_->Check(
     95       extension_,
     96       base::Bind(&ExtensionInstallChecker::OnRequirementsCheckDone,
     97                  weak_ptr_factory_.GetWeakPtr(),
     98                  current_sequence_number_));
     99 }
    100 
    101 void ExtensionInstallChecker::OnRequirementsCheckDone(
    102     int sequence_number,
    103     std::vector<std::string> errors) {
    104   // Some pending results may arrive after fail fast.
    105   if (sequence_number != current_sequence_number_)
    106     return;
    107 
    108   requirement_errors_ = errors;
    109 
    110   running_checks_ &= ~CHECK_REQUIREMENTS;
    111   MaybeInvokeCallback();
    112 }
    113 
    114 void ExtensionInstallChecker::CheckBlacklistState() {
    115   DCHECK(extension_.get());
    116 
    117   extensions::Blacklist* blacklist =
    118       ExtensionSystem::Get(profile_)->blacklist();
    119   blacklist->IsBlacklisted(
    120       extension_->id(),
    121       base::Bind(&ExtensionInstallChecker::OnBlacklistStateCheckDone,
    122                  weak_ptr_factory_.GetWeakPtr(),
    123                  current_sequence_number_));
    124 }
    125 
    126 void ExtensionInstallChecker::OnBlacklistStateCheckDone(int sequence_number,
    127                                                         BlacklistState state) {
    128   // Some pending results may arrive after fail fast.
    129   if (sequence_number != current_sequence_number_)
    130     return;
    131 
    132   blacklist_state_ = state;
    133 
    134   running_checks_ &= ~CHECK_BLACKLIST;
    135   MaybeInvokeCallback();
    136 }
    137 
    138 void ExtensionInstallChecker::ResetResults() {
    139   requirement_errors_.clear();
    140   blacklist_state_ = NOT_BLACKLISTED;
    141   policy_allows_load_ = true;
    142   policy_error_.clear();
    143 }
    144 
    145 void ExtensionInstallChecker::MaybeInvokeCallback() {
    146   if (callback_.is_null())
    147     return;
    148 
    149   // Set bits for failed checks.
    150   int failed_mask = 0;
    151   if (blacklist_state_ == BLACKLISTED_MALWARE)
    152     failed_mask |= CHECK_BLACKLIST;
    153   if (!requirement_errors_.empty())
    154     failed_mask |= CHECK_REQUIREMENTS;
    155   if (!policy_allows_load_)
    156     failed_mask |= CHECK_MANAGEMENT_POLICY;
    157 
    158   // Invoke callback if all checks are complete or there was at least one
    159   // failure and |fail_fast_| is true.
    160   if (!is_running() || (failed_mask && fail_fast_)) {
    161     // If we are failing fast, discard any pending results.
    162     weak_ptr_factory_.InvalidateWeakPtrs();
    163     running_checks_ = 0;
    164     ++current_sequence_number_;
    165 
    166     Callback callback_copy = callback_;
    167     callback_.Reset();
    168 
    169     // This instance may be owned by the callback recipient and deleted here,
    170     // so reset |callback_| first and invoke a copy of the callback.
    171     callback_copy.Run(failed_mask);
    172   }
    173 }
    174 
    175 }  // namespace extensions
    176