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 "content/public/browser/web_contents.h"
12#include "content/public/browser/web_ui.h"
13#include "content/public/browser/web_ui_data_source.h"
14#include "grit/generated_resources.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(base::Value::CreateStringValue(
72      base::UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(
73          crx_file, pem_file))));
74  web_ui()->CallJavascriptFunction(
75      "extensions.PackExtensionOverlay.showSuccessMessage", arguments);
76}
77
78void PackExtensionHandler::OnPackFailure(const std::string& error,
79                                         ExtensionCreator::ErrorType type) {
80  if (type == ExtensionCreator::kCRXExists) {
81    base::StringValue error_str(error);
82    base::StringValue extension_path_str(extension_path_.value());
83    base::StringValue key_path_str(private_key_path_.value());
84    base::FundamentalValue overwrite_flag(ExtensionCreator::kOverwriteCRX);
85
86    web_ui()->CallJavascriptFunction(
87        "extensions.ExtensionSettings.askToOverrideWarning",
88        error_str, extension_path_str, key_path_str, overwrite_flag);
89  } else {
90    ShowAlert(error);
91  }
92}
93
94void PackExtensionHandler::FileSelected(const base::FilePath& path, int index,
95                                        void* params) {
96  base::ListValue results;
97  results.Append(base::Value::CreateStringValue(path.value()));
98  web_ui()->CallJavascriptFunction("window.handleFilePathSelected", results);
99}
100
101void PackExtensionHandler::MultiFilesSelected(
102    const std::vector<base::FilePath>& files, void* params) {
103  NOTREACHED();
104}
105
106void PackExtensionHandler::HandlePackMessage(const base::ListValue* args) {
107  DCHECK_EQ(3U, args->GetSize());
108
109  double flags_double = 0.0;
110  base::FilePath::StringType extension_path_str;
111  base::FilePath::StringType private_key_path_str;
112  if (!args->GetString(0, &extension_path_str) ||
113      !args->GetString(1, &private_key_path_str) ||
114      !args->GetDouble(2, &flags_double)) {
115    NOTREACHED();
116    return;
117  }
118
119  extension_path_ = base::FilePath(extension_path_str);
120  private_key_path_ = base::FilePath(private_key_path_str);
121
122  int run_flags = static_cast<int>(flags_double);
123
124  base::FilePath root_directory = extension_path_;
125  base::FilePath key_file = private_key_path_;
126  last_used_path_ = extension_path_;
127
128  if (root_directory.empty()) {
129    if (extension_path_.empty()) {
130      ShowAlert(l10n_util::GetStringUTF8(
131          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED));
132    } else {
133      ShowAlert(l10n_util::GetStringUTF8(
134          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID));
135    }
136
137    return;
138  }
139
140  if (!private_key_path_.empty() && key_file.empty()) {
141    ShowAlert(l10n_util::GetStringUTF8(
142        IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID));
143    return;
144  }
145
146  pack_job_ = new PackExtensionJob(this, root_directory, key_file, run_flags);
147  pack_job_->Start();
148}
149
150void PackExtensionHandler::HandleSelectFilePathMessage(
151    const base::ListValue* args) {
152  DCHECK_EQ(2U, args->GetSize());
153
154  std::string select_type;
155  if (!args->GetString(0, &select_type))
156    NOTREACHED();
157
158  std::string operation;
159  if (!args->GetString(1, &operation))
160    NOTREACHED();
161
162  ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER;
163  ui::SelectFileDialog::FileTypeInfo info;
164  int file_type_index = 0;
165  base::FilePath path_to_use = last_used_path_;
166  if (select_type == "file") {
167    type = ui::SelectFileDialog::SELECT_OPEN_FILE;
168    path_to_use = base::FilePath();
169  }
170
171  base::string16 select_title;
172  if (operation == "load") {
173    select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
174  } else if (operation == "pem") {
175    select_title = l10n_util::GetStringUTF16(
176        IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
177    info.extensions.push_back(std::vector<base::FilePath::StringType>());
178        info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
179        info.extension_description_overrides.push_back(
180            l10n_util::GetStringUTF16(
181                IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
182        info.include_all_files = true;
183    file_type_index = 1;
184  } else {
185    NOTREACHED();
186  }
187
188  load_extension_dialog_ = ui::SelectFileDialog::Create(
189      this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
190  load_extension_dialog_->SelectFile(
191      type,
192      select_title,
193      path_to_use,
194      &info,
195      file_type_index,
196      base::FilePath::StringType(),
197      web_ui()->GetWebContents()->GetTopLevelNativeWindow(),
198      NULL);
199}
200
201void PackExtensionHandler::ShowAlert(const std::string& message) {
202  base::ListValue arguments;
203  arguments.Append(base::Value::CreateStringValue(message));
204  web_ui()->CallJavascriptFunction(
205      "extensions.PackExtensionOverlay.showError", arguments);
206}
207
208}  // namespace extensions
209