[epiphany/wip/tingping/password-manager: 7/7] Move password management out of web process



commit f82e6b580984dfe92954757adb629636b0c2dd33
Author: Patrick Griffis <pgriffis igalia com>
Date:   Wed Aug 22 17:36:45 2018 -0400

    Move password management out of web process
    
    This is required for reasonable sandboxing. Note that this doesn't
    block a malicious process but it does block malicious JS from
    being possible.

 embed/ephy-embed-shell.c                 | 350 ++++++++++++++++++++++++++-----
 embed/ephy-embed-shell.h                 |   2 +
 embed/ephy-web-extension-proxy.c         |  59 ++++--
 embed/ephy-web-extension-proxy.h         |  11 +-
 embed/ephy-web-view.c                    | 149 +++++--------
 embed/ephy-web-view.h                    |  13 ++
 embed/web-extension/ephy-web-extension.c | 303 ++++++--------------------
 embed/web-extension/resources/js/ephy.js | 104 +++++++--
 lib/sync/ephy-password-manager.c         | 149 -------------
 lib/widgets/meson.build                  |   1 +
 src/ephy-shell.c                         |   5 +-
 src/ephy-shell.h                         |   2 -
 src/prefs-dialog.c                       |   4 +-
 13 files changed, 570 insertions(+), 582 deletions(-)
---
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index d1a99ad4a..cd71ec62d 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -34,10 +34,12 @@
 #include "ephy-filters-manager.h"
 #include "ephy-flatpak-utils.h"
 #include "ephy-history-service.h"
+#include "ephy-password-manager.h"
 #include "ephy-profile-utils.h"
 #include "ephy-settings.h"
 #include "ephy-snapshot-service.h"
 #include "ephy-tabs-catalog.h"
+#include "ephy-uri-helpers.h"
 #include "ephy-uri-tester-shared.h"
 #include "ephy-view-source-handler.h"
 #include "ephy-web-app-utils.h"
@@ -61,6 +63,7 @@ typedef struct {
   WebKitUserContentManager *user_content;
   EphyDownloadsManager *downloads_manager;
   EphyPermissionsManager *permissions_manager;
+  EphyPasswordManager *password_manager;
   EphyAboutHandler *about_handler;
   EphyViewSourceHandler *source_handler;
   char *guid;
@@ -77,7 +80,6 @@ enum {
   PAGE_CREATED,
   ALLOW_TLS_CERTIFICATE,
   ALLOW_UNSAFE_BROWSING,
-  FORM_AUTH_DATA_SAVE_REQUESTED,
   SENSITIVE_FORM_FOCUSED,
 
   LAST_SIGNAL
@@ -102,6 +104,46 @@ G_DEFINE_TYPE_WITH_CODE (EphyEmbedShell, ephy_embed_shell, DZL_TYPE_APPLICATION,
                          G_IMPLEMENT_INTERFACE (EPHY_TYPE_TABS_CATALOG,
                                                 ephy_embed_shell_tabs_catalog_iface_init))
 
+static EphyWebView *
+ephy_embed_shell_get_view_for_page_id (EphyEmbedShell *self,
+                                                  guint64         page_id,
+                                                  const char     *origin)
+{
+  GList *windows = gtk_application_get_windows (GTK_APPLICATION (self));
+
+  for (GList *l = windows; l && l->data; l = l->next) {
+    g_autoptr(GList) tabs = ephy_embed_container_get_children (l->data);
+
+    for (GList *t = tabs; t && t->data; t = t->next) {
+      EphyWebView *ephy_view = ephy_embed_get_web_view (t->data);
+      WebKitWebView *web_view = WEBKIT_WEB_VIEW (ephy_view);
+
+      if (webkit_web_view_get_page_id (web_view) != page_id)
+        continue;
+
+      g_autofree char *real_origin = ephy_uri_to_security_origin (webkit_web_view_get_uri (web_view));
+
+      if (g_strcmp0 (real_origin, origin)) {
+        g_debug ("Extension's origin '%s' doesn't match real origin '%s'", origin, real_origin);
+        return NULL;
+      }
+
+      return ephy_view;
+    }
+  }
+
+  return NULL;
+}
+
+static EphyWebExtensionProxy *
+ephy_embed_shell_get_extension_proxy_for_page_id (EphyEmbedShell *self,
+                                                             guint64         page_id,
+                                                             const char     *origin)
+{
+  EphyWebView *view = ephy_embed_shell_get_view_for_page_id (self, page_id, origin);
+  return view ? ephy_web_view_get_web_extension_proxy (view) : NULL;
+}
+
 static GList *
 tabs_catalog_get_tabs_info (EphyTabsCatalog *catalog)
 {
@@ -166,6 +208,7 @@ ephy_embed_shell_dispose (GObject *object)
   g_clear_object (&priv->source_handler);
   g_clear_object (&priv->user_content);
   g_clear_object (&priv->downloads_manager);
+  g_clear_object (&priv->password_manager);
   g_clear_object (&priv->permissions_manager);
   g_clear_object (&priv->web_context);
   g_clear_pointer (&priv->guid, g_free);
@@ -176,28 +219,6 @@ ephy_embed_shell_dispose (GObject *object)
   G_OBJECT_CLASS (ephy_embed_shell_parent_class)->dispose (object);
 }
 
-static void
-web_extension_form_auth_data_message_received_cb (WebKitUserContentManager *manager,
-                                                  WebKitJavascriptResult   *message,
-                                                  EphyEmbedShell           *shell)
-{
-  guint request_id;
-  guint64 page_id;
-  const char *origin;
-  const char *username;
-  GVariant *variant;
-  gchar *message_str;
-
-  message_str = jsc_value_to_string (webkit_javascript_result_get_js_value (message));
-  variant = g_variant_parse (G_VARIANT_TYPE ("(utss)"), message_str, NULL, NULL, NULL);
-  g_free (message_str);
-
-  g_variant_get (variant, "(ut&s&s)", &request_id, &page_id, &origin, &username);
-  g_signal_emit (shell, signals[FORM_AUTH_DATA_SAVE_REQUESTED], 0,
-                 request_id, page_id, origin, username);
-  g_variant_unref (variant);
-}
-
 static void
 web_extension_sensitive_form_focused_message_received_cb (WebKitUserContentManager *manager,
                                                           WebKitJavascriptResult   *message,
@@ -323,6 +344,210 @@ web_extension_about_apps_message_received_cb (WebKitUserContentManager *manager,
   g_free (app_id);
 }
 
+typedef struct {
+  EphyEmbedShell *shell;
+  char *origin;
+  gint32 promise_id;
+  gint32 page_id;
+} PasswordManagerData;
+
+static void
+password_manager_query_finished_cb (GList               *records,
+                                    PasswordManagerData *data)
+{
+  EphyPasswordRecord *record;
+  const char *username = NULL;
+  const char *password = NULL;
+
+  record = records && records->data ? EPHY_PASSWORD_RECORD (records->data) : NULL;
+  if (record) {
+    username = ephy_password_record_get_username (record);
+    password = ephy_password_record_get_password (record);
+  }
+
+  EphyWebExtensionProxy *proxy = ephy_embed_shell_get_extension_proxy_for_page_id (
+                                    data->shell, data->page_id, data->origin);
+  if (proxy)
+    ephy_web_extension_proxy_password_query_response (proxy, username, password, data->promise_id);
+
+  g_object_unref (data->shell);
+  g_free (data->origin);
+  g_free (data);
+}
+
+static char *
+property_to_string_or_null (JSCValue *value, const char *name)
+{
+  g_autoptr(JSCValue) prop = jsc_value_object_get_property (value, name);
+  if (jsc_value_is_null (prop) || jsc_value_is_undefined (prop))
+    return NULL;
+  return jsc_value_to_string (prop);
+}
+
+static int
+property_to_int32 (JSCValue *value, const char *name)
+{
+  g_autoptr(JSCValue) prop = jsc_value_object_get_property (value, name);
+  return jsc_value_to_int32 (prop);
+}
+
+static void
+web_extension_password_manager_query_received_cb (WebKitUserContentManager *manager,
+                                                  WebKitJavascriptResult   *message,
+                                                  EphyEmbedShell           *shell)
+{
+  EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
+  JSCValue *value = webkit_javascript_result_get_js_value (message);
+  g_autofree char *origin = property_to_string_or_null (value, "origin");
+  g_autofree char *target_origin = property_to_string_or_null (value, "targetOrigin");
+  g_autofree char *username = property_to_string_or_null (value, "username");
+  g_autofree char *username_field = property_to_string_or_null (value, "usernameField");
+  g_autofree char *password_field = property_to_string_or_null (value, "passwordField");
+  gint32 promise_id = property_to_int32 (value, "promiseID");
+  gint32 page_id = property_to_int32 (value, "pageID");
+
+  PasswordManagerData *data = g_new (PasswordManagerData, 1);
+  data->shell = g_object_ref (shell);
+  data->promise_id = promise_id;
+  data->page_id = page_id;
+  data->origin = g_steal_pointer (&origin);
+
+  ephy_password_manager_query (priv->password_manager,
+                               NULL,
+                               origin,
+                               target_origin,
+                               username,
+                               username_field,
+                               password_field,
+                               (EphyPasswordManagerQueryCallback)password_manager_query_finished_cb,
+                               data);
+}
+
+typedef struct {
+  EphyPasswordManager *password_manager;
+  EphyPermissionsManager *permissions_manager;
+  char *origin;
+  char *target_origin;
+  char *username;
+  char *password;
+  char *username_field;
+  char *password_field;
+  gboolean is_new;
+} SaveAuthRequest;
+
+static void
+save_auth_request_free (SaveAuthRequest *request)
+{
+  g_object_unref (request->password_manager);
+  g_object_unref (request->permissions_manager);
+  g_free (request->origin);
+  g_free (request->target_origin);
+  g_free (request->username);
+  g_free (request->password);
+  g_free (request->username_field);
+  g_free (request->password_field);
+  g_free (request);
+}
+
+static void
+save_auth_request_response_cb (gint                 response_id,
+                               SaveAuthRequest      *data)
+{
+  if (response_id == GTK_RESPONSE_REJECT) {
+    ephy_permissions_manager_set_permission (data->permissions_manager,
+                                             EPHY_PERMISSION_TYPE_SAVE_PASSWORD,
+                                             data->origin,
+                                             EPHY_PERMISSION_DENY);
+  } else if (response_id == GTK_RESPONSE_YES) {
+    ephy_password_manager_save (data->password_manager, data->origin, data->target_origin,
+                                data->username, data->password, data->username_field,
+                                data->password_field, data->is_new);
+  }
+}
+
+static void
+web_extension_password_manager_save_real (EphyEmbedShell *shell,
+                                          JSCValue       *value,
+                                          gboolean        is_request)
+{
+  EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
+
+  g_autofree char *origin = property_to_string_or_null (value, "origin");
+  g_autofree char *target_origin = property_to_string_or_null (value, "targetOrigin");
+  g_autofree char *username = property_to_string_or_null (value, "username");
+  g_autofree char *password = property_to_string_or_null (value, "password");
+  g_autofree char *username_field = property_to_string_or_null (value, "usernameField");
+  g_autofree char *password_field = property_to_string_or_null (value, "passwordField");
+  g_autoptr(JSCValue) is_new_prop = jsc_value_object_get_property (value, "isNew");
+  gboolean is_new = jsc_value_to_boolean (is_new_prop);
+  gint32 page_id = property_to_int32 (value, "pageID");
+
+  // This also sanity checks that a page isn't saving websites for other origins
+  EphyWebView *view = ephy_embed_shell_get_view_for_page_id (
+                                    shell, page_id, origin);
+  if (!view)
+    return;
+
+  if (!is_request) {
+    ephy_password_manager_save (priv->password_manager, origin, target_origin, username,
+                                password, username_field, password_field, is_new);
+    return;
+  }
+
+  SaveAuthRequest *request = g_new (SaveAuthRequest, 1);
+  request->password_manager = g_object_ref (priv->password_manager);
+  request->permissions_manager = g_object_ref (priv->permissions_manager);
+  request->origin = g_steal_pointer (&origin);
+  request->target_origin = g_steal_pointer (&target_origin);
+  request->username = g_steal_pointer (&username);
+  request->password = g_steal_pointer (&password);
+  request->username_field = g_steal_pointer (&username_field);
+  request->password_field = g_steal_pointer (&password_field);
+  request->is_new = is_new;
+  ephy_web_view_show_auth_form_save_request (view, origin, username,
+                                             (EphySaveRequestCallback)save_auth_request_response_cb,
+                                             request, (GDestroyNotify)save_auth_request_free);
+}
+
+static void
+web_extension_password_manager_save_received_cb (WebKitUserContentManager *manager,
+                                                 WebKitJavascriptResult   *message,
+                                                 EphyEmbedShell           *shell)
+{
+  JSCValue *value = webkit_javascript_result_get_js_value (message);
+  web_extension_password_manager_save_real (shell, value, FALSE);
+}
+
+static void
+web_extension_password_manager_request_save_received_cb (WebKitUserContentManager *manager,
+                                                         WebKitJavascriptResult   *message,
+                                                         EphyEmbedShell           *shell)
+{
+  JSCValue *value = webkit_javascript_result_get_js_value (message);
+  web_extension_password_manager_save_real (shell, value, TRUE);
+}
+
+static void
+web_extension_password_manager_cached_users_received_cb (WebKitUserContentManager *manager,
+                                                         WebKitJavascriptResult   *message,
+                                                         EphyEmbedShell           *shell)
+{
+  EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
+
+  JSCValue *value = webkit_javascript_result_get_js_value (message);
+  g_autofree char *origin = jsc_value_to_string (jsc_value_object_get_property (value, "origin"));
+  gint32 promise_id = jsc_value_to_int32 (jsc_value_object_get_property (value, "promiseID"));
+  gint32 page_id = jsc_value_to_int32 (jsc_value_object_get_property (value, "pageID"));
+
+  GList *cached_users;
+  cached_users = ephy_password_manager_get_cached_users (priv->password_manager, origin);
+
+  EphyWebExtensionProxy *proxy = ephy_embed_shell_get_extension_proxy_for_page_id (
+                                    shell, page_id, origin);
+  if (proxy)
+    ephy_web_extension_proxy_password_cached_users_response (proxy, cached_users, promise_id);
+}
+
 static void
 history_service_url_title_changed_cb (EphyHistoryService *service,
                                       const char         *url,
@@ -932,13 +1157,6 @@ ephy_embed_shell_startup (GApplication *application)
                     G_CALLBACK (web_extension_unsafe_browsing_error_page_message_received_cb),
                     shell);
 
-  webkit_user_content_manager_register_script_message_handler_in_world (priv->user_content,
-                                                                        "formAuthData",
-                                                                        priv->guid);
-  g_signal_connect (priv->user_content, "script-message-received::formAuthData",
-                    G_CALLBACK (web_extension_form_auth_data_message_received_cb),
-                    shell);
-
   webkit_user_content_manager_register_script_message_handler_in_world (priv->user_content,
                                                                         "sensitiveFormFocused",
                                                                         priv->guid);
@@ -952,6 +1170,34 @@ ephy_embed_shell_startup (GApplication *application)
                     G_CALLBACK (web_extension_about_apps_message_received_cb),
                     shell);
 
+  webkit_user_content_manager_register_script_message_handler_in_world (priv->user_content,
+                                                                        "passwordManagerQuery",
+                                                                        priv->guid);
+  g_signal_connect (priv->user_content, "script-message-received::passwordManagerQuery",
+                    G_CALLBACK (web_extension_password_manager_query_received_cb),
+                    shell);
+
+  webkit_user_content_manager_register_script_message_handler_in_world (priv->user_content,
+                                                                        "passwordManagerQueryUsernames",
+                                                                        priv->guid);
+  g_signal_connect (priv->user_content, "script-message-received::passwordManagerQueryUsernames",
+                    G_CALLBACK (web_extension_password_manager_cached_users_received_cb),
+                    shell);
+
+  webkit_user_content_manager_register_script_message_handler_in_world (priv->user_content,
+                                                                        "passwordManagerSave",
+                                                                        priv->guid);
+  g_signal_connect (priv->user_content, "script-message-received::passwordManagerSave",
+                    G_CALLBACK (web_extension_password_manager_save_received_cb),
+                    shell);
+
+  webkit_user_content_manager_register_script_message_handler_in_world (priv->user_content,
+                                                                        "passwordManagerRequestSave",
+                                                                        priv->guid);
+  g_signal_connect (priv->user_content, "script-message-received::passwordManagerRequestSave",
+                    G_CALLBACK (web_extension_password_manager_request_save_received_cb),
+                    shell);
+
   ephy_embed_shell_setup_process_model (shell);
   g_signal_connect (priv->web_context, "initialize-web-extensions",
                     G_CALLBACK (initialize_web_extensions),
@@ -962,6 +1208,8 @@ ephy_embed_shell_startup (GApplication *application)
                     G_CALLBACK (initialize_notification_permissions),
                     shell);
 
+  priv->password_manager = ephy_password_manager_new ();
+
   /* Favicon Database */
   if (priv->mode == EPHY_EMBED_SHELL_MODE_PRIVATE)
     favicon_db_path = g_build_filename (ephy_dot_dir (), "icondatabase", NULL);
@@ -1038,12 +1286,21 @@ ephy_embed_shell_shutdown (GApplication *application)
   webkit_user_content_manager_unregister_script_message_handler (priv->user_content,
                                                                  "unsafeBrowsingErrorPage");
   webkit_user_content_manager_unregister_script_message_handler_in_world (priv->user_content,
-                                                                          "formAuthData",
+                                                                          "passwordManagerRequestSave",
                                                                           priv->guid);
   webkit_user_content_manager_unregister_script_message_handler_in_world (priv->user_content,
                                                                           "sensitiveFormFocused",
                                                                           priv->guid);
   webkit_user_content_manager_unregister_script_message_handler (priv->user_content, "aboutApps");
+  webkit_user_content_manager_unregister_script_message_handler_in_world (priv->user_content,
+                                                                          "passwordManagerQuery",
+                                                                          priv->guid);
+  webkit_user_content_manager_unregister_script_message_handler_in_world (priv->user_content,
+                                                                          "passwordManagerSave",
+                                                                          priv->guid);
+  webkit_user_content_manager_unregister_script_message_handler_in_world (priv->user_content,
+                                                                          "passwordManagerQueryUsernames",
+                                                                          priv->guid);
 
   g_list_foreach (priv->web_extensions, (GFunc)ephy_embed_shell_unwatch_web_extension, application);
 
@@ -1224,29 +1481,6 @@ ephy_embed_shell_class_init (EphyEmbedShellClass *klass)
                   G_TYPE_NONE, 1,
                   G_TYPE_UINT64);
 
-  /**
-   * EphyEmbedShell::form-auth-data-save-requested:
-   * @shell: the #EphyEmbedShell
-   * @request_id: the identifier of the request
-   * @page_id: the identifier of the web page
-   * @hostname: the hostname
-   * @username: the username
-   *
-   * Emitted when a web page requests confirmation to save
-   * the form authentication data for the given @hostname and
-   * @username
-   */
-  signals[FORM_AUTH_DATA_SAVE_REQUESTED] =
-    g_signal_new ("form-auth-data-save-requested",
-                  EPHY_TYPE_EMBED_SHELL,
-                  G_SIGNAL_RUN_FIRST,
-                  0, NULL, NULL, NULL,
-                  G_TYPE_NONE, 4,
-                  G_TYPE_UINT,
-                  G_TYPE_UINT64,
-                  G_TYPE_STRING,
-                  G_TYPE_STRING);
-
   /**
    * EphyEmbedShell::sensitive-form-focused
    * @shell: the #EphyEmbedShell
@@ -1522,3 +1756,11 @@ ephy_embed_shell_get_search_engine_manager (EphyEmbedShell *shell)
     priv->search_engine_manager = ephy_search_engine_manager_new ();
   return priv->search_engine_manager;
 }
+
+EphyPasswordManager *
+ephy_embed_shell_get_password_manager (EphyEmbedShell *shell)
+{
+  EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
+
+  return priv->password_manager;
+}
diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h
index 23f2792ca..cf7cf557b 100644
--- a/embed/ephy-embed-shell.h
+++ b/embed/ephy-embed-shell.h
@@ -28,6 +28,7 @@
 #include "ephy-encodings.h"
 #include "ephy-gsb-service.h"
 #include "ephy-history-service.h"
+#include "ephy-password-manager.h"
 #include "ephy-permissions-manager.h"
 #include "ephy-search-engine-manager.h"
 
@@ -84,5 +85,6 @@ WebKitUserContentManager *ephy_embed_shell_get_user_content_manager (EphyEmbedSh
 EphyDownloadsManager     *ephy_embed_shell_get_downloads_manager    (EphyEmbedShell *shell);
 EphyPermissionsManager   *ephy_embed_shell_get_permissions_manager  (EphyEmbedShell *shell);
 EphySearchEngineManager  *ephy_embed_shell_get_search_engine_manager (EphyEmbedShell *shell);
+EphyPasswordManager      *ephy_embed_shell_get_password_manager      (EphyEmbedShell *shell);
 
 G_END_DECLS
diff --git a/embed/ephy-web-extension-proxy.c b/embed/ephy-web-extension-proxy.c
index 7d2dc4e3f..45c272fb7 100644
--- a/embed/ephy-web-extension-proxy.c
+++ b/embed/ephy-web-extension-proxy.c
@@ -188,25 +188,6 @@ ephy_web_extension_proxy_new (GDBusConnection *connection)
   return web_extension;
 }
 
-void
-ephy_web_extension_proxy_form_auth_data_save_confirmation_response (EphyWebExtensionProxy *web_extension,
-                                                                    guint                  request_id,
-                                                                    gboolean               response)
-{
-  g_assert (EPHY_IS_WEB_EXTENSION_PROXY (web_extension));
-
-  if (!web_extension->proxy)
-    return;
-
-  g_dbus_proxy_call (web_extension->proxy,
-                     "FormAuthDataSaveConfirmationResponse",
-                     g_variant_new ("(ub)", request_id, response),
-                     G_DBUS_CALL_FLAGS_NONE,
-                     -1,
-                     web_extension->cancellable,
-                     NULL, NULL);
-}
-
 void
 ephy_web_extension_proxy_history_set_urls (EphyWebExtensionProxy *web_extension,
                                            GList                 *urls)
@@ -313,3 +294,43 @@ ephy_web_extension_proxy_history_clear (EphyWebExtensionProxy *web_extension)
                      web_extension->cancellable,
                      NULL, NULL);
 }
+
+void
+ephy_web_extension_proxy_password_cached_users_response (EphyWebExtensionProxy *web_extension,
+                                                         GList                 *users,
+                                                         gint32                 id)
+{
+  if (!web_extension->proxy)
+    return;
+
+  GList *l;
+  g_auto(GVariantBuilder) builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_STRING_ARRAY);
+  for (l = users; l != NULL; l = l->next)
+    g_variant_builder_add (&builder, "s", l->data);
+
+  g_dbus_proxy_call (web_extension->proxy,
+                     "PasswordQueryUsernamesResponse",
+                     g_variant_new ("(asi)", &builder, id),
+                     G_DBUS_CALL_FLAGS_NONE,
+                     -1,
+                     web_extension->cancellable,
+                     NULL, NULL);
+}
+
+void
+ephy_web_extension_proxy_password_query_response (EphyWebExtensionProxy *web_extension,
+                                                  const char            *username,
+                                                  const char            *password,
+                                                  gint32                 id)
+{
+  if (!web_extension->proxy)
+    return;
+
+  g_dbus_proxy_call (web_extension->proxy,
+                     "PasswordQueryResponse",
+                     g_variant_new ("(ssi)", username ?: "", password ?: "", id),
+                     G_DBUS_CALL_FLAGS_NONE,
+                     -1,
+                     web_extension->cancellable,
+                     NULL, NULL);
+}
\ No newline at end of file
diff --git a/embed/ephy-web-extension-proxy.h b/embed/ephy-web-extension-proxy.h
index 180224674..6e3450f7e 100644
--- a/embed/ephy-web-extension-proxy.h
+++ b/embed/ephy-web-extension-proxy.h
@@ -29,9 +29,6 @@ G_BEGIN_DECLS
 G_DECLARE_FINAL_TYPE (EphyWebExtensionProxy, ephy_web_extension_proxy, EPHY, WEB_EXTENSION_PROXY, GObject)
 
 EphyWebExtensionProxy *ephy_web_extension_proxy_new                                       (GDBusConnection   
    *connection);
-void                   ephy_web_extension_proxy_form_auth_data_save_confirmation_response 
(EphyWebExtensionProxy *web_extension,
-                                                                                           guint             
     request_id,
-                                                                                           gboolean          
     response);
 void                   ephy_web_extension_proxy_history_set_urls                          
(EphyWebExtensionProxy *web_extension,
                                                                                            GList             
    *urls);
 void                   ephy_web_extension_proxy_history_set_url_thumbnail                 
(EphyWebExtensionProxy *web_extension,
@@ -45,5 +42,11 @@ void                   ephy_web_extension_proxy_history_delete_url
 void                   ephy_web_extension_proxy_history_delete_host                       
(EphyWebExtensionProxy *web_extension,
                                                                                            const char        
    *host);
 void                   ephy_web_extension_proxy_history_clear                             
(EphyWebExtensionProxy *web_extension);
-
+void                   ephy_web_extension_proxy_password_cached_users_response            
(EphyWebExtensionProxy *web_extension,
+                                                                                           GList             
    *users,
+                                                                                           gint32            
     id);
+void                   ephy_web_extension_proxy_password_query_response                   
(EphyWebExtensionProxy *web_extension,
+                                                                                           const char        
    *username,
+                                                                                           const char        
    *password,
+                                                                                           gint32            
     id);
 G_END_DECLS
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index 3c4a183f2..4a12e2071 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -44,7 +44,6 @@
 #include "ephy-uri-helpers.h"
 #include "ephy-view-source-handler.h"
 #include "ephy-web-app-utils.h"
-#include "ephy-web-extension-proxy.h"
 #include "ephy-zoom.h"
 
 #include <gio/gio.h>
@@ -571,6 +570,56 @@ ephy_web_view_create_form_auth_save_confirmation_info_bar (EphyWebView *web_view
   return info_bar;
 }
 
+typedef struct {
+  EphySaveRequestCallback callback;
+  gpointer callback_data;
+  GDestroyNotify callback_destroy;
+} SaveRequestData;
+
+static void
+save_auth_request_destroy (SaveRequestData *data,
+                           GClosure        *ignored)
+{
+  if (data->callback_destroy)
+    data->callback_destroy (data->callback_data);
+
+  g_free (data);
+}
+
+static void
+info_bar_save_request_response_cb (GtkInfoBar          *info_bar,
+                                   gint                 response_id,
+                                   SaveRequestData     *data)
+{
+  g_assert (data->callback);
+  data->callback (response_id, data->callback_data);
+  gtk_widget_destroy (GTK_WIDGET (info_bar));
+}
+
+void
+ephy_web_view_show_auth_form_save_request (EphyWebView            *web_view,
+                                           const char             *origin,
+                                           const char             *username,
+                                           EphySaveRequestCallback response_callback,
+                                           gpointer                response_data,
+                                           GDestroyNotify          response_destroy)
+{
+  GtkWidget *info_bar;
+
+  info_bar = ephy_web_view_create_form_auth_save_confirmation_info_bar (web_view, origin, username);
+
+  SaveRequestData *data = g_new(SaveRequestData, 1);
+  data->callback = response_callback;
+  data->callback_data = response_data;
+  data->callback_destroy = response_destroy;
+
+  g_signal_connect_data (info_bar, "response",
+                         G_CALLBACK (info_bar_save_request_response_cb),
+                         data, (GClosureNotify)save_auth_request_destroy, 0);
+
+  gtk_widget_show (info_bar);
+}
+
 static void
 update_navigation_flags (WebKitWebView *view)
 {
@@ -721,94 +770,6 @@ icon_changed_cb (EphyWebView *view,
   _ephy_web_view_update_icon (view);
 }
 
-typedef struct {
-  EphyWebView *web_view;
-  guint request_id;
-  char *origin;
-} FormAuthRequestData;
-
-static FormAuthRequestData *
-form_auth_request_data_new (EphyWebView *web_view,
-                            guint        request_id,
-                            const char  *origin)
-{
-  FormAuthRequestData *data;
-  data = g_slice_new (FormAuthRequestData);
-  data->web_view = web_view;
-  data->request_id = request_id;
-  data->origin = g_strdup (origin);
-  return data;
-}
-
-static void
-form_auth_request_data_free (FormAuthRequestData *data)
-{
-  g_free (data->origin);
-  g_slice_free (FormAuthRequestData, data);
-}
-
-static void
-form_auth_save_confirmation_info_bar_destroyed_cb (FormAuthRequestData *data,
-                                                   GObject             *where_the_info_bar_was)
-{
-  /* Ensure the hash table entry in the web process is removed. */
-  if (data->web_view->web_extension)
-    ephy_web_extension_proxy_form_auth_data_save_confirmation_response (data->web_view->web_extension,
-                                                                        data->request_id,
-                                                                        FALSE);
-  form_auth_request_data_free (data);
-}
-
-static void
-form_auth_data_save_confirmation_response (GtkInfoBar          *info_bar,
-                                           gint                 response_id,
-                                           FormAuthRequestData *data)
-{
-  if (data->web_view->web_extension) {
-    ephy_web_extension_proxy_form_auth_data_save_confirmation_response (data->web_view->web_extension,
-                                                                        data->request_id,
-                                                                        response_id == GTK_RESPONSE_YES);
-  }
-
-  if (response_id == GTK_RESPONSE_REJECT) {
-    EphyEmbedShell *shell = ephy_embed_shell_get_default ();
-    EphyPermissionsManager *manager = ephy_embed_shell_get_permissions_manager (shell);
-
-    ephy_permissions_manager_set_permission (manager,
-                                             EPHY_PERMISSION_TYPE_SAVE_PASSWORD,
-                                             data->origin,
-                                             EPHY_PERMISSION_DENY);
-  }
-
-  g_object_weak_unref (G_OBJECT (info_bar), (GWeakNotify)form_auth_save_confirmation_info_bar_destroyed_cb, 
data);
-  gtk_widget_destroy (GTK_WIDGET (info_bar));
-  form_auth_request_data_free (data);
-}
-
-static void
-form_auth_data_save_requested (EphyEmbedShell *shell,
-                               guint           request_id,
-                               guint64         page_id,
-                               const char     *origin,
-                               const char     *username,
-                               EphyWebView    *web_view)
-{
-  GtkWidget *info_bar;
-  FormAuthRequestData *data;
-
-  if (webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)) != page_id)
-    return;
-
-  info_bar = ephy_web_view_create_form_auth_save_confirmation_info_bar (web_view, origin, username);
-  data = form_auth_request_data_new (web_view, request_id, origin);
-  g_signal_connect (info_bar, "response",
-                    G_CALLBACK (form_auth_data_save_confirmation_response),
-                    data);
-  g_object_weak_ref (G_OBJECT (info_bar), (GWeakNotify)form_auth_save_confirmation_info_bar_destroyed_cb, 
data);
-
-  gtk_widget_show (info_bar);
-}
-
 static void
 sensitive_form_focused_cb (EphyEmbedShell *shell,
                            guint64         page_id,
@@ -892,10 +853,6 @@ page_created_cb (EphyEmbedShell        *shell,
   view->web_extension = web_extension;
   g_object_add_weak_pointer (G_OBJECT (view->web_extension), (gpointer *)&view->web_extension);
 
-  g_signal_connect_object (shell, "form-auth-data-save-requested",
-                           G_CALLBACK (form_auth_data_save_requested),
-                           view, 0);
-
   g_signal_connect_object (shell, "sensitive-form-focused",
                            G_CALLBACK (sensitive_form_focused_cb),
                            view, 0);
@@ -3746,3 +3703,9 @@ ephy_web_view_get_reader_mode_state (EphyWebView *view)
 {
   return view->reader_active;
 }
+
+EphyWebExtensionProxy *
+ephy_web_view_get_web_extension_proxy (EphyWebView *view)
+{
+  return view->web_extension;
+}
diff --git a/embed/ephy-web-view.h b/embed/ephy-web-view.h
index bd4a6c1b8..6fa09f481 100644
--- a/embed/ephy-web-view.h
+++ b/embed/ephy-web-view.h
@@ -26,6 +26,7 @@
 #include "ephy-embed-shell.h"
 #include "ephy-history-types.h"
 #include "ephy-security-levels.h"
+#include "ephy-web-extension-proxy.h"
 
 G_BEGIN_DECLS
 
@@ -69,6 +70,9 @@ typedef enum {
   EPHY_WEB_VIEW_ERROR_UNSAFE_BROWSING
 } EphyWebViewErrorPage;
 
+typedef void (* EphySaveRequestCallback) (int      response_id,
+                                          gpointer data);
+
 GType                      ephy_web_view_chrome_get_type          (void);
 GType                      ephy_web_view_security_level_get_type  (void);
 GtkWidget *                ephy_web_view_new                      (void);
@@ -157,4 +161,13 @@ gboolean                   ephy_web_view_is_reader_mode_available (EphyWebView
 
 gboolean                   ephy_web_view_get_reader_mode_state    (EphyWebView               *view);
 
+EphyWebExtensionProxy     *ephy_web_view_get_web_extension_proxy  (EphyWebView               *view);
+
+void                       ephy_web_view_show_auth_form_save_request (EphyWebView            *web_view,
+                                                                      const char             *origin,
+                                                                      const char             *username,
+                                                                      EphySaveRequestCallback 
response_callback,
+                                                                      gpointer                response_data,
+                                                                      GDestroyNotify          
response_destroy);
+
 G_END_DECLS
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
index 9b3fddfa7..4e11b600f 100644
--- a/embed/web-extension/ephy-web-extension.c
+++ b/embed/web-extension/ephy-web-extension.c
@@ -25,12 +25,9 @@
 #include "ephy-dbus-util.h"
 #include "ephy-debug.h"
 #include "ephy-file-helpers.h"
-#include "ephy-password-manager.h"
 #include "ephy-permissions-manager.h"
 #include "ephy-prefs.h"
 #include "ephy-settings.h"
-#include "ephy-sync-service.h"
-#include "ephy-sync-utils.h"
 #include "ephy-uri-helpers.h"
 #include "ephy-uri-tester.h"
 #include "ephy-web-overview-model.h"
@@ -53,14 +50,14 @@ struct _EphyWebExtension {
   GDBusConnection *dbus_connection;
   GArray *page_created_signals_pending;
 
-  EphySyncService *sync_service;
-  EphyPasswordManager *password_manager;
-  GHashTable *form_auth_data_save_requests;
   EphyWebOverviewModel *overview_model;
   EphyPermissionsManager *permissions_manager;
   EphyUriTester *uri_tester;
 
   WebKitScriptWorld *script_world;
+  WebKitWebPage *web_page;
+
+  gboolean is_private_profile;
 };
 
 static const char introspection_xml[] =
@@ -69,10 +66,6 @@ static const char introspection_xml[] =
   "  <signal name='PageCreated'>"
   "   <arg type='t' name='page_id' direction='out'/>"
   "  </signal>"
-  "  <method name='FormAuthDataSaveConfirmationResponse'>"
-  "   <arg type='u' name='request_id' direction='in'/>"
-  "   <arg type='b' name='should_store' direction='in'/>"
-  "  </method>"
   "  <method name='HistorySetURLs'>"
   "   <arg type='a(ss)' name='urls' direction='in'/>"
   "  </method>"
@@ -91,6 +84,15 @@ static const char introspection_xml[] =
   "   <arg type='s' name='host' direction='in'/>"
   "  </method>"
   "  <method name='HistoryClear'/>"
+  "  <method name='PasswordQueryResponse'>"
+  "    <arg type='s' name='username' direction='in'/>"
+  "    <arg type='s' name='password' direction='in'/>"
+  "    <arg type='i' name='id' direction='in'/>"
+  "  </method>"
+  "  <method name='PasswordQueryUsernamesResponse'>"
+  "    <arg type='as' name='users' direction='in'/>"
+  "    <arg type='i' name='id' direction='in'/>"
+  "  </method>"
   " </interface>"
   "</node>";
 
@@ -187,106 +189,6 @@ web_page_send_request (WebKitWebPage     *web_page,
   return FALSE;
 }
 
-typedef struct {
-  char *origin;
-  char *target_origin;
-  char *username;
-  char *password;
-  char *username_field_name;
-  char *password_field_name;
-  gboolean is_new;
-} SaveAuthRequest;
-
-static SaveAuthRequest *
-save_auth_request_new (const char *origin,
-                       const char *target_origin,
-                       const char *username,
-                       const char *password,
-                       const char *username_field_name,
-                       const char *password_field_name,
-                       gboolean    is_new)
-{
-  SaveAuthRequest *request;
-
-  request = g_new (SaveAuthRequest, 1);
-  request->origin = g_strdup (origin);
-  request->target_origin = g_strdup (target_origin);
-  request->username = g_strdup (username);
-  request->password = g_strdup (password);
-  request->username_field_name = g_strdup (username_field_name);
-  request->password_field_name = g_strdup (password_field_name);
-  request->is_new = is_new;
-
-  return request;
-}
-
-static void
-save_auth_request_free (SaveAuthRequest *request)
-{
-  g_free (request->origin);
-  g_free (request->target_origin);
-  g_free (request->username);
-  g_free (request->password);
-  g_free (request->username_field_name);
-  g_free (request->password_field_name);
-
-  g_free (request);
-}
-
-static GHashTable *
-ephy_web_extension_get_form_auth_data_save_requests (EphyWebExtension *extension)
-{
-  if (!extension->form_auth_data_save_requests) {
-    extension->form_auth_data_save_requests =
-      g_hash_table_new_full (g_direct_hash,
-                             g_direct_equal,
-                             NULL,
-                             (GDestroyNotify)save_auth_request_free);
-  }
-
-  return extension->form_auth_data_save_requests;
-}
-
-static guint
-form_auth_data_save_request_new_id (void)
-{
-  static guint form_auth_data_save_request_id = 0;
-
-  return ++form_auth_data_save_request_id;
-}
-
-static char *
-save_auth_requester (guint64     page_id,
-                     const char *origin,
-                     const char *target_origin,
-                     const char *username,
-                     const char *password,
-                     const char *username_field_name,
-                     const char *password_field_name,
-                     gboolean    is_new)
-{
-  GVariant *variant;
-  guint request_id;
-  char *retval;
-
-  request_id = form_auth_data_save_request_new_id ();
-  variant = g_variant_new ("(utss)",
-                           request_id,
-                           page_id,
-                           origin,
-                           username ? username : "");
-
-  retval = g_variant_print (variant, FALSE);
-  g_variant_unref (variant);
-
-  g_hash_table_insert (ephy_web_extension_get_form_auth_data_save_requests (ephy_web_extension_get ()),
-                       GINT_TO_POINTER (request_id), save_auth_request_new (origin, target_origin, username,
-                                                                            password, username_field_name,
-                                                                            password_field_name, is_new));
-
-  return retval;
-}
-
 static void
 web_page_will_submit_form (WebKitWebPage            *web_page,
                            WebKitDOMHTMLFormElement *dom_form,
@@ -301,7 +203,6 @@ web_page_will_submit_form (WebKitWebPage            *web_page,
   JSCContext *js_context;
   JSCValue *js_ephy;
   JSCValue *js_form;
-  JSCValue *js_requester;
   JSCValue *js_result;
 
   form_submit_handled =
@@ -318,21 +219,12 @@ web_page_will_submit_form (WebKitWebPage            *web_page,
   js_context = webkit_frame_get_js_context_for_script_world (source_frame, extension->script_world);
   js_ephy = jsc_context_get_value (js_context, "Ephy");
   js_form = webkit_frame_get_js_value_for_dom_object_in_script_world (frame, WEBKIT_DOM_OBJECT (dom_form), 
extension->script_world);
-  js_requester = jsc_value_new_function (js_context,
-                                         "saveAuthRequester",
-                                         G_CALLBACK (save_auth_requester), NULL, NULL,
-                                         G_TYPE_STRING, 8,
-                                         G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_STRING,
-                                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-                                         G_TYPE_STRING, G_TYPE_BOOLEAN);
   js_result = jsc_value_object_invoke_method (js_ephy,
                                               "handleFormSubmission",
                                               G_TYPE_UINT64, webkit_web_page_get_id (web_page),
                                               JSC_TYPE_VALUE, js_form,
-                                              JSC_TYPE_VALUE, js_requester,
                                               G_TYPE_NONE);
   g_object_unref (js_result);
-  g_object_unref (js_requester);
   g_object_unref (js_form);
   g_object_unref (js_ephy);
   g_object_unref (js_context);
@@ -382,7 +274,7 @@ web_page_form_controls_associated (WebKitWebPage    *web_page,
                                           G_CALLBACK (sensitive_form_message_serializer), NULL, NULL,
                                           G_TYPE_STRING, 2,
                                           G_TYPE_UINT64, G_TYPE_BOOLEAN);
-  remember_passwords = extension->password_manager &&
+  remember_passwords = !extension->is_private_profile &&
                        g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_REMEMBER_PASSWORDS);
   js_result = jsc_value_object_invoke_method (js_ephy,
                                               "formControlsAssociated",
@@ -496,6 +388,7 @@ ephy_web_extension_page_created_cb (EphyWebExtension *extension,
   g_object_unref (js_context);
 
   page_id = webkit_web_page_get_id (web_page);
+  extension->web_page = web_page;
   if (extension->dbus_connection)
     ephy_web_extension_emit_page_created (extension, page_id);
   else
@@ -515,6 +408,18 @@ ephy_web_extension_page_created_cb (EphyWebExtension *extension,
                     extension);
 }
 
+static JSCValue *
+get_password_manager (EphyWebExtension *self)
+{
+  g_assert (self->web_page);
+
+  WebKitFrame *frame = webkit_web_page_get_main_frame (self->web_page);
+  JSCContext *context = webkit_frame_get_js_context_for_script_world (frame,
+                          self->script_world);
+  g_autoptr(JSCValue) ephy = jsc_context_get_value (context, "Ephy");
+  return jsc_value_object_get_property (ephy, "passwordManager");
+}
+
 static void
 handle_method_call (GDBusConnection       *connection,
                     const char            *sender,
@@ -530,32 +435,7 @@ handle_method_call (GDBusConnection       *connection,
   if (g_strcmp0 (interface_name, EPHY_WEB_EXTENSION_INTERFACE) != 0)
     return;
 
-  if (g_strcmp0 (method_name, "FormAuthDataSaveConfirmationResponse") == 0) {
-    SaveAuthRequest *request;
-    guint request_id;
-    gboolean should_store;
-    GHashTable *requests;
-
-    requests = ephy_web_extension_get_form_auth_data_save_requests (extension);
-
-    g_variant_get (parameters, "(ub)", &request_id, &should_store);
-
-    request = g_hash_table_lookup (requests, GINT_TO_POINTER (request_id));
-    if (!request)
-      return;
-
-    if (should_store) {
-      ephy_password_manager_save (extension->password_manager,
-                                  request->origin,
-                                  request->target_origin,
-                                  request->username,
-                                  request->password,
-                                  request->username_field_name,
-                                  request->password_field_name,
-                                  request->is_new);
-    }
-    g_hash_table_remove (requests, GINT_TO_POINTER (request_id));
-  } else if (g_strcmp0 (method_name, "HistorySetURLs") == 0) {
+  if (g_strcmp0 (method_name, "HistorySetURLs") == 0) {
     if (extension->overview_model) {
       GVariantIter iter;
       GVariant *array;
@@ -611,6 +491,29 @@ handle_method_call (GDBusConnection       *connection,
     if (extension->overview_model)
       ephy_web_overview_model_clear (extension->overview_model);
     g_dbus_method_invocation_return_value (invocation, NULL);
+  } else if (g_strcmp0 (method_name, "PasswordQueryUsernamesResponse") == 0) {
+    g_autofree const char **users;
+    g_autoptr(JSCValue) ret;
+    gint32 id;
+
+    users = g_variant_get_strv (g_variant_get_child_value (parameters, 0), NULL);
+    g_variant_get_child (parameters, 1, "i", &id);
+
+    g_autoptr(JSCValue) password_manager = get_password_manager (extension);
+    ret = jsc_value_object_invoke_method (password_manager, "_onQueryUsernamesResponse",
+                                          G_TYPE_STRV, users, G_TYPE_INT, id, G_TYPE_NONE);
+  } else if(g_strcmp0 (method_name, "PasswordQueryResponse") == 0) {
+    const char *username;
+    const char *password;
+    gint32 id;
+    g_autoptr(JSCValue) ret;
+
+    g_variant_get (parameters, "(&s&si)", &username, &password, &id);
+    g_autoptr(JSCValue) password_manager = get_password_manager (extension);
+    ret = jsc_value_object_invoke_method (password_manager, "_onQueryResponse",
+                                          G_TYPE_STRING, username,
+                                          G_TYPE_STRING, password,
+                                          G_TYPE_INT, id, G_TYPE_NONE);
   }
 }
 
@@ -620,78 +523,6 @@ static const GDBusInterfaceVTable interface_vtable = {
   NULL
 };
 
-static void
-ephy_prefs_passwords_sync_enabled_cb (GSettings *settings,
-                                      char      *key,
-                                      gpointer   user_data)
-{
-  EphyWebExtension *extension;
-  EphySynchronizableManager *manager;
-
-  extension = EPHY_WEB_EXTENSION (user_data);
-  manager = EPHY_SYNCHRONIZABLE_MANAGER (extension->password_manager);
-
-  if (g_settings_get_boolean (settings, key))
-    ephy_sync_service_register_manager (extension->sync_service, manager);
-  else
-    ephy_sync_service_unregister_manager (extension->sync_service, manager);
-}
-
-static void
-ephy_web_extension_create_sync_service (EphyWebExtension *extension)
-{
-  EphySynchronizableManager *manager;
-
-  g_assert (EPHY_IS_WEB_EXTENSION (extension));
-  g_assert (EPHY_IS_PASSWORD_MANAGER (extension->password_manager));
-  g_assert (!extension->sync_service);
-
-  extension->sync_service = ephy_sync_service_new (FALSE);
-  manager = EPHY_SYNCHRONIZABLE_MANAGER (extension->password_manager);
-
-  if (ephy_sync_utils_passwords_sync_is_enabled ())
-    ephy_sync_service_register_manager (extension->sync_service, manager);
-
-  g_signal_connect (EPHY_SETTINGS_SYNC, "changed::"EPHY_PREFS_SYNC_PASSWORDS_ENABLED,
-                    G_CALLBACK (ephy_prefs_passwords_sync_enabled_cb), extension);
-}
-
-static void
-ephy_web_extension_destroy_sync_service (EphyWebExtension *extension)
-{
-  EphySynchronizableManager *manager;
-
-  g_assert (EPHY_IS_WEB_EXTENSION (extension));
-  g_assert (EPHY_IS_PASSWORD_MANAGER (extension->password_manager));
-  g_assert (EPHY_IS_SYNC_SERVICE (extension->sync_service));
-
-  manager = EPHY_SYNCHRONIZABLE_MANAGER (extension->password_manager);
-  ephy_sync_service_unregister_manager (extension->sync_service, manager);
-  g_signal_handlers_disconnect_by_func (EPHY_SETTINGS_SYNC,
-                                        ephy_prefs_passwords_sync_enabled_cb,
-                                        extension);
-
-  g_clear_object (&extension->sync_service);
-}
-
-static void
-ephy_prefs_sync_user_cb (GSettings *settings,
-                         char      *key,
-                         gpointer   user_data)
-{
-  EphyWebExtension *extension = EPHY_WEB_EXTENSION (user_data);
-
-  /* If the sync user has changed we need to destroy the previous sync service
-   * (which is no longer valid because the user specific data has been cleared)
-   * and create a new one which will load the new user specific data. This way
-   * we will correctly upload new saved passwords in the future.
-   */
-  if (ephy_sync_utils_user_is_signed_in ())
-    ephy_web_extension_create_sync_service (extension);
-  else if (extension->sync_service)
-    ephy_web_extension_destroy_sync_service (extension);
-}
-
 static void
 ephy_web_extension_dispose (GObject *object)
 {
@@ -701,17 +532,6 @@ ephy_web_extension_dispose (GObject *object)
   g_clear_object (&extension->overview_model);
   g_clear_object (&extension->permissions_manager);
 
-  if (extension->password_manager) {
-    if (extension->sync_service)
-      ephy_web_extension_destroy_sync_service (extension);
-    g_clear_object (&extension->password_manager);
-  }
-
-  if (extension->form_auth_data_save_requests) {
-    g_hash_table_destroy (extension->form_auth_data_save_requests);
-    extension->form_auth_data_save_requests = NULL;
-  }
-
   if (extension->page_created_signals_pending) {
     g_array_free (extension->page_created_signals_pending, TRUE);
     extension->page_created_signals_pending = NULL;
@@ -923,10 +743,14 @@ window_object_cleared_cb (WebKitScriptWorld *world,
                                                  js_context,
                                                  js_ephy);
 
-  if (extension->password_manager) {
-    ephy_password_manager_export_to_js_context (extension->password_manager,
-                                                js_context,
-                                                js_ephy);
+  if (!extension->is_private_profile) {
+    guint64 page_id = webkit_web_page_get_id (page);
+    g_assert (page_id < G_MAXINT32);
+
+    g_autoptr(JSCValue) js_password_manager_ctor = jsc_value_object_get_property (js_ephy, 
"PasswordManager");
+    g_autoptr(JSCValue) js_password_manager = jsc_value_constructor_call (js_password_manager_ctor,
+                                                                          G_TYPE_INT, page_id, G_TYPE_NONE);
+    jsc_value_object_set_property (js_ephy, "passwordManager", js_password_manager);
 
     js_function = jsc_value_new_function (js_context,
                                           "autoFill",
@@ -982,17 +806,8 @@ ephy_web_extension_initialize (EphyWebExtension   *extension,
                     extension);
 
   extension->extension = g_object_ref (wk_extension);
-  if (!is_private_profile) {
-    extension->password_manager = ephy_password_manager_new ();
-
-    if (is_browser_mode) {
-      if (ephy_sync_utils_user_is_signed_in ())
-        ephy_web_extension_create_sync_service (extension);
 
-      g_signal_connect (EPHY_SETTINGS_SYNC, "changed::"EPHY_PREFS_SYNC_USER,
-                        G_CALLBACK (ephy_prefs_sync_user_cb), extension);
-    }
-  }
+  extension->is_private_profile = is_private_profile;
 
   extension->permissions_manager = ephy_permissions_manager_new ();
 
diff --git a/embed/web-extension/resources/js/ephy.js b/embed/web-extension/resources/js/ephy.js
index b4c3f6864..637f7be45 100644
--- a/embed/web-extension/resources/js/ephy.js
+++ b/embed/web-extension/resources/js/ephy.js
@@ -309,6 +309,81 @@ Ephy.PreFillUserMenu = class PreFillUserMenu
     }
 };
 
+Ephy.PasswordManager = class PasswordManager
+{
+    constructor(pageID)
+    {
+        this._pageID = pageID;
+        this._pendingPromises = [];
+        this._promiseCounter = 0;
+    }
+
+    _takePendingPromise(id)
+    {
+        let element = this._pendingPromises.find(element => element.promiseID === id);
+        if (element)
+            this._pendingPromises = this._pendingPromises.filter(element => element.promiseID !== id);
+        return element;
+    }
+
+    _onQueryResponse(username, password, id)
+    {
+        let element = this._takePendingPromise(id)
+        if (element) {
+            if (username !== '' && password !== '')
+                element.resolver({username, password});
+            else
+                element.resolver(null);
+        }
+    }
+
+    query(origin, targetOrigin, username, usernameField, passwordField)
+    {
+        return new Promise((resolver, reject) => {
+            let promiseID = this._promiseCounter++;
+            window.webkit.messageHandlers.passwordManagerQuery.postMessage({
+                origin, targetOrigin, username, usernameField, passwordField, promiseID,
+                pageID: this._pageID,
+            });
+            this._pendingPromises.push({promiseID, resolver});
+        });
+    }
+
+    save(origin, targetOrigin, username, password, usernameField, passwordField, isNew)
+    {
+        window.webkit.messageHandlers.passwordManagerSave.postMessage({
+            origin, targetOrigin, username, password, usernameField, passwordField, isNew,
+            pageID: this._pageID,
+        });
+    }
+
+    requestSave(origin, targetOrigin, username, password, usernameField, passwordField, isNew, pageID)
+    {
+        window.webkit.messageHandlers.passwordManagerRequestSave.postMessage({
+            origin, targetOrigin, username, password, usernameField, passwordField, isNew,
+            pageID,
+        });
+    }
+
+    _onQueryUsernamesResponse(users, id)
+    {
+        let element = this._takePendingPromise(id)
+        if (element)
+            element.resolver(users);
+    }
+
+    queryUsernames(origin)
+    {
+        return new Promise((resolver, reject) => {
+            let promiseID = this._promiseCounter++;
+            window.webkit.messageHandlers.passwordManagerQueryUsernames.postMessage({
+                origin, promiseID, pageID: this._pageID,
+            });
+            this._pendingPromises.push({promiseID, resolver});
+        });
+    }
+}
+
 Ephy.FormManager = class FormManager
 {
     constructor(pageID, form)
@@ -367,18 +442,20 @@ Ephy.FormManager = class FormManager
         Ephy.log('Hooking and pre-filling a form');
 
         if (this._formAuth.usernameNode) {
-            let users = Ephy.passwordManager.cachedUsers(this._formAuth.url.origin);
-            if (users.length > 1) {
-                Ephy.log('More than one password saved, hooking menu for choosing which on focus');
-                this._preFillUserMenu = new Ephy.PreFillUserMenu(this, this._formAuth.usernameNode, users, 
this._formAuth.passwordNode);
-            } else {
-                Ephy.log('Single item in cached_users, not hooking menu for choosing.');
-            }
+            Ephy.passwordManager.queryUsernames(this._formAuth.url.origin).then((users) => {
+                if (users.length > 1) {
+                    Ephy.log('More than one password saved, hooking menu for choosing which on focus');
+                    this._preFillUserMenu = new Ephy.PreFillUserMenu(this, this._formAuth.usernameNode, 
users, this._formAuth.passwordNode);
+                } else {
+                    Ephy.log('Single item in username list, not hooking menu for choosing.');
+                }
+
+                this.preFill();
+            });
         } else {
-            Ephy.log('No items in cached_users, not hooking menu for choosing.');
+            Ephy.log('No items in username list, not hooking menu for choosing.');
+            this.preFill();
         }
-
-        this.preFill();
     }
 
     preFill()
@@ -412,7 +489,7 @@ Ephy.FormManager = class FormManager
         );
     }
 
-    handleFormSubmission(saveAuthRequester)
+    handleFormSubmission()
     {
         if (!this._formAuth)
             return;
@@ -472,13 +549,14 @@ Ephy.FormManager = class FormManager
                     Ephy.log('No result on query; asking whether we should store.');
                 }
 
-                window.webkit.messageHandlers.formAuthData.postMessage(saveAuthRequester(self._pageID,
+                Ephy.passwordManager.requestSave(
                     self._formAuth.url.origin, self._formAuth.targetURL.origin,
                     self._formAuth.usernameNode && self._formAuth.usernameNode.value ? 
self._formAuth.usernameNode.value : null,
                     self._formAuth.passwordNode.value ? self._formAuth.passwordNode.value : null,
                     self._formAuth.usernameNode ? self._formAuth.usernameNode.name : null,
                     self._formAuth.passwordNode.name ? self._formAuth.passwordNode.name : null,
-                    authInfo == null));
+                    authInfo == null,
+                    self._pageID);
             }
         );
     }
diff --git a/lib/sync/ephy-password-manager.c b/lib/sync/ephy-password-manager.c
index 8efd1f489..250a416e1 100644
--- a/lib/sync/ephy-password-manager.c
+++ b/lib/sync/ephy-password-manager.c
@@ -1106,152 +1106,3 @@ ephy_synchronizable_manager_iface_init (EphySynchronizableManagerInterface *ifac
   iface->save = synchronizable_manager_save;
   iface->merge = synchronizable_manager_merge;
 }
-
-typedef struct {
-  EphyPasswordManager *password_manager;
-  const char *origin;
-  const char *target_origin;
-  const char *username;
-  const char *username_field;
-  const char *password_field;
-} PasswordManagerPromiseData;
-
-static void
-js_password_manager_query_finished_cb (GList    *records,
-                                       JSCValue *resolve)
-{
-  JSCContext *js_context;
-  JSCValue *result, *value;
-  EphyPasswordRecord *record;
-
-  record = records && records->data ? EPHY_PASSWORD_RECORD (records->data) : NULL;
-  js_context = jsc_value_get_context (resolve);
-
-  if (record) {
-    JSCValue *property;
-
-    result = jsc_value_new_object (js_context, NULL, NULL);
-
-    property = jsc_value_new_string (js_context, ephy_password_record_get_username (record));
-    jsc_value_object_set_property (result, "username", property);
-    g_object_unref (property);
-
-    property = jsc_value_new_string (js_context, ephy_password_record_get_password (record));
-    jsc_value_object_set_property (result, "password", property);
-    g_object_unref (property);
-  } else {
-    result = jsc_value_new_null (js_context);
-  }
-
-  value = jsc_value_function_call (resolve, JSC_TYPE_VALUE, result, G_TYPE_NONE);
-  g_object_unref (value);
-  g_object_unref (result);
-
-  g_list_free_full (records, g_object_unref);
-  g_object_unref (resolve);
-}
-
-static void
-js_password_manager_query_resolve (JSCValue                   *resolve,
-                                   JSCValue                   *reject,
-                                   PasswordManagerPromiseData *data)
-{
-  ephy_password_manager_query (data->password_manager,
-                               NULL,
-                               data->origin,
-                               data->target_origin,
-                               data->username,
-                               data->username_field,
-                               data->password_field,
-                               (EphyPasswordManagerQueryCallback)js_password_manager_query_finished_cb,
-                               g_object_ref (resolve));
-}
-
-static JSCValue *
-js_password_manager_query (EphyPasswordManager *self,
-                           const char          *origin,
-                           const char          *target_origin,
-                           const char          *username,
-                           const char          *username_field,
-                           const char          *password_field)
-{
-  JSCContext *js_context = jsc_context_get_current ();
-  JSCValue *executor, *promise, *retval;
-  PasswordManagerPromiseData data = { self, origin, target_origin, username, username_field, password_field 
};
-
-  executor = jsc_value_new_function (js_context, NULL,
-                                     G_CALLBACK (js_password_manager_query_resolve),
-                                     &data, NULL,
-                                     G_TYPE_NONE, 2,
-                                     JSC_TYPE_VALUE,
-                                     JSC_TYPE_VALUE);
-  promise = jsc_context_get_value (js_context, "Promise");
-  retval = jsc_value_constructor_call (promise, JSC_TYPE_VALUE, executor, G_TYPE_NONE);
-  g_object_unref (executor);
-  g_object_unref (promise);
-
-  return retval;
-}
-
-static void
-js_password_manager_save (EphyPasswordManager *self,
-                          const char          *origin,
-                          const char          *target_origin,
-                          const char          *username,
-                          const char          *password,
-                          const char          *username_field,
-                          const char          *password_field,
-                          gboolean             is_new)
-{
-  ephy_password_manager_save (self, origin, target_origin, username, password, username_field, 
password_field, is_new);
-}
-
-static GPtrArray *
-js_password_manager_cached_users (EphyPasswordManager *self,
-                                  const char          *origin)
-{
-  JSCContext *js_context = jsc_context_get_current ();
-  GPtrArray *retval;
-  GList *cached_users, *l;
-
-  cached_users = ephy_password_manager_get_cached_users (self, origin);
-  retval = g_ptr_array_new_with_free_func (g_object_unref);
-
-  for (l = cached_users; l && l->data; l = g_list_next (l))
-    g_ptr_array_add (retval, jsc_value_new_string (js_context, l->data));
-
-  return retval;
-}
-
-void
-ephy_password_manager_export_to_js_context (EphyPasswordManager *self,
-                                            JSCContext          *js_context,
-                                            JSCValue            *js_namespace)
-{
-  JSCClass *js_class;
-  JSCValue *js_password_manager;
-
-  js_class = jsc_context_register_class (js_context, "PasswordManager", NULL, NULL, NULL);
-  jsc_class_add_method (js_class,
-                        "query",
-                        G_CALLBACK (js_password_manager_query), NULL, NULL,
-                        JSC_TYPE_VALUE, 5,
-                        G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-                        G_TYPE_STRING, G_TYPE_STRING);
-  jsc_class_add_method (js_class,
-                        "save",
-                        G_CALLBACK (js_password_manager_save), NULL, NULL,
-                        G_TYPE_NONE, 7,
-                        G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-                        G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-                        G_TYPE_BOOLEAN);
-  jsc_class_add_method (js_class,
-                        "cachedUsers",
-                        G_CALLBACK (js_password_manager_cached_users), NULL, NULL,
-                        G_TYPE_PTR_ARRAY, 1,
-                        G_TYPE_STRING);
-
-  js_password_manager = jsc_value_new_object (js_context, self, js_class);
-  jsc_value_object_set_property (js_namespace, "passwordManager", js_password_manager);
-  g_object_unref (js_password_manager);
-}
diff --git a/lib/widgets/meson.build b/lib/widgets/meson.build
index a42577859..afdb75293 100644
--- a/lib/widgets/meson.build
+++ b/lib/widgets/meson.build
@@ -42,6 +42,7 @@ libephywidgets_includes = include_directories(
   '../history',
   '../..',
   '../../embed',
+  '../sync',
   'contrib'
 )
 
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index d38d2450e..67aa19132 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -71,6 +71,7 @@ static EphyShell *ephy_shell = NULL;
 
 static void ephy_shell_dispose (GObject *object);
 static void ephy_shell_finalize (GObject *object);
+static EphyPasswordManager *ephy_shell_get_password_manager (EphyShell *shell);
 
 G_DEFINE_TYPE (EphyShell, ephy_shell, EPHY_TYPE_EMBED_SHELL)
 
@@ -904,13 +905,13 @@ ephy_shell_get_bookmarks_manager (EphyShell *shell)
  *
  * Return value: (transfer none): An #EphyPasswordManager.
  */
-EphyPasswordManager *
+static EphyPasswordManager *
 ephy_shell_get_password_manager (EphyShell *shell)
 {
   g_assert (EPHY_IS_SHELL (shell));
 
   if (shell->password_manager == NULL)
-    shell->password_manager = ephy_password_manager_new ();
+    shell->password_manager = g_object_ref (ephy_embed_shell_get_password_manager (EPHY_EMBED_SHELL 
(shell)));
 
   return shell->password_manager;
 }
diff --git a/src/ephy-shell.h b/src/ephy-shell.h
index b07bb4dad..cf8564b54 100644
--- a/src/ephy-shell.h
+++ b/src/ephy-shell.h
@@ -105,8 +105,6 @@ GNetworkMonitor *ephy_shell_get_net_monitor              (EphyShell *shell);
 
 EphyBookmarksManager *ephy_shell_get_bookmarks_manager   (EphyShell *shell);
 
-EphyPasswordManager *ephy_shell_get_password_manager     (EphyShell *shell);
-
 EphyHistoryManager *ephy_shell_get_history_manager       (EphyShell *shell);
 
 EphyOpenTabsManager *ephy_shell_get_open_tabs_manager    (EphyShell *shell);
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
index edcd1b474..d53fbc671 100644
--- a/src/prefs-dialog.c
+++ b/src/prefs-dialog.c
@@ -204,7 +204,7 @@ sync_collection_toggled_cb (GtkToggleButton *button,
   if (GTK_WIDGET (button) == dialog->sync_bookmarks_checkbutton) {
     manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_bookmarks_manager (shell));
   } else if (GTK_WIDGET (button) == dialog->sync_passwords_checkbutton) {
-    manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_password_manager (shell));
+    manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_embed_shell_get_password_manager (EPHY_EMBED_SHELL(shell)));
   } else if (GTK_WIDGET (button) == dialog->sync_history_checkbutton) {
     manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_history_manager (shell));
   } else if (GTK_WIDGET (button) == dialog->sync_open_tabs_checkbutton) {
@@ -904,7 +904,7 @@ on_manage_passwords_button_clicked (GtkWidget   *button,
   EphyPasswordsDialog *passwords_dialog;
   EphyPasswordManager *password_manager;
 
-  password_manager = ephy_shell_get_password_manager (ephy_shell_get_default ());
+  password_manager = ephy_embed_shell_get_password_manager (EPHY_EMBED_SHELL(ephy_shell_get_default ()));
   passwords_dialog = ephy_passwords_dialog_new (password_manager);
 
   gtk_window_set_transient_for (GTK_WINDOW (passwords_dialog), GTK_WINDOW (dialog));


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