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