Home | History | Annotate | Download | only in gtk
      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:
     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 
     35   ~CryptoModuleBlockingDialogDelegate() {
     36     password_.replace(0, password_.size(), password_.size(), 0);
     37   }
     38 
     39   // crypto::CryptoModuleBlockingDialogDelegate implementation.
     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:
     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   }
     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 
    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 
    185 void CryptoModulePasswordDialog::Show() {
    186   gtk_util::ShowDialog(dialog_);
    187 }
    188 
    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 
    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 
    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*
    224     NewCryptoModuleBlockingDialogDelegate(
    225         CryptoModulePasswordReason reason,
    226         const std::string& server) {
    227   return new CryptoModuleBlockingDialogDelegate(reason, server);
    228 }
    229 
    230 }  // namespace browser
    231