summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Ivascu <gabrielivascu@gnome.org>2017-11-26 02:11:35 +0200
committerGabriel Ivascu <gabrielivascu@gnome.org>2017-11-26 02:42:14 +0200
commit40385b3d53674266cfe6b09b537837dde9e4d5d0 (patch)
tree1b87042e1b7178dc7d00b0ff9f6b748ebea22126
parentf92f634eceb6fc3a339982cc35c6b6ccbf362fb2 (diff)
downloadepiphany-wip/sync-device-name.tar.gz
sync: Fix incorrect device name on accounts.firefox.comwip/sync-device-name
This also fixes Epiphany's synced tabs not being viewable in Firefox. https://bugzilla.gnome.org/show_bug.cgi?id=790370
-rw-r--r--lib/ephy-profile-utils.h3
-rw-r--r--lib/ephy-sync-utils.c79
-rw-r--r--lib/ephy-sync-utils.h6
-rw-r--r--lib/sync/debug/ephy-sync-debug.c200
-rw-r--r--lib/sync/debug/ephy-sync-debug.h44
-rw-r--r--lib/sync/ephy-open-tabs-manager.c23
-rw-r--r--lib/sync/ephy-sync-service.c307
-rw-r--r--lib/sync/ephy-sync-service.h7
-rw-r--r--src/prefs-dialog.c4
-rw-r--r--src/profile-migrator/ephy-profile-migrator.c52
10 files changed, 550 insertions, 175 deletions
diff --git a/lib/ephy-profile-utils.h b/lib/ephy-profile-utils.h
index 3c215a4c6..9b97968ff 100644
--- a/lib/ephy-profile-utils.h
+++ b/lib/ephy-profile-utils.h
@@ -24,11 +24,12 @@
G_BEGIN_DECLS
-#define EPHY_PROFILE_MIGRATION_VERSION 22
+#define EPHY_PROFILE_MIGRATION_VERSION 23
#define EPHY_INSECURE_PASSWORDS_MIGRATION_VERSION 11
#define EPHY_SETTINGS_MIGRATION_VERSION 16
#define EPHY_FIREFOX_SYNC_PASSWORDS_MIGRATION_VERSION 19
#define EPHY_TARGET_ORIGIN_MIGRATION_VERSION 21
+#define EPHY_SYNC_DEVICE_ID_MIGRATION_VERSION 23
#define EPHY_BOOKMARKS_FILE "bookmarks.gvdb"
#define EPHY_HISTORY_FILE "ephy-history.db"
diff --git a/lib/ephy-sync-utils.c b/lib/ephy-sync-utils.c
index 97936b759..260d78d3a 100644
--- a/lib/ephy-sync-utils.c
+++ b/lib/ephy-sync-utils.c
@@ -23,6 +23,8 @@
#include "ephy-settings.h"
+#include <inttypes.h>
+#include <json-glib/json-glib.h>
#include <libsoup/soup.h>
#include <stdio.h>
#include <string.h>
@@ -230,6 +232,46 @@ ephy_sync_utils_get_random_sync_id (void)
return id;
}
+char *
+ephy_sync_utils_make_client_record (const char *device_bso_id,
+ const char *device_id,
+ const char *device_name)
+{
+ JsonNode *node;
+ JsonObject *object;
+ JsonArray *array;
+ char *protocol;
+ char *retval;
+
+ g_assert (device_bso_id);
+ g_assert (device_id);
+ g_assert (device_name);
+
+ array = json_array_new ();
+ protocol = g_strdup_printf ("1.%"PRIu32, EPHY_SYNC_STORAGE_VERSION);
+ json_array_add_string_element (array, protocol);
+
+ object = json_object_new ();
+ json_object_set_string_member (object, "id", device_bso_id);
+ json_object_set_string_member (object, "fxaDeviceId", device_id);
+ json_object_set_string_member (object, "name", device_name);
+ json_object_set_string_member (object, "type", "desktop");
+ json_object_set_string_member (object, "version", VERSION);
+ json_object_set_array_member (object, "protocols", array);
+ json_object_set_string_member (object, "os", "Linux");
+ json_object_set_string_member (object, "appPackage", "org.gnome.epiphany");
+ json_object_set_string_member (object, "application", "Epiphany");
+
+ node = json_node_new (JSON_NODE_OBJECT);
+ json_node_take_object (node, object);
+ retval = json_to_string (node, FALSE);
+
+ g_free (protocol);
+ json_node_unref (node);
+
+ return retval;
+}
+
void
ephy_sync_utils_set_device_id (const char *id)
{
@@ -240,15 +282,29 @@ ephy_sync_utils_set_device_id (const char *id)
char *
ephy_sync_utils_get_device_id (void)
{
- char *id;
+ return g_settings_get_string (EPHY_SETTINGS_SYNC, EPHY_PREFS_SYNC_DEVICE_ID);
+}
- id = g_settings_get_string (EPHY_SETTINGS_SYNC, EPHY_PREFS_SYNC_DEVICE_ID);
- if (!g_strcmp0 (id, "")) {
- g_free (id);
- id = ephy_sync_utils_get_random_sync_id ();
+char *
+ephy_sync_utils_get_device_bso_id (void)
+{
+ char *base64;
+ char *sync_id;
+ char *device_id;
+
+ device_id = g_settings_get_string (EPHY_SETTINGS_SYNC, EPHY_PREFS_SYNC_DEVICE_ID);
+ if (!g_strcmp0 (device_id, "")) {
+ /* This should never be reached. */
+ return g_strnfill (EPHY_SYNC_BSO_ID_LEN, '0');
}
- return id;
+ base64 = g_base64_encode ((guint8 *)device_id, EPHY_SYNC_DEVICE_ID_LEN);
+ sync_id = g_strndup (base64, EPHY_SYNC_BSO_ID_LEN);
+
+ g_free (base64);
+ g_free (device_id);
+
+ return sync_id;
}
void
@@ -264,11 +320,12 @@ ephy_sync_utils_get_device_name (void)
char *name;
name = g_settings_get_string (EPHY_SETTINGS_SYNC, EPHY_PREFS_SYNC_DEVICE_NAME);
- if (!g_strcmp0 (name, "")) {
- g_free (name);
- name = g_strdup_printf ("%s's GNOME Web on %s",
- g_get_user_name (), g_get_host_name ());
- }
+ if (g_strcmp0 (name, ""))
+ return name;
+
+ g_free (name);
+ name = g_strdup_printf ("%s’s GNOME Web on %s", g_get_user_name (), g_get_host_name ());
+ g_settings_set_string (EPHY_SETTINGS_SYNC, EPHY_PREFS_SYNC_DEVICE_NAME, name);
return name;
}
diff --git a/lib/ephy-sync-utils.h b/lib/ephy-sync-utils.h
index 4b2a5823b..5110068b2 100644
--- a/lib/ephy-sync-utils.h
+++ b/lib/ephy-sync-utils.h
@@ -34,6 +34,7 @@ const SecretSchema *ephy_sync_utils_get_secret_schema (void) G_GNUC_CONST;
#define EPHY_SYNC_FX_ACCOUNTS_SERVER_URL "https://api.accounts.firefox.com/v1"
#define EPHY_SYNC_STORAGE_VERSION 5
+#define EPHY_SYNC_DEVICE_ID_LEN 32
#define EPHY_SYNC_BSO_ID_LEN 12
char *ephy_sync_utils_encode_hex (const guint8 *data,
@@ -53,8 +54,13 @@ void ephy_sync_utils_generate_random_bytes (void *random_ctx,
char *ephy_sync_utils_get_audience (const char *url);
char *ephy_sync_utils_get_random_sync_id (void);
+char *ephy_sync_utils_make_client_record (const char *sync_id,
+ const char *device_id,
+ const char *device_name);
+
void ephy_sync_utils_set_device_id (const char *id);
char *ephy_sync_utils_get_device_id (void);
+char *ephy_sync_utils_get_device_bso_id (void);
void ephy_sync_utils_set_device_name (const char *name);
char *ephy_sync_utils_get_device_name (void);
diff --git a/lib/sync/debug/ephy-sync-debug.c b/lib/sync/debug/ephy-sync-debug.c
index 7cb7875ec..8a5a46c31 100644
--- a/lib/sync/debug/ephy-sync-debug.c
+++ b/lib/sync/debug/ephy-sync-debug.c
@@ -26,7 +26,6 @@
#include "ephy-sync-crypto.h"
#include "ephy-sync-utils.h"
-#include <json-glib/json-glib.h>
#include <libsoup/soup.h>
#include <string.h>
@@ -125,8 +124,37 @@ free_secrets:
}
static char *
-ephy_sync_debug_get_body_for_delete (const char *id,
- SyncCryptoKeyBundle *bundle)
+ephy_sync_debug_make_upload_body (const char *id,
+ const char *record,
+ SyncCryptoKeyBundle *bundle)
+{
+ JsonNode *node;
+ JsonObject *json;
+ char *payload;
+ char *body;
+
+ g_assert (id);
+ g_assert (record);
+ g_assert (bundle);
+
+ payload = ephy_sync_crypto_encrypt_record (record, bundle);
+ json = json_object_new ();
+ json_object_set_string_member (json, "id", id);
+ json_object_set_string_member (json, "payload", payload);
+ node = json_node_new (JSON_NODE_OBJECT);
+ json_node_set_object (node, json);
+ body = json_to_string (node, FALSE);
+
+ g_free (payload);
+ json_object_unref (json);
+ json_node_unref (node);
+
+ return body;
+}
+
+static char *
+ephy_sync_debug_make_delete_body (const char *id,
+ SyncCryptoKeyBundle *bundle)
{
JsonNode *node;
JsonObject *json;
@@ -613,6 +641,47 @@ free_endpoint:
}
/**
+ * ephy_sync_debug_upload_record:
+ * @collection: the collection name
+ * @id: the record id
+ * @record: record's JSON representation
+ *
+ * Upload record with id @id to collection @collection.
+ **/
+void
+ephy_sync_debug_upload_record (const char *collection,
+ const char *id,
+ const char *record)
+{
+ SyncCryptoKeyBundle *bundle;
+ char *id_safe;
+ char *endpoint;
+ char *body;
+ char *response;
+
+ g_assert (collection);
+ g_assert (id);
+ g_assert (record);
+
+ bundle = ephy_sync_debug_get_bundle_for_collection (collection);
+ if (!bundle)
+ return;
+
+ id_safe = soup_uri_encode (id, NULL);
+ endpoint = g_strdup_printf ("storage/%s/%s", collection, id_safe);
+ body = ephy_sync_debug_make_upload_body (id, record, bundle);
+ response = ephy_sync_debug_send_request (endpoint, "PUT", body);
+
+ LOG ("%s", response);
+
+ g_free (id_safe);
+ g_free (endpoint);
+ g_free (body);
+ g_free (response);
+ ephy_sync_crypto_key_bundle_free (bundle);
+}
+
+/**
* ephy_sync_debug_delete_collection:
* @collection: the collection name
*
@@ -652,7 +721,7 @@ ephy_sync_debug_delete_collection (const char *collection)
for (guint i = 0; i < json_array_get_length (array); i++) {
const char *id = json_array_get_string_element (array, i);
char *id_safe = soup_uri_encode (id, NULL);
- char *body = ephy_sync_debug_get_body_for_delete (id, bundle);
+ char *body = ephy_sync_debug_make_delete_body (id, bundle);
char *to = g_strdup_printf ("storage/%s/%s", collection, id_safe);
char *resp = ephy_sync_debug_send_request (to, "PUT", body);
@@ -701,7 +770,7 @@ ephy_sync_debug_delete_record (const char *collection,
id_safe = soup_uri_encode (id, NULL);
endpoint = g_strdup_printf ("storage/%s/%s", collection, id_safe);
- body = ephy_sync_debug_get_body_for_delete (id, bundle);
+ body = ephy_sync_debug_make_delete_body (id, bundle);
response = ephy_sync_debug_send_request (endpoint, "PUT", body);
LOG ("%s", response);
@@ -935,3 +1004,124 @@ free_response:
free_secrets:
json_object_unref (secrets);
}
+
+/**
+ * ephy_sync_debug_view_connected_devices:
+ *
+ * Displays the current devices connected to Firefox Sync for the signed in user.
+ *
+ * https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#get-accountdevices
+ **/
+void
+ephy_sync_debug_view_connected_devices (void)
+{
+ JsonObject *secrets;
+ SoupSession *session;
+ SoupMessage *msg;
+ guint8 *id;
+ guint8 *key;
+ guint8 *tmp;
+ char *id_hex;
+ char *url;
+ const char *session_token;
+
+ secrets = ephy_sync_debug_load_secrets ();
+ if (!secrets)
+ return;
+
+ session_token = json_object_get_string_member (secrets, "session_token");
+ ephy_sync_crypto_derive_session_token (session_token, &id, &key, &tmp);
+
+ url = g_strdup_printf ("%s/account/devices", EPHY_SYNC_FX_ACCOUNTS_SERVER_URL);
+ id_hex = ephy_sync_utils_encode_hex (id, 32);
+ msg = ephy_sync_debug_prepare_soup_message (url, "GET", NULL, id_hex, key, 32);
+ session = soup_session_new ();
+ soup_session_send_message (session, msg);
+
+ LOG ("%s", msg->response_body->data);
+
+ g_object_unref (session);
+ g_object_unref (msg);
+ g_free (id_hex);
+ g_free (url);
+ g_free (id);
+ g_free (key);
+ g_free (tmp);
+ json_object_unref (secrets);
+}
+
+/**
+ * ephy_sync_debug_get_current_device:
+ *
+ * Gets the current device connected to Firefox Sync for the signed in user.
+ *
+ * https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#get-accountdevices
+ *
+ * Return value: (transfer full): the current device as a #JsonObject
+ **/
+JsonObject *
+ephy_sync_debug_get_current_device (void)
+{
+ JsonObject *retval = NULL;
+ JsonObject *secrets;
+ JsonNode *response;
+ JsonArray *array;
+ SoupSession *session;
+ SoupMessage *msg;
+ GError *error = NULL;
+ guint8 *id;
+ guint8 *key;
+ guint8 *tmp;
+ char *id_hex;
+ char *url;
+ const char *session_token;
+ guint status_code;
+
+ secrets = ephy_sync_debug_load_secrets ();
+ if (!secrets)
+ return NULL;
+
+ session_token = json_object_get_string_member (secrets, "session_token");
+ ephy_sync_crypto_derive_session_token (session_token, &id, &key, &tmp);
+
+ url = g_strdup_printf ("%s/account/devices", EPHY_SYNC_FX_ACCOUNTS_SERVER_URL);
+ id_hex = ephy_sync_utils_encode_hex (id, 32);
+ msg = ephy_sync_debug_prepare_soup_message (url, "GET", NULL, id_hex, key, 32);
+ session = soup_session_new ();
+ status_code = soup_session_send_message (session, msg);
+
+ if (status_code != 200) {
+ LOG ("Failed to GET account devices: %s", msg->response_body->data);
+ goto free_session;
+ }
+
+ response = json_from_string (msg->response_body->data, &error);
+ if (error) {
+ LOG ("Response is not a valid JSON: %s", error->message);
+ g_error_free (error);
+ goto free_session;
+ }
+
+ array = json_node_get_array (response);
+ for (guint i = 0; i < json_array_get_length (array); i++) {
+ JsonObject *device = json_array_get_object_element (array, i);
+
+ if (json_object_get_boolean_member (device, "isCurrentDevice")) {
+ retval = json_object_ref (device);
+ break;
+ }
+ }
+
+ json_node_unref (response);
+free_session:
+ g_object_unref (session);
+ g_object_unref (msg);
+ g_free (id_hex);
+ g_free (url);
+ g_free (id);
+ g_free (key);
+ g_free (tmp);
+ json_object_unref (secrets);
+
+ return retval;
+}
diff --git a/lib/sync/debug/ephy-sync-debug.h b/lib/sync/debug/ephy-sync-debug.h
index dc35b4831..bff0c1f2c 100644
--- a/lib/sync/debug/ephy-sync-debug.h
+++ b/lib/sync/debug/ephy-sync-debug.h
@@ -21,27 +21,33 @@
#pragma once
#include <glib.h>
+#include <json-glib/json-glib.h>
G_BEGIN_DECLS
-void ephy_sync_debug_view_secrets (void);
-void ephy_sync_debug_view_collection (const char *collection,
- gboolean decrypt);
-void ephy_sync_debug_view_record (const char *collection,
- const char *id,
- gboolean decrypt);
-void ephy_sync_debug_delete_collection (const char *collection);
-void ephy_sync_debug_delete_record (const char *collection,
- const char *id);
-void ephy_sync_debug_erase_collection (const char *collection);
-void ephy_sync_debug_erase_record (const char *collection,
- const char *id);
-void ephy_sync_debug_view_collection_info (void);
-void ephy_sync_debug_view_quota_info (void);
-void ephy_sync_debug_view_collection_usage (void);
-void ephy_sync_debug_view_collection_counts (void);
-void ephy_sync_debug_view_configuration_info (void);
-void ephy_sync_debug_view_meta_global_record (void);
-void ephy_sync_debug_view_crypto_keys_record (void);
+void ephy_sync_debug_view_secrets (void);
+void ephy_sync_debug_view_collection (const char *collection,
+ gboolean decrypt);
+void ephy_sync_debug_view_record (const char *collection,
+ const char *id,
+ gboolean decrypt);
+void ephy_sync_debug_upload_record (const char *collection,
+ const char *id,
+ const char *body);
+void ephy_sync_debug_delete_collection (const char *collection);
+void ephy_sync_debug_delete_record (const char *collection,
+ const char *id);
+void ephy_sync_debug_erase_collection (const char *collection);
+void ephy_sync_debug_erase_record (const char *collection,
+ const char *id);
+void ephy_sync_debug_view_collection_info (void);
+void ephy_sync_debug_view_quota_info (void);
+void ephy_sync_debug_view_collection_usage (void);
+void ephy_sync_debug_view_collection_counts (void);
+void ephy_sync_debug_view_configuration_info (void);
+void ephy_sync_debug_view_meta_global_record (void);
+void ephy_sync_debug_view_crypto_keys_record (void);
+void ephy_sync_debug_view_connected_devices (void);
+JsonObject *ephy_sync_debug_get_current_device (void);
G_END_DECLS
diff --git a/lib/sync/ephy-open-tabs-manager.c b/lib/sync/ephy-open-tabs-manager.c
index 32ee9a6f8..76c888b6b 100644
--- a/lib/sync/ephy-open-tabs-manager.c
+++ b/lib/sync/ephy-open-tabs-manager.c
@@ -144,23 +144,24 @@ ephy_open_tabs_manager_get_local_tabs (EphyOpenTabsManager *self)
EphyOpenTabsRecord *local_tabs;
EphyTabInfo *info;
GList *tabs_info;
- char *id;
- char *name;
+ char *device_bso_id;
+ char *device_name;
g_assert (EPHY_IS_OPEN_TABS_MANAGER (self));
- id = ephy_sync_utils_get_device_id ();
- name = ephy_sync_utils_get_device_name ();
- local_tabs = ephy_open_tabs_record_new (id, name);
+ device_bso_id = ephy_sync_utils_get_device_bso_id ();
+ device_name = ephy_sync_utils_get_device_name ();
+ local_tabs = ephy_open_tabs_record_new (device_bso_id, device_name);
tabs_info = ephy_tabs_catalog_get_tabs_info (self->catalog);
+
for (GList *l = tabs_info; l && l->data; l = l->next) {
info = (EphyTabInfo *)l->data;
ephy_open_tabs_record_add_tab (local_tabs, info->title, info->url, info->favicon);
}
- g_free (id);
- g_free (name);
+ g_free (device_bso_id);
+ g_free (device_name);
g_list_free_full (tabs_info, (GDestroyNotify)ephy_tab_info_free);
return local_tabs;
@@ -258,15 +259,15 @@ synchronizable_manager_merge (EphySynchronizableManager *manager,
EphyOpenTabsManager *self = EPHY_OPEN_TABS_MANAGER (manager);
EphyOpenTabsRecord *local_tabs;
GList *to_upload = NULL;
- char *id;
+ char *device_bso_id;
- id = ephy_sync_utils_get_device_id ();
+ device_bso_id = ephy_sync_utils_get_device_bso_id ();
g_list_free_full (self->remote_records, g_object_unref);
self->remote_records = NULL;
for (GList *l = remotes_updated; l && l->data; l = l->next) {
/* Exclude the record which describes the local open tabs. */
- if (!g_strcmp0 (id, ephy_open_tabs_record_get_id (l->data)))
+ if (!g_strcmp0 (device_bso_id, ephy_open_tabs_record_get_id (l->data)))
continue;
self->remote_records = g_list_prepend (self->remote_records, g_object_ref (l->data));
@@ -278,7 +279,7 @@ synchronizable_manager_merge (EphySynchronizableManager *manager,
local_tabs = ephy_open_tabs_manager_get_local_tabs (self);
to_upload = g_list_prepend (to_upload, local_tabs);
- g_free (id);
+ g_free (device_bso_id);
callback (to_upload, TRUE, user_data);
}
diff --git a/lib/sync/ephy-sync-service.c b/lib/sync/ephy-sync-service.c
index 7df8c7c84..b66fb97e5 100644
--- a/lib/sync/ephy-sync-service.c
+++ b/lib/sync/ephy-sync-service.c
@@ -686,6 +686,7 @@ ephy_sync_service_destroy_session (EphySyncService *self,
session_token = ephy_sync_service_get_secret (self, secrets[SESSION_TOKEN]);
g_assert (session_token);
+ /* This also destroys the device associated with the session token. */
url = g_strdup_printf ("%s/session/destroy", EPHY_SYNC_FX_ACCOUNTS_SERVER_URL);
ephy_sync_crypto_derive_session_token (session_token, &token_id,
&req_hmac_key, &tmp);
@@ -889,7 +890,7 @@ get_signed_certificate_cb (SoupSession *session,
if (json_object_get_int_member (json, "errno") == 110) {
message = _("The password of your Firefox account seems to have been changed.");
suggestion = _("Please visit Preferences and sign in with the new password to continue syncing.");
- ephy_sync_service_sign_out (self, FALSE);
+ ephy_sync_service_sign_out (self);
}
g_warning ("Failed to sign certificate. Status code: %u, response: %s",
@@ -1598,6 +1599,79 @@ ephy_sync_service_store_secrets (EphySyncService *self)
}
static void
+upload_client_record_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ EphySyncService *self = EPHY_SYNC_SERVICE (user_data);
+
+ if (msg->status_code != 200) {
+ g_warning ("Failed to upload client record. Status code: %u, response: %s",
+ msg->status_code, msg->response_body->data);
+ if (self->is_signing_in)
+ ephy_sync_service_report_sign_in_error (self, _("Failed to upload client record."), NULL, TRUE);
+ } else {
+ LOG ("Successfully uploaded client record");
+ if (self->is_signing_in)
+ ephy_sync_service_store_secrets (self);
+ }
+}
+
+static void
+ephy_sync_service_upload_client_record (EphySyncService *self)
+{
+ SyncCryptoKeyBundle *bundle;
+ JsonNode *node;
+ JsonObject *bso;
+ char *device_bso_id;
+ char *device_id;
+ char *device_name;
+ char *record;
+ char *encrypted;
+ char *body;
+ char *endpoint;
+
+ g_assert (EPHY_IS_SYNC_SERVICE (self));
+
+ /* Make device ID and name. */
+ device_bso_id = ephy_sync_utils_get_device_bso_id ();
+ device_id = ephy_sync_utils_get_device_id ();
+ device_name = ephy_sync_utils_get_device_name ();
+
+ /* Make BSO as string. */
+ record = ephy_sync_utils_make_client_record (device_bso_id, device_id, device_name);
+ bundle = ephy_sync_service_get_key_bundle (self, "clients");
+ encrypted = ephy_sync_crypto_encrypt_record (record, bundle);
+
+ bso = json_object_new ();
+ json_object_set_string_member (bso, "id", device_bso_id);
+ json_object_set_string_member (bso, "payload", encrypted);
+
+ node = json_node_new (JSON_NODE_OBJECT);
+ json_node_set_object (node, bso);
+ body = json_to_string (node, FALSE);
+
+ /* Upload BSO and store the new device ID and name. */
+ LOG ("Uploading client record, device_bso_id=%s, device_id=%s, device_name=%s",
+ device_bso_id, device_id, device_name);
+ endpoint = g_strdup_printf ("storage/clients/%s", device_bso_id);
+ ephy_sync_service_queue_storage_request (self, endpoint,
+ SOUP_METHOD_PUT, body, -1, -1,
+ upload_client_record_cb, self);
+
+ g_free (device_bso_id);
+ g_free (device_id);
+ g_free (device_name);
+ g_free (record);
+ g_free (encrypted);
+ g_free (endpoint);
+ g_free (body);
+ json_object_unref (bso);
+ json_node_unref (node);
+ ephy_sync_crypto_key_bundle_free (bundle);
+}
+
+static void
ephy_sync_service_finalize (GObject *object)
{
EphySyncService *self = EPHY_SYNC_SERVICE (object);
@@ -1730,7 +1804,7 @@ upload_crypto_keys_cb (SoupSession *session,
} else {
LOG ("Successfully uploaded crypto/keys record");
ephy_sync_service_set_secret (self, secrets[CRYPTO_KEYS], self->crypto_keys);
- ephy_sync_service_register_device (self, NULL);
+ ephy_sync_service_upload_client_record (self);
}
g_clear_pointer (&self->crypto_keys, g_free);
@@ -1828,7 +1902,7 @@ get_crypto_keys_cb (SoupSession *session,
}
ephy_sync_service_set_secret (self, secrets[CRYPTO_KEYS], crypto_keys);
- ephy_sync_service_register_device (self, NULL);
+ ephy_sync_service_upload_client_record (self);
goto out_no_error;
out_error:
@@ -2034,6 +2108,94 @@ ephy_sync_service_verify_storage_version (EphySyncService *self)
}
static void
+upload_fxa_device_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ EphySyncService *self = user_data;
+ JsonNode *node;
+ JsonObject *object;
+ GError *error = NULL;
+
+ if (msg->status_code != 200) {
+ g_warning ("Failed to upload device info on FxA Server. Status code: %u, response: %s",
+ msg->status_code, msg->response_body->data);
+ goto out_error;
+ }
+
+ node = json_from_string (msg->response_body->data, &error);
+ if (error) {
+ g_warning ("Response is not a valid JSON: %s", error->message);
+ g_error_free (error);
+ goto out_error;
+ }
+
+ object = json_node_get_object (node);
+ ephy_sync_utils_set_device_id (json_object_get_string_member (object, "id"));
+ json_node_unref (node);
+
+ LOG ("Successfully uploaded device info on FxA Server");
+ if (self->is_signing_in)
+ ephy_sync_service_verify_storage_version (self);
+ return;
+
+out_error:
+ if (self->is_signing_in)
+ ephy_sync_service_report_sign_in_error (self, _("Failed to upload device info"), NULL, TRUE);
+}
+
+static void
+ephy_sync_service_upload_fxa_device (EphySyncService *self)
+{
+ JsonNode *node;
+ JsonObject *object;
+ const char *session_token;
+ char *body;
+ char *device_name;
+ char *token_id_hex;
+ guint8 *token_id;
+ guint8 *req_hmac_key;
+ guint8 *tmp;
+
+ g_assert (EPHY_IS_SYNC_SERVICE (self));
+
+ object = json_object_new ();
+ device_name = ephy_sync_utils_get_device_name ();
+ json_object_set_string_member (object, "name", device_name);
+ json_object_set_string_member (object, "type", "desktop");
+
+ /* If we are signing in, the ID for the newly registered device will be returned
+ * by the FxA server in the response. Otherwise, we are updating the current
+ * device (i.e. setting its name), so we use the previously obtained ID. */
+ if (!self->is_signing_in) {
+ char *device_id = ephy_sync_utils_get_device_id ();
+ json_object_set_string_member (object, "id", device_id);
+ g_free (device_id);
+ }
+
+ node = json_node_new (JSON_NODE_OBJECT);
+ json_node_take_object (node, object);
+ body = json_to_string (node, FALSE);
+
+ session_token = ephy_sync_service_get_secret (self, secrets[SESSION_TOKEN]);
+ ephy_sync_crypto_derive_session_token (session_token, &token_id, &req_hmac_key, &tmp);
+ token_id_hex = ephy_sync_utils_encode_hex (token_id, 32);
+
+ LOG ("Uploading device info on FxA Server...");
+ ephy_sync_service_fxa_hawk_post (self, "account/device", token_id_hex,
+ req_hmac_key, 32, body,
+ upload_fxa_device_cb, self);
+
+ g_free (body);
+ g_free (device_name);
+ g_free (token_id_hex);
+ g_free (token_id);
+ g_free (req_hmac_key);
+ g_free (tmp);
+ json_node_unref (node);
+}
+
+static void
ephy_sync_service_sign_in_finish (EphySyncService *self,
SignInAsyncData *data,
const char *bundle)
@@ -2071,7 +2233,7 @@ ephy_sync_service_sign_in_finish (EphySyncService *self,
kb_hex = ephy_sync_utils_encode_hex (kb, 32);
ephy_sync_service_set_secret (self, secrets[MASTER_KEY], kb_hex);
- ephy_sync_service_verify_storage_version (self);
+ ephy_sync_service_upload_fxa_device (self);
g_free (kb_hex);
g_free (kb);
@@ -2265,104 +2427,16 @@ ephy_sync_service_unregister_manager (EphySyncService *self,
g_signal_handlers_disconnect_by_func (manager, synchronizable_modified_cb, self);
}
-static void
-register_device_cb (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
-{
- EphySyncService *self = EPHY_SYNC_SERVICE (user_data);
-
- if (msg->status_code != 200) {
- g_warning ("Failed to register device. Status code: %u, response: %s",
- msg->status_code, msg->response_body->data);
- if (self->is_signing_in)
- ephy_sync_service_report_sign_in_error (self, _("Failed to register device."), NULL, TRUE);
- } else {
- LOG ("Successfully registered device");
- if (self->is_signing_in)
- ephy_sync_service_store_secrets (self);
- }
-}
-
void
-ephy_sync_service_register_device (EphySyncService *self,
- const char *device_name)
+ephy_sync_service_update_device_name (EphySyncService *self,
+ const char *name)
{
- SyncCryptoKeyBundle *bundle;
- JsonNode *node;
- JsonObject *bso;
- JsonObject *record;
- JsonArray *array;
- char *id;
- char *name;
- char *protocol;
- char *cleartext;
- char *encrypted;
- char *body;
- char *endpoint;
-
g_assert (EPHY_IS_SYNC_SERVICE (self));
+ g_assert (name);
- /* Make protocol. */
- protocol = g_strdup_printf ("1.%d", EPHY_SYNC_STORAGE_VERSION);
- array = json_array_new ();
- json_array_add_string_element (array, protocol);
-
- /* Make device ID and name. */
- id = ephy_sync_utils_get_device_id ();
- if (device_name)
- name = g_strdup (device_name);
- else
- name = ephy_sync_utils_get_device_name ();
-
- /* Set record members. */
- record = json_object_new ();
- json_object_set_string_member (record, "id", id);
- json_object_set_string_member (record, "fxaDeviceId",
- ephy_sync_service_get_secret (self, secrets[UID]));
- json_object_set_string_member (record, "name", name);
- json_object_set_string_member (record, "type", "desktop");
- json_object_set_string_member (record, "version", VERSION);
- json_object_set_array_member (record, "protocols", array);
- json_object_set_string_member (record, "os", "Linux");
- json_object_set_string_member (record, "appPackage", "org.gnome.epiphany");
- json_object_set_string_member (record, "application", "Epiphany");
-
- /* Get record's string representation. */
- node = json_node_new (JSON_NODE_OBJECT);
- json_node_set_object (node, record);
- cleartext = json_to_string (node, FALSE);
-
- /* Make BSO as string. */
- bundle = ephy_sync_service_get_key_bundle (self, "clients");
- encrypted = ephy_sync_crypto_encrypt_record (cleartext, bundle);
- bso = json_object_new ();
- json_object_set_string_member (bso, "id", id);
- json_object_set_string_member (bso, "payload", encrypted);
- json_node_set_object (node, bso);
- body = json_to_string (node, FALSE);
-
- /* Upload BSO and store the new device ID and name. */
- LOG ("Registering device with name '%s'...", name);
- endpoint = g_strdup_printf ("storage/clients/%s", id);
- ephy_sync_service_queue_storage_request (self, endpoint,
- SOUP_METHOD_PUT, body, -1, -1,
- register_device_cb, self);
-
- ephy_sync_utils_set_device_id (id);
ephy_sync_utils_set_device_name (name);
-
- g_free (endpoint);
- g_free (body);
- g_free (encrypted);
- ephy_sync_crypto_key_bundle_free (bundle);
- g_free (cleartext);
- g_free (name);
- g_free (id);
- g_free (protocol);
- json_object_unref (record);
- json_object_unref (bso);
- json_node_unref (node);
+ ephy_sync_service_upload_fxa_device (self);
+ ephy_sync_service_upload_client_record (self);
}
static void
@@ -2379,62 +2453,52 @@ delete_open_tabs_record_cb (SoupSession *session,
}
static void
-unregister_device_cb (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
+delete_client_record_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
{
if (msg->status_code != 200) {
- g_warning ("Failed to unregister device. Status code: %u, response: %s",
+ g_warning ("Failed to delete client record. Status code: %u, response: %s",
msg->status_code, msg->response_body->data);
} else {
- LOG ("Successfully unregistered device");
+ LOG ("Successfully deleted client record");
}
}
static void
-ephy_sync_service_unregister_device (EphySyncService *self)
+ephy_sync_service_cleanup_storage_singletons (EphySyncService *self)
{
char *endpoint;
- char *id;
+ char *device_bso_id;
g_assert (EPHY_IS_SYNC_SERVICE (self));
- id = ephy_sync_utils_get_device_id ();
+ device_bso_id = ephy_sync_utils_get_device_bso_id ();
/* Delete the client record associated to this device. */
- endpoint = g_strdup_printf ("storage/clients/%s", id);
+ endpoint = g_strdup_printf ("storage/clients/%s", device_bso_id);
ephy_sync_service_queue_storage_request (self, endpoint,
SOUP_METHOD_DELETE,
NULL, -1, -1,
- unregister_device_cb, NULL);
+ delete_client_record_cb, NULL);
g_free (endpoint);
/* Delete the open tabs record associated to this device. */
- endpoint = g_strdup_printf ("storage/tabs/%s", id);
+ endpoint = g_strdup_printf ("storage/tabs/%s", device_bso_id);
ephy_sync_service_queue_storage_request (self, endpoint,
SOUP_METHOD_DELETE,
NULL, -1, -1,
delete_open_tabs_record_cb, NULL);
g_free (endpoint);
- g_free (id);
+ g_free (device_bso_id);
}
void
-ephy_sync_service_sign_out (EphySyncService *self,
- gboolean unregister_device)
+ephy_sync_service_sign_out (EphySyncService *self)
{
g_assert (EPHY_IS_SYNC_SERVICE (self));
- /* If we sign out without unregistering the device, then the current id of
- * the device should not be cleared, but preserved for further use (Ephy will
- * use the same id next time the user signs in). This way we prevent a zombie
- * record in the clients collection on the Sync Storage Server.
- */
- if (unregister_device) {
- ephy_sync_service_unregister_device (self);
- ephy_sync_utils_set_device_id (NULL);
- }
-
ephy_sync_service_stop_periodical_sync (self);
+ ephy_sync_service_cleanup_storage_singletons (self);
ephy_sync_service_destroy_session (self, NULL);
ephy_sync_service_forget_secrets (self);
ephy_sync_service_clear_storage_queue (self);
@@ -2451,6 +2515,7 @@ ephy_sync_service_sign_out (EphySyncService *self,
ephy_sync_utils_set_passwords_sync_is_initial (TRUE);
ephy_sync_utils_set_history_sync_is_initial (TRUE);
+ ephy_sync_utils_set_device_id (NULL);
ephy_sync_utils_set_sync_time (0);
ephy_sync_utils_set_sync_user (NULL);
}
diff --git a/lib/sync/ephy-sync-service.h b/lib/sync/ephy-sync-service.h
index 815d64909..d50e4174d 100644
--- a/lib/sync/ephy-sync-service.h
+++ b/lib/sync/ephy-sync-service.h
@@ -37,12 +37,11 @@ void ephy_sync_service_sign_in (EphySyncService *self,
const char *session_token,
const char *key_fetch_token,
const char *unwrap_kb);
-void ephy_sync_service_sign_out (EphySyncService *self,
- gboolean unregister_device);
+void ephy_sync_service_sign_out (EphySyncService *self);
void ephy_sync_service_sync (EphySyncService *self);
void ephy_sync_service_start_sync (EphySyncService *self);
-void ephy_sync_service_register_device (EphySyncService *self,
- const char *device_name);
+void ephy_sync_service_update_device_name (EphySyncService *self,
+ const char *name);
void ephy_sync_service_register_manager (EphySyncService *self,
EphySynchronizableManager *manager);
void ephy_sync_service_unregister_manager (EphySyncService *self,
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
index 4490018d8..0931b465b 100644
--- a/src/prefs-dialog.c
+++ b/src/prefs-dialog.c
@@ -583,7 +583,7 @@ on_sync_sign_out_button_clicked (GtkWidget *button,
{
EphySyncService *service = ephy_shell_get_sync_service (ephy_shell_get_default ());
- ephy_sync_service_sign_out (service, TRUE);
+ ephy_sync_service_sign_out (service);
/* Show Firefox Accounts iframe. */
sync_setup_firefox_iframe (dialog);
@@ -644,7 +644,7 @@ on_sync_device_name_save_button_clicked (GtkWidget *button,
gtk_entry_set_text (GTK_ENTRY (dialog->sync_device_name_entry), name);
g_free (name);
} else {
- ephy_sync_service_register_device (service, text);
+ ephy_sync_service_update_device_name (service, text);
}
gtk_widget_set_sensitive (GTK_WIDGET (dialog->sync_device_name_entry), FALSE);
diff --git a/src/profile-migrator/ephy-profile-migrator.c b/src/profile-migrator/ephy-profile-migrator.c
index 0f7d6215b..227b545b3 100644
--- a/src/profile-migrator/ephy-profile-migrator.c
+++ b/src/profile-migrator/ephy-profile-migrator.c
@@ -30,6 +30,7 @@
#include "ephy-search-engine-manager.h"
#include "ephy-settings.h"
#include "ephy-sqlite-connection.h"
+#include "ephy-sync-debug.h"
#include "ephy-sync-utils.h"
#include "ephy-uri-tester-shared.h"
#include "ephy-web-app-utils.h"
@@ -922,6 +923,54 @@ migrate_sync_settings_path (void)
}
static void
+migrate_sync_device_info (void)
+{
+ JsonObject *device;
+ const char *device_id;
+ const char *device_name;
+ char *prev_device_id;
+ char *device_bso_id;
+ char *record;
+ int default_profile_migration_version;
+
+ default_profile_migration_version = ephy_profile_utils_get_migration_version_for_profile_dir (ephy_default_dot_dir ());
+ if (default_profile_migration_version >= EPHY_SYNC_DEVICE_ID_MIGRATION_VERSION)
+ return;
+
+ if (!ephy_sync_utils_user_is_signed_in ())
+ return;
+
+ /* Fetch the device info from the Firefox Accounts Server. */
+ device = ephy_sync_debug_get_current_device ();
+ if (!device) {
+ g_warning ("Failed to migrate sync device info. Sign in again to Sync "
+ "to have your device re-registered and continue syncing.");
+ return;
+ }
+
+ /* Erase previous records from the Sync Storage Server. */
+ prev_device_id = ephy_sync_utils_get_device_id ();
+ ephy_sync_debug_erase_record ("clients", prev_device_id);
+ ephy_sync_debug_erase_record ("tabs", prev_device_id);
+
+ /* Use the device id and name assigned by the Firefox Accounts Server at sign in.
+ * The user can change later the device name in the Preferences dialog. */
+ device_id = json_object_get_string_member (device, "id");
+ ephy_sync_utils_set_device_id (device_id);
+ device_name = json_object_get_string_member (device, "name");
+ ephy_sync_utils_set_device_name (device_name);
+
+ device_bso_id = ephy_sync_utils_get_device_bso_id ();
+ record = ephy_sync_utils_make_client_record (device_bso_id, device_id, device_name);
+ ephy_sync_debug_upload_record ("clients", device_bso_id, record);
+
+ g_free (record);
+ g_free (device_bso_id);
+ g_free (prev_device_id);
+ json_object_unref (device);
+}
+
+static void
migrate_nothing (void)
{
/* Used to replace migrators that have been removed. Only remove migrators
@@ -956,7 +1005,8 @@ const EphyProfileMigrator migrators[] = {
/* 19 */ migrate_passwords_to_firefox_sync_passwords,
/* 20 */ migrate_history_to_firefox_sync_history,
/* 21 */ migrate_passwords_add_target_origin,
- /* 22 */ migrate_sync_settings_path
+ /* 22 */ migrate_sync_settings_path,
+ /* 23 */ migrate_sync_device_info,
};
static gboolean