• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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