[epiphany/wip/sync: 3/22] lib: Replace ephy-form-auth-data with ephy-password-manager



commit 25ecbff59dcafd77ec6ae1de3f9641f7b1b3746d
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date:   Sat Apr 29 17:18:56 2017 +0300

    lib: Replace ephy-form-auth-data with ephy-password-manager

 embed/ephy-web-view.c                        |    1 -
 embed/web-extension/ephy-web-extension.c     |  168 ++++-----
 lib/ephy-form-auth-data.c                    |  403 ---------------------
 lib/ephy-form-auth-data.h                    |   76 ----
 lib/ephy-password-manager.c                  |  483 ++++++++++++++++++++++++++
 lib/ephy-password-manager.h                  |   77 ++++
 lib/ephy-password-record.c                   |  236 +++++++++++++
 lib/ephy-password-record.h                   |   45 +++
 lib/meson.build                              |    3 +-
 po/POTFILES.in                               |    2 +-
 src/clear-data-dialog.c                      |    1 -
 src/ephy-shell.c                             |   20 +
 src/ephy-shell.h                             |    3 +
 src/passwords-dialog.c                       |  172 +++------
 src/passwords-dialog.h                       |    4 +-
 src/prefs-dialog.c                           |    4 +-
 src/profile-migrator/ephy-profile-migrator.c |   18 +-
 src/resources/gtk/passwords-dialog.ui        |    2 +-
 18 files changed, 1010 insertions(+), 708 deletions(-)
---
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index 1d9eb2f..4129100 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -33,7 +33,6 @@
 #include "ephy-favicon-helpers.h"
 #include "ephy-file-helpers.h"
 #include "ephy-file-monitor.h"
-#include "ephy-form-auth-data.h"
 #include "ephy-history-service.h"
 #include "ephy-lib-type-builtins.h"
 #include "ephy-permissions-manager.h"
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
index edde1f3..b628358 100644
--- a/embed/web-extension/ephy-web-extension.c
+++ b/embed/web-extension/ephy-web-extension.c
@@ -26,7 +26,7 @@
 #include "ephy-debug.h"
 #include "ephy-embed-form-auth.h"
 #include "ephy-file-helpers.h"
-#include "ephy-form-auth-data.h"
+#include "ephy-password-manager.h"
 #include "ephy-permissions-manager.h"
 #include "ephy-prefs.h"
 #include "ephy-settings.h"
@@ -51,7 +51,7 @@ struct _EphyWebExtension {
   GDBusConnection *dbus_connection;
   GArray *page_created_signals_pending;
 
-  EphyFormAuthDataCache *form_auth_data_cache;
+  EphyPasswordManager *password_manager;
   GHashTable *form_auth_data_save_requests;
   EphyWebOverviewModel *overview_model;
   EphyPermissionsManager *permissions_manager;
@@ -283,19 +283,12 @@ store_password (EphyEmbedFormAuth *form_auth)
 
   uri = ephy_embed_form_auth_get_uri (form_auth);
   uri_str = soup_uri_to_string (uri, FALSE);
-  ephy_form_auth_data_store (uri_str,
-                             username_field_name,
-                             password_field_name,
-                             username_field_value,
-                             password_field_value,
-                             NULL, NULL);
-
-  /* Update internal caching */
-  ephy_form_auth_data_cache_add (extension->form_auth_data_cache,
-                                 uri_str,
-                                 username_field_name,
-                                 password_field_name,
-                                 username_field_value);
+  ephy_password_manager_save (extension->password_manager,
+                              uri_str,
+                              username_field_name,
+                              password_field_name,
+                              username_field_value,
+                              password_field_value);
 
   g_free (uri_str);
   g_free (username_field_name);
@@ -368,9 +361,8 @@ out:
 }
 
 static void
-should_store_cb (const char *username,
-                 const char *password,
-                 gpointer    user_data)
+should_store_cb (GSList   *records,
+                 gpointer  user_data)
 {
   EphyEmbedFormAuth *form_auth = EPHY_EMBED_FORM_AUTH (user_data);
   EphyWebExtension *web_extension;
@@ -407,9 +399,12 @@ should_store_cb (const char *username,
   if (password_field_value == NULL || strlen (password_field_value) == 0)
     goto out;
 
-  if (password) {
+  if (records && records->data) {
+    EphyPasswordRecord *record = EPHY_PASSWORD_RECORD (records->data);
     WebKitDOMNode *username_node;
     char *username_field_value = NULL;
+    const char *username = ephy_password_record_get_username (record);
+    const char *password = ephy_password_record_get_password (record);
 
     username_node = ephy_embed_form_auth_get_username_node (form_auth);
     if (username_node)
@@ -440,6 +435,8 @@ out:
   if (origin != NULL)
     g_free (origin);
   g_free (uri_string);
+  g_object_unref (form_auth);
+  g_slist_free_full (records, g_object_unref);
 }
 
 static gboolean
@@ -447,6 +444,7 @@ form_submitted_cb (WebKitDOMHTMLFormElement *dom_form,
                    WebKitDOMEvent           *dom_event,
                    WebKitWebPage            *web_page)
 {
+  EphyWebExtension *extension = ephy_web_extension_get ();
   EphyEmbedFormAuth *form_auth;
   SoupURI *uri;
   WebKitDOMNode *username_node = NULL;
@@ -475,13 +473,13 @@ form_submitted_cb (WebKitDOMHTMLFormElement *dom_form,
   g_object_get (password_node, "name", &password_field_name, NULL);
   uri_str = soup_uri_to_string (uri, FALSE);
 
-  ephy_form_auth_data_query (uri_str,
-                             username_field_name,
-                             password_field_name,
-                             username_field_value,
-                             should_store_cb,
-                             form_auth,
-                             (GDestroyNotify)g_object_unref);
+  ephy_password_manager_query (extension->password_manager,
+                               uri_str,
+                               username_field_name,
+                               password_field_name,
+                               username_field_value,
+                               should_store_cb,
+                               form_auth);
 
   g_free (username_field_name);
   g_free (username_field_value);
@@ -492,19 +490,22 @@ form_submitted_cb (WebKitDOMHTMLFormElement *dom_form,
 }
 
 static void
-fill_form_cb (const char *username,
-              const char *password,
-              gpointer    user_data)
+fill_form_cb (GSList   *records,
+              gpointer  user_data)
 {
   EphyEmbedFormAuth *form_auth = EPHY_EMBED_FORM_AUTH (user_data);
   WebKitDOMHTMLInputElement *username_node;
   WebKitDOMHTMLInputElement *password_node;
+  const char *username;
+  const char *password;
 
-  if (username == NULL && password == NULL) {
+  if (!(records && records->data)) {
     LOG ("No result");
     return;
   }
 
+  username = ephy_password_record_get_username (EPHY_PASSWORD_RECORD (records->data));
+  password = ephy_password_record_get_password (EPHY_PASSWORD_RECORD (records->data));
   username_node = WEBKIT_DOM_HTML_INPUT_ELEMENT (ephy_embed_form_auth_get_username_node (form_auth));
   password_node = WEBKIT_DOM_HTML_INPUT_ELEMENT (ephy_embed_form_auth_get_password_node (form_auth));
 
@@ -517,44 +518,20 @@ fill_form_cb (const char *username,
   }
   webkit_dom_html_input_element_set_auto_filled (password_node, TRUE);
   webkit_dom_html_input_element_set_editing_value (password_node, password);
-}
-
-static gint
-ephy_form_auth_data_compare (EphyFormAuthData  *form_data,
-                             EphyEmbedFormAuth *form_auth)
-{
-  WebKitDOMNode *username_node;
-  WebKitDOMNode *password_node;
-  char *username_field_name = NULL;
-  char *password_field_name = NULL;
-  gboolean retval;
-
-  username_node = ephy_embed_form_auth_get_username_node (form_auth);
-  if (username_node)
-    g_object_get (username_node, "name", &username_field_name, NULL);
-  password_node = ephy_embed_form_auth_get_password_node (form_auth);
-  if (password_node)
-    g_object_get (password_node, "name", &password_field_name, NULL);
-
-  retval = g_strcmp0 (username_field_name, form_data->form_username) == 0 &&
-           g_strcmp0 (password_field_name, form_data->form_password) == 0;
-
-  g_free (username_field_name);
-  g_free (password_field_name);
 
-  return retval ? 0 : 1;
+  g_slist_free_full (records, g_object_unref);
 }
 
 static void
 pre_fill_form (EphyEmbedFormAuth *form_auth)
 {
-  GSList *form_auth_data_list;
-  GSList *l;
-  EphyFormAuthData *form_data;
   SoupURI *uri;
   char *uri_str;
-  char *username;
+  char *username = NULL;
+  char *username_field_name = NULL;
+  char *password_field_name = NULL;
   WebKitDOMNode *username_node;
+  WebKitDOMNode *password_node;
   EphyWebExtension *extension;
 
   uri = ephy_embed_form_auth_get_uri (form_auth);
@@ -563,34 +540,31 @@ pre_fill_form (EphyEmbedFormAuth *form_auth)
 
   extension = ephy_web_extension_get ();
   uri_str = soup_uri_to_string (uri, FALSE);
-  form_auth_data_list = ephy_form_auth_data_cache_get_list (extension->form_auth_data_cache, uri_str);
-  l = g_slist_find_custom (form_auth_data_list, form_auth, (GCompareFunc)ephy_form_auth_data_compare);
-  if (!l) {
-    g_free (uri_str);
-    return;
-  }
-
-  form_data = (EphyFormAuthData *)l->data;
   username_node = ephy_embed_form_auth_get_username_node (form_auth);
-  if (username_node)
+  if (username_node) {
+    g_object_get (username_node, "name", &username_field_name, NULL);
     g_object_get (username_node, "value", &username, NULL);
-  else
-    username = NULL;
+  }
+  password_node = ephy_embed_form_auth_get_password_node (form_auth);
+  if (password_node)
+    g_object_get (password_node, "name", &password_field_name, NULL);
 
   /* The username node is empty, so pre-fill with the default. */
   if (username != NULL && g_str_equal (username, ""))
     g_clear_pointer (&username, g_free);
 
-  ephy_form_auth_data_query (uri_str,
-                             form_data->form_username,
-                             form_data->form_password,
-                             username,
-                             fill_form_cb,
-                             g_object_ref (form_auth),
-                             (GDestroyNotify)g_object_unref);
+  ephy_password_manager_query (extension->password_manager,
+                               uri_str,
+                               username_field_name,
+                               password_field_name,
+                               username,
+                               fill_form_cb,
+                               form_auth);
 
-  g_free (username);
   g_free (uri_str);
+  g_free (username);
+  g_free (username_field_name);
+  g_free (password_field_name);
 }
 
 static void
@@ -757,7 +731,7 @@ show_user_choices (WebKitDOMDocument *document,
   WebKitDOMElement *main_div;
   WebKitDOMElement *ul;
   GSList *iter;
-  GSList *auth_data_list;
+  GSList *password_records_list;
   gboolean username_node_ever_edited;
   double x, y;
   double input_width;
@@ -803,30 +777,32 @@ show_user_choices (WebKitDOMDocument *document,
                                     "padding: 0;",
                                     NULL);
 
-  auth_data_list = (GSList *)g_object_get_data (G_OBJECT (username_node),
-                                                "ephy-auth-data-list");
+  password_records_list = (GSList *)g_object_get_data (G_OBJECT (username_node),
+                                                       "ephy-password-records-list");
 
   username_node_ever_edited =
     GPOINTER_TO_INT (g_object_get_data (G_OBJECT (username_node),
                                         "ephy-user-ever-edited"));
 
-  for (iter = auth_data_list; iter; iter = iter->next) {
-    EphyFormAuthData *data;
+  for (iter = password_records_list; iter; iter = iter->next) {
+    EphyPasswordRecord *record;
     WebKitDOMElement *li;
     WebKitDOMElement *anchor;
     char *child_style;
+    const char *record_username;
     gboolean is_selected;
 
-    data = (EphyFormAuthData *)iter->data;
+    record = EPHY_PASSWORD_RECORD (iter->data);
+    record_username = ephy_password_record_get_username (record);
 
     /* Filter out the available names that do not match, but show all options in
      * case we have been triggered by something other than the user editing the
      * input.
      */
-    if (username_node_ever_edited && !g_str_has_prefix (data->username, username))
+    if (username_node_ever_edited && !g_str_has_prefix (record_username, username))
       continue;
 
-    is_selected = !g_strcmp0 (username, data->username);
+    is_selected = !g_strcmp0 (username, record_username);
 
     li = webkit_dom_document_create_element (document, "li", NULL);
     webkit_dom_element_set_attribute (li, "tabindex", "-1", NULL);
@@ -858,7 +834,7 @@ show_user_choices (WebKitDOMDocument *document,
                                                 username_node);
 
     webkit_dom_node_set_text_content (WEBKIT_DOM_NODE (anchor),
-                                      data->username,
+                                      record_username,
                                       NULL);
   }
 
@@ -1125,14 +1101,14 @@ web_page_form_controls_associated (WebKitWebPage    *web_page,
                                                   web_page);
     }
 
-    if (!extension->form_auth_data_cache ||
+    if (!extension->password_manager ||
         !g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_REMEMBER_PASSWORDS))
       continue;
 
     /* We have a field that may be the user, and one for a password. */
     if (ephy_web_dom_utils_find_form_auth_elements (form, &username_node, &password_node)) {
       EphyEmbedFormAuth *form_auth;
-      GSList *auth_data_list;
+      GSList *password_records_list;
       const char *uri;
 
       LOG ("Hooking and pre-filling a form");
@@ -1150,11 +1126,11 @@ web_page_form_controls_associated (WebKitWebPage    *web_page,
 
       /* Plug in the user autocomplete */
       uri = webkit_web_page_get_uri (web_page);
-      auth_data_list = ephy_form_auth_data_cache_get_list (extension->form_auth_data_cache, uri);
+      password_records_list = ephy_password_manager_get_cached_by_uri (extension->password_manager, uri);
 
-      if (auth_data_list && auth_data_list->next && username_node) {
+      if (password_records_list && password_records_list->next && username_node) {
         LOG ("More than 1 password saved, hooking menu for choosing which on focus");
-        g_object_set_data (G_OBJECT (username_node), "ephy-auth-data-list", auth_data_list);
+        g_object_set_data (G_OBJECT (username_node), "ephy-password-records-list", password_records_list);
         g_object_set_data (G_OBJECT (username_node), "ephy-form-auth", form_auth);
         g_object_set_data (G_OBJECT (username_node), "ephy-document", document);
         webkit_dom_event_target_add_event_listener (WEBKIT_DOM_EVENT_TARGET (username_node), "input",
@@ -1173,7 +1149,7 @@ web_page_form_controls_associated (WebKitWebPage    *web_page,
                                                     G_CALLBACK (username_node_changed_cb), FALSE,
                                                     web_page);
       } else
-        LOG ("No items or a single item in auth_data_list, not hooking menu for choosing.");
+        LOG ("No items or a single item in password_records_list, not hooking menu for choosing.");
 
       pre_fill_form (form_auth);
 
@@ -1476,9 +1452,7 @@ ephy_web_extension_dispose (GObject *object)
   g_clear_object (&extension->uri_tester);
   g_clear_object (&extension->overview_model);
   g_clear_object (&extension->permissions_manager);
-
-  g_clear_pointer (&extension->form_auth_data_cache,
-                   ephy_form_auth_data_cache_free);
+  g_clear_object (&extension->password_manager);
 
   if (extension->form_auth_data_save_requests) {
     g_hash_table_destroy (extension->form_auth_data_save_requests);
@@ -1589,7 +1563,7 @@ ephy_web_extension_initialize (EphyWebExtension   *extension,
 
   extension->extension = g_object_ref (wk_extension);
   if (!is_private_profile)
-    extension->form_auth_data_cache = ephy_form_auth_data_cache_new ();
+    extension->password_manager = ephy_password_manager_new ();
 
   extension->permissions_manager = ephy_permissions_manager_new ();
 
diff --git a/lib/ephy-password-manager.c b/lib/ephy-password-manager.c
new file mode 100644
index 0000000..2337755
--- /dev/null
+++ b/lib/ephy-password-manager.c
@@ -0,0 +1,483 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2017 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  This file is part of Epiphany.
+ *
+ *  Epiphany is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Epiphany is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Epiphany.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "ephy-password-manager.h"
+
+#include "ephy-debug.h"
+#include "ephy-uri-helpers.h"
+
+#include <glib/gi18n.h>
+
+const SecretSchema *
+ephy_password_manager_get_password_schema (void)
+{
+  static const SecretSchema schema = {
+    "org.epiphany.FormPassword", SECRET_SCHEMA_NONE,
+    {
+      { URI_KEY, SECRET_SCHEMA_ATTRIBUTE_STRING },
+      { FORM_USERNAME_KEY, SECRET_SCHEMA_ATTRIBUTE_STRING },
+      { FORM_PASSWORD_KEY, SECRET_SCHEMA_ATTRIBUTE_STRING },
+      { USERNAME_KEY, SECRET_SCHEMA_ATTRIBUTE_STRING },
+      { "NULL", 0 },
+    }
+  };
+  return &schema;
+}
+
+struct _EphyPasswordManager {
+  GObject parent_instance;
+
+  GSList *records;
+};
+
+G_DEFINE_TYPE (EphyPasswordManager, ephy_password_manager, G_TYPE_OBJECT)
+
+typedef struct {
+  EphyPasswordManagerQueryCallback callback;
+  gpointer user_data;
+} QueryAsyncData;
+
+static QueryAsyncData *
+query_async_data_new (EphyPasswordManagerQueryCallback callback,
+                      gpointer                         user_data)
+{
+  QueryAsyncData *data;
+
+  data = g_slice_new (QueryAsyncData);
+  data->callback = callback;
+  data->user_data = user_data;
+
+  return data;
+}
+
+static void
+query_async_data_free (QueryAsyncData *data)
+{
+  g_slice_free (QueryAsyncData, data);
+}
+
+static void
+ephy_password_manager_dispose (GObject *object)
+{
+  EphyPasswordManager *self = EPHY_PASSWORD_MANAGER (object);
+
+  g_slist_free_full (self->records, g_object_unref);
+  self->records = NULL;
+
+  G_OBJECT_CLASS (ephy_password_manager_parent_class)->dispose (object);
+}
+
+static void
+ephy_password_manager_class_init (EphyPasswordManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = ephy_password_manager_dispose;
+}
+
+static void
+secret_service_search_all_cb (SecretService       *service,
+                              GAsyncResult        *result,
+                              EphyPasswordManager *self)
+{
+  GList *matches = NULL;
+  GError *error = NULL;
+
+  matches = secret_service_search_finish (service, result, &error);
+  if (error) {
+    g_warning ("Failed to search secrets in password schema: %s", error->message);
+    g_error_free (error);
+    return;
+  }
+
+  for (GList *l = matches; l && l->data; l = l->next) {
+    SecretItem *item = (SecretItem *)l->data;
+    SecretValue *value = secret_item_get_secret (item);
+    GHashTable *attributes = secret_item_get_attributes (item);
+    const char *uri = g_hash_table_lookup (attributes, URI_KEY);
+    const char *form_username = g_hash_table_lookup (attributes, FORM_USERNAME_KEY);
+    const char *form_password = g_hash_table_lookup (attributes, FORM_PASSWORD_KEY);
+    const char *username = g_hash_table_lookup (attributes, USERNAME_KEY);
+    const char *password = secret_value_get (value, NULL);
+    EphyPasswordRecord *record;
+
+    LOG ("Loading password record for uri=%s, form_username=%s, form_password=%s, username=%s",
+         uri, form_username, form_password, username);
+
+    record = ephy_password_record_new (uri, form_username, form_password, username, password);
+    self->records = g_slist_prepend (self->records, record);
+
+    secret_value_unref (value);
+    g_hash_table_unref (attributes);
+  }
+
+  g_list_free_full (matches, g_object_unref);
+}
+
+static void
+ephy_password_manager_load_passwords (EphyPasswordManager *self)
+{
+  GHashTable *attributes;
+
+  g_assert (EPHY_IS_PASSWORD_MANAGER (self));
+
+  attributes = secret_attributes_build (EPHY_FORM_PASSWORD_SCHEMA, NULL);
+  secret_service_search (NULL,
+                         EPHY_FORM_PASSWORD_SCHEMA,
+                         attributes,
+                         SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS,
+                         NULL,
+                         (GAsyncReadyCallback)secret_service_search_all_cb,
+                         self);
+
+  g_hash_table_unref (attributes);
+}
+
+static void
+ephy_password_manager_init (EphyPasswordManager *self)
+{
+  ephy_password_manager_load_passwords (self);
+}
+
+EphyPasswordManager *
+ephy_password_manager_new (void)
+{
+  return EPHY_PASSWORD_MANAGER (g_object_new (EPHY_TYPE_PASSWORD_MANAGER, NULL));
+}
+
+GSList *
+ephy_password_manager_get_cached_by_uri (EphyPasswordManager *self,
+                                         const char          *uri)
+{
+  GSList *list = NULL;
+  char *origin;
+
+  g_return_val_if_fail (EPHY_IS_PASSWORD_MANAGER (self), NULL);
+  g_return_val_if_fail (uri, NULL);
+
+  origin = ephy_uri_to_security_origin (uri);
+
+  for (GSList *l = self->records; l && l->data; l = l->next) {
+    EphyPasswordRecord *record = EPHY_PASSWORD_RECORD (l->data);
+
+    if (!g_strcmp0 (origin, ephy_password_record_get_origin (record)))
+      list = g_slist_prepend (list, record);
+  }
+
+  g_free (origin);
+
+  return list;
+}
+
+static EphyPasswordRecord *
+ephy_password_manager_get_cached (EphyPasswordManager *self,
+                                  const char          *origin,
+                                  const char          *form_username,
+                                  const char          *form_password,
+                                  const char          *username)
+{
+  g_assert (EPHY_IS_PASSWORD_MANAGER (self));
+
+  for (GSList *l = self->records; l && l->data; l = l->next) {
+    EphyPasswordRecord *record = EPHY_PASSWORD_RECORD (l->data);
+
+    if (!g_strcmp0 (origin, ephy_password_record_get_origin (record)) &&
+        !g_strcmp0 (form_username, ephy_password_record_get_form_username (record)) &&
+        !g_strcmp0 (form_password, ephy_password_record_get_form_password (record)) &&
+        !g_strcmp0 (username, ephy_password_record_get_username (record)))
+      return record;
+  }
+
+  return NULL;
+}
+
+void
+ephy_password_manager_save (EphyPasswordManager *self,
+                            const char          *uri,
+                            const char          *form_username,
+                            const char          *form_password,
+                            const char          *username,
+                            const char          *password)
+{
+  EphyPasswordRecord *record = NULL;
+  char *origin;
+
+  g_return_if_fail (EPHY_IS_PASSWORD_MANAGER (self));
+  g_return_if_fail (uri);
+  g_return_if_fail (password);
+  g_return_if_fail (!form_username || username);
+  g_return_if_fail (!form_password || password);
+
+  origin = ephy_uri_to_security_origin (uri);
+
+  /* Check if there is an existing record for the given parameters.
+   * If there is, don't create a new record, only update password. */
+  record = ephy_password_manager_get_cached (self, origin,
+                                             form_username, form_password,
+                                             username);
+  if (record) {
+    ephy_password_record_set_password (record, password);
+  } else {
+    record = ephy_password_record_new (origin, form_username, form_password,
+                                       username, password);
+    self->records = g_slist_prepend (self->records, record);
+  }
+
+  /* Add/overwrite the password in the secret schema. */
+  ephy_password_manager_store (origin,
+                               form_username, form_password,
+                               username, password,
+                               NULL, NULL);
+
+  g_free (origin);
+}
+
+static GHashTable *
+get_attributes_table (const char *uri,
+                      const char *form_username,
+                      const char *form_password,
+                      const char *username)
+{
+  GHashTable *attributes = secret_attributes_build (EPHY_FORM_PASSWORD_SCHEMA, NULL);
+
+  if (uri)
+    g_hash_table_insert (attributes, g_strdup (URI_KEY), ephy_uri_to_security_origin (uri));
+  if (username)
+    g_hash_table_insert (attributes, g_strdup (USERNAME_KEY), g_strdup (username));
+  if (form_username)
+    g_hash_table_insert (attributes, g_strdup (FORM_USERNAME_KEY), g_strdup (form_username));
+  if (form_password)
+    g_hash_table_insert (attributes, g_strdup (FORM_PASSWORD_KEY), g_strdup (form_password));
+
+  return attributes;
+}
+
+static void
+secret_service_search_cb (SecretService  *service,
+                          GAsyncResult   *result,
+                          QueryAsyncData *data)
+{
+  GList *matches = NULL;
+  GSList *records = NULL;
+  GError *error = NULL;
+
+  matches = secret_service_search_finish (service, result, &error);
+  if (error) {
+    g_warning ("Failed to search secrets in password schema: %s", error->message);
+    g_error_free (error);
+    goto out;
+  }
+
+  for (GList *l = matches; l && l->data; l = l->next) {
+    SecretItem *item = (SecretItem *)l->data;
+    GHashTable *attributes = secret_item_get_attributes (item);
+    SecretValue *value = secret_item_get_secret (item);
+    const char *origin = g_hash_table_lookup (attributes, URI_KEY);
+    const char *form_username = g_hash_table_lookup (attributes, FORM_USERNAME_KEY);
+    const char *form_password = g_hash_table_lookup (attributes, FORM_PASSWORD_KEY);
+    const char *username = g_hash_table_lookup (attributes, USERNAME_KEY);
+    const char *password = secret_value_get (value, NULL);
+    EphyPasswordRecord *record;
+
+    LOG ("Query found password record for (%s, %s, %s, %s)",
+         origin, form_username, form_password, username);
+
+    record = ephy_password_record_new (origin, form_username, form_password, username, password);
+    records = g_slist_prepend (records, record);
+
+    secret_value_unref (value);
+    g_hash_table_unref (attributes);
+  }
+
+out:
+  if (data->callback)
+    data->callback (records, data->user_data);
+  query_async_data_free (data);
+  g_list_free_full (matches, g_object_unref);
+}
+
+void
+ephy_password_manager_query (EphyPasswordManager              *self,
+                             const char                       *uri,
+                             const char                       *form_username,
+                             const char                       *form_password,
+                             const char                       *username,
+                             EphyPasswordManagerQueryCallback  callback,
+                             gpointer                          user_data)
+{
+  QueryAsyncData *data;
+  GHashTable *attributes;
+
+  g_return_if_fail (EPHY_IS_PASSWORD_MANAGER (self));
+
+  LOG ("Querying password records for uri=%s, form_username=%s, form_password=%s, username=%s",
+       uri, form_username, form_password, username);
+
+  attributes = get_attributes_table (uri, form_username, form_password, username);
+  data = query_async_data_new (callback, user_data);
+
+  secret_service_search (NULL,
+                         EPHY_FORM_PASSWORD_SCHEMA,
+                         attributes,
+                         SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS,
+                         NULL,
+                         (GAsyncReadyCallback)secret_service_search_cb,
+                         data);
+
+  g_hash_table_unref (attributes);
+}
+
+static void
+secret_service_store_cb (SecretService *service,
+                         GAsyncResult  *result,
+                         GTask         *task)
+{
+  GError *error = NULL;
+
+  secret_service_store_finish (service, result, &error);
+  if (error)
+    g_task_return_error (task, error);
+  else
+    g_task_return_boolean (task, TRUE);
+
+  g_object_unref (task);
+}
+
+void
+ephy_password_manager_store (const char          *uri,
+                             const char          *form_username,
+                             const char          *form_password,
+                             const char          *username,
+                             const char          *password,
+                             GAsyncReadyCallback  callback,
+                             gpointer             user_data)
+{
+  SecretValue *value;
+  GHashTable *attributes;
+  GTask *task;
+  char *origin;
+  char *label;
+
+  g_return_if_fail (uri);
+  g_return_if_fail (password);
+  g_return_if_fail (!form_username || username);
+  g_return_if_fail (!form_password || password);
+
+  task = g_task_new (NULL, NULL, callback, user_data);
+  value = secret_value_new (password, -1, "text/plain");
+  attributes = get_attributes_table (uri, form_username, form_password, username);
+  origin = ephy_uri_to_security_origin (uri);
+
+  if (username) {
+    /* Translators: The first %s is the username and the second one is the
+     * security origin where this is happening. Example: gnome gmail com and
+     * https://mail.google.com. */
+    label = g_strdup_printf (_("Password for %s in a form in %s"), username, origin);
+  } else {
+    /* Translators: The %s is the security origin where this is happening.
+     * Example: https://mail.google.com. */
+    label = g_strdup_printf (_("Password in a form in %s"), origin);
+  }
+
+  LOG ("Storing password record for uri=%s, form_username=%s, form_password=%s, username=%s",
+       uri, form_username, form_password, username);
+
+  secret_service_store (NULL, EPHY_FORM_PASSWORD_SCHEMA,
+                        attributes, NULL, label, value, NULL,
+                        (GAsyncReadyCallback)secret_service_store_cb,
+                        g_object_ref (task));
+
+  g_free (label);
+  g_free (origin);
+  secret_value_unref (value);
+  g_hash_table_unref (attributes);
+  g_object_unref (task);
+}
+
+gboolean
+ephy_password_manager_store_finish (GAsyncResult  *result,
+                                    GError       **error)
+{
+  g_return_val_if_fail (!error || !(*error), FALSE);
+  g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+secret_service_clear_cb (SecretService *service,
+                         GAsyncResult  *result,
+                         gpointer       user_data)
+{
+  GError *error = NULL;
+
+  secret_service_clear_finish (service, result, &error);
+  if (error) {
+    g_warning ("Failed to clear secrets from password schema: %s", error->message);
+    g_error_free (error);
+  }
+}
+
+void
+ephy_password_manager_forget (EphyPasswordManager *self,
+                              const char          *origin,
+                              const char          *form_username,
+                              const char          *form_password,
+                              const char          *username)
+{
+  EphyPasswordRecord *record;
+  GHashTable *attributes;
+
+  g_return_if_fail (EPHY_IS_PASSWORD_MANAGER (self));
+  g_return_if_fail (origin);
+  g_return_if_fail (form_password);
+  g_return_if_fail (!form_username || username);
+
+  attributes = get_attributes_table (origin, form_username, form_password, username);
+  secret_service_clear (NULL, EPHY_FORM_PASSWORD_SCHEMA, attributes, NULL,
+                        (GAsyncReadyCallback)secret_service_clear_cb, NULL);
+
+  /* If record is in cache, delete it. */
+  record = ephy_password_manager_get_cached (self, origin,
+                                             form_username, form_password,
+                                             username);
+  if (record) {
+    self->records = g_slist_remove (self->records, record);
+    g_object_unref (record);
+  }
+}
+
+void
+ephy_password_manager_forget_all (EphyPasswordManager *self)
+{
+  GHashTable *attributes;
+
+  g_return_if_fail (EPHY_IS_PASSWORD_MANAGER (self));
+
+  attributes = secret_attributes_build (EPHY_FORM_PASSWORD_SCHEMA, NULL);
+  secret_service_clear (NULL, EPHY_FORM_PASSWORD_SCHEMA, attributes, NULL,
+                        (GAsyncReadyCallback)secret_service_clear_cb, NULL);
+
+  g_slist_free_full (self->records, g_object_unref);
+  self->records = NULL;
+
+  g_hash_table_unref (attributes);
+}
diff --git a/lib/ephy-password-manager.h b/lib/ephy-password-manager.h
new file mode 100644
index 0000000..aa967aa
--- /dev/null
+++ b/lib/ephy-password-manager.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2017 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  This file is part of Epiphany.
+ *
+ *  Epiphany is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Epiphany is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Epiphany.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "ephy-password-record.h"
+
+#include <glib-object.h>
+#include <libsecret/secret.h>
+
+G_BEGIN_DECLS
+
+const SecretSchema *ephy_password_manager_get_password_schema (void) G_GNUC_CONST;
+
+#define URI_KEY           "uri"
+#define FORM_USERNAME_KEY "form_username"
+#define FORM_PASSWORD_KEY "form_password"
+#define USERNAME_KEY      "username"
+
+#define EPHY_FORM_PASSWORD_SCHEMA ephy_password_manager_get_password_schema ()
+
+#define EPHY_TYPE_PASSWORD_MANAGER (ephy_password_manager_get_type ())
+
+G_DECLARE_FINAL_TYPE (EphyPasswordManager, ephy_password_manager, EPHY, PASSWORD_MANAGER, GObject)
+
+typedef void (*EphyPasswordManagerQueryCallback) (GSList *records, gpointer user_data);
+
+EphyPasswordManager *ephy_password_manager_new                (void);
+GSList              *ephy_password_manager_get_cached_by_uri  (EphyPasswordManager *self,
+                                                               const char          *uri);
+void                 ephy_password_manager_save               (EphyPasswordManager *self,
+                                                               const char          *uri,
+                                                               const char          *form_username,
+                                                               const char          *form_password,
+                                                               const char          *username,
+                                                               const char          *password);
+void                 ephy_password_manager_query              (EphyPasswordManager              *self,
+                                                               const char                       *uri,
+                                                               const char                       
*form_username,
+                                                               const char                       
*form_password,
+                                                               const char                       *username,
+                                                               EphyPasswordManagerQueryCallback  callback,
+                                                               gpointer                          user_data);
+void                 ephy_password_manager_store               (const char          *uri,
+                                                                const char          *form_username,
+                                                                const char          *form_password,
+                                                                const char          *username,
+                                                                const char          *password,
+                                                                GAsyncReadyCallback  callback,
+                                                                gpointer             user_data);
+gboolean             ephy_password_manager_store_finish        (GAsyncResult  *result,
+                                                                GError       **error);
+void                 ephy_password_manager_forget              (EphyPasswordManager *self,
+                                                                const char          *origin,
+                                                                const char          *form_username,
+                                                                const char          *form_password,
+                                                                const char          *username);
+void                 ephy_password_manager_forget_all          (EphyPasswordManager *self);
+
+G_END_DECLS
diff --git a/lib/ephy-password-record.c b/lib/ephy-password-record.c
new file mode 100644
index 0000000..1d3852f
--- /dev/null
+++ b/lib/ephy-password-record.c
@@ -0,0 +1,236 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2017 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  This file is part of Epiphany.
+ *
+ *  Epiphany is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Epiphany is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Epiphany.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "ephy-password-record.h"
+
+struct _EphyPasswordRecord {
+  GObject parent_instance;
+
+  char       *origin;
+  char       *form_username;
+  char       *form_password;
+  char       *username;
+  char       *password;
+};
+
+G_DEFINE_TYPE (EphyPasswordRecord, ephy_password_record, G_TYPE_OBJECT)
+
+enum {
+  PROP_0,
+  PROP_ORIGIN,
+  PROP_FORM_USERNAME,
+  PROP_FORM_PASSWORD,
+  PROP_USERNAME,
+  PROP_PASSWORD,
+  LAST_PROP,
+};
+
+static GParamSpec *obj_properties[LAST_PROP];
+
+static void
+ephy_password_record_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  EphyPasswordRecord *self = EPHY_PASSWORD_RECORD (object);
+
+  switch (prop_id) {
+    case PROP_ORIGIN:
+      g_free (self->origin);
+      self->origin = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_FORM_USERNAME:
+      g_free (self->form_username);
+      self->form_username = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_FORM_PASSWORD:
+      g_free (self->form_password);
+      self->form_password = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_USERNAME:
+      g_free (self->username);
+      self->username = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_PASSWORD:
+      ephy_password_record_set_password (self, g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+ephy_password_record_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  EphyPasswordRecord *self = EPHY_PASSWORD_RECORD (object);
+
+  switch (prop_id) {
+    case PROP_ORIGIN:
+      g_value_set_string (value, ephy_password_record_get_origin (self));
+      break;
+    case PROP_FORM_USERNAME:
+      g_value_set_string (value, ephy_password_record_get_form_username (self));
+      break;
+    case PROP_FORM_PASSWORD:
+      g_value_set_string (value, ephy_password_record_get_form_password (self));
+      break;
+    case PROP_USERNAME:
+      g_value_set_string (value, ephy_password_record_get_username (self));
+      break;
+    case PROP_PASSWORD:
+      g_value_set_string (value, ephy_password_record_get_password (self));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+ephy_password_record_dispose (GObject *object)
+{
+  EphyPasswordRecord *self = EPHY_PASSWORD_RECORD (object);
+
+  g_clear_pointer (&self->origin, g_free);
+  g_clear_pointer (&self->form_username, g_free);
+  g_clear_pointer (&self->form_password, g_free);
+  g_clear_pointer (&self->username, g_free);
+  g_clear_pointer (&self->password, g_free);
+
+  G_OBJECT_CLASS (ephy_password_record_parent_class)->dispose (object);
+}
+
+static void
+ephy_password_record_class_init (EphyPasswordRecordClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = ephy_password_record_set_property;
+  object_class->get_property = ephy_password_record_get_property;
+  object_class->dispose = ephy_password_record_dispose;
+
+  obj_properties[PROP_ORIGIN] =
+    g_param_spec_string ("origin",
+                         "Origin",
+                         "Origin url that password is applicable at",
+                         "Default origin",
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+  obj_properties[PROP_FORM_USERNAME] =
+    g_param_spec_string ("form-username",
+                         "Form username",
+                         "HTML field name of the username",
+                         "Default form username",
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+  obj_properties[PROP_FORM_PASSWORD] =
+    g_param_spec_string ("form-password",
+                         "Form password",
+                         "HTML field name of the password",
+                         "Default form password",
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+  obj_properties[PROP_USERNAME] =
+    g_param_spec_string ("username",
+                         "Username",
+                         "Username to log in as",
+                         "Default username",
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+  obj_properties[PROP_PASSWORD] =
+    g_param_spec_string ("password",
+                         "Password",
+                         "Password for the username",
+                         "Default password",
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, LAST_PROP, obj_properties);
+}
+
+static void
+ephy_password_record_init (EphyPasswordRecord *self)
+{
+}
+
+EphyPasswordRecord *
+ephy_password_record_new (const char *origin,
+                          const char *form_username,
+                          const char *form_password,
+                          const char *username,
+                          const char *password)
+{
+  return EPHY_PASSWORD_RECORD (g_object_new (EPHY_TYPE_PASSWORD_RECORD,
+                                             "origin", origin,
+                                             "form-username", form_username,
+                                             "form-password", form_password,
+                                             "username", username,
+                                             "password", password,
+                                             NULL));
+}
+
+const char *
+ephy_password_record_get_origin (EphyPasswordRecord *self)
+{
+  g_return_val_if_fail (EPHY_IS_PASSWORD_RECORD (self), NULL);
+
+  return self->origin;
+}
+
+const char *
+ephy_password_record_get_form_username (EphyPasswordRecord *self)
+{
+  g_return_val_if_fail (EPHY_IS_PASSWORD_RECORD (self), NULL);
+
+  return self->form_username;
+}
+
+const char *
+ephy_password_record_get_form_password (EphyPasswordRecord *self)
+{
+  g_return_val_if_fail (EPHY_IS_PASSWORD_RECORD (self), NULL);
+
+  return self->form_password;
+}
+
+const char *
+ephy_password_record_get_username (EphyPasswordRecord *self)
+{
+  g_return_val_if_fail (EPHY_IS_PASSWORD_RECORD (self), NULL);
+
+  return self->username;
+}
+
+const char *
+ephy_password_record_get_password (EphyPasswordRecord *self)
+{
+  g_return_val_if_fail (EPHY_IS_PASSWORD_RECORD (self), NULL);
+
+  return self->password;
+}
+
+void
+ephy_password_record_set_password (EphyPasswordRecord *self,
+                                   const char         *password)
+{
+  g_return_if_fail (EPHY_IS_PASSWORD_RECORD (self));
+
+  g_free (self->password);
+  self->password = g_strdup (password);
+}
diff --git a/lib/ephy-password-record.h b/lib/ephy-password-record.h
new file mode 100644
index 0000000..2dcd128
--- /dev/null
+++ b/lib/ephy-password-record.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2017 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  This file is part of Epiphany.
+ *
+ *  Epiphany is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Epiphany is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Epiphany.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+#include <libsecret/secret.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_PASSWORD_RECORD (ephy_password_record_get_type ())
+
+G_DECLARE_FINAL_TYPE (EphyPasswordRecord, ephy_password_record, EPHY, PASSWORD_RECORD, GObject)
+
+EphyPasswordRecord *ephy_password_record_new                (const char *origin,
+                                                             const char *form_username,
+                                                             const char *form_passwords,
+                                                             const char *username,
+                                                             const char *password);
+const char         *ephy_password_record_get_origin         (EphyPasswordRecord *self);
+const char         *ephy_password_record_get_form_username  (EphyPasswordRecord *self);
+const char         *ephy_password_record_get_form_password  (EphyPasswordRecord *self);
+const char         *ephy_password_record_get_username       (EphyPasswordRecord *self);
+const char         *ephy_password_record_get_password       (EphyPasswordRecord *self);
+void                ephy_password_record_set_password       (EphyPasswordRecord *self,
+                                                             const char         *password);
+
+G_END_DECLS
diff --git a/lib/meson.build b/lib/meson.build
index 78ce8fa..6e88051 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -20,9 +20,10 @@ libephymisc_sources = [
   'ephy-favicon-helpers.c',
   'ephy-file-helpers.c',
   'ephy-filters-manager.c',
-  'ephy-form-auth-data.c',
   'ephy-gui.c',
   'ephy-langs.c',
+  'ephy-password-manager.c',
+  'ephy-password-record.c',
   'ephy-permissions-manager.c',
   'ephy-profile-utils.c',
   'ephy-search-engine-manager.c',
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 62bdad5..04ee4ee 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,9 +12,9 @@ embed/ephy-encodings.c
 embed/ephy-find-toolbar.c
 embed/ephy-web-view.c
 lib/ephy-file-helpers.c
-lib/ephy-form-auth-data.c
 lib/ephy-gui.c
 lib/ephy-langs.c
+lib/ephy-password-manager.c
 lib/ephy-string.c
 lib/ephy-time-helpers.c
 lib/ephy-zoom.h
diff --git a/src/clear-data-dialog.c b/src/clear-data-dialog.c
index ec532ae..4934e71 100644
--- a/src/clear-data-dialog.c
+++ b/src/clear-data-dialog.c
@@ -26,7 +26,6 @@
 #include <string.h>
 #include <webkit2/webkit2.h>
 
-#include "ephy-form-auth-data.h"
 #include "ephy-history-service.h"
 #include "ephy-embed-shell.h"
 
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index 4801cfd..6f917a5 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -56,6 +56,7 @@ struct _EphyShell {
   GList *windows;
   GObject *lockdown;
   EphyBookmarksManager *bookmarks_manager;
+  EphyPasswordManager *password_manager;
   GNetworkMonitor *network_monitor;
   GtkWidget *history_dialog;
   GObject *prefs_dialog;
@@ -345,6 +346,8 @@ ephy_shell_startup (GApplication *application)
                               G_BINDING_SYNC_CREATE);
     }
 
+    ephy_shell->password_manager = ephy_password_manager_new ();
+
     /* Create the sync service and register synchronizable managers. */
     ephy_shell->sync_service = ephy_sync_service_new ();
     if (g_settings_get_boolean (EPHY_SETTINGS_SYNC, EPHY_PREFS_SYNC_BOOKMARKS_ENABLED))
@@ -618,6 +621,7 @@ ephy_shell_dispose (GObject *object)
   g_clear_object (&shell->network_monitor);
   g_clear_object (&shell->sync_service);
   g_clear_object (&shell->bookmarks_manager);
+  g_clear_object (&shell->password_manager);
 
   g_slist_free_full (shell->open_uris_idle_ids, remove_open_uris_idle_cb);
   shell->open_uris_idle_ids = NULL;
@@ -805,6 +809,22 @@ ephy_shell_get_bookmarks_manager (EphyShell *shell)
 }
 
 /**
+ * ephy_shell_get_password_manager:
+ * @shell: the #EphyShell
+ *
+ * Returns the passwords manager.
+ *
+ * Return value: (transfer none): An #EphyPasswordManager.
+ */
+EphyPasswordManager *
+ephy_shell_get_password_manager (EphyShell *shell)
+{
+  g_return_val_if_fail (EPHY_IS_SHELL (shell), NULL);
+
+  return shell->password_manager;
+}
+
+/**
  * ephy_shell_get_net_monitor:
  *
  * Return value: (transfer none):
diff --git a/src/ephy-shell.h b/src/ephy-shell.h
index bd79449..6734d82 100644
--- a/src/ephy-shell.h
+++ b/src/ephy-shell.h
@@ -25,6 +25,7 @@
 #include "ephy-bookmarks-manager.h"
 #include "ephy-embed-shell.h"
 #include "ephy-embed.h"
+#include "ephy-password-manager.h"
 #include "ephy-session.h"
 #include "ephy-sync-service.h"
 #include "ephy-window.h"
@@ -102,6 +103,8 @@ GNetworkMonitor *ephy_shell_get_net_monitor              (EphyShell *shell);
 
 EphyBookmarksManager *ephy_shell_get_bookmarks_manager   (EphyShell *shell);
 
+EphyPasswordManager *ephy_shell_get_password_manager     (EphyShell *shell);
+
 EphySyncService *ephy_shell_get_sync_service             (EphyShell *shell);
 
 GtkWidget       *ephy_shell_get_history_dialog           (EphyShell *shell);
diff --git a/src/passwords-dialog.c b/src/passwords-dialog.c
index fcdaafa..2f0637f 100644
--- a/src/passwords-dialog.c
+++ b/src/passwords-dialog.c
@@ -27,7 +27,6 @@
 #define SECRET_API_SUBJECT_TO_CHANGE
 #include <libsecret/secret.h>
 
-#include "ephy-form-auth-data.h"
 #include "ephy-uri-helpers.h"
 #include "passwords-dialog.h"
 
@@ -39,14 +38,11 @@ typedef enum {
   COL_PASSWORDS_DATA,
 } PasswordsDialogColumn;
 
-#define URI_KEY           "uri"
-#define FORM_USERNAME_KEY "form_username"
-#define FORM_PASSWORD_KEY "form_password"
-#define USERNAME_KEY      "username"
-
 struct _EphyPasswordsDialog {
   GtkDialog parent_instance;
 
+  EphyPasswordManager *manager;
+  GSList *records;
   GtkWidget *passwords_treeview;
   GtkTreeSelection *tree_selection;
   GtkWidget *liststore;
@@ -59,8 +55,6 @@ struct _EphyPasswordsDialog {
 
   GActionGroup *action_group;
 
-  SecretService *ss;
-  GCancellable *ss_cancellable;
   gboolean filled;
 
   char *search_text;
@@ -83,31 +77,13 @@ ephy_passwords_dialog_dispose (GObject *object)
 {
   EphyPasswordsDialog *dialog = EPHY_PASSWORDS_DIALOG (object);
 
-  if (dialog->ss_cancellable != NULL) {
-    g_cancellable_cancel (dialog->ss_cancellable);
-    g_clear_object (&(dialog->ss_cancellable));
-  }
-
-  g_clear_object (&(dialog->ss));
   g_free (dialog->search_text);
   dialog->search_text = NULL;
 
-  G_OBJECT_CLASS (ephy_passwords_dialog_parent_class)->dispose (object);
-}
-
-static void
-secret_remove_ready_cb (GObject             *source,
-                        GAsyncResult        *res,
-                        EphyPasswordsDialog *dialog)
-{
-  secret_item_delete_finish (SECRET_ITEM (source), res, NULL);
-}
+  g_slist_free_full (dialog->records, g_object_unref);
+  dialog->records = NULL;
 
-static void
-secret_remove (EphyPasswordsDialog *dialog,
-               SecretItem          *item)
-{
-  secret_item_delete (item, NULL, (GAsyncReadyCallback)secret_remove_ready_cb, dialog);
+  G_OBJECT_CLASS (ephy_passwords_dialog_parent_class)->dispose (object);
 }
 
 static void
@@ -155,15 +131,21 @@ forget (GSimpleAction *action,
   /* Removal */
   for (r = rlist; r != NULL; r = r->next) {
     GValue val = { 0, };
-    SecretItem *item;
+    EphyPasswordRecord *record;
     GtkTreeIter filter_iter;
     GtkTreeIter child_iter;
 
     path = gtk_tree_row_reference_get_path ((GtkTreeRowReference *)r->data);
     gtk_tree_model_get_iter (model, &iter, path);
     gtk_tree_model_get_value (model, &iter, COL_PASSWORDS_DATA, &val);
-    item = g_value_get_object (&val);
-    secret_remove (dialog, item);
+    record = g_value_get_object (&val);
+    ephy_password_manager_forget (dialog->manager,
+                                  ephy_password_record_get_origin (record),
+                                  ephy_password_record_get_form_username (record),
+                                  ephy_password_record_get_form_password (record),
+                                  ephy_password_record_get_username (record));
+    dialog->records = g_slist_remove (dialog->records, record);
+    g_object_unref (record);
     g_value_unset (&val);
 
     gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (dialog->treemodelsort),
@@ -362,105 +344,53 @@ ephy_passwords_dialog_class_init (EphyPasswordsDialogClass *klass)
 }
 
 static void
-delete_all_passwords_ready_cb (GObject             *source_object,
-                               GAsyncResult        *res,
-                               EphyPasswordsDialog *dialog)
-{
-  secret_service_clear_finish (dialog->ss, res, NULL);
-  reload_model (dialog);
-}
-
-static void
 forget_all (GSimpleAction *action,
             GVariant      *parameter,
             gpointer       user_data)
 {
   EphyPasswordsDialog *dialog = EPHY_PASSWORDS_DIALOG (user_data);
-  GHashTable *attributes;
-
-  attributes = secret_attributes_build (EPHY_FORM_PASSWORD_SCHEMA, NULL);
-  secret_service_clear (dialog->ss,
-                        EPHY_FORM_PASSWORD_SCHEMA,
-                        attributes,
-                        dialog->ss_cancellable,
-                        (GAsyncReadyCallback)delete_all_passwords_ready_cb,
-                        dialog);
-  g_hash_table_unref (attributes);
+
+  ephy_password_manager_forget_all (dialog->manager);
+  g_slist_free_full (dialog->records, g_object_unref);
+  dialog->records = NULL;
+
+  reload_model (dialog);
 }
 
 static void
-secrets_search_ready_cb (GObject             *source_object,
-                         GAsyncResult        *res,
-                         EphyPasswordsDialog *dialog)
+populate_model_cb (GSList   *records,
+                   gpointer  user_data)
 {
-  GList *matches;
-  GList *l;
-
-  matches = secret_service_search_finish (dialog->ss, res, NULL);
-
-  for (l = matches; l != NULL; l = l->next) {
-    SecretItem *item = l->data;
-    SecretValue *value = NULL;
-    GHashTable *attributes = NULL;
-    const char *username = NULL;
-    const char *password = NULL;
-    char *origin = NULL;
-    GtkTreeIter iter;
+  EphyPasswordsDialog *dialog = EPHY_PASSWORDS_DIALOG (user_data);
 
-    attributes = secret_item_get_attributes (item);
-    username = g_hash_table_lookup (attributes, USERNAME_KEY);
-    value = secret_item_get_secret (item);
-    password = secret_value_get (value, NULL);
-    origin = ephy_uri_to_security_origin (g_hash_table_lookup (attributes, URI_KEY));
-    if (origin == NULL) {
-      g_hash_table_unref (attributes);
-      continue;
-    }
+  for (GSList *l = records; l && l->data; l = l->next) {
+    EphyPasswordRecord *record = EPHY_PASSWORD_RECORD (l->data);
+    GtkTreeIter iter;
 
     gtk_list_store_insert_with_values (GTK_LIST_STORE (dialog->liststore),
                                        &iter,
                                        -1,
-                                       COL_PASSWORDS_ORIGIN, origin,
-                                       COL_PASSWORDS_USER, username,
-                                       COL_PASSWORDS_PASSWORD, password,
+                                       COL_PASSWORDS_ORIGIN, ephy_password_record_get_origin (record),
+                                       COL_PASSWORDS_USER, ephy_password_record_get_username (record),
+                                       COL_PASSWORDS_PASSWORD, ephy_password_record_get_password (record),
                                        COL_PASSWORDS_INVISIBLE, "●●●●●●●●",
-                                       COL_PASSWORDS_DATA, item,
+                                       COL_PASSWORDS_DATA, record,
                                        -1);
-
-    g_free (origin);
-    g_hash_table_unref (attributes);
   }
 
-  g_list_free_full (matches, g_object_unref);
+  dialog->records = records;
 }
 
 static void
 populate_model (EphyPasswordsDialog *dialog)
 {
-  GHashTable *attributes;
-
+  g_assert (EPHY_IS_PASSWORDS_DIALOG (dialog));
   g_assert (dialog->filled == FALSE);
 
-  attributes = secret_attributes_build (EPHY_FORM_PASSWORD_SCHEMA, NULL);
-
-  secret_service_search (dialog->ss,
-                         EPHY_FORM_PASSWORD_SCHEMA,
-                         attributes,
-                         SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS,
-                         dialog->ss_cancellable,
-                         (GAsyncReadyCallback)secrets_search_ready_cb,
-                         dialog);
-
-  g_hash_table_unref (attributes);
-}
-
-static void
-secrets_ready_cb (GObject             *source_object,
-                  GAsyncResult        *res,
-                  EphyPasswordsDialog *dialog)
-{
-  dialog->ss = secret_service_get_finish (res, NULL);
-  populate_model (dialog);
+  /* Ask for all password records. */
+  ephy_password_manager_query (dialog->manager,
+                               NULL, NULL, NULL, NULL,
+                               populate_model_cb, dialog);
 }
 
 static gboolean
@@ -511,6 +441,15 @@ create_action_group (EphyPasswordsDialog *dialog)
 }
 
 static void
+show_dialog_cb (GtkWidget *widget,
+                gpointer   user_data)
+{
+  EphyPasswordsDialog *dialog = EPHY_PASSWORDS_DIALOG (widget);
+
+  populate_model (dialog);
+}
+
+static void
 ephy_passwords_dialog_init (EphyPasswordsDialog *dialog)
 {
   gtk_widget_init_template (GTK_WIDGET (dialog));
@@ -520,22 +459,23 @@ ephy_passwords_dialog_init (EphyPasswordsDialog *dialog)
                                           dialog,
                                           NULL);
 
-  dialog->ss_cancellable = g_cancellable_new ();
-  secret_service_get (SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS,
-                      dialog->ss_cancellable,
-                      (GAsyncReadyCallback)secrets_ready_cb,
-                      dialog);
-
   dialog->action_group = create_action_group (dialog);
   gtk_widget_insert_action_group (GTK_WIDGET (dialog), "passwords", dialog->action_group);
 
   update_selection_actions (G_ACTION_MAP (dialog->action_group), FALSE);
+
+  g_signal_connect (GTK_WIDGET (dialog), "show", G_CALLBACK (show_dialog_cb), NULL);
 }
 
 EphyPasswordsDialog *
-ephy_passwords_dialog_new (void)
+ephy_passwords_dialog_new (EphyPasswordManager *manager)
 {
-  return g_object_new (EPHY_TYPE_PASSWORDS_DIALOG,
-                       "use-header-bar", TRUE,
-                       NULL);
+  EphyPasswordsDialog *dialog;
+
+  dialog = EPHY_PASSWORDS_DIALOG (g_object_new (EPHY_TYPE_PASSWORDS_DIALOG,
+                                                "use-header-bar", TRUE,
+                                                NULL));
+  dialog->manager = manager;
+
+  return dialog;
 }
diff --git a/src/passwords-dialog.h b/src/passwords-dialog.h
index 02a256d..eafbf2a 100644
--- a/src/passwords-dialog.h
+++ b/src/passwords-dialog.h
@@ -20,11 +20,13 @@
 
 #pragma once
 
+#include "ephy-password-manager.h"
+
 G_BEGIN_DECLS
 
 #define EPHY_TYPE_PASSWORDS_DIALOG (ephy_passwords_dialog_get_type ())
 G_DECLARE_FINAL_TYPE (EphyPasswordsDialog, ephy_passwords_dialog, EPHY, PASSWORDS_DIALOG, GtkDialog);
 
-EphyPasswordsDialog *ephy_passwords_dialog_new (void);
+EphyPasswordsDialog *ephy_passwords_dialog_new (EphyPasswordManager *manager);
 
 G_END_DECLS
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
index 5148a17..ddc44c2 100644
--- a/src/prefs-dialog.c
+++ b/src/prefs-dialog.c
@@ -533,8 +533,10 @@ on_manage_passwords_button_clicked (GtkWidget   *button,
                                     PrefsDialog *dialog)
 {
   EphyPasswordsDialog *passwords_dialog;
+  EphyPasswordManager *password_manager;
 
-  passwords_dialog = ephy_passwords_dialog_new ();
+  password_manager = ephy_shell_get_password_manager (ephy_shell_get_default ());
+  passwords_dialog = ephy_passwords_dialog_new (password_manager);
 
   gtk_window_set_transient_for (GTK_WINDOW (passwords_dialog), GTK_WINDOW (dialog));
   gtk_window_set_modal (GTK_WINDOW (passwords_dialog), TRUE);
diff --git a/src/profile-migrator/ephy-profile-migrator.c b/src/profile-migrator/ephy-profile-migrator.c
index 91eb262..1f19ebf 100644
--- a/src/profile-migrator/ephy-profile-migrator.c
+++ b/src/profile-migrator/ephy-profile-migrator.c
@@ -34,8 +34,8 @@
 #include "ephy-bookmarks-manager.h"
 #include "ephy-debug.h"
 #include "ephy-file-helpers.h"
-#include "ephy-form-auth-data.h"
 #include "ephy-history-service.h"
+#include "ephy-password-manager.h"
 #include "ephy-prefs.h"
 #include "ephy-profile-utils.h"
 #include "ephy-search-engine-manager.h"
@@ -285,7 +285,7 @@ store_form_auth_data_cb (GObject      *object,
 {
   GError *error = NULL;
 
-  if (ephy_form_auth_data_store_finish (res, &error) == FALSE) {
+  if (ephy_password_manager_store_finish (res, &error) == FALSE) {
     g_warning ("Couldn't store a form password: %s", error->message);
     g_error_free (error);
     goto out;
@@ -348,13 +348,13 @@ load_collection_items_cb (SecretCollection *collection,
       secret_item_load_secret_sync (item, NULL, NULL);
       secret = secret_item_get_secret (item);
       password = secret_value_get (secret, NULL);
-      ephy_form_auth_data_store (actual_server,
-                                 form_username,
-                                 form_password,
-                                 username,
-                                 password,
-                                 (GAsyncReadyCallback)store_form_auth_data_cb,
-                                 g_hash_table_ref (attributes));
+      ephy_password_manager_store (actual_server,
+                                   form_username,
+                                   form_password,
+                                   username,
+                                   password,
+                                   (GAsyncReadyCallback)store_form_auth_data_cb,
+                                   g_hash_table_ref (attributes));
       g_free (actual_server);
       secret_value_unref (secret);
       g_hash_table_unref (t);
diff --git a/src/resources/gtk/passwords-dialog.ui b/src/resources/gtk/passwords-dialog.ui
index 7c69985..dd9b1a2 100644
--- a/src/resources/gtk/passwords-dialog.ui
+++ b/src/resources/gtk/passwords-dialog.ui
@@ -12,7 +12,7 @@
       <!-- column-name INVISIBLE -->
       <column type="gchararray"/>
       <!-- column-name DATA -->
-      <column type="SecretItem"/>
+      <column type="EphyPasswordRecord"/>
     </columns>
   </object>
   <object class="GtkTreeModelFilter" id="treemodelfilter">


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]