[epiphany/wip/tingping/password-manager: 7/7] Move password management out of web process
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany/wip/tingping/password-manager: 7/7] Move password management out of web process
- Date: Mon, 27 Aug 2018 20:05:49 +0000 (UTC)
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]