1 // Copyright (c) 2011 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/crypto_module_password_dialog.h"
6
7 #include <gtk/gtk.h>
8
9 #include "base/basictypes.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/task.h"
12 #include "base/utf_string_conversions.h"
13 #include "crypto/crypto_module_blocking_password_delegate.h"
14 #include "chrome/browser/ui/gtk/gtk_util.h"
15 #include "content/browser/browser_thread.h"
16 #include "googleurl/src/gurl.h"
17 #include "grit/generated_resources.h"
18 #include "ui/base/gtk/gtk_signal.h"
19 #include "ui/base/l10n/l10n_util.h"
20
21 namespace {
22
23 class CryptoModuleBlockingDialogDelegate
24 : public crypto::CryptoModuleBlockingPasswordDelegate {
25 public:
CryptoModuleBlockingDialogDelegate(browser::CryptoModulePasswordReason reason,const std::string & server)26 CryptoModuleBlockingDialogDelegate(browser::CryptoModulePasswordReason reason,
27 const std::string& server)
28 : event_(false, false),
29 reason_(reason),
30 server_(server),
31 password_(),
32 cancelled_(false) {
33 }
34
~CryptoModuleBlockingDialogDelegate()35 ~CryptoModuleBlockingDialogDelegate() {
36 password_.replace(0, password_.size(), password_.size(), 0);
37 }
38
39 // crypto::CryptoModuleBlockingDialogDelegate implementation.
RequestPassword(const std::string & slot_name,bool retry,bool * cancelled)40 virtual std::string RequestPassword(const std::string& slot_name, bool retry,
41 bool* cancelled) {
42 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
43 DCHECK(!event_.IsSignaled());
44 event_.Reset();
45 if (BrowserThread::PostTask(
46 BrowserThread::UI, FROM_HERE,
47 NewRunnableMethod(this,
48 &CryptoModuleBlockingDialogDelegate::ShowDialog,
49 slot_name,
50 retry))) {
51 event_.Wait();
52 }
53 *cancelled = cancelled_;
54 return password_;
55 }
56
57 private:
ShowDialog(const std::string & slot_name,bool retry)58 void ShowDialog(const std::string& slot_name, bool retry) {
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
60 ShowCryptoModulePasswordDialog(
61 slot_name, retry, reason_, server_,
62 NewCallback(this, &CryptoModuleBlockingDialogDelegate::GotPassword));
63 }
GotPassword(const char * password)64 void GotPassword(const char* password) {
65 if (password)
66 password_ = password;
67 else
68 cancelled_ = true;
69 event_.Signal();
70 }
71 base::WaitableEvent event_;
72 browser::CryptoModulePasswordReason reason_;
73 std::string server_;
74 std::string password_;
75 bool cancelled_;
76
77 DISALLOW_COPY_AND_ASSIGN(CryptoModuleBlockingDialogDelegate);
78 };
79
80 // TODO(mattm): change into a constrained dialog.
81 class CryptoModulePasswordDialog {
82 public:
83 CryptoModulePasswordDialog(const std::string& slot_name,
84 bool retry,
85 browser::CryptoModulePasswordReason reason,
86 const std::string& server,
87 browser::CryptoModulePasswordCallback* callback);
88
89 void Show();
90
91 private:
92 CHROMEGTK_CALLBACK_1(CryptoModulePasswordDialog, void, OnResponse, int);
93 CHROMEGTK_CALLBACK_0(CryptoModulePasswordDialog, void, OnWindowDestroy);
94
95 scoped_ptr<browser::CryptoModulePasswordCallback> callback_;
96
97 GtkWidget* dialog_;
98 GtkWidget* password_entry_;
99
100 DISALLOW_COPY_AND_ASSIGN(CryptoModulePasswordDialog);
101 };
102
CryptoModulePasswordDialog(const std::string & slot_name,bool retry,browser::CryptoModulePasswordReason reason,const std::string & server,browser::CryptoModulePasswordCallback * callback)103 CryptoModulePasswordDialog::CryptoModulePasswordDialog(
104 const std::string& slot_name,
105 bool retry,
106 browser::CryptoModulePasswordReason reason,
107 const std::string& server,
108 browser::CryptoModulePasswordCallback* callback)
109 : callback_(callback) {
110 dialog_ = gtk_dialog_new_with_buttons(
111 l10n_util::GetStringUTF8(IDS_CRYPTO_MODULE_AUTH_DIALOG_TITLE).c_str(),
112 NULL,
113 GTK_DIALOG_NO_SEPARATOR,
114 NULL); // Populate the buttons later, for control over the OK button.
115 gtk_dialog_add_button(GTK_DIALOG(dialog_),
116 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
117 GtkWidget* ok_button = gtk_util::AddButtonToDialog(
118 dialog_,
119 l10n_util::GetStringUTF8(
120 IDS_CRYPTO_MODULE_AUTH_DIALOG_OK_BUTTON_LABEL).c_str(),
121 GTK_STOCK_OK,
122 GTK_RESPONSE_ACCEPT);
123 GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT);
124 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);
125
126 // Select an appropriate text for the reason.
127 std::string text;
128 const string16& server16 = UTF8ToUTF16(server);
129 const string16& slot16 = UTF8ToUTF16(slot_name);
130 switch (reason) {
131 case browser::kCryptoModulePasswordKeygen:
132 text = l10n_util::GetStringFUTF8(
133 IDS_CRYPTO_MODULE_AUTH_DIALOG_TEXT_KEYGEN, slot16, server16);
134 break;
135 case browser::kCryptoModulePasswordCertEnrollment:
136 text = l10n_util::GetStringFUTF8(
137 IDS_CRYPTO_MODULE_AUTH_DIALOG_TEXT_CERT_ENROLLMENT, slot16, server16);
138 break;
139 case browser::kCryptoModulePasswordClientAuth:
140 text = l10n_util::GetStringFUTF8(
141 IDS_CRYPTO_MODULE_AUTH_DIALOG_TEXT_CLIENT_AUTH, slot16, server16);
142 break;
143 case browser::kCryptoModulePasswordListCerts:
144 text = l10n_util::GetStringFUTF8(
145 IDS_CRYPTO_MODULE_AUTH_DIALOG_TEXT_LIST_CERTS, slot16);
146 break;
147 case browser::kCryptoModulePasswordCertImport:
148 text = l10n_util::GetStringFUTF8(
149 IDS_CRYPTO_MODULE_AUTH_DIALOG_TEXT_CERT_IMPORT, slot16);
150 break;
151 case browser::kCryptoModulePasswordCertExport:
152 text = l10n_util::GetStringFUTF8(
153 IDS_CRYPTO_MODULE_AUTH_DIALOG_TEXT_CERT_EXPORT, slot16);
154 break;
155 default:
156 NOTREACHED();
157 }
158 GtkWidget* label = gtk_label_new(text.c_str());
159 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
160 gtk_util::LeftAlignMisc(label);
161 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), label,
162 FALSE, FALSE, 0);
163
164 password_entry_ = gtk_entry_new();
165 gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
166 gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);
167
168 GtkWidget* password_box = gtk_hbox_new(FALSE, gtk_util::kLabelSpacing);
169 gtk_box_pack_start(GTK_BOX(password_box),
170 gtk_label_new(l10n_util::GetStringUTF8(
171 IDS_CRYPTO_MODULE_AUTH_DIALOG_PASSWORD_FIELD).c_str()),
172 FALSE, FALSE, 0);
173 gtk_box_pack_start(GTK_BOX(password_box), password_entry_,
174 TRUE, TRUE, 0);
175
176 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), password_box,
177 FALSE, FALSE, 0);
178
179 g_signal_connect(dialog_, "response",
180 G_CALLBACK(OnResponseThunk), this);
181 g_signal_connect(dialog_, "destroy",
182 G_CALLBACK(OnWindowDestroyThunk), this);
183 }
184
Show()185 void CryptoModulePasswordDialog::Show() {
186 gtk_util::ShowDialog(dialog_);
187 }
188
OnResponse(GtkWidget * dialog,int response_id)189 void CryptoModulePasswordDialog::OnResponse(GtkWidget* dialog,
190 int response_id) {
191 if (response_id == GTK_RESPONSE_ACCEPT)
192 callback_->Run(gtk_entry_get_text(GTK_ENTRY(password_entry_)));
193 else
194 callback_->Run(static_cast<const char*>(NULL));
195
196 // This will cause gtk to zero out the buffer. (see
197 // gtk_entry_buffer_normal_delete_text:
198 // http://git.gnome.org/browse/gtk+/tree/gtk/gtkentrybuffer.c#n187)
199 gtk_editable_delete_text(GTK_EDITABLE(password_entry_), 0, -1);
200 gtk_widget_destroy(dialog_);
201 }
202
OnWindowDestroy(GtkWidget * widget)203 void CryptoModulePasswordDialog::OnWindowDestroy(GtkWidget* widget) {
204 delete this;
205 }
206
207 } // namespace
208
209 // Every post-task we do blocks, so there's no need to ref-count.
210 DISABLE_RUNNABLE_METHOD_REFCOUNT(CryptoModuleBlockingDialogDelegate);
211
212 namespace browser {
213
ShowCryptoModulePasswordDialog(const std::string & slot_name,bool retry,CryptoModulePasswordReason reason,const std::string & server,CryptoModulePasswordCallback * callback)214 void ShowCryptoModulePasswordDialog(const std::string& slot_name,
215 bool retry,
216 CryptoModulePasswordReason reason,
217 const std::string& server,
218 CryptoModulePasswordCallback* callback) {
219 (new CryptoModulePasswordDialog(slot_name, retry, reason, server,
220 callback))->Show();
221 }
222
223 crypto::CryptoModuleBlockingPasswordDelegate*
NewCryptoModuleBlockingDialogDelegate(CryptoModulePasswordReason reason,const std::string & server)224 NewCryptoModuleBlockingDialogDelegate(
225 CryptoModulePasswordReason reason,
226 const std::string& server) {
227 return new CryptoModuleBlockingDialogDelegate(reason, server);
228 }
229
230 } // namespace browser
231