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