1/* 2 * Copyright (C) 2012 Igalia S.L. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20#include "config.h" 21#include "WebKitAuthenticationWidget.h" 22 23#include "CredentialBackingStore.h" 24#include "GtkVersioning.h" 25#include <glib/gi18n-lib.h> 26#include <wtf/gobject/GUniquePtr.h> 27#include <wtf/text/CString.h> 28 29using namespace WebCore; 30 31struct _WebKitAuthenticationWidgetPrivate { 32 AuthenticationChallenge challenge; 33 CredentialStorageMode credentialStorageMode; 34 35 GtkWidget* loginEntry; 36 GtkWidget* passwordEntry; 37 GtkWidget* rememberCheckButton; 38}; 39 40G_DEFINE_TYPE(WebKitAuthenticationWidget, webkit_authentication_widget, GTK_TYPE_BOX) 41 42static const int gLayoutColumnSpacing = 12; 43static const int gLayoutRowSpacing = 6; 44static const int gButtonSpacing = 5; 45 46#ifdef GTK_API_VERSION_2 47static void packTwoColumnLayoutInBox(GtkWidget* box, ...) 48{ 49 va_list argumentList; 50 va_start(argumentList, box); 51 52 GtkWidget* table = gtk_table_new(1, 2, FALSE); 53 gtk_table_set_col_spacings(GTK_TABLE(table), gLayoutColumnSpacing); 54 gtk_table_set_row_spacings(GTK_TABLE(table), gLayoutRowSpacing); 55 56 GtkWidget* firstColumnWidget = va_arg(argumentList, GtkWidget*); 57 int rowNumber = 0; 58 while (firstColumnWidget) { 59 if (rowNumber) 60 gtk_table_resize(GTK_TABLE(table), rowNumber + 1, 2); 61 62 GtkWidget* secondColumnWidget = va_arg(argumentList, GtkWidget*); 63 GtkAttachOptions attachOptions = static_cast<GtkAttachOptions>(GTK_EXPAND | GTK_FILL); 64 gtk_table_attach( 65 GTK_TABLE(table), firstColumnWidget, 66 0, secondColumnWidget ? 1 : 2, 67 rowNumber, rowNumber + 1, 68 attachOptions, attachOptions, 69 0, 0); 70 gtk_widget_show(firstColumnWidget); 71 72 if (secondColumnWidget) { 73 gtk_table_attach_defaults(GTK_TABLE(table), secondColumnWidget, 1, 2, rowNumber, rowNumber + 1); 74 gtk_widget_show(secondColumnWidget); 75 } 76 77 firstColumnWidget = va_arg(argumentList, GtkWidget*); 78 rowNumber++; 79 } 80 81 va_end(argumentList); 82 83 gtk_box_pack_start(GTK_BOX(box), table, FALSE, FALSE, 0); 84 gtk_widget_show(table); 85} 86#else 87static void packTwoColumnLayoutInBox(GtkWidget* box, ...) 88{ 89 va_list argumentList; 90 va_start(argumentList, box); 91 92 GtkWidget* grid = gtk_grid_new(); 93 gtk_grid_set_column_spacing(GTK_GRID(grid), gLayoutRowSpacing); 94 gtk_grid_set_row_spacing(GTK_GRID(grid), gLayoutRowSpacing); 95 gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE); 96 97 GtkWidget* firstColumnWidget = va_arg(argumentList, GtkWidget*); 98 int rowNumber = 0; 99 while (firstColumnWidget) { 100 GtkWidget* secondColumnWidget = va_arg(argumentList, GtkWidget*); 101 int firstWidgetWidth = secondColumnWidget ? 1 : 2; 102 103 gtk_grid_attach(GTK_GRID(grid), firstColumnWidget, 0, rowNumber, firstWidgetWidth, 1); 104 gtk_widget_set_hexpand(firstColumnWidget, TRUE); 105 gtk_widget_set_vexpand(firstColumnWidget, TRUE); 106 gtk_widget_show(firstColumnWidget); 107 108 if (secondColumnWidget) { 109 gtk_grid_attach(GTK_GRID(grid), secondColumnWidget, 1, rowNumber, 1, 1); 110 gtk_widget_set_hexpand(secondColumnWidget, TRUE); 111 gtk_widget_set_vexpand(secondColumnWidget, TRUE); 112 gtk_widget_show(secondColumnWidget); 113 } 114 115 firstColumnWidget = va_arg(argumentList, GtkWidget*); 116 rowNumber++; 117 } 118 119 va_end(argumentList); 120 121 gtk_box_pack_start(GTK_BOX(box), grid, FALSE, FALSE, 0); 122 gtk_widget_show(grid); 123} 124#endif 125 126static GtkWidget* createLabel(const char* labelString, int horizontalPadding = 0) 127{ 128 GtkWidget* label = gtk_label_new(labelString); 129 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); 130 if (horizontalPadding) 131 gtk_misc_set_padding(GTK_MISC(label), 0, horizontalPadding); 132 return label; 133} 134 135static GtkWidget* createEntry(GtkWidget** member) 136{ 137 *member = gtk_entry_new(); 138 gtk_entry_set_activates_default(GTK_ENTRY(*member), TRUE); 139 return *member; 140} 141 142static void webkitAuthenticationWidgetInitialize(WebKitAuthenticationWidget* authWidget) 143{ 144 gtk_orientable_set_orientation(GTK_ORIENTABLE(authWidget), GTK_ORIENTATION_HORIZONTAL); 145 gtk_box_set_spacing(GTK_BOX(authWidget), gLayoutColumnSpacing); 146 gtk_container_set_border_width(GTK_CONTAINER(authWidget), gButtonSpacing); 147 148 GtkWidget* icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG); 149 gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0.0); 150 gtk_box_pack_start(GTK_BOX(authWidget), icon, FALSE, FALSE, 0); 151 gtk_widget_show(icon); 152 153 WebKitAuthenticationWidgetPrivate* priv = authWidget->priv; 154 GUniquePtr<char> prompt(g_strdup_printf( 155 _("The site %s:%i requests a username and password"), 156 priv->challenge.protectionSpace().host().utf8().data(), 157 priv->challenge.protectionSpace().port())); 158 159 priv->rememberCheckButton = gtk_check_button_new_with_mnemonic(_("_Remember password")); 160 gtk_label_set_line_wrap(GTK_LABEL(gtk_bin_get_child(GTK_BIN(priv->rememberCheckButton))), TRUE); 161 162 String realm = authWidget->priv->challenge.protectionSpace().realm(); 163 if (!realm.isEmpty()) { 164 packTwoColumnLayoutInBox( 165 GTK_WIDGET(authWidget), 166 createLabel(prompt.get(), gLayoutRowSpacing), NULL, 167 createLabel(_("Server message:")), createLabel(realm.utf8().data()), 168 createLabel(_("Username:")), createEntry(&priv->loginEntry), 169 createLabel(_("Password:")), createEntry(&priv->passwordEntry), 170 priv->rememberCheckButton, NULL, 171 NULL); 172 173 } else { 174 packTwoColumnLayoutInBox( 175 GTK_WIDGET(authWidget), 176 createLabel(prompt.get(), gLayoutRowSpacing), NULL, 177 createLabel(_("Username:")), createEntry(&priv->loginEntry), 178 createLabel(_("Password:")), createEntry(&priv->passwordEntry), 179 priv->rememberCheckButton, NULL, NULL, 180 NULL); 181 } 182 gtk_entry_set_visibility(GTK_ENTRY(priv->passwordEntry), FALSE); 183 gtk_widget_set_visible(priv->rememberCheckButton, priv->credentialStorageMode != DisallowPersistentStorage); 184 185 const Credential& credentialFromPersistentStorage = priv->challenge.proposedCredential(); 186 if (!credentialFromPersistentStorage.isEmpty()) { 187 gtk_entry_set_text(GTK_ENTRY(priv->loginEntry), credentialFromPersistentStorage.user().utf8().data()); 188 gtk_entry_set_text(GTK_ENTRY(priv->passwordEntry), credentialFromPersistentStorage.password().utf8().data()); 189 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->rememberCheckButton), TRUE); 190 } 191 192 gtk_widget_grab_focus(priv->loginEntry); 193} 194 195static void webkitAuthenticationWidgetFinalize(GObject* object) 196{ 197 WEBKIT_AUTHENTICATION_WIDGET(object)->priv->~WebKitAuthenticationWidgetPrivate(); 198 G_OBJECT_CLASS(webkit_authentication_widget_parent_class)->finalize(object); 199} 200 201static void webkit_authentication_widget_init(WebKitAuthenticationWidget* authWidget) 202{ 203 WebKitAuthenticationWidgetPrivate* priv = G_TYPE_INSTANCE_GET_PRIVATE(authWidget, WEBKIT_TYPE_AUTHENTICATION_WIDGET, WebKitAuthenticationWidgetPrivate); 204 new (priv) WebKitAuthenticationWidgetPrivate(); 205 authWidget->priv = priv; 206} 207 208static void webkit_authentication_widget_class_init(WebKitAuthenticationWidgetClass* klass) 209{ 210 GObjectClass* objectClass = G_OBJECT_CLASS(klass); 211 objectClass->finalize = webkitAuthenticationWidgetFinalize; 212 g_type_class_add_private(objectClass, sizeof(WebKitAuthenticationWidgetPrivate)); 213} 214 215GtkWidget* webkitAuthenticationWidgetNew(const AuthenticationChallenge& challenge, CredentialStorageMode mode) 216{ 217 WebKitAuthenticationWidget* authWidget = WEBKIT_AUTHENTICATION_WIDGET(g_object_new(WEBKIT_TYPE_AUTHENTICATION_WIDGET, NULL)); 218 authWidget->priv->challenge = challenge; 219 authWidget->priv->credentialStorageMode = mode; 220 webkitAuthenticationWidgetInitialize(authWidget); 221 return GTK_WIDGET(authWidget); 222} 223 224Credential webkitAuthenticationWidgetCreateCredential(WebKitAuthenticationWidget* authWidget) 225{ 226 const char* username = gtk_entry_get_text(GTK_ENTRY(authWidget->priv->loginEntry)); 227 const char* password = gtk_entry_get_text(GTK_ENTRY(authWidget->priv->passwordEntry)); 228 bool rememberPassword = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(authWidget->priv->rememberCheckButton)); 229 230 CredentialPersistence persistence; 231 if (rememberPassword && authWidget->priv->credentialStorageMode == AllowPersistentStorage) 232 persistence = CredentialPersistencePermanent; 233 else 234 persistence = CredentialPersistenceForSession; 235 return Credential(String::fromUTF8(username), String::fromUTF8(password), persistence); 236} 237 238AuthenticationChallenge& webkitAuthenticationWidgetGetChallenge(WebKitAuthenticationWidget* authWidget) 239{ 240 return authWidget->priv->challenge; 241} 242