]> spindle.queued.net Git - midori/commitdiff
Save logins in a text file instead of a keyring
authorChristian Dywan <christian@twotoasts.de>
Mon, 7 Sep 2009 21:51:43 +0000 (23:51 +0200)
committerChristian Dywan <christian@twotoasts.de>
Tue, 8 Sep 2009 22:33:34 +0000 (00:33 +0200)
This means GNOME keyring isn't required for saving logins.

katze/katze-http-auth.c
midori/main.c

index 59770e732aa9a92a7ea648aaf5d7077585369bff..fb02082237b91827718e8616b150cb9107158008 100644 (file)
 #include <libsoup/soup.h>
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
+#include <glib/gstdio.h>
 
 struct _KatzeHttpAuth
 {
     GObject parent_instance;
+    gchar* filename;
+    GHashTable* logins;
 };
 
 struct _KatzeHttpAuthClass
@@ -29,6 +32,20 @@ struct _KatzeHttpAuthClass
     GObjectClass parent_class;
 };
 
+typedef struct
+{
+    KatzeHttpAuth* http_auth;
+    SoupAuth* auth;
+    gchar* username;
+    gchar* password;
+} KatzeHttpAuthSave;
+
+typedef struct
+{
+    gchar* username;
+    gchar* password;
+} KatzeHttpAuthLogin;
+
 static void
 katze_http_auth_session_feature_iface_init (SoupSessionFeatureInterface *iface,
                                             gpointer                     data);
@@ -37,28 +54,87 @@ G_DEFINE_TYPE_WITH_CODE (KatzeHttpAuth, katze_http_auth, G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
                          katze_http_auth_session_feature_iface_init));
 
-#ifdef HAVE_LIBSOUP_2_27_91
+enum
+{
+    PROP_0,
+
+    PROP_FILENAME
+};
+
+static void
+katze_http_auth_set_property (GObject*      object,
+                              guint         prop_id,
+                              const GValue* value,
+                              GParamSpec*   pspec);
+
+static void
+katze_http_auth_get_property (GObject*    object,
+                              guint       prop_id,
+                              GValue*     value,
+                              GParamSpec* pspec);
+
 static void
-authentication_message_got_headers_cb (SoupMessage* msg,
-                                       SoupAuth*    auth)
+katze_http_auth_finalize (GObject* object);
+
+static gchar*
+katze_http_auth_soup_auth_get_hash (SoupAuth* auth)
+{
+    return g_strdup_printf ("%s:%s:%s",
+        soup_auth_get_host (auth),
+        soup_auth_get_scheme_name (auth),
+        soup_auth_get_realm (auth));
+}
+
+static void
+authentication_message_got_headers_cb (SoupMessage*       msg,
+                                       KatzeHttpAuthSave* save)
 {
     /* Anything but 401 and 5xx means the password was accepted */
     if (msg->status_code != 401 && msg->status_code < 500)
     {
-        gchar* username = g_object_get_data (G_OBJECT (msg), "username");
-        gchar* password = g_object_get_data (G_OBJECT (msg), "password");
-        soup_auth_save_password (auth, username, password);
+        gchar* opaque_info;
+        FILE* file;
+
+        opaque_info = katze_http_auth_soup_auth_get_hash (save->auth);
+
+        if (!g_hash_table_lookup (save->http_auth->logins, opaque_info))
+        {
+            KatzeHttpAuthLogin* login;
+            login = g_new (KatzeHttpAuthLogin, 1);
+            login->username = save->username;
+            login->password = save->password;
+            g_hash_table_insert (save->http_auth->logins, opaque_info, login);
+
+            if ((file = g_fopen (save->http_auth->filename, "a")))
+            {
+                fprintf (file, "%s\t%s\t%s\n", opaque_info,
+                         login->username, login->password);
+                fclose (file);
+            }
+        }
+        else
+        {
+            /* FIXME g_free (save->username);
+            g_free (save->password); */
+        }
+    }
+    else
+    {
+        /* FIXME g_free (save->username);
+        g_free (save->password); */
     }
+
+    /* FIXME g_object_unref (save->auth); */
+    /* FIXME g_free (save); */
+    g_signal_handlers_disconnect_by_func (msg,
+        authentication_message_got_headers_cb, save);
 }
-#endif
 
 static void
-authentication_dialog_response_cb (GtkWidget* dialog,
-                                   gint       response,
-                                   SoupAuth*  auth)
+authentication_dialog_response_cb (GtkWidget*         dialog,
+                                   gint               response,
+                                   KatzeHttpAuthSave* save)
 {
-    GtkWidget* username;
-    GtkWidget* password;
     SoupSession* session;
     SoupMessage* msg;
 
@@ -66,36 +142,42 @@ authentication_dialog_response_cb (GtkWidget* dialog,
 
     if (response == GTK_RESPONSE_OK)
     {
+        GtkEntry* username = g_object_get_data (G_OBJECT (dialog), "username");
+        GtkEntry* password = g_object_get_data (G_OBJECT (dialog), "password");
+
+        soup_auth_authenticate (save->auth,
+            gtk_entry_get_text (username), gtk_entry_get_text (password));
 
-        username = g_object_get_data (G_OBJECT (dialog), "username");
-        password = g_object_get_data (G_OBJECT (dialog), "password");
-
-        soup_auth_authenticate (auth,
-            gtk_entry_get_text (GTK_ENTRY (username)),
-            gtk_entry_get_text (GTK_ENTRY (password)));
-        #ifdef HAVE_LIBSOUP_2_27_91
-        g_object_set_data_full (G_OBJECT (msg), "username",
-            g_strdup (gtk_entry_get_text (GTK_ENTRY (username))), g_free);
-        g_object_set_data_full (G_OBJECT (msg), "password",
-            g_strdup (gtk_entry_get_text (GTK_ENTRY (password))), g_free);
-        g_signal_connect (msg, "got-headers",
-            G_CALLBACK (authentication_message_got_headers_cb), auth);
-        #endif
+        if (save->http_auth->filename)
+        {
+            save->username = g_strdup (gtk_entry_get_text (username));
+            save->password = g_strdup (gtk_entry_get_text (password));
+            g_signal_connect (msg, "got-headers",
+                G_CALLBACK (authentication_message_got_headers_cb), save);
+        }
+        else
+        {
+            g_object_unref (save->auth);
+            g_free (save);
+        }
     }
 
     session = g_object_get_data (G_OBJECT (dialog), "session");
-    gtk_widget_destroy (dialog);
     if (g_object_get_data (G_OBJECT (msg), "paused"))
         soup_session_unpause_message (session, msg);
-    g_object_unref (auth);
+    gtk_widget_destroy (dialog);
+    g_object_unref (msg);
 }
 
 static void
-katze_http_auth_session_authenticate_cb (SoupSession* session,
-                                         SoupMessage* msg,
-                                         SoupAuth*    auth,
-                                         gboolean     retrying)
+katze_http_auth_session_authenticate_cb (SoupSession*   session,
+                                         SoupMessage*   msg,
+                                         SoupAuth*      auth,
+                                         gboolean       retrying,
+                                         KatzeHttpAuth* http_auth)
 {
+    gchar* opaque_info;
+    KatzeHttpAuthLogin* login;
     GtkWidget* dialog;
     GtkSizeGroup* sizegroup;
     GtkWidget* hbox;
@@ -103,24 +185,26 @@ katze_http_auth_session_authenticate_cb (SoupSession* session,
     GtkWidget* label;
     GtkWidget* align;
     GtkWidget* entry;
-    #ifdef HAVE_LIBSOUP_2_27_91
-    GSList* users;
-    #endif
+    KatzeHttpAuthSave* save;
 
     /* We want to ask for authentication exactly once, so we
        enforce this with a tag. There might be a better way. */
     if (!retrying && g_object_get_data (G_OBJECT (msg), "katze-session-tag"))
         return;
 
-    if (soup_message_is_keepalive (msg))
+    if (1)
     {
         /* We use another tag to indicate whether a message is paused.
            There doesn't seem to be API in libSoup to find that out. */
-        soup_session_pause_message (session, msg);
+        soup_session_pause_message (session, g_object_ref (msg));
         g_object_set_data (G_OBJECT (msg), "paused", (void*)1);
     }
     g_object_set_data (G_OBJECT (msg), "katze-session-tag", (void*)1);
 
+    opaque_info = katze_http_auth_soup_auth_get_hash (auth);
+    login = g_hash_table_lookup (http_auth->logins, opaque_info);
+    g_free (opaque_info);
+
     dialog = gtk_dialog_new_with_buttons (_("Authentication Required"),
         NULL,
         GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
@@ -157,11 +241,8 @@ katze_http_auth_session_authenticate_cb (SoupSession* session,
     gtk_size_group_add_widget (sizegroup, align);
     gtk_box_pack_start (GTK_BOX (hbox), align, TRUE, TRUE, 0);
     entry = gtk_entry_new ();
-    #ifdef HAVE_LIBSOUP_2_27_91
-    users = soup_auth_get_saved_users (auth);
-    if (users)
-        gtk_entry_set_text (GTK_ENTRY (entry), users->data);
-    #endif
+    if (login)
+        gtk_entry_set_text (GTK_ENTRY (entry), login->username);
     gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
     gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
     g_object_set_data (G_OBJECT (dialog), "username", entry);
@@ -173,14 +254,8 @@ katze_http_auth_session_authenticate_cb (SoupSession* session,
     gtk_size_group_add_widget (sizegroup, align);
     gtk_box_pack_start (GTK_BOX (hbox), align, TRUE, TRUE, 0);
     entry = gtk_entry_new_with_max_length (32);
-    #ifdef HAVE_LIBSOUP_2_27_91
-    if (users)
-    {
-        gtk_entry_set_text (GTK_ENTRY (entry),
-            soup_auth_get_saved_password (auth, users->data));
-        g_slist_free (users);
-    }
-    #endif
+    if (login)
+        gtk_entry_set_text (GTK_ENTRY (entry), login->password);
     gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
     gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
     gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
@@ -191,15 +266,19 @@ katze_http_auth_session_authenticate_cb (SoupSession* session,
 
     g_object_set_data (G_OBJECT (dialog), "session", session);
     g_object_set_data (G_OBJECT (dialog), "msg", msg);
+
+    save = g_new (KatzeHttpAuthSave, 1);
+    save->http_auth = http_auth;
+    save->auth = g_object_ref (auth);
     g_signal_connect (dialog, "response",
-        G_CALLBACK (authentication_dialog_response_cb), g_object_ref (auth));
+        G_CALLBACK (authentication_dialog_response_cb), save);
     gtk_widget_show (dialog);
 }
 
 static void
-katze_http_auth_session_request_queued_cb (SoupSession* session,
-                                           SoupMessage* msg,
-                                           gpointer     data)
+katze_http_auth_session_request_queued_cb (SoupSession*   session,
+                                           SoupMessage*   msg,
+                                           KatzeHttpAuth* http_auth)
 {
     /* WebKit has its own authentication dialog in recent versions.
        We want only one, and we choose our own to have localization. */
@@ -208,7 +287,7 @@ katze_http_auth_session_request_queued_cb (SoupSession* session,
         soup_session_remove_feature_by_type (session, type);
 
     g_signal_connect (session, "authenticate",
-        G_CALLBACK (katze_http_auth_session_authenticate_cb), NULL);
+        G_CALLBACK (katze_http_auth_session_authenticate_cb), http_auth);
     g_signal_handlers_disconnect_by_func (session,
         katze_http_auth_session_request_queued_cb, NULL);
 }
@@ -218,7 +297,7 @@ katze_http_auth_attach (SoupSessionFeature* feature,
                         SoupSession*        session)
 {
     g_signal_connect (session, "request-queued",
-        G_CALLBACK (katze_http_auth_session_request_queued_cb), NULL);
+        G_CALLBACK (katze_http_auth_session_request_queued_cb), feature);
 }
 
 static void
@@ -242,11 +321,139 @@ katze_http_auth_session_feature_iface_init (SoupSessionFeatureInterface *iface,
 static void
 katze_http_auth_class_init (KatzeHttpAuthClass* class)
 {
-    /* Nothing to do. */
+    GObjectClass* gobject_class;
+    GParamFlags flags;
+
+    gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->finalize = katze_http_auth_finalize;
+    gobject_class->set_property = katze_http_auth_set_property;
+    gobject_class->get_property = katze_http_auth_get_property;
+
+    flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+
+    /**
+     * KatzeHttpAuth:filename:
+     *
+     * An absolute path and name of a file for storing logins.
+     *
+     * Since: 0.1.10
+     */
+    g_object_class_install_property (gobject_class,
+                                     PROP_FILENAME,
+                                     g_param_spec_string (
+                                     "filename",
+                                     "Filename",
+                                     "An absolute path and name of a file for storing logins",
+                                     NULL,
+                                     flags));
+}
+
+static void
+katze_http_auth_login_free (KatzeHttpAuthLogin* login)
+{
+    g_free (login->username);
+    g_free (login->password);
+    g_free (login);
+}
+
+static void
+katze_http_auth_set_filename (KatzeHttpAuth* http_auth,
+                              const gchar*   filename)
+{
+    FILE* file;
+
+    katze_assign (http_auth->filename, g_strdup (filename));
+
+    g_hash_table_remove_all (http_auth->logins);
+
+    if ((file = g_fopen (filename, "r")))
+    {
+        gchar line[255];
+        guint number = 0;
+
+        while (fgets (line, 255, file))
+        {
+            gchar** parts = g_strsplit (line, "\t", 3);
+            if (parts && parts[0] && parts[1] && parts[2])
+            {
+                KatzeHttpAuthLogin* login;
+                gint length;
+
+                login = g_new (KatzeHttpAuthLogin, 1);
+                login->username = parts[1];
+                length = strlen (parts[2]);
+                if (parts[2][length - 1] == '\n')
+                    length--;
+                login->password = g_strndup (parts[2], length);
+                g_hash_table_insert (http_auth->logins, parts[0], login);
+                g_free (parts);
+            }
+            else
+            {
+                g_strfreev (parts);
+                g_warning ("Error in line %d in HTTP Auth file", number);
+            }
+            number++;
+        }
+        fclose (file);
+    }
 }
 
 static void
 katze_http_auth_init (KatzeHttpAuth* http_auth)
 {
-    /* Nothing to do. */
+    http_auth->filename = NULL;
+
+    http_auth->logins = g_hash_table_new_full (g_str_hash, g_str_equal,
+        (GDestroyNotify)g_free, (GDestroyNotify)katze_http_auth_login_free);
+}
+
+static void
+katze_http_auth_finalize (GObject* object)
+{
+    KatzeHttpAuth* http_auth = KATZE_HTTP_AUTH (object);
+
+    g_free (http_auth->filename);
+
+    g_hash_table_unref (http_auth->logins);
+
+    G_OBJECT_CLASS (katze_http_auth_parent_class)->finalize (object);
+}
+
+static void
+katze_http_auth_set_property (GObject*      object,
+                              guint         prop_id,
+                              const GValue* value,
+                              GParamSpec*   pspec)
+{
+    KatzeHttpAuth* http_auth = KATZE_HTTP_AUTH (object);
+
+    switch (prop_id)
+    {
+    case PROP_FILENAME:
+        katze_http_auth_set_filename (http_auth, g_value_get_string (value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+katze_http_auth_get_property (GObject*    object,
+                              guint       prop_id,
+                              GValue*     value,
+                              GParamSpec* pspec)
+{
+    KatzeHttpAuth* http_auth = KATZE_HTTP_AUTH (object);
+
+    switch (prop_id)
+    {
+    case PROP_FILENAME:
+        g_value_set_string (value, http_auth->filename);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
 }
index c5a5457f8dee967526a9cdcacffc9faa69e21cb3..d445ae13c28dbbf72a3b859d31a710a3dfb1871a 100644 (file)
@@ -1110,21 +1110,9 @@ midori_soup_session_prepare (SoupSession*       session,
                              SoupCookieJar*     cookie_jar,
                              MidoriWebSettings* settings)
 {
-    GModule* module;
     SoupSessionFeature* feature;
     gchar* config_file;
 
-    if (g_module_supported ())
-        if ((module = g_module_open ("libsoup-gnome-2.4.so", G_MODULE_BIND_LOCAL)))
-        {
-            #ifdef HAVE_LIBSOUP_2_27_91
-            GType (*get_type_function) (void);
-            if (g_module_symbol (module, "soup_password_manager_gnome_get_type",
-                                 (void*) &get_type_function))
-                soup_session_add_feature_by_type (session, get_type_function ());
-            #endif
-        }
-
     soup_session_settings_notify_http_proxy_cb (settings, NULL, session);
     g_signal_connect (settings, "notify::http-proxy",
         G_CALLBACK (soup_session_settings_notify_http_proxy_cb), session);
@@ -1137,7 +1125,11 @@ midori_soup_session_prepare (SoupSession*       session,
         G_CALLBACK (soup_session_settings_notify_ident_string_cb), session);
     #endif
 
-    soup_session_add_feature_by_type (session, KATZE_TYPE_HTTP_AUTH);
+    config_file = build_config_filename ("logins");
+    feature = g_object_new (KATZE_TYPE_HTTP_AUTH, "filename", config_file, NULL);
+    g_free (config_file);
+    soup_session_add_feature (session, feature);
+    g_object_unref (feature);
     midori_soup_session_debug (session);
 
     feature = g_object_new (KATZE_TYPE_HTTP_COOKIES, NULL);
@@ -1145,7 +1137,7 @@ midori_soup_session_prepare (SoupSession*       session,
     g_object_set_data_full (G_OBJECT (feature), "filename",
                             config_file, (GDestroyNotify)g_free);
     soup_session_add_feature (session, SOUP_SESSION_FEATURE (cookie_jar));
-    soup_session_add_feature (session, feature);
+    g_object_unref (feature);
 }
 
 static void