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/pack_extension_handler.h"
6
7#include "base/bind.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/extensions/extension_creator.h"
10#include "chrome/browser/ui/chrome_select_file_policy.h"
11#include "chrome/grit/generated_resources.h"
12#include "content/public/browser/web_contents.h"
13#include "content/public/browser/web_ui.h"
14#include "content/public/browser/web_ui_data_source.h"
15#include "ui/base/l10n/l10n_util.h"
16
17namespace extensions {
18
19PackExtensionHandler::PackExtensionHandler() {
20}
21
22PackExtensionHandler::~PackExtensionHandler() {
23  // There may be pending file dialogs, we need to tell them that we've gone
24  // away so they don't try and call back to us.
25  if (load_extension_dialog_.get())
26    load_extension_dialog_->ListenerDestroyed();
27
28  if (pack_job_.get())
29    pack_job_->ClearClient();
30}
31
32void PackExtensionHandler::GetLocalizedValues(
33    content::WebUIDataSource* source) {
34  source->AddString("packExtensionOverlay",
35      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_TITLE));
36  source->AddString("packExtensionHeading",
37      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_HEADING));
38  source->AddString("packExtensionCommit",
39      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_BUTTON));
40  source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK));
41  source->AddString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
42  source->AddString("packExtensionRootDir",
43      l10n_util::GetStringUTF16(
44          IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL));
45  source->AddString("packExtensionPrivateKey",
46      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL));
47  source->AddString("packExtensionBrowseButton",
48      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_BROWSE));
49  source->AddString("packExtensionProceedAnyway",
50      l10n_util::GetStringUTF16(IDS_EXTENSION_PROCEED_ANYWAY));
51  source->AddString("packExtensionWarningTitle",
52      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_WARNING_TITLE));
53  source->AddString("packExtensionErrorTitle",
54      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_ERROR_TITLE));
55}
56
57void PackExtensionHandler::RegisterMessages() {
58  web_ui()->RegisterMessageCallback(
59      "pack",
60      base::Bind(&PackExtensionHandler::HandlePackMessage,
61                 base::Unretained(this)));
62  web_ui()->RegisterMessageCallback(
63      "packExtensionSelectFilePath",
64      base::Bind(&PackExtensionHandler::HandleSelectFilePathMessage,
65                 base::Unretained(this)));
66}
67
68void PackExtensionHandler::OnPackSuccess(const base::FilePath& crx_file,
69                                         const base::FilePath& pem_file) {
70  base::ListValue arguments;
71  arguments.Append(new base::StringValue(base::UTF16ToUTF8(
72      PackExtensionJob::StandardSuccessMessage(crx_file, pem_file))));
73  web_ui()->CallJavascriptFunction(
74      "extensions.PackExtensionOverlay.showSuccessMessage", arguments);
75}
76
77void PackExtensionHandler::OnPackFailure(const std::string& error,
78                                         ExtensionCreator::ErrorType type) {
79  if (type == ExtensionCreator::kCRXExists) {
80    base::StringValue error_str(error);
81    base::StringValue extension_path_str(extension_path_.value());
82    base::StringValue key_path_str(private_key_path_.value());
83    base::FundamentalValue overwrite_flag(ExtensionCreator::kOverwriteCRX);
84
85    web_ui()->CallJavascriptFunction(
86        "extensions.ExtensionSettings.askToOverrideWarning",
87        error_str, extension_path_str, key_path_str, overwrite_flag);
88  } else {
89    ShowAlert(error);
90  }
91}
92
93void PackExtensionHandler::FileSelected(const base::FilePath& path, int index,
94                                        void* params) {
95  base::ListValue results;
96  results.Append(new base::StringValue(path.value()));
97  web_ui()->CallJavascriptFunction("window.handleFilePathSelected", results);
98}
99
100void PackExtensionHandler::MultiFilesSelected(
101    const std::vector<base::FilePath>& files, void* params) {
102  NOTREACHED();
103}
104
105void PackExtensionHandler::HandlePackMessage(const base::ListValue* args) {
106  DCHECK_EQ(3U, args->GetSize());
107
108  double flags_double = 0.0;
109  base::FilePath::StringType extension_path_str;
110  base::FilePath::StringType private_key_path_str;
111  if (!args->GetString(0, &extension_path_str) ||
112      !args->GetString(1, &private_key_path_str) ||
113      !args->GetDouble(2, &flags_double)) {
114    NOTREACHED();
115    return;
116  }
117
118  extension_path_ = base::FilePath(extension_path_str);
119  private_key_path_ = base::FilePath(private_key_path_str);
120
121  int run_flags = static_cast<int>(flags_double);
122
123  base::FilePath root_directory = extension_path_;
124  base::FilePath key_file = private_key_path_;
125  last_used_path_ = extension_path_;
126
127  if (root_directory.empty()) {
128    if (extension_path_.empty()) {
129      ShowAlert(l10n_util::GetStringUTF8(
130          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED));
131    } else {
132      ShowAlert(l10n_util::GetStringUTF8(
133          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID));
134    }
135
136    return;
137  }
138
139  if (!private_key_path_.empty() && key_file.empty()) {
140    ShowAlert(l10n_util::GetStringUTF8(
141        IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID));
142    return;
143  }
144
145  pack_job_ = new PackExtensionJob(this, root_directory, key_file, run_flags);
146  pack_job_->Start();
147}
148
149void PackExtensionHandler::HandleSelectFilePathMessage(
150    const base::ListValue* args) {
151  DCHECK_EQ(2U, args->GetSize());
152
153  std::string select_type;
154  if (!args->GetString(0, &select_type))
155    NOTREACHED();
156
157  std::string operation;
158  if (!args->GetString(1, &operation))
159    NOTREACHED();
160
161  ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER;
162  ui::SelectFileDialog::FileTypeInfo info;
163  int file_type_index = 0;
164  base::FilePath path_to_use = last_used_path_;
165  if (select_type == "file") {
166    type = ui::SelectFileDialog::SELECT_OPEN_FILE;
167    path_to_use = base::FilePath();
168  }
169
170  base::string16 select_title;
171  if (operation == "load") {
172    select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
173  } else if (operation == "pem") {
174    select_title = l10n_util::GetStringUTF16(
175        IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
176    info.extensions.push_back(std::vector<base::FilePath::StringType>());
177        info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
178        info.extension_description_overrides.push_back(
179            l10n_util::GetStringUTF16(
180                IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
181        info.include_all_files = true;
182    file_type_index = 1;
183  } else {
184    NOTREACHED();
185  }
186
187  load_extension_dialog_ = ui::SelectFileDialog::Create(
188      this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
189  load_extension_dialog_->SelectFile(
190      type,
191      select_title,
192      path_to_use,
193      &info,
194      file_type_index,
195      base::FilePath::StringType(),
196      web_ui()->GetWebContents()->GetTopLevelNativeWindow(),
197      NULL);
198}
199
200void PackExtensionHandler::ShowAlert(const std::string& message) {
201  base::ListValue arguments;
202  arguments.Append(new base::StringValue(message));
203  web_ui()->CallJavascriptFunction(
204      "extensions.PackExtensionOverlay.showError", arguments);
205}
206
207}  // namespace extensions
208