1 // Copyright (c) 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/unpacked_installer.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "base/command_line.h" 10 #include "base/file_util.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/threading/thread_restrictions.h" 14 #include "chrome/browser/extensions/extension_error_reporter.h" 15 #include "chrome/browser/extensions/extension_install_prompt.h" 16 #include "chrome/browser/extensions/extension_install_ui.h" 17 #include "chrome/browser/extensions/extension_service.h" 18 #include "chrome/browser/extensions/permissions_updater.h" 19 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/common/chrome_switches.h" 21 #include "chrome/common/extensions/api/plugins/plugins_handler.h" 22 #include "content/public/browser/browser_thread.h" 23 #include "extensions/browser/extension_prefs.h" 24 #include "extensions/browser/extension_registry.h" 25 #include "extensions/browser/install_flag.h" 26 #include "extensions/common/extension.h" 27 #include "extensions/common/extension_l10n_util.h" 28 #include "extensions/common/file_util.h" 29 #include "extensions/common/id_util.h" 30 #include "extensions/common/manifest.h" 31 #include "sync/api/string_ordinal.h" 32 33 using content::BrowserThread; 34 using extensions::Extension; 35 36 namespace { 37 38 const char kUnpackedExtensionsBlacklistedError[] = 39 "Loading of unpacked extensions is disabled by the administrator."; 40 41 // Manages an ExtensionInstallPrompt for a particular extension. 42 class SimpleExtensionLoadPrompt : public ExtensionInstallPrompt::Delegate { 43 public: 44 SimpleExtensionLoadPrompt(const Extension* extension, 45 Profile* profile, 46 const base::Closure& callback); 47 virtual ~SimpleExtensionLoadPrompt(); 48 49 void ShowPrompt(); 50 51 // ExtensionInstallUI::Delegate 52 virtual void InstallUIProceed() OVERRIDE; 53 virtual void InstallUIAbort(bool user_initiated) OVERRIDE; 54 55 private: 56 scoped_ptr<ExtensionInstallPrompt> install_ui_; 57 scoped_refptr<const Extension> extension_; 58 base::Closure callback_; 59 }; 60 61 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt( 62 const Extension* extension, 63 Profile* profile, 64 const base::Closure& callback) 65 : install_ui_(ExtensionInstallUI::CreateInstallPromptWithProfile( 66 profile)), 67 extension_(extension), 68 callback_(callback) { 69 } 70 71 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() { 72 } 73 74 void SimpleExtensionLoadPrompt::ShowPrompt() { 75 std::string confirm = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 76 switches::kAppsGalleryInstallAutoConfirmForTests); 77 if (confirm == "accept") { 78 InstallUIProceed(); 79 return; 80 } 81 if (confirm == "cancel") { 82 InstallUIAbort(false); 83 return; 84 } 85 86 install_ui_->ConfirmInstall( 87 this, 88 extension_.get(), 89 ExtensionInstallPrompt::GetDefaultShowDialogCallback()); 90 } 91 92 void SimpleExtensionLoadPrompt::InstallUIProceed() { 93 callback_.Run(); 94 delete this; 95 } 96 97 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) { 98 delete this; 99 } 100 101 } // namespace 102 103 namespace extensions { 104 105 // static 106 scoped_refptr<UnpackedInstaller> UnpackedInstaller::Create( 107 ExtensionService* extension_service) { 108 DCHECK(extension_service); 109 return scoped_refptr<UnpackedInstaller>( 110 new UnpackedInstaller(extension_service)); 111 } 112 113 UnpackedInstaller::UnpackedInstaller(ExtensionService* extension_service) 114 : service_weak_(extension_service->AsWeakPtr()), 115 prompt_for_plugins_(true), 116 require_modern_manifest_version_(true), 117 be_noisy_on_failure_(true), 118 installer_(extension_service->profile()) { 119 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 120 } 121 122 UnpackedInstaller::~UnpackedInstaller() { 123 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || 124 BrowserThread::CurrentlyOn(BrowserThread::FILE)); 125 } 126 127 void UnpackedInstaller::Load(const base::FilePath& path_in) { 128 DCHECK(extension_path_.empty()); 129 extension_path_ = path_in; 130 BrowserThread::PostTask( 131 BrowserThread::FILE, 132 FROM_HERE, 133 base::Bind(&UnpackedInstaller::GetAbsolutePath, this)); 134 } 135 136 bool UnpackedInstaller::LoadFromCommandLine(const base::FilePath& path_in, 137 std::string* extension_id) { 138 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 139 DCHECK(extension_path_.empty()); 140 141 if (!service_weak_.get()) 142 return false; 143 // Load extensions from the command line synchronously to avoid a race 144 // between extension loading and loading an URL from the command line. 145 base::ThreadRestrictions::ScopedAllowIO allow_io; 146 147 extension_path_ = base::MakeAbsoluteFilePath(path_in); 148 149 if (!IsLoadingUnpackedAllowed()) { 150 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError); 151 return false; 152 } 153 154 std::string error; 155 installer_.set_extension( 156 file_util::LoadExtension( 157 extension_path_, Manifest::COMMAND_LINE, GetFlags(), &error).get()); 158 159 if (!installer_.extension().get() || 160 !extension_l10n_util::ValidateExtensionLocales( 161 extension_path_, 162 installer_.extension()->manifest()->value(), 163 &error)) { 164 ReportExtensionLoadError(error); 165 return false; 166 } 167 168 ShowInstallPrompt(); 169 170 *extension_id = installer_.extension()->id(); 171 return true; 172 } 173 174 void UnpackedInstaller::ShowInstallPrompt() { 175 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 176 if (!service_weak_.get()) 177 return; 178 179 const ExtensionSet& disabled_extensions = 180 ExtensionRegistry::Get(service_weak_->profile())->disabled_extensions(); 181 if (service_weak_->show_extensions_prompts() && prompt_for_plugins_ && 182 PluginInfo::HasPlugins(installer_.extension().get()) && 183 !disabled_extensions.Contains(installer_.extension()->id())) { 184 SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt( 185 installer_.extension().get(), 186 installer_.profile(), 187 base::Bind(&UnpackedInstaller::CallCheckRequirements, this)); 188 prompt->ShowPrompt(); 189 return; 190 } 191 CallCheckRequirements(); 192 } 193 194 void UnpackedInstaller::CallCheckRequirements() { 195 installer_.CheckRequirements( 196 base::Bind(&UnpackedInstaller::OnRequirementsChecked, this)); 197 } 198 199 void UnpackedInstaller::OnRequirementsChecked( 200 std::vector<std::string> requirement_errors) { 201 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 202 203 if (!requirement_errors.empty()) { 204 ReportExtensionLoadError(JoinString(requirement_errors, ' ')); 205 return; 206 } 207 208 ConfirmInstall(); 209 } 210 211 int UnpackedInstaller::GetFlags() { 212 std::string id = id_util::GenerateIdForPath(extension_path_); 213 bool allow_file_access = 214 Manifest::ShouldAlwaysAllowFileAccess(Manifest::UNPACKED); 215 ExtensionPrefs* prefs = ExtensionPrefs::Get(service_weak_->profile()); 216 if (prefs->HasAllowFileAccessSetting(id)) 217 allow_file_access = prefs->AllowFileAccess(id); 218 219 int result = Extension::FOLLOW_SYMLINKS_ANYWHERE; 220 if (allow_file_access) 221 result |= Extension::ALLOW_FILE_ACCESS; 222 if (require_modern_manifest_version_) 223 result |= Extension::REQUIRE_MODERN_MANIFEST_VERSION; 224 225 return result; 226 } 227 228 bool UnpackedInstaller::IsLoadingUnpackedAllowed() const { 229 if (!service_weak_.get()) 230 return true; 231 // If there is a "*" in the extension blacklist, then no extensions should be 232 // allowed at all (except explicitly whitelisted extensions). 233 ExtensionPrefs* prefs = ExtensionPrefs::Get(service_weak_->profile()); 234 return !prefs->ExtensionsBlacklistedByDefault(); 235 } 236 237 void UnpackedInstaller::GetAbsolutePath() { 238 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 239 240 extension_path_ = base::MakeAbsoluteFilePath(extension_path_); 241 242 std::string error; 243 if (!file_util::CheckForIllegalFilenames(extension_path_, &error)) { 244 BrowserThread::PostTask( 245 BrowserThread::UI, 246 FROM_HERE, 247 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error)); 248 return; 249 } 250 BrowserThread::PostTask( 251 BrowserThread::UI, FROM_HERE, 252 base::Bind(&UnpackedInstaller::CheckExtensionFileAccess, this)); 253 } 254 255 void UnpackedInstaller::CheckExtensionFileAccess() { 256 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 257 if (!service_weak_.get()) 258 return; 259 260 if (!IsLoadingUnpackedAllowed()) { 261 ReportExtensionLoadError(kUnpackedExtensionsBlacklistedError); 262 return; 263 } 264 265 BrowserThread::PostTask( 266 BrowserThread::FILE, 267 FROM_HERE, 268 base::Bind(&UnpackedInstaller::LoadWithFileAccess, this, GetFlags())); 269 } 270 271 void UnpackedInstaller::LoadWithFileAccess(int flags) { 272 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 273 274 std::string error; 275 installer_.set_extension( 276 file_util::LoadExtension( 277 extension_path_, Manifest::UNPACKED, flags, &error).get()); 278 279 if (!installer_.extension().get() || 280 !extension_l10n_util::ValidateExtensionLocales( 281 extension_path_, 282 installer_.extension()->manifest()->value(), 283 &error)) { 284 BrowserThread::PostTask( 285 BrowserThread::UI, 286 FROM_HERE, 287 base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error)); 288 return; 289 } 290 291 BrowserThread::PostTask( 292 BrowserThread::UI, 293 FROM_HERE, 294 base::Bind(&UnpackedInstaller::ShowInstallPrompt, this)); 295 } 296 297 void UnpackedInstaller::ReportExtensionLoadError(const std::string &error) { 298 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 299 if (!on_failure_callback_.is_null()) 300 on_failure_callback_.Run(extension_path_, error); 301 302 if (service_weak_.get()) { 303 ExtensionErrorReporter::GetInstance()->ReportLoadError( 304 extension_path_, 305 error, 306 service_weak_->profile(), 307 be_noisy_on_failure_); 308 } 309 } 310 311 void UnpackedInstaller::ConfirmInstall() { 312 DCHECK_CURRENTLY_ON(BrowserThread::UI); 313 base::string16 error = installer_.CheckManagementPolicy(); 314 if (!error.empty()) { 315 ReportExtensionLoadError(base::UTF16ToUTF8(error)); 316 return; 317 } 318 319 PermissionsUpdater perms_updater(service_weak_->profile()); 320 perms_updater.GrantActivePermissions(installer_.extension().get()); 321 322 service_weak_->OnExtensionInstalled(installer_.extension().get(), 323 syncer::StringOrdinal(), 324 kInstallFlagInstallImmediately); 325 } 326 327 } // namespace extensions 328