1 // Copyright (c) 2012 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/ui/webui/extensions/install_extension_handler.h"
6
7 #include "base/bind.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/extensions/crx_installer.h"
11 #include "chrome/browser/extensions/extension_install_prompt.h"
12 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/unpacked_installer.h"
14 #include "chrome/browser/extensions/zipfile_installer.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/browser/web_ui.h"
19 #include "content/public/browser/web_ui_data_source.h"
20 #include "content/public/common/drop_data.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/common/feature_switch.h"
23 #include "net/base/filename_util.h"
24 #include "ui/base/l10n/l10n_util.h"
25
26 namespace extensions {
27
InstallExtensionHandler()28 InstallExtensionHandler::InstallExtensionHandler() {
29 }
30
~InstallExtensionHandler()31 InstallExtensionHandler::~InstallExtensionHandler() {
32 }
33
GetLocalizedValues(content::WebUIDataSource * source)34 void InstallExtensionHandler::GetLocalizedValues(
35 content::WebUIDataSource* source) {
36 source->AddString(
37 "extensionSettingsInstallDropTarget",
38 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALL_DROP_TARGET));
39 source->AddBoolean(
40 "offStoreInstallEnabled",
41 FeatureSwitch::easy_off_store_install()->IsEnabled());
42 }
43
RegisterMessages()44 void InstallExtensionHandler::RegisterMessages() {
45 web_ui()->RegisterMessageCallback(
46 "startDrag",
47 base::Bind(&InstallExtensionHandler::HandleStartDragMessage,
48 base::Unretained(this)));
49 web_ui()->RegisterMessageCallback(
50 "stopDrag",
51 base::Bind(&InstallExtensionHandler::HandleStopDragMessage,
52 base::Unretained(this)));
53 web_ui()->RegisterMessageCallback(
54 "installDroppedFile",
55 base::Bind(&InstallExtensionHandler::HandleInstallMessage,
56 base::Unretained(this)));
57 web_ui()->RegisterMessageCallback(
58 "installDroppedDirectory",
59 base::Bind(&InstallExtensionHandler::HandleInstallDirectoryMessage,
60 base::Unretained(this)));
61 }
62
HandleStartDragMessage(const base::ListValue * args)63 void InstallExtensionHandler::HandleStartDragMessage(
64 const base::ListValue* args) {
65 content::DropData* drop_data =
66 web_ui()->GetWebContents()->GetDropData();
67 if (!drop_data) {
68 DLOG(ERROR) << "No current drop data.";
69 return;
70 }
71
72 if (drop_data->filenames.empty()) {
73 DLOG(ERROR) << "Current drop data contains no files.";
74 return;
75 }
76
77 const ui::FileInfo& file_info = drop_data->filenames.front();
78
79 file_to_install_ = file_info.path;
80 // Use the display name if provided, for checking file names
81 // (.path is likely a random hash value in that case).
82 // TODO(dcheng): It would be nice to make this a FilePath too.
83 file_display_name_ = file_info.display_name.empty()
84 ? file_info.path.AsUTF16Unsafe()
85 : file_info.display_name.AsUTF16Unsafe();
86 }
87
HandleStopDragMessage(const base::ListValue * args)88 void InstallExtensionHandler::HandleStopDragMessage(
89 const base::ListValue* args) {
90 file_to_install_.clear();
91 file_display_name_.clear();
92 }
93
HandleInstallMessage(const base::ListValue * args)94 void InstallExtensionHandler::HandleInstallMessage(
95 const base::ListValue* args) {
96 if (file_to_install_.empty()) {
97 LOG(ERROR) << "No file captured to install.";
98 return;
99 }
100
101 Profile* profile = Profile::FromBrowserContext(
102 web_ui()->GetWebContents()->GetBrowserContext());
103
104 const bool kCaseSensitive = false;
105
106 if (EndsWith(
107 file_display_name_, base::ASCIIToUTF16(".zip"), kCaseSensitive)) {
108 ZipFileInstaller::Create(ExtensionSystem::Get(profile)->extension_service())
109 ->LoadFromZipFile(file_to_install_);
110 } else {
111 scoped_ptr<ExtensionInstallPrompt> prompt(
112 new ExtensionInstallPrompt(web_ui()->GetWebContents()));
113 scoped_refptr<CrxInstaller> crx_installer(CrxInstaller::Create(
114 ExtensionSystem::Get(profile)->extension_service(), prompt.Pass()));
115 crx_installer->set_error_on_unsupported_requirements(true);
116 crx_installer->set_off_store_install_allow_reason(
117 CrxInstaller::OffStoreInstallAllowedFromSettingsPage);
118 crx_installer->set_install_immediately(true);
119
120 if (EndsWith(file_display_name_,
121 base::ASCIIToUTF16(".user.js"),
122 kCaseSensitive)) {
123 crx_installer->InstallUserScript(
124 file_to_install_, net::FilePathToFileURL(file_to_install_));
125 } else if (EndsWith(file_display_name_,
126 base::ASCIIToUTF16(".crx"),
127 kCaseSensitive)) {
128 crx_installer->InstallCrx(file_to_install_);
129 } else {
130 CHECK(false);
131 }
132 }
133
134 file_to_install_.clear();
135 file_display_name_.clear();
136 }
137
HandleInstallDirectoryMessage(const base::ListValue * args)138 void InstallExtensionHandler::HandleInstallDirectoryMessage(
139 const base::ListValue* args) {
140 Profile* profile = Profile::FromBrowserContext(
141 web_ui()->GetWebContents()->GetBrowserContext());
142 UnpackedInstaller::Create(
143 ExtensionSystem::Get(profile)->
144 extension_service())->Load(file_to_install_);
145 }
146
147 } // namespace extensions
148