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 15namespace extensions { 16 17ExtensionInstallChecker::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 27ExtensionInstallChecker::~ExtensionInstallChecker() { 28} 29 30void 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 69void 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 78void 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 89void 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 101void 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 114void 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 126void 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 138void ExtensionInstallChecker::ResetResults() { 139 requirement_errors_.clear(); 140 blacklist_state_ = NOT_BLACKLISTED; 141 policy_allows_load_ = true; 142 policy_error_.clear(); 143} 144 145void 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