[epiphany/wip/sync-rebase: 42/74] ephy-sync: Implement the sync logic
- From: Gabriel - Cristian Ivascu <gabrielivascu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany/wip/sync-rebase: 42/74] ephy-sync: Implement the sync logic
- Date: Thu, 29 Sep 2016 17:46:20 +0000 (UTC)
commit 9d5a609f604b506a87cae80fb8fcfb33b3ad6d96
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date: Mon Aug 8 21:10:40 2016 +0300
ephy-sync: Implement the sync logic
data/org.gnome.epiphany.gschema.xml | 5 +
lib/ephy-prefs.h | 1 +
src/Makefile.am | 2 -
src/bookmarks/ephy-bookmark-properties-grid.c | 66 ++-
src/bookmarks/ephy-bookmark.c | 74 ++-
src/bookmarks/ephy-bookmark.h | 8 +
src/bookmarks/ephy-bookmarks-manager.c | 34 +-
src/bookmarks/ephy-bookmarks-manager.h | 2 +
src/ephy-shell.c | 18 +-
src/ephy-shell.h | 2 +-
src/ephy-sync-bookmarks.c | 124 ---
src/ephy-sync-bookmarks.h | 36 -
src/ephy-sync-crypto.c | 927 +++++++++------------
src/ephy-sync-crypto.h | 136 ++--
src/ephy-sync-secret.c | 65 +-
src/ephy-sync-secret.h | 18 +-
src/ephy-sync-service.c | 1099 +++++++++++++++++--------
src/ephy-sync-service.h | 61 +-
src/ephy-sync-utils.c | 135 +++-
src/ephy-sync-utils.h | 29 +-
src/prefs-dialog.c | 25 +-
21 files changed, 1616 insertions(+), 1251 deletions(-)
---
diff --git a/data/org.gnome.epiphany.gschema.xml b/data/org.gnome.epiphany.gschema.xml
index 80bee0a..b8f28e5 100644
--- a/data/org.gnome.epiphany.gschema.xml
+++ b/data/org.gnome.epiphany.gschema.xml
@@ -82,6 +82,11 @@
<summary>The sync user currently logged in</summary>
<description>The email linked to the Firefox Account used to sync data with Mozilla's
servers.</description>
</key>
+ <key type="d" name="sync-time">
+ <default>0</default>
+ <summary>Sync timestamp</summary>
+ <description>The timestamp at which last we had the last sync</description>
+ </key>
</schema>
<schema path="/org/gnome/epiphany/ui/" id="org.gnome.Epiphany.ui">
<key type="b" name="always-show-tabs-bar">
diff --git a/lib/ephy-prefs.h b/lib/ephy-prefs.h
index cae64b5..d9b1643 100644
--- a/lib/ephy-prefs.h
+++ b/lib/ephy-prefs.h
@@ -111,6 +111,7 @@ typedef enum
#define EPHY_PREFS_PROCESS_MODEL "process-model"
#define EPHY_PREFS_MAX_PROCESSES "max-processes"
#define EPHY_PREFS_SYNC_USER "sync-user"
+#define EPHY_PREFS_SYNC_TIME "sync-time"
#define EPHY_PREFS_LOCKDOWN_SCHEMA "org.gnome.Epiphany.lockdown"
#define EPHY_PREFS_LOCKDOWN_FULLSCREEN "disable-fullscreen"
diff --git a/src/Makefile.am b/src/Makefile.am
index 2341708..1be6894 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -44,8 +44,6 @@ libephymain_la_SOURCES = \
ephy-session.h \
ephy-shell.c \
ephy-shell.h \
- ephy-sync-bookmarks.c \
- ephy-sync-bookmarks.h \
ephy-sync-crypto.c \
ephy-sync-crypto.h \
ephy-sync-secret.c \
diff --git a/src/bookmarks/ephy-bookmark-properties-grid.c b/src/bookmarks/ephy-bookmark-properties-grid.c
index 73356a0..11f65ac 100644
--- a/src/bookmarks/ephy-bookmark-properties-grid.c
+++ b/src/bookmarks/ephy-bookmark-properties-grid.c
@@ -23,6 +23,7 @@
#include "ephy-bookmarks-manager.h"
#include "ephy-debug.h"
#include "ephy-shell.h"
+#include "ephy-sync-service.h"
#include "ephy-bookmarks-type-builtins.h"
#include <libsoup/soup.h>
@@ -45,6 +46,10 @@ struct _EphyBookmarkPropertiesGrid {
GtkWidget *add_tag_entry;
GtkWidget *add_tag_button;
GtkWidget *remove_bookmark_button;
+
+ char *prev_name;
+ char *prev_address;
+ GSequence *prev_tags;
};
G_DEFINE_TYPE (EphyBookmarkPropertiesGrid, ephy_bookmark_properties_grid, GTK_TYPE_GRID)
@@ -235,10 +240,13 @@ ephy_bookmarks_properties_grid_actions_remove_bookmark (GSimpleAction *action,
GVariant *value,
gpointer user_data)
{
+ EphySyncService *service;
EphyBookmarkPropertiesGrid *self = user_data;
g_assert (EPHY_IS_BOOKMARK_PROPERTIES_GRID (self));
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ ephy_sync_service_delete_bookmark (service, self->bookmark, FALSE);
ephy_bookmarks_manager_remove_bookmark (self->manager, self->bookmark);
if (self->type == EPHY_BOOKMARK_PROPERTIES_GRID_TYPE_DIALOG)
@@ -312,6 +320,7 @@ ephy_bookmark_properties_grid_constructed (GObject *object)
/* Set text for name entry */
gtk_entry_set_text (GTK_ENTRY (self->name_entry),
ephy_bookmark_get_title (self->bookmark));
+ self->prev_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->name_entry)));
g_object_bind_property (GTK_ENTRY (self->name_entry), "text",
self->bookmark, "title",
@@ -321,6 +330,7 @@ ephy_bookmark_properties_grid_constructed (GObject *object)
if (self->type == EPHY_BOOKMARK_PROPERTIES_GRID_TYPE_DIALOG) {
address = ephy_bookmark_get_url (self->bookmark);
gtk_entry_set_text (GTK_ENTRY (self->address_entry), address);
+ self->prev_address = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->address_entry)));
g_object_bind_property (GTK_ENTRY (self->address_entry), "text",
self->bookmark, "url",
@@ -328,6 +338,7 @@ ephy_bookmark_properties_grid_constructed (GObject *object)
}
/* Create tag widgets */
+ self->prev_tags = g_sequence_new (g_free);
tags = ephy_bookmarks_manager_get_tags (self->manager);
bookmark_tags = ephy_bookmark_get_tags (self->bookmark);
for (iter = g_sequence_get_begin_iter (tags);
@@ -340,8 +351,11 @@ ephy_bookmark_properties_grid_constructed (GObject *object)
if (g_sequence_lookup (bookmark_tags,
(gpointer)tag,
(GCompareDataFunc)ephy_bookmark_tags_compare,
- NULL))
+ NULL)) {
selected = TRUE;
+ g_sequence_insert_sorted (self->prev_tags, g_strdup (tag),
+ (GCompareDataFunc)ephy_bookmark_tags_compare, NULL);
+ }
widget = ephy_bookmark_properties_grid_create_tag_widget (self, tag, selected);
gtk_flow_box_insert (GTK_FLOW_BOX (self->tags_box), widget, -1);
@@ -359,10 +373,60 @@ ephy_bookmark_properties_grid_finalize (GObject *object)
{
EphyBookmarkPropertiesGrid *self = EPHY_BOOKMARK_PROPERTIES_GRID (object);
+ if (ephy_bookmark_is_uploaded (self->bookmark) == FALSE)
+ goto out;
+
+ /* Check if any actual changes were made to the name, address or tags. If yes,
+ * set the uploaded flag to FALSE. */
+
+ if (self->prev_name != NULL) {
+ if (g_strcmp0 (self->prev_name, ephy_bookmark_get_title (self->bookmark)) != 0) {
+ ephy_bookmark_set_uploaded (self->bookmark, FALSE);
+ goto out;
+ }
+ }
+
+ if (self->prev_address != NULL) {
+ if (g_strcmp0 (self->prev_address, ephy_bookmark_get_url (self->bookmark)) != 0) {
+ ephy_bookmark_set_uploaded (self->bookmark, FALSE);
+ goto out;
+ }
+ }
+
+ if (self->prev_tags != NULL) {
+ GSequence *tags = ephy_bookmark_get_tags (self->bookmark);
+ GSequenceIter *iter;
+
+ /* Check for added tags. */
+ for (iter = g_sequence_get_begin_iter (tags);
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter)) {
+ if (!g_sequence_lookup (self->prev_tags, g_sequence_get (iter),
+ (GCompareDataFunc)ephy_bookmark_tags_compare, NULL)) {
+ ephy_bookmark_set_uploaded (self->bookmark, FALSE);
+ goto out;
+ }
+ }
+
+ /* Check for deleted tags. */
+ for (iter = g_sequence_get_begin_iter (self->prev_tags);
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter)) {
+ if (!g_sequence_lookup (tags, g_sequence_get (iter),
+ (GCompareDataFunc)ephy_bookmark_tags_compare, NULL)) {
+ ephy_bookmark_set_uploaded (self->bookmark, FALSE);
+ goto out;
+ }
+ }
+ }
+
+out:
ephy_bookmarks_manager_save_to_file_async (self->manager, NULL,
ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
NULL);
+ g_clear_pointer (&self->prev_name, g_free);
+ g_clear_pointer (&self->prev_address, g_free);
+ g_clear_pointer (&self->prev_tags, g_sequence_free);
+
G_OBJECT_CLASS (ephy_bookmark_properties_grid_parent_class)->finalize (object);
}
diff --git a/src/bookmarks/ephy-bookmark.c b/src/bookmarks/ephy-bookmark.c
index 5ca99ea..41750fe 100644
--- a/src/bookmarks/ephy-bookmark.c
+++ b/src/bookmarks/ephy-bookmark.c
@@ -24,7 +24,6 @@
#include "ephy-sync-crypto.h"
#include "ephy-sync-utils.h"
-#include <json-glib/json-glib.h>
#include <string.h>
struct _EphyBookmark {
@@ -37,6 +36,7 @@ struct _EphyBookmark {
char *id;
double modified;
+ gboolean uploaded;
};
static JsonSerializableIface *serializable_iface = NULL;
@@ -190,7 +190,7 @@ ephy_bookmark_class_init (EphyBookmarkClass *klass)
static void
ephy_bookmark_init (EphyBookmark *self)
{
- self->id = ephy_sync_crypto_generate_random_string (12);
+ self->id = ephy_sync_crypto_generate_random_hex (32);
}
static JsonNode *
@@ -332,6 +332,17 @@ ephy_bookmark_get_title (EphyBookmark *bookmark)
return bookmark->title;
}
+void
+ephy_bookmark_set_id (EphyBookmark *self,
+ const char *id)
+{
+ g_return_if_fail (EPHY_IS_BOOKMARK (self));
+ g_return_if_fail (id != NULL);
+
+ g_free (self->id);
+ self->id = g_strdup (id);
+}
+
const char *
ephy_bookmark_get_id (EphyBookmark *self)
{
@@ -358,6 +369,23 @@ ephy_bookmark_get_modified (EphyBookmark *self)
}
void
+ephy_bookmark_set_uploaded (EphyBookmark *self,
+ gboolean uploaded)
+{
+ g_return_if_fail (EPHY_IS_BOOKMARK (self));
+
+ self->uploaded = uploaded;
+}
+
+gboolean
+ephy_bookmark_is_uploaded (EphyBookmark *self)
+{
+ g_return_val_if_fail (EPHY_IS_BOOKMARK (self), FALSE);
+
+ return self->uploaded;
+}
+
+void
ephy_bookmark_add_tag (EphyBookmark *self,
const char *tag)
{
@@ -474,7 +502,7 @@ ephy_bookmark_to_bso (EphyBookmark *self)
g_return_val_if_fail (EPHY_IS_BOOKMARK (self), NULL);
- service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
sync_key = ephy_sync_crypto_decode_hex (ephy_sync_service_get_token (service, TOKEN_KB));
serialized = json_gobject_to_data (G_OBJECT (self), NULL);
encrypted = ephy_sync_crypto_aes_256 (AES_256_MODE_ENCRYPT, sync_key,
@@ -489,3 +517,43 @@ ephy_bookmark_to_bso (EphyBookmark *self)
return bso;
}
+
+EphyBookmark *
+ephy_bookmark_from_bso (JsonObject *bso)
+{
+ EphySyncService *service;
+ EphyBookmark *bookmark = NULL;
+ GObject *object;
+ GError *error = NULL;
+ guint8 *sync_key;
+ guint8 *decoded;
+ gsize decoded_len;
+ char *decrypted;
+
+ g_return_val_if_fail (bso != NULL, NULL);
+
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ sync_key = ephy_sync_crypto_decode_hex (ephy_sync_service_get_token (service, TOKEN_KB));
+ decoded = ephy_sync_crypto_base64_urlsafe_decode (json_object_get_string_member (bso, "payload"),
+ &decoded_len, FALSE);
+ decrypted = (char *) ephy_sync_crypto_aes_256 (AES_256_MODE_DECRYPT, sync_key,
+ decoded, decoded_len, NULL);
+ object = json_gobject_from_data (EPHY_TYPE_BOOKMARK, decrypted, strlen (decrypted), &error);
+
+ if (object == NULL) {
+ g_warning ("Failed to create GObject from data: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ bookmark = EPHY_BOOKMARK (object);
+ ephy_bookmark_set_id (bookmark, json_object_get_string_member (bso, "id"));
+ ephy_bookmark_set_modified (bookmark, json_object_get_double_member (bso, "modified"));
+ ephy_bookmark_set_uploaded (bookmark, TRUE);
+
+out:
+ g_free (decoded);
+ g_free (decrypted);
+
+ return bookmark;
+}
diff --git a/src/bookmarks/ephy-bookmark.h b/src/bookmarks/ephy-bookmark.h
index 76508bd..2bfc6e2 100644
--- a/src/bookmarks/ephy-bookmark.h
+++ b/src/bookmarks/ephy-bookmark.h
@@ -19,6 +19,7 @@
#pragma once
#include <glib-object.h>
+#include <json-glib/json-glib.h>
G_BEGIN_DECLS
@@ -42,12 +43,18 @@ void ephy_bookmark_set_title (EphyBookmark *self,
const char *title);
const char *ephy_bookmark_get_title (EphyBookmark *self);
+void ephy_bookmark_set_id (EphyBookmark *self,
+ const char *id);
const char *ephy_bookmark_get_id (EphyBookmark *self);
void ephy_bookmark_set_modified (EphyBookmark *self,
double modified);
double ephy_bookmark_get_modified (EphyBookmark *self);
+void ephy_bookmark_set_uploaded (EphyBookmark *self,
+ gboolean uploaded);
+gboolean ephy_bookmark_is_uploaded (EphyBookmark *self);
+
void ephy_bookmark_add_tag (EphyBookmark *self,
const char *tag);
void ephy_bookmark_remove_tag (EphyBookmark *self,
@@ -62,5 +69,6 @@ int ephy_bookmark_tags_compare (const char *tag1,
const char *tag2);
char *ephy_bookmark_to_bso (EphyBookmark *self);
+EphyBookmark *ephy_bookmark_from_bso (JsonObject *bso);
G_END_DECLS
diff --git a/src/bookmarks/ephy-bookmarks-manager.c b/src/bookmarks/ephy-bookmarks-manager.c
index 02d89f4..40d4617 100644
--- a/src/bookmarks/ephy-bookmarks-manager.c
+++ b/src/bookmarks/ephy-bookmarks-manager.c
@@ -69,10 +69,13 @@ build_variant (EphyBookmark *bookmark)
GSequence *tags;
GSequenceIter *iter;
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("(xsas)"));
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(xssdbas)"));
g_variant_builder_add (&builder, "x", ephy_bookmark_get_time_added (bookmark));
g_variant_builder_add (&builder, "s", ephy_bookmark_get_title (bookmark));
+ g_variant_builder_add (&builder, "s", ephy_bookmark_get_id (bookmark));
+ g_variant_builder_add (&builder, "d", ephy_bookmark_get_modified (bookmark));
+ g_variant_builder_add (&builder, "b", ephy_bookmark_is_uploaded (bookmark));
g_variant_builder_open (&builder, G_VARIANT_TYPE ("as"));
tags = ephy_bookmark_get_tags (bookmark);
@@ -349,6 +352,27 @@ ephy_bookmarks_manager_get_bookmark_by_url (EphyBookmarksManager *self,
return NULL;
}
+EphyBookmark *
+ephy_bookmarks_manager_get_bookmark_by_id (EphyBookmarksManager *self,
+ const char *id)
+{
+ GSequenceIter *iter;
+
+ g_return_val_if_fail (EPHY_IS_BOOKMARKS_MANAGER (self), FALSE);
+ g_return_val_if_fail (id != NULL, FALSE);
+
+ for (iter = g_sequence_get_begin_iter (self->bookmarks);
+ !g_sequence_iter_is_end (iter);
+ iter = g_sequence_iter_next (iter)) {
+ EphyBookmark *bookmark = g_sequence_get (iter);
+
+ if (g_strcmp0 (ephy_bookmark_get_id (bookmark), id) == 0)
+ return bookmark;
+ }
+
+ return NULL;
+}
+
void
ephy_bookmarks_manager_create_tag (EphyBookmarksManager *self, const char *tag)
{
@@ -535,11 +559,14 @@ ephy_bookmarks_manager_load_from_file (EphyBookmarksManager *self)
char *tag;
const char *title;
gint64 time_added;
+ char *id;
+ double modified;
+ gboolean uploaded;
/* Obtain the correspoding GVariant. */
value = gvdb_table_get_value (table, list[i]);
- g_variant_get (value, "(x&sas)", &time_added, &title, &iter);
+ g_variant_get (value, "(x&s&sdbas)", &time_added, &title, &id, &modified, &uploaded, &iter);
/* Add all stored tags in a GSequence. */
tags = g_sequence_new (g_free);
@@ -553,6 +580,9 @@ ephy_bookmarks_manager_load_from_file (EphyBookmarksManager *self)
/* Create the new bookmark. */
bookmark = ephy_bookmark_new (list[i], title, tags);
ephy_bookmark_set_time_added (bookmark, time_added);
+ ephy_bookmark_set_id (bookmark, id);
+ ephy_bookmark_set_modified (bookmark, modified);
+ ephy_bookmark_set_uploaded (bookmark, uploaded);
g_sequence_prepend (bookmarks, bookmark);
}
ephy_bookmarks_manager_add_bookmarks (self, bookmarks);
diff --git a/src/bookmarks/ephy-bookmarks-manager.h b/src/bookmarks/ephy-bookmarks-manager.h
index bf906d1..ab79df3 100644
--- a/src/bookmarks/ephy-bookmarks-manager.h
+++ b/src/bookmarks/ephy-bookmarks-manager.h
@@ -36,6 +36,8 @@ void ephy_bookmarks_manager_remove_bookmark (EphyBookmarks
EphyBookmark *bookmark);
EphyBookmark *ephy_bookmarks_manager_get_bookmark_by_url (EphyBookmarksManager *self,
const char *url);
+EphyBookmark *ephy_bookmarks_manager_get_bookmark_by_id (EphyBookmarksManager *self,
+ const char *id);
void ephy_bookmarks_manager_create_tag (EphyBookmarksManager *self,
const char *tag);
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index 6f4e7e7..24dffae 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -563,6 +563,15 @@ ephy_shell_init (EphyShell *shell)
ephy_shell = shell;
g_object_add_weak_pointer (G_OBJECT (ephy_shell),
(gpointer *)ptr);
+
+ ephy_shell->sync_service = ephy_sync_service_new ();
+ /* Do a start up sync and set a periodical sync afterwards. */
+ if (ephy_sync_service_is_signed_in (ephy_shell->sync_service) == TRUE) {
+ ephy_sync_service_do_periodical_sync (ephy_shell->sync_service);
+ g_timeout_add_seconds (ephy_sync_service_get_sync_frequency (ephy_shell->sync_service),
+ (GSourceFunc)ephy_sync_service_do_periodical_sync,
+ ephy_shell->sync_service);
+ }
}
static void
@@ -605,20 +614,17 @@ ephy_shell_finalize (GObject *object)
}
/**
- * ephy_shell_get_global_sync_service:
+ * ephy_shell_get_sync_service:
*
* Retrieve the default #EphySyncService object
*
- * Return value: (transfer none):
+ * Return value: (transfer none): the default #EphySyncService
**/
EphySyncService *
-ephy_shell_get_global_sync_service (EphyShell *shell)
+ephy_shell_get_sync_service (EphyShell *shell)
{
g_return_val_if_fail (EPHY_IS_SHELL (shell), NULL);
- if (shell->sync_service == NULL)
- shell->sync_service = ephy_sync_service_new ();
-
return shell->sync_service;
}
diff --git a/src/ephy-shell.h b/src/ephy-shell.h
index 23dfe89..3ec9e60 100644
--- a/src/ephy-shell.h
+++ b/src/ephy-shell.h
@@ -100,7 +100,7 @@ GNetworkMonitor *ephy_shell_get_net_monitor (EphyShell *shell);
EphyBookmarksManager *ephy_shell_get_bookmarks_manager (EphyShell *shell);
-EphySyncService *ephy_shell_get_global_sync_service (EphyShell *shell);
+EphySyncService *ephy_shell_get_sync_service (EphyShell *shell);
GtkWidget *ephy_shell_get_history_window (EphyShell *shell);
diff --git a/src/ephy-sync-crypto.c b/src/ephy-sync-crypto.c
index 947a69e..73a2f30 100644
--- a/src/ephy-sync-crypto.c
+++ b/src/ephy-sync-crypto.c
@@ -19,6 +19,8 @@
#include "config.h"
#include "ephy-sync-crypto.h"
+#include "ephy-sync-utils.h"
+
#include <glib/gstdio.h>
#include <libsoup/soup.h>
#include <nettle/aes.h>
@@ -28,125 +30,74 @@
static const gchar hex_digits[] = "0123456789abcdef";
-static guint8 *
-concatenate_bytes (guint8 *first_data,
- gsize first_length,
- ...) G_GNUC_NULL_TERMINATED;
-
EphySyncCryptoHawkOptions *
-ephy_sync_crypto_hawk_options_new (gchar *app,
- gchar *dlg,
- gchar *ext,
- gchar *content_type,
- gchar *hash,
- gchar *local_time_offset,
- gchar *nonce,
- gchar *payload,
- gchar *timestamp)
-{
- EphySyncCryptoHawkOptions *hawk_options;
-
- hawk_options = g_slice_new (EphySyncCryptoHawkOptions);
- hawk_options->app = app;
- hawk_options->dlg = dlg;
- hawk_options->ext = ext;
- hawk_options->content_type = content_type;
- hawk_options->hash = hash;
- hawk_options->local_time_offset = local_time_offset;
- hawk_options->nonce = nonce;
- hawk_options->payload = payload;
- hawk_options->timestamp = timestamp;
-
- return hawk_options;
+ephy_sync_crypto_hawk_options_new (const gchar *app,
+ const gchar *dlg,
+ const gchar *ext,
+ const gchar *content_type,
+ const gchar *hash,
+ const gchar *local_time_offset,
+ const gchar *nonce,
+ const gchar *payload,
+ const gchar *timestamp)
+{
+ EphySyncCryptoHawkOptions *options;
+
+ options = g_slice_new (EphySyncCryptoHawkOptions);
+ options->app = g_strdup (app);
+ options->dlg = g_strdup (dlg);
+ options->ext = g_strdup (ext);
+ options->content_type = g_strdup (content_type);
+ options->hash = g_strdup (hash);
+ options->local_time_offset = g_strdup (local_time_offset);
+ options->nonce = g_strdup (nonce);
+ options->payload = g_strdup (payload);
+ options->timestamp = g_strdup (timestamp);
+
+ return options;
}
static EphySyncCryptoHawkArtifacts *
-ephy_sync_crypto_hawk_artifacts_new (gchar *app,
- gchar *dlg,
- gchar *ext,
- gchar *hash,
- gchar *host,
- gchar *method,
- gchar *nonce,
- gchar *port,
- gchar *resource,
- gchar *ts)
-{
- EphySyncCryptoHawkArtifacts *hawk_artifacts;
-
- hawk_artifacts = g_slice_new (EphySyncCryptoHawkArtifacts);
- hawk_artifacts->app = app;
- hawk_artifacts->dlg = dlg;
- hawk_artifacts->ext = ext;
- hawk_artifacts->hash = hash;
- hawk_artifacts->host = host;
- hawk_artifacts->method = method;
- hawk_artifacts->nonce = nonce;
- hawk_artifacts->port = port;
- hawk_artifacts->resource = resource;
- hawk_artifacts->ts = ts;
-
- return hawk_artifacts;
-}
-
-static EphySyncCryptoHawkHeader *
-ephy_sync_crypto_hawk_header_new (gchar *header,
- EphySyncCryptoHawkArtifacts *artifacts)
-{
- EphySyncCryptoHawkHeader *hawk_header;
-
- hawk_header = g_slice_new (EphySyncCryptoHawkHeader);
- hawk_header->header = header;
- hawk_header->artifacts = artifacts;
-
- return hawk_header;
-}
-
-static EphySyncCryptoProcessedKFT *
-ephy_sync_crypto_processed_kft_new (guint8 *tokenID,
- guint8 *reqHMACkey,
- guint8 *respHMACkey,
- guint8 *respXORkey)
-{
- EphySyncCryptoProcessedKFT *processed_kft;
-
- processed_kft = g_slice_new (EphySyncCryptoProcessedKFT);
- processed_kft->tokenID = tokenID;
- processed_kft->reqHMACkey = reqHMACkey;
- processed_kft->respHMACkey = respHMACkey;
- processed_kft->respXORkey = respXORkey;
-
- return processed_kft;
-}
-static EphySyncCryptoProcessedST *
-ephy_sync_crypto_processed_st_new (guint8 *tokenID,
- guint8 *reqHMACkey,
- guint8 *requestKey)
+ephy_sync_crypto_hawk_artifacts_new (const gchar *app,
+ const gchar *dlg,
+ const gchar *ext,
+ const gchar *hash,
+ const gchar *host,
+ const gchar *method,
+ const gchar *nonce,
+ guint port,
+ const gchar *resource,
+ gint64 ts)
{
- EphySyncCryptoProcessedST *processed_st;
+ EphySyncCryptoHawkArtifacts *artifacts;
- processed_st = g_slice_new (EphySyncCryptoProcessedST);
- processed_st->tokenID = tokenID;
- processed_st->reqHMACkey = reqHMACkey;
- processed_st->requestKey = requestKey;
+ artifacts = g_slice_new (EphySyncCryptoHawkArtifacts);
+ artifacts->app = g_strdup (app);
+ artifacts->dlg = g_strdup (dlg);
+ artifacts->ext = g_strdup (ext);
+ artifacts->hash = g_strdup (hash);
+ artifacts->host = g_strdup (host);
+ artifacts->method = g_strdup (method);
+ artifacts->nonce = g_strdup (nonce);
+ artifacts->port = g_strdup_printf ("%u", port);
+ artifacts->resource = g_strdup (resource);
+ artifacts->ts = g_strdup_printf ("%ld", ts);
- return processed_st;
+ return artifacts;
}
-static EphySyncCryptoSyncKeys *
-ephy_sync_crypto_sync_keys_new (guint8 *kA,
- guint8 *kB,
- guint8 *wrapKB)
+static EphySyncCryptoHawkHeader *
+ephy_sync_crypto_hawk_header_new (gchar *header,
+ EphySyncCryptoHawkArtifacts *artifacts)
{
- EphySyncCryptoSyncKeys *sync_keys;
+ EphySyncCryptoHawkHeader *hheader;
- sync_keys = g_slice_new (EphySyncCryptoSyncKeys);
- sync_keys->kA = kA;
- sync_keys->kB = kB;
- sync_keys->wrapKB = wrapKB;
+ hheader = g_slice_new (EphySyncCryptoHawkHeader);
+ hheader->header = header;
+ hheader->artifacts = artifacts;
- return sync_keys;
+ return hheader;
}
static EphySyncCryptoRSAKeyPair *
@@ -163,88 +114,51 @@ ephy_sync_crypto_rsa_key_pair_new (struct rsa_public_key public,
}
void
-ephy_sync_crypto_hawk_options_free (EphySyncCryptoHawkOptions *hawk_options)
-{
- g_return_if_fail (hawk_options != NULL);
-
- g_free (hawk_options->app);
- g_free (hawk_options->dlg);
- g_free (hawk_options->ext);
- g_free (hawk_options->content_type);
- g_free (hawk_options->hash);
- g_free (hawk_options->local_time_offset);
- g_free (hawk_options->nonce);
- g_free (hawk_options->payload);
- g_free (hawk_options->timestamp);
-
- g_slice_free (EphySyncCryptoHawkOptions, hawk_options);
-}
-
-static void
-ephy_sync_crypto_hawk_artifacts_free (EphySyncCryptoHawkArtifacts *hawk_artifacts)
-{
- g_return_if_fail (hawk_artifacts != NULL);
-
- g_free (hawk_artifacts->app);
- g_free (hawk_artifacts->dlg);
- g_free (hawk_artifacts->ext);
- g_free (hawk_artifacts->hash);
- g_free (hawk_artifacts->host);
- g_free (hawk_artifacts->method);
- g_free (hawk_artifacts->nonce);
- g_free (hawk_artifacts->port);
- g_free (hawk_artifacts->resource);
- g_free (hawk_artifacts->ts);
-
- g_slice_free (EphySyncCryptoHawkArtifacts, hawk_artifacts);
-}
-
-void
-ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader *hawk_header)
-{
- g_return_if_fail (hawk_header != NULL);
-
- g_free (hawk_header->header);
- ephy_sync_crypto_hawk_artifacts_free (hawk_header->artifacts);
-
- g_slice_free (EphySyncCryptoHawkHeader, hawk_header);
-}
-
-void
-ephy_sync_crypto_processed_kft_free (EphySyncCryptoProcessedKFT *processed_kft)
+ephy_sync_crypto_hawk_options_free (EphySyncCryptoHawkOptions *options)
{
- g_return_if_fail (processed_kft != NULL);
+ g_return_if_fail (options != NULL);
- g_free (processed_kft->tokenID);
- g_free (processed_kft->reqHMACkey);
- g_free (processed_kft->respHMACkey);
- g_free (processed_kft->respXORkey);
+ g_free (options->app);
+ g_free (options->dlg);
+ g_free (options->ext);
+ g_free (options->content_type);
+ g_free (options->hash);
+ g_free (options->local_time_offset);
+ g_free (options->nonce);
+ g_free (options->payload);
+ g_free (options->timestamp);
- g_slice_free (EphySyncCryptoProcessedKFT, processed_kft);
+ g_slice_free (EphySyncCryptoHawkOptions, options);
}
-void
-ephy_sync_crypto_processed_st_free (EphySyncCryptoProcessedST *processed_st)
+static void
+ephy_sync_crypto_hawk_artifacts_free (EphySyncCryptoHawkArtifacts *artifacts)
{
- g_return_if_fail (processed_st != NULL);
+ g_return_if_fail (artifacts != NULL);
- g_free (processed_st->tokenID);
- g_free (processed_st->reqHMACkey);
- g_free (processed_st->requestKey);
+ g_free (artifacts->app);
+ g_free (artifacts->dlg);
+ g_free (artifacts->ext);
+ g_free (artifacts->hash);
+ g_free (artifacts->host);
+ g_free (artifacts->method);
+ g_free (artifacts->nonce);
+ g_free (artifacts->port);
+ g_free (artifacts->resource);
+ g_free (artifacts->ts);
- g_slice_free (EphySyncCryptoProcessedST, processed_st);
+ g_slice_free (EphySyncCryptoHawkArtifacts, artifacts);
}
void
-ephy_sync_crypto_sync_keys_free (EphySyncCryptoSyncKeys *sync_keys)
+ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader *hheader)
{
- g_return_if_fail (sync_keys != NULL);
+ g_return_if_fail (hheader != NULL);
- g_free (sync_keys->kA);
- g_free (sync_keys->kB);
- g_free (sync_keys->wrapKB);
+ g_free (hheader->header);
+ ephy_sync_crypto_hawk_artifacts_free (hheader->artifacts);
- g_slice_free (EphySyncCryptoSyncKeys, sync_keys);
+ g_slice_free (EphySyncCryptoHawkHeader, hheader);
}
void
@@ -259,18 +173,23 @@ ephy_sync_crypto_rsa_key_pair_free (EphySyncCryptoRSAKeyPair *keypair)
}
static gchar *
-kw (const gchar *name)
+ephy_sync_crypto_kw (const gchar *name)
{
+ g_return_val_if_fail (name != NULL, NULL);
+
return g_strconcat ("identity.mozilla.com/picl/v1/", name, NULL);
}
static guint8 *
-xor (guint8 *a,
- guint8 *b,
- gsize length)
+ephy_sync_crypto_xor (guint8 *a,
+ guint8 *b,
+ gsize length)
{
guint8 *xored;
+ g_return_val_if_fail (a != NULL, NULL);
+ g_return_val_if_fail (b != NULL, NULL);
+
xored = g_malloc (length);
for (gsize i = 0; i < length; i++)
xored[i] = a[i] ^ b[i];
@@ -279,54 +198,23 @@ xor (guint8 *a,
}
static gboolean
-are_equal (guint8 *a,
- guint8 *b)
+ephy_sync_crypto_equals (guint8 *a,
+ guint8 *b,
+ gsize length)
{
- gchar *a_hex;
- gchar *b_hex;
- gboolean retval;
-
- a_hex = ephy_sync_crypto_encode_hex (a, 0);
- b_hex = ephy_sync_crypto_encode_hex (b, 0);
- retval = g_str_equal (a_hex, b_hex);
-
- g_free (a_hex);
- g_free (b_hex);
-
- return retval;
-}
+ g_return_val_if_fail (a != NULL, FALSE);
+ g_return_val_if_fail (b != NULL, FALSE);
-static gchar *
-find_and_replace_string (const gchar *src,
- const gchar *find,
- const gchar *repl)
-{
- const gchar *haystack = src;
- const gchar *needle = NULL;
- gsize haystack_length = strlen (src);
- gsize find_length = strlen (find);
- gsize repl_length = strlen (repl);
- gsize new_length = 0;
- gsize skip_length = 0;
- gchar *new = g_malloc (haystack_length + 1);
-
- while ((needle = g_strstr_len (haystack, -1, find)) != NULL) {
- haystack_length += find_length - repl_length;
- new = g_realloc (new, haystack_length + 1);
- skip_length = needle - haystack;
- memcpy (new + new_length, haystack, skip_length);
- memcpy (new + new_length + skip_length, repl, repl_length);
- new_length += skip_length + repl_length;
- haystack = needle + find_length;
- }
- strcpy (new + new_length, haystack);
+ for (gsize i = 0; i < length; i++)
+ if (a[i] != b[i])
+ return FALSE;
- return new;
+ return TRUE;
}
static gchar *
-normalize_string (const gchar *mac_type,
- EphySyncCryptoHawkArtifacts *artifacts)
+ephy_sync_crypto_normalize_string (const gchar *type,
+ EphySyncCryptoHawkArtifacts *artifacts)
{
gchar *host;
gchar *info;
@@ -335,27 +223,22 @@ normalize_string (const gchar *mac_type,
gchar *normalized;
gchar *tmp;
- g_return_val_if_fail (mac_type, NULL);
- g_return_val_if_fail (artifacts, NULL);
+ g_return_val_if_fail (type != NULL, NULL);
+ g_return_val_if_fail (artifacts != NULL, NULL);
- info = g_strdup_printf ("hawk.%d.%s", HAWK_VERSION, mac_type);
+ info = g_strdup_printf ("hawk.%d.%s", HAWK_VERSION, type);
method = g_ascii_strup (artifacts->method, -1);
host = g_ascii_strdown (artifacts->host, -1);
normalized = g_strjoin ("\n",
- info,
- artifacts->ts,
- artifacts->nonce,
- method,
- artifacts->resource,
- host,
- artifacts->port,
- artifacts->hash ? artifacts->hash : "",
+ info, artifacts->ts, artifacts->nonce,
+ method, artifacts->resource, host,
+ artifacts->port, artifacts->hash ? artifacts->hash : "",
NULL);
if (artifacts->ext && strlen (artifacts->ext) > 0) {
- tmp = find_and_replace_string (artifacts->ext, "\\", "\\\\");
- n_ext = find_and_replace_string (tmp, "\n", "\\n");
+ tmp = ephy_sync_utils_find_and_replace (artifacts->ext, "\\", "\\\\");
+ n_ext = ephy_sync_utils_find_and_replace (tmp, "\n", "\\n");
g_free (tmp);
}
@@ -378,11 +261,13 @@ normalize_string (const gchar *mac_type,
}
static gchar *
-parse_content_type (const gchar *content_type)
+ephy_sync_crypto_parse_content_type (const gchar *content_type)
{
gchar **tokens;
gchar *retval;
+ g_return_val_if_fail (content_type != NULL, NULL);
+
tokens = g_strsplit (content_type, ";", -1);
retval = g_ascii_strdown (g_strstrip (tokens[0]), -1);
g_strfreev (tokens);
@@ -391,8 +276,8 @@ parse_content_type (const gchar *content_type)
}
static gchar *
-calculate_payload_hash (const gchar *payload,
- const gchar *content_type)
+ephy_sync_crypto_calculate_payload_hash (const gchar *payload,
+ const gchar *content_type)
{
guint8 *digest;
gchar *digest_hex;
@@ -400,14 +285,12 @@ calculate_payload_hash (const gchar *payload,
gchar *update;
gchar *hash;
- g_return_val_if_fail (payload, NULL);
- g_return_val_if_fail (content_type, NULL);
+ g_return_val_if_fail (payload != NULL, NULL);
+ g_return_val_if_fail (content_type != NULL, NULL);
- content = parse_content_type (content_type);
+ content = ephy_sync_crypto_parse_content_type (content_type);
update = g_strdup_printf ("hawk.%d.payload\n%s\n%s\n",
- HAWK_VERSION,
- content,
- payload);
+ HAWK_VERSION, content, payload);
digest_hex = g_compute_checksum_for_string (G_CHECKSUM_SHA256, update, -1);
digest = ephy_sync_crypto_decode_hex (digest_hex);
@@ -422,24 +305,22 @@ calculate_payload_hash (const gchar *payload,
}
static gchar *
-calculate_mac (const gchar *mac_type,
- guint8 *key,
- gsize key_length,
- EphySyncCryptoHawkArtifacts *artifacts)
+ephy_sync_crypto_calculate_mac (const gchar *type,
+ guint8 *key,
+ gsize key_len,
+ EphySyncCryptoHawkArtifacts *artifacts)
{
guint8 *digest;
gchar *digest_hex;
gchar *normalized;
gchar *mac;
- g_return_val_if_fail (mac_type, NULL);
- g_return_val_if_fail (key, NULL);
- g_return_val_if_fail (artifacts, NULL);
+ g_return_val_if_fail (type != NULL, NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (artifacts != NULL, NULL);
- normalized = normalize_string (mac_type, artifacts);
- digest_hex = g_compute_hmac_for_string (G_CHECKSUM_SHA256,
- key, key_length,
- normalized, -1);
+ normalized = ephy_sync_crypto_normalize_string (type, artifacts);
+ digest_hex = g_compute_hmac_for_string (G_CHECKSUM_SHA256, key, key_len, normalized, -1);
digest = ephy_sync_crypto_decode_hex (digest_hex);
mac = g_base64_encode (digest, g_checksum_type_get_length (G_CHECKSUM_SHA256));
@@ -451,66 +332,33 @@ calculate_mac (const gchar *mac_type,
}
static gchar *
-append_token_to_header (gchar *header,
- const gchar *token_name,
- gchar *token_value)
+ephy_sync_crypto_append_to_header (gchar *header,
+ const gchar *name,
+ gchar *value)
{
gchar *new_header;
gchar *tmp;
+ g_return_val_if_fail (header != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (value != NULL, NULL);
+
tmp = header;
- new_header = g_strconcat (header, ", ",
- token_name, "=\"",
- token_value, "\"",
- NULL);
+ new_header = g_strconcat (header, ", ", name, "=\"", value, "\"", NULL);
g_free (tmp);
return new_header;
}
-static guint8 *
-concatenate_bytes (guint8 *first_data,
- gsize first_length,
- ...)
-{
- va_list args;
- guint8 *data;
- guint8 *out;
- gsize length;
- gsize out_length;
-
- out_length = first_length;
- out = g_malloc (out_length);
- memcpy (out, first_data, out_length);
-
- va_start (args, first_length);
-
- while ((data = va_arg (args, guint8 *)) != NULL) {
- length = va_arg (args, gsize);
- out = g_realloc (out, out_length + length);
- memcpy (out + out_length, data, length);
- out_length += length;
- }
-
- va_end (args);
-
- return out;
-}
-
-/*
- * HMAC-based Extract-and-Expand Key Derivation Function.
- * Uses sha256 as hash function.
- * https://tools.ietf.org/html/rfc5869
- */
static void
-hkdf (guint8 *in,
- gsize in_length,
- guint8 *salt,
- gsize salt_length,
- guint8 *info,
- gsize info_length,
- guint8 *out,
- gsize out_length)
+ephy_sync_crypto_hkdf (guint8 *in,
+ gsize in_len,
+ guint8 *salt,
+ gsize salt_len,
+ guint8 *info,
+ gsize info_len,
+ guint8 *out,
+ gsize out_len)
{
gchar *prk_hex;
gchar *tmp_hex;
@@ -519,56 +367,53 @@ hkdf (guint8 *in,
guint8 *out_full;
guint8 *data;
guint8 counter;
- gsize hash_length;
- gsize data_length;
+ gsize hash_len;
+ gsize data_len;
gsize n;
- hash_length = g_checksum_type_get_length (G_CHECKSUM_SHA256);
- g_assert (out_length <= hash_length * 255);
+ g_return_if_fail (in != NULL);
+ g_return_if_fail (info != NULL);
+ g_return_if_fail (out != NULL);
- /* If salt value was not provided, use an array of hash_length zeros */
+ hash_len = g_checksum_type_get_length (G_CHECKSUM_SHA256);
+ g_assert (out_len <= hash_len * 255);
+
+ /* If salt value was not provided, use an array of hash_len zeros */
if (salt == NULL) {
- salt = g_malloc0 (hash_length);
- salt_length = hash_length;
+ salt = g_malloc0 (hash_len);
+ salt_len = hash_len;
}
/* Step 1: Extract */
- prk_hex = g_compute_hmac_for_data (G_CHECKSUM_SHA256,
- salt, salt_length,
- in, in_length);
+ prk_hex = g_compute_hmac_for_data (G_CHECKSUM_SHA256, salt, salt_len, in, in_len);
prk = ephy_sync_crypto_decode_hex (prk_hex);
/* Step 2: Expand */
counter = 1;
- n = (out_length + hash_length - 1) / hash_length;
- out_full = g_malloc (n * hash_length);
+ n = (out_len + hash_len - 1) / hash_len;
+ out_full = g_malloc (n * hash_len);
for (gsize i = 0; i < n; i++, counter++) {
if (i == 0) {
- data = concatenate_bytes (info, info_length,
- &counter, 1,
- NULL);
- data_length = info_length + 1;
+ data = ephy_sync_utils_concatenate_bytes (info, info_len, &counter, 1, NULL);
+ data_len = info_len + 1;
} else {
- data = concatenate_bytes (out_full + (i - 1) * hash_length, hash_length,
- info, info_length,
- &counter, 1,
- NULL);
- data_length = hash_length + info_length + 1;
+ data = ephy_sync_utils_concatenate_bytes (out_full + (i - 1) * hash_len, hash_len,
+ info, info_len, &counter, 1,
+ NULL);
+ data_len = hash_len + info_len + 1;
}
- tmp_hex = g_compute_hmac_for_data (G_CHECKSUM_SHA256,
- prk, hash_length,
- data, data_length);
+ tmp_hex = g_compute_hmac_for_data (G_CHECKSUM_SHA256, prk, hash_len, data, data_len);
tmp = ephy_sync_crypto_decode_hex (tmp_hex);
- memcpy (out_full + i * hash_length, tmp, hash_length);
+ memcpy (out_full + i * hash_len, tmp, hash_len);
g_free (data);
g_free (tmp);
g_free (tmp_hex);
}
- memcpy (out, out_full, out_length);
+ memcpy (out, out_full, out_len);
g_free (prk_hex);
g_free (salt);
@@ -577,71 +422,81 @@ hkdf (guint8 *in,
}
static void
-random_func (void *ctx,
- gsize length,
- guint8 *dst)
+ephy_sync_crypto_random_gen (void *ctx,
+ gsize length,
+ guint8 *dst)
{
for (gsize i = 0; i < length; i++)
dst[i] = g_random_int ();
}
static void
-base64_to_base64_urlsafe (gchar *text)
+ephy_sync_crypto_b64_to_b64_urlsafe (gchar *text)
{
+ g_return_if_fail (text != NULL);
+
/* Replace '+' with '-' and '/' with '_' */
g_strcanon (text, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=/", '-');
g_strcanon (text, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=-", '_');
}
static void
-base64_urlsafe_to_base64 (gchar *text)
+ephy_sync_crypto_b64_urlsafe_to_b64 (gchar *text)
{
+ g_return_if_fail (text != NULL);
+
/* Replace '-' with '+' and '_' with '/' */
g_strcanon (text, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=_", '+');
g_strcanon (text, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+", '/');
}
-EphySyncCryptoProcessedKFT *
-ephy_sync_crypto_process_key_fetch_token (const gchar *keyFetchToken)
+void
+ephy_sync_crypto_process_key_fetch_token (const gchar *keyFetchToken,
+ guint8 **tokenID,
+ guint8 **reqHMACkey,
+ guint8 **respHMACkey,
+ guint8 **respXORkey)
{
guint8 *kft;
guint8 *out1;
guint8 *out2;
- guint8 *tokenID;
- guint8 *reqHMACkey;
- guint8 *respHMACkey;
- guint8 *respXORkey;
guint8 *keyRequestKey;
gchar *info_kft;
gchar *info_keys;
+ g_return_if_fail (keyFetchToken != NULL);
+ g_return_if_fail (tokenID != NULL);
+ g_return_if_fail (reqHMACkey != NULL);
+ g_return_if_fail (respHMACkey != NULL);
+ g_return_if_fail (respXORkey != NULL);
+
kft = ephy_sync_crypto_decode_hex (keyFetchToken);
- info_kft = kw ("keyFetchToken");
- info_keys = kw ("account/keys");
+ info_kft = ephy_sync_crypto_kw ("keyFetchToken");
+ info_keys = ephy_sync_crypto_kw ("account/keys");
out1 = g_malloc (3 * EPHY_SYNC_TOKEN_LENGTH);
out2 = g_malloc (3 * EPHY_SYNC_TOKEN_LENGTH);
- hkdf (kft, EPHY_SYNC_TOKEN_LENGTH,
- NULL, 0,
- (guint8 *) info_kft, strlen (info_kft),
- out1, 3 * EPHY_SYNC_TOKEN_LENGTH);
+ ephy_sync_crypto_hkdf (kft, EPHY_SYNC_TOKEN_LENGTH,
+ NULL, 0,
+ (guint8 *) info_kft, strlen (info_kft),
+ out1, 3 * EPHY_SYNC_TOKEN_LENGTH);
- tokenID = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- reqHMACkey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ *tokenID = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ *reqHMACkey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
keyRequestKey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- memcpy (tokenID, out1, EPHY_SYNC_TOKEN_LENGTH);
- memcpy (reqHMACkey, out1 + EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (*tokenID, out1, EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (*reqHMACkey, out1 + EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
memcpy (keyRequestKey, out1 + 2 * EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
- hkdf (keyRequestKey, EPHY_SYNC_TOKEN_LENGTH,
- NULL, 0,
- (guint8 *) info_keys, strlen (info_keys),
- out2, 3 * EPHY_SYNC_TOKEN_LENGTH);
+ ephy_sync_crypto_hkdf (keyRequestKey, EPHY_SYNC_TOKEN_LENGTH,
+ NULL, 0,
+ (guint8 *) info_keys, strlen (info_keys),
+ out2, 3 * EPHY_SYNC_TOKEN_LENGTH);
- respHMACkey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- respXORkey = g_malloc (2 * EPHY_SYNC_TOKEN_LENGTH);
- memcpy (respHMACkey, out2, EPHY_SYNC_TOKEN_LENGTH);
- memcpy (respXORkey, out2 + EPHY_SYNC_TOKEN_LENGTH, 2 * EPHY_SYNC_TOKEN_LENGTH);
+ *respHMACkey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ *respXORkey = g_malloc (2 * EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (*respHMACkey, out2, EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (*respXORkey, out2 + EPHY_SYNC_TOKEN_LENGTH, 2 * EPHY_SYNC_TOKEN_LENGTH);
g_free (kft);
g_free (out1);
@@ -649,53 +504,51 @@ ephy_sync_crypto_process_key_fetch_token (const gchar *keyFetchToken)
g_free (info_kft);
g_free (info_keys);
g_free (keyRequestKey);
-
- return ephy_sync_crypto_processed_kft_new (tokenID,
- reqHMACkey,
- respHMACkey,
- respXORkey);
}
-EphySyncCryptoProcessedST *
-ephy_sync_crypto_process_session_token (const gchar *sessionToken)
+void
+ephy_sync_crypto_process_session_token (const gchar *sessionToken,
+ guint8 **tokenID,
+ guint8 **reqHMACkey,
+ guint8 **requestKey)
{
guint8 *st;
guint8 *out;
- guint8 *tokenID;
- guint8 *reqHMACkey;
- guint8 *requestKey;
gchar *info;
+ g_return_if_fail (sessionToken != NULL);
+ g_return_if_fail (tokenID != NULL);
+ g_return_if_fail (reqHMACkey != NULL);
+ g_return_if_fail (requestKey != NULL);
+
st = ephy_sync_crypto_decode_hex (sessionToken);
- info = kw ("sessionToken");
+ info = ephy_sync_crypto_kw ("sessionToken");
out = g_malloc (3 * EPHY_SYNC_TOKEN_LENGTH);
- hkdf (st, EPHY_SYNC_TOKEN_LENGTH,
- NULL, 0,
- (guint8 *) info, strlen (info),
- out, 3 * EPHY_SYNC_TOKEN_LENGTH);
+ ephy_sync_crypto_hkdf (st, EPHY_SYNC_TOKEN_LENGTH,
+ NULL, 0,
+ (guint8 *) info, strlen (info),
+ out, 3 * EPHY_SYNC_TOKEN_LENGTH);
- tokenID = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- reqHMACkey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- requestKey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- memcpy (tokenID, out, EPHY_SYNC_TOKEN_LENGTH);
- memcpy (reqHMACkey, out + EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
- memcpy (requestKey, out + 2 * EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
+ *tokenID = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ *reqHMACkey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ *requestKey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (*tokenID, out, EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (*reqHMACkey, out + EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (*requestKey, out + 2 * EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
g_free (st);
g_free (out);
g_free (info);
-
- return ephy_sync_crypto_processed_st_new (tokenID,
- reqHMACkey,
- requestKey);
}
-EphySyncCryptoSyncKeys *
-ephy_sync_crypto_retrieve_sync_keys (const gchar *bundle,
- guint8 *respHMACkey,
- guint8 *respXORkey,
- guint8 *unwrapBKey)
+void
+ephy_sync_crypto_compute_sync_keys (const gchar *bundle,
+ guint8 *respHMACkey,
+ guint8 *respXORkey,
+ guint8 *unwrapBKey,
+ guint8 **kA,
+ guint8 **kB)
{
guint8 *bdl;
guint8 *ciphertext;
@@ -703,16 +556,20 @@ ephy_sync_crypto_retrieve_sync_keys (const gchar *bundle,
guint8 *respMAC2;
guint8 *xored;
guint8 *wrapKB;
- guint8 *kA;
- guint8 *kB;
gchar *respMAC2_hex;
- EphySyncCryptoSyncKeys *retval = NULL;
+
+ g_return_if_fail (bundle != NULL);
+ g_return_if_fail (respHMACkey != NULL);
+ g_return_if_fail (respXORkey != NULL);
+ g_return_if_fail (unwrapBKey != NULL);
+ g_return_if_fail (kA != NULL);
+ g_return_if_fail (kB != NULL);
bdl = ephy_sync_crypto_decode_hex (bundle);
ciphertext = g_malloc (2 * EPHY_SYNC_TOKEN_LENGTH);
respMAC = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
wrapKB = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- kA = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ *kA = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
memcpy (ciphertext, bdl, 2 * EPHY_SYNC_TOKEN_LENGTH);
memcpy (respMAC, bdl + 2 * EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
@@ -720,27 +577,20 @@ ephy_sync_crypto_retrieve_sync_keys (const gchar *bundle,
respHMACkey, EPHY_SYNC_TOKEN_LENGTH,
ciphertext, 2 * EPHY_SYNC_TOKEN_LENGTH);
respMAC2 = ephy_sync_crypto_decode_hex (respMAC2_hex);
+ g_assert (ephy_sync_crypto_equals (respMAC, respMAC2, EPHY_SYNC_TOKEN_LENGTH) == TRUE);
- if (are_equal (respMAC, respMAC2) == FALSE) {
- g_warning ("respMAC and respMAC2 differ");
- goto out;
- }
-
- xored = xor (ciphertext, respXORkey, 2 * EPHY_SYNC_TOKEN_LENGTH);
- memcpy (kA, xored, EPHY_SYNC_TOKEN_LENGTH);
+ xored = ephy_sync_crypto_xor (ciphertext, respXORkey, 2 * EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (*kA, xored, EPHY_SYNC_TOKEN_LENGTH);
memcpy (wrapKB, xored + EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
- kB = xor (unwrapBKey, wrapKB, EPHY_SYNC_TOKEN_LENGTH);
- retval = ephy_sync_crypto_sync_keys_new (kA, kB, wrapKB);
+ *kB = ephy_sync_crypto_xor (unwrapBKey, wrapKB, EPHY_SYNC_TOKEN_LENGTH);
-out:
g_free (bdl);
g_free (ciphertext);
g_free (respMAC);
g_free (respMAC2);
- g_free (respMAC2_hex);
g_free (xored);
-
- return retval;
+ g_free (wrapKB);
+ g_free (respMAC2_hex);
}
EphySyncCryptoHawkHeader *
@@ -748,14 +598,12 @@ ephy_sync_crypto_compute_hawk_header (const gchar *url,
const gchar *method,
const gchar *id,
guint8 *key,
- gsize key_length,
+ gsize key_len,
EphySyncCryptoHawkOptions *options)
{
EphySyncCryptoHawkArtifacts *artifacts;
SoupURI *uri;
- gboolean has_options;
- const gchar *hostname;
- const gchar *resource;
+ gchar *resource;
gchar *hash;
gchar *header;
gchar *mac;
@@ -763,92 +611,87 @@ ephy_sync_crypto_compute_hawk_header (const gchar *url,
gchar *payload;
gchar *timestamp;
gint64 ts;
- guint port;
- g_return_val_if_fail (url && strlen (url) > 0, NULL);
- g_return_val_if_fail (method && strlen (method) > 0, NULL);
- g_return_val_if_fail (id && strlen (id) > 0, NULL);
- g_return_val_if_fail (key, NULL);
+ g_return_val_if_fail (url != NULL, NULL);
+ g_return_val_if_fail (method != NULL, NULL);
+ g_return_val_if_fail (id != NULL, NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ ts = ephy_sync_utils_current_time_seconds ();
+ nonce = options && options->nonce ? options->nonce : ephy_sync_crypto_generate_random_hex (6);
+ hash = options ? options->hash : NULL;
+ payload = options ? options->payload : NULL;
+ timestamp = options ? options->timestamp : NULL;
+ uri = soup_uri_new (url);
+ resource = (gchar *) soup_uri_get_path (uri);
- has_options = options != NULL;
- ts = g_get_real_time () / 1000000;
+ if (soup_uri_get_query (uri) != NULL)
+ resource = g_strconcat (resource, "?", soup_uri_get_query (uri), NULL);
- timestamp = has_options ? options->timestamp : NULL;
- if (timestamp) {
+ if (timestamp != NULL) {
gchar *local_time_offset;
gint64 offset;
- local_time_offset = has_options ? options->local_time_offset : NULL;
+ local_time_offset = options ? options->local_time_offset : NULL;
offset = local_time_offset ? g_ascii_strtoll (local_time_offset, NULL, 10) : 0;
-
ts = g_ascii_strtoll (timestamp, NULL, 10) + offset;
}
- nonce = has_options ? options->nonce : NULL;
- nonce = nonce ? nonce : ephy_sync_crypto_generate_random_string (6);
- hash = has_options ? options->hash : NULL;
- payload = has_options ? options->payload : NULL;
-
- uri = soup_uri_new (url);
- g_return_val_if_fail (uri, NULL);
- hostname = soup_uri_get_host (uri);
- port = soup_uri_get_port (uri);
- if (soup_uri_get_query (uri) != NULL)
- resource = g_strdup_printf ("%s?%s", soup_uri_get_path (uri), soup_uri_get_query (uri));
- else
- resource = soup_uri_get_path (uri);
-
- if (!hash && payload) {
- const gchar *content_type;
-
- content_type = has_options ? options->content_type : "text/plain";
- hash = calculate_payload_hash (payload, content_type);
+ if (hash == NULL && payload != NULL) {
+ const gchar *content_type = options ? options->content_type : "text/plain";
+ hash = ephy_sync_crypto_calculate_payload_hash (payload, content_type);
}
- artifacts = ephy_sync_crypto_hawk_artifacts_new (has_options ? options->app : NULL,
- has_options ? options->dlg : NULL,
- has_options ? options->ext : NULL,
+ artifacts = ephy_sync_crypto_hawk_artifacts_new (options ? options->app : NULL,
+ options ? options->dlg : NULL,
+ options ? options->ext : NULL,
hash,
- g_strdup (hostname),
- g_strdup (method),
+ soup_uri_get_host (uri),
+ method,
nonce,
- g_strdup_printf ("%u", port),
- g_strdup (resource),
- g_strdup_printf ("%ld", ts));
+ soup_uri_get_port (uri),
+ resource,
+ ts);
- mac = calculate_mac ("header", key, key_length, artifacts);
+ mac = ephy_sync_crypto_calculate_mac ("header", key, key_len, artifacts);
header = g_strconcat ("Hawk id=\"", id, "\"",
", ts=\"", artifacts->ts, "\"",
", nonce=\"", artifacts->nonce, "\"",
NULL);
- if (artifacts->hash && strlen (artifacts->hash) > 0)
- header = append_token_to_header (header, "hash", artifacts->hash);
+ if (artifacts->hash != NULL && strlen (artifacts->hash) > 0)
+ header = ephy_sync_crypto_append_to_header (header, "hash", artifacts->hash);
- if (artifacts->ext && strlen (artifacts->ext) > 0) {
+ if (artifacts->ext != NULL && strlen (artifacts->ext) > 0) {
gchar *h_ext;
gchar *tmp_ext;
- tmp_ext = find_and_replace_string (artifacts->ext, "\\", "\\\\");
- h_ext = find_and_replace_string (tmp_ext, "\n", "\\n");
- header = append_token_to_header (header, "ext", h_ext);
+ tmp_ext = ephy_sync_utils_find_and_replace (artifacts->ext, "\\", "\\\\");
+ h_ext = ephy_sync_utils_find_and_replace (tmp_ext, "\n", "\\n");
+ header = ephy_sync_crypto_append_to_header (header, "ext", h_ext);
g_free (h_ext);
g_free (tmp_ext);
}
- header = append_token_to_header (header, "mac", mac);
+ header = ephy_sync_crypto_append_to_header (header, "mac", mac);
- if (artifacts->app) {
- header = append_token_to_header (header, "app", artifacts->app);
+ if (artifacts->app != NULL) {
+ header = ephy_sync_crypto_append_to_header (header, "app", artifacts->app);
- if (artifacts->dlg)
- header = append_token_to_header (header, "dlg", artifacts->dlg);
+ if (artifacts->dlg != NULL)
+ header = ephy_sync_crypto_append_to_header (header, "dlg", artifacts->dlg);
}
soup_uri_free (uri);
+ if (options == NULL || options->nonce == NULL)
+ g_free (nonce);
+
+ if (soup_uri_get_query (uri) != NULL)
+ g_free (resource);
+
return ephy_sync_crypto_hawk_header_new (header, artifacts);
}
@@ -867,7 +710,7 @@ ephy_sync_crypto_generate_rsa_key_pair (void)
/* Key sizes below 2048 are considered breakable and should not be used */
retval = rsa_generate_keypair (&public, &private,
- NULL, random_func,
+ NULL, ephy_sync_crypto_random_gen,
NULL, NULL, 2048, 0);
if (retval == 0) {
g_warning ("Failed to generate RSA key pair");
@@ -900,6 +743,10 @@ ephy_sync_crypto_create_assertion (const gchar *certificate,
gsize expected_size;
gsize count;
+ g_return_val_if_fail (certificate != NULL, NULL);
+ g_return_val_if_fail (audience != NULL, NULL);
+ g_return_val_if_fail (keypair != NULL, NULL);
+
expires_at = g_get_real_time () / 1000 + duration * 1000;
body = g_strdup_printf ("{\"exp\": %lu, \"aud\": \"%s\"}", expires_at, audience);
body_b64 = ephy_sync_crypto_base64_urlsafe_encode ((guint8 *) body, strlen (body), TRUE);
@@ -911,7 +758,7 @@ ephy_sync_crypto_create_assertion (const gchar *certificate,
digest = ephy_sync_crypto_decode_hex (digest_hex);
if (rsa_sha256_sign_digest_tr (&keypair->public, &keypair->private,
- NULL, random_func,
+ NULL, ephy_sync_crypto_random_gen,
digest, signature) == 0) {
g_warning ("Failed to sign the message. Giving up.");
goto out;
@@ -927,8 +774,7 @@ ephy_sync_crypto_create_assertion (const gchar *certificate,
}
sig_b64 = ephy_sync_crypto_base64_urlsafe_encode (sig, count, TRUE);
- assertion = g_strdup_printf ("%s~%s.%s.%s",
- certificate, header_b64, body_b64, sig_b64);
+ assertion = g_strdup_printf ("%s~%s.%s.%s", certificate, header_b64, body_b64, sig_b64);
out:
g_free (body);
@@ -945,117 +791,120 @@ out:
}
gchar *
-ephy_sync_crypto_generate_random_string (gsize length)
+ephy_sync_crypto_generate_random_hex (gsize length)
{
- guchar *bytes;
- gchar *base64_string;
- gchar *string;
+ FILE *fp;
+ gsize num_bytes;
+ guint8 *bytes;
+ gchar *hex;
+ gchar *out;
- bytes = g_malloc (length);
- for (gsize i = 0; i < length; i++)
- bytes[i] = g_random_int ();
+ g_assert (length > 0);
+ num_bytes = (length + 1) / 2;
+ bytes = g_malloc (num_bytes);
- base64_string = g_base64_encode (bytes, length);
- base64_to_base64_urlsafe (base64_string);
- string = g_strndup (base64_string, length);
+ fp = fopen ("/dev/urandom", "r");
+ fread (bytes, sizeof (guint8), num_bytes, fp);
+ hex = ephy_sync_crypto_encode_hex (bytes, num_bytes);
+ out = g_strndup (hex, length);
g_free (bytes);
- g_free (base64_string);
+ g_free (hex);
+ fclose (fp);
- return string;
+ return out;
}
gchar *
ephy_sync_crypto_base64_urlsafe_encode (guint8 *data,
- gsize data_length,
+ gsize data_len,
gboolean strip)
{
- gchar *encoded;
gchar *base64;
- gsize start;
+ gchar *out;
+ gsize start = 0;
gssize end;
- base64 = g_base64_encode (data, data_length);
+ g_return_val_if_fail (data != NULL, NULL);
- if (strip == FALSE) {
- base64_to_base64_urlsafe (base64);
- return base64;
- }
+ base64 = g_base64_encode (data, data_len);
+ end = strlen (base64) - 1;
- /* Strip all the '=' */
- start = 0;
- while (start < strlen (base64) && base64[start] == '=')
- start++;
+ if (strip == TRUE) {
+ while (start < strlen (base64) && base64[start] == '=')
+ start++;
- end = strlen (base64) - 1;
- while (end >= 0 && base64[end] == '=')
- end--;
+ while (end >= 0 && base64[end] == '=')
+ end--;
+ }
- encoded = g_strndup (base64 + start, end - start + 1);
- base64_to_base64_urlsafe (encoded);
+ out = g_strndup (base64 + start, end - start + 1);
+ ephy_sync_crypto_b64_to_b64_urlsafe (out);
g_free (base64);
- return encoded;
+ return out;
}
guint8 *
-ephy_sync_crypto_base64_urlsafe_decode (gchar *text,
- gsize *out_length)
+ephy_sync_crypto_base64_urlsafe_decode (const gchar *text,
+ gsize *out_len,
+ gboolean fill)
{
- guint8 *decoded;
- gchar *text_copy;
+ guint8 *out;
+ gchar *to_decode;
+ gchar *suffix = NULL;
- text_copy = g_strdup (text);
- base64_urlsafe_to_base64 (text_copy);
- decoded = g_base64_decode (text_copy, out_length);
+ g_return_val_if_fail (text != NULL, NULL);
+ g_return_val_if_fail (out_len != NULL, NULL);
- g_free (text_copy);
+ if (fill == TRUE)
+ suffix = g_strnfill ((4 - strlen (text) % 4) % 4, '=');
- return decoded;
+ to_decode = g_strconcat (text, suffix, NULL);
+ ephy_sync_crypto_b64_urlsafe_to_b64 (to_decode);
+ out = g_base64_decode (to_decode, out_len);
+
+ g_free (suffix);
+ g_free (to_decode);
+
+ return out;
}
guint8 *
ephy_sync_crypto_aes_256 (EphySyncCryptoAES256Mode mode,
const guint8 *key,
const guint8 *data,
- gsize data_length,
- gsize *out_length)
+ gsize data_len,
+ gsize *out_len)
{
struct aes256_ctx aes;
- gsize padded_length;
+ gsize padded_len = data_len;
guint8 *padded_data;
guint8 *out;
g_return_val_if_fail (key != NULL, NULL);
g_return_val_if_fail (data != NULL, NULL);
- if (mode == AES_256_MODE_DECRYPT)
- g_assert (data_length % AES_BLOCK_SIZE == 0);
-
- padded_length = data_length;
- if (data_length % AES_BLOCK_SIZE != 0)
- padded_length = data_length + (AES_BLOCK_SIZE - data_length % AES_BLOCK_SIZE);
-
- out = g_malloc (padded_length);
- padded_data = g_malloc0 (padded_length);
- memcpy (padded_data, data, data_length);
-
- switch (mode) {
- case AES_256_MODE_ENCRYPT:
- aes256_set_encrypt_key (&aes, key);
- aes256_encrypt (&aes, padded_length, out, padded_data);
- break;
- case AES_256_MODE_DECRYPT:
- aes256_set_decrypt_key (&aes, key);
- aes256_decrypt (&aes, padded_length, out, padded_data);
- break;
- default:
- g_assert_not_reached ();
+ if (mode == AES_256_MODE_ENCRYPT)
+ padded_len = data_len + (AES_BLOCK_SIZE - data_len % AES_BLOCK_SIZE);
+ else if (mode == AES_256_MODE_DECRYPT)
+ g_assert (data_len % AES_BLOCK_SIZE == 0);
+
+ out = g_malloc0 (padded_len);
+ padded_data = g_malloc0 (padded_len);
+ memcpy (padded_data, data, data_len);
+
+ if (mode == AES_256_MODE_ENCRYPT) {
+ aes256_set_encrypt_key (&aes, key);
+ aes256_encrypt (&aes, padded_len, out, padded_data);
+ } else if (mode == AES_256_MODE_DECRYPT) {
+ aes256_set_decrypt_key (&aes, key);
+ aes256_decrypt (&aes, padded_len, out, padded_data);
}
- if (out_length != NULL)
- *out_length = padded_length;
+ if (out_len != NULL)
+ *out_len = padded_len;
g_free (padded_data);
@@ -1064,12 +913,14 @@ ephy_sync_crypto_aes_256 (EphySyncCryptoAES256Mode mode,
gchar *
ephy_sync_crypto_encode_hex (guint8 *data,
- gsize data_length)
+ gsize data_len)
{
gchar *retval;
gsize length;
- length = data_length == 0 ? EPHY_SYNC_TOKEN_LENGTH : data_length;
+ g_return_val_if_fail (data != NULL, NULL);
+
+ length = data_len == 0 ? EPHY_SYNC_TOKEN_LENGTH : data_len;
retval = g_malloc (length * 2 + 1);
for (gsize i = 0; i < length; i++) {
@@ -1085,19 +936,17 @@ ephy_sync_crypto_encode_hex (guint8 *data,
}
guint8 *
-ephy_sync_crypto_decode_hex (const gchar *hex_string)
+ephy_sync_crypto_decode_hex (const gchar *hex)
{
guint8 *retval;
- gsize hex_length;
-
- hex_length = strlen (hex_string);
- g_return_val_if_fail (hex_length % 2 == 0, NULL);
+ gsize hex_len = strlen (hex);
- retval = g_malloc (hex_length / 2);
+ g_return_val_if_fail (hex != NULL, NULL);
+ g_return_val_if_fail (hex_len % 2 == 0, NULL);
- for (gsize i = 0, j = 0; i < hex_length; i += 2, j++) {
- sscanf(hex_string + i, "%2hhx", retval + j);
- }
+ retval = g_malloc (hex_len / 2);
+ for (gsize i = 0, j = 0; i < hex_len; i += 2, j++)
+ sscanf(hex + i, "%2hhx", retval + j);
return retval;
}
diff --git a/src/ephy-sync-crypto.h b/src/ephy-sync-crypto.h
index 4cf1adb..628cb30 100644
--- a/src/ephy-sync-crypto.h
+++ b/src/ephy-sync-crypto.h
@@ -62,93 +62,63 @@ typedef struct {
} EphySyncCryptoHawkHeader;
typedef struct {
- guint8 *tokenID;
- guint8 *reqHMACkey;
- guint8 *respHMACkey;
- guint8 *respXORkey;
-} EphySyncCryptoProcessedKFT;
-
-typedef struct {
- guint8 *tokenID;
- guint8 *reqHMACkey;
- guint8 *requestKey;
-} EphySyncCryptoProcessedST;
-
-typedef struct {
- guint8 *kA;
- guint8 *kB;
- guint8 *wrapKB;
-} EphySyncCryptoSyncKeys;
-
-typedef struct {
struct rsa_public_key public;
struct rsa_private_key private;
} EphySyncCryptoRSAKeyPair;
-EphySyncCryptoHawkOptions *ephy_sync_crypto_hawk_options_new (gchar *app,
- gchar *dlg,
- gchar *ext,
- gchar *content_type,
- gchar *hash,
- gchar *local_time_offset,
- gchar *nonce,
- gchar *payload,
- gchar *timestamp);
-
-void ephy_sync_crypto_hawk_options_free (EphySyncCryptoHawkOptions
*hawk_options);
-
-void ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader *hawk_header);
-
-void ephy_sync_crypto_processed_kft_free (EphySyncCryptoProcessedKFT
*processed_kft);
-
-void ephy_sync_crypto_processed_st_free (EphySyncCryptoProcessedST
*processed_st);
-
-void ephy_sync_crypto_sync_keys_free (EphySyncCryptoSyncKeys *sync_keys);
-
-void ephy_sync_crypto_rsa_key_pair_free (EphySyncCryptoRSAKeyPair *keypair);
-
-EphySyncCryptoProcessedKFT *ephy_sync_crypto_process_key_fetch_token (const gchar *keyFetchToken);
-
-EphySyncCryptoProcessedST *ephy_sync_crypto_process_session_token (const gchar *sessionToken);
-
-EphySyncCryptoSyncKeys *ephy_sync_crypto_retrieve_sync_keys (const gchar *bundle,
- guint8 *respHMACkey,
- guint8 *respXORkey,
- guint8 *unwrapBKey);
-
-EphySyncCryptoHawkHeader *ephy_sync_crypto_compute_hawk_header (const gchar *url,
- const gchar *method,
- const gchar *id,
- guint8 *key,
- gsize key_length,
- EphySyncCryptoHawkOptions *options);
-
-EphySyncCryptoRSAKeyPair *ephy_sync_crypto_generate_rsa_key_pair (void);
-
-gchar *ephy_sync_crypto_create_assertion (const gchar *certificate,
- const gchar *audience,
- guint64 duration,
- EphySyncCryptoRSAKeyPair *keypair);
-
-gchar *ephy_sync_crypto_generate_random_string (gsize length);
-
-gchar *ephy_sync_crypto_base64_urlsafe_encode (guint8 *data,
- gsize data_length,
- gboolean strip);
-
-guint8 *ephy_sync_crypto_base64_urlsafe_decode (gchar *text,
- gsize *out_length);
-
-guint8 *ephy_sync_crypto_aes_256 (EphySyncCryptoAES256Mode mode,
- const guint8 *key,
- const guint8 *data,
- gsize data_length,
- gsize *out_length);
-
-gchar *ephy_sync_crypto_encode_hex (guint8 *data,
- gsize data_length);
-
-guint8 *ephy_sync_crypto_decode_hex (const gchar *hex_string);
+EphySyncCryptoHawkOptions *ephy_sync_crypto_hawk_options_new (const gchar *app,
+ const gchar *dlg,
+ const gchar *ext,
+ const gchar *content_type,
+ const gchar *hash,
+ const gchar *local_time_offset,
+ const gchar *nonce,
+ const gchar *payload,
+ const gchar *timestamp);
+void ephy_sync_crypto_hawk_options_free (EphySyncCryptoHawkOptions *options);
+void ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader *header);
+void ephy_sync_crypto_rsa_key_pair_free (EphySyncCryptoRSAKeyPair *keypair);
+void ephy_sync_crypto_process_key_fetch_token (const gchar *keyFetchToken,
+ guint8 **tokenID,
+ guint8 **reqHMACkey,
+ guint8 **respHMACkey,
+ guint8 **respXORkey);
+void ephy_sync_crypto_process_session_token (const gchar *sessionToken,
+ guint8 **tokenID,
+ guint8 **reqHMACkey,
+ guint8 **requestKey);
+void ephy_sync_crypto_compute_sync_keys (const gchar *bundle,
+ guint8 *respHMACkey,
+ guint8 *respXORkey,
+ guint8 *unwrapBKey,
+ guint8 **kA,
+ guint8 **kB);
+EphySyncCryptoHawkHeader *ephy_sync_crypto_compute_hawk_header (const gchar *url,
+ const gchar *method,
+ const gchar *id,
+ guint8 *key,
+ gsize key_len,
+ EphySyncCryptoHawkOptions *options);
+EphySyncCryptoRSAKeyPair *ephy_sync_crypto_generate_rsa_key_pair (void);
+gchar *ephy_sync_crypto_create_assertion (const gchar *certificate,
+ const gchar *audience,
+ guint64 duration,
+ EphySyncCryptoRSAKeyPair *keypair);
+gchar *ephy_sync_crypto_generate_random_hex (gsize length);
+gchar *ephy_sync_crypto_base64_urlsafe_encode (guint8 *data,
+ gsize data_len,
+ gboolean strip);
+guint8 *ephy_sync_crypto_base64_urlsafe_decode (const gchar *text,
+ gsize *out_len,
+ gboolean fill);
+guint8 *ephy_sync_crypto_aes_256 (EphySyncCryptoAES256Mode mode,
+ const guint8 *key,
+ const guint8 *data,
+ gsize data_len,
+ gsize *out_len);
+gchar *ephy_sync_crypto_encode_hex (guint8 *data,
+ gsize data_len);
+guint8 *ephy_sync_crypto_decode_hex (const gchar *hex_string);
G_END_DECLS
diff --git a/src/ephy-sync-secret.c b/src/ephy-sync-secret.c
index d1df199..58603eb 100644
--- a/src/ephy-sync-secret.c
+++ b/src/ephy-sync-secret.c
@@ -63,62 +63,51 @@ store_token_cb (SecretService *service,
}
void
-ephy_sync_secret_forget_all_tokens (void)
+ephy_sync_secret_forget_tokens (void)
{
GHashTable *attributes;
attributes = secret_attributes_build (EPHY_SYNC_TOKEN_SCHEMA, NULL);
- secret_service_clear (NULL,
- EPHY_SYNC_TOKEN_SCHEMA,
- attributes,
- NULL,
- (GAsyncReadyCallback) forget_all_tokens_cb,
- NULL);
+ secret_service_clear (NULL, EPHY_SYNC_TOKEN_SCHEMA, attributes,
+ NULL, (GAsyncReadyCallback) forget_all_tokens_cb, NULL);
g_hash_table_unref (attributes);
}
void
-ephy_sync_secret_load_tokens (EphySyncService *sync_service)
+ephy_sync_secret_load_tokens (EphySyncService *service)
{
SecretItem *secret_item;
SecretValue *secret_value;
GHashTable *attributes;
GError *error = NULL;
GList *matches;
- GList *tmp;
- EphySyncServiceTokenType type;
- const gchar *emailUTF8;
+ EphySyncTokenType type;
+ const gchar *email;
const gchar *value;
gchar *user_email;
- user_email = ephy_sync_service_get_user_email (sync_service);
+ user_email = ephy_sync_service_get_user_email (service);
attributes = secret_attributes_build (EPHY_SYNC_TOKEN_SCHEMA, NULL);
/* Do this synchronously so the tokens will be available immediately */
- matches = secret_service_search_sync (NULL,
- EPHY_SYNC_TOKEN_SCHEMA,
- attributes,
+ matches = secret_service_search_sync (NULL, EPHY_SYNC_TOKEN_SCHEMA, attributes,
SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK |
SECRET_SEARCH_LOAD_SECRETS,
- NULL,
- &error);
-
- for (tmp = matches; tmp != NULL; tmp = tmp->next) {
- secret_item = tmp->data;
+ NULL, &error);
+ for (GList *m = matches; m != NULL; m = m->next) {
+ secret_item = m->data;
attributes = secret_item_get_attributes (secret_item);
- emailUTF8 = g_hash_table_lookup (attributes, EMAIL_KEY);
- type = g_ascii_strtoull (g_hash_table_lookup (attributes, TOKEN_TYPE_KEY),
- NULL, 10);
+ email = g_hash_table_lookup (attributes, EMAIL_KEY);
+ type = g_ascii_strtoull (g_hash_table_lookup (attributes, TOKEN_TYPE_KEY), NULL, 10);
secret_value = secret_item_get_secret (secret_item);
value = secret_value_get_text (secret_value);
/* Sanity check */
- if (g_strcmp0 (emailUTF8, user_email))
+ if (g_strcmp0 (email, user_email) != 0)
continue;
- ephy_sync_service_set_token (sync_service, g_strdup (value), type);
-
+ ephy_sync_service_set_token (service, g_strdup (value), type);
g_hash_table_unref (attributes);
}
@@ -126,22 +115,22 @@ ephy_sync_secret_load_tokens (EphySyncService *sync_service)
}
void
-ephy_sync_secret_store_token (const gchar *emailUTF8,
- gchar *value,
- EphySyncServiceTokenType type)
+ephy_sync_secret_store_token (const gchar *email,
+ gchar *value,
+ EphySyncTokenType type)
{
SecretValue *secret_value;
GHashTable *attributes;
const gchar *name;
gchar *label;
- g_return_if_fail (emailUTF8);
+ g_return_if_fail (email);
g_return_if_fail (value);
- name = ephy_sync_service_token_name_from_type (type);
+ name = ephy_sync_utils_token_name_from_type (type);
secret_value = secret_value_new (value, -1, "text/plain");
attributes = secret_attributes_build (EPHY_SYNC_TOKEN_SCHEMA,
- EMAIL_KEY, emailUTF8,
+ EMAIL_KEY, email,
TOKEN_TYPE_KEY, type,
TOKEN_NAME_KEY, name,
NULL);
@@ -150,15 +139,9 @@ ephy_sync_secret_store_token (const gchar *emailUTF8,
*/
label = g_strdup_printf (_("Token value for %s token"), name);
- secret_service_store (NULL,
- EPHY_SYNC_TOKEN_SCHEMA,
- attributes,
- NULL,
- label,
- secret_value,
- NULL,
- (GAsyncReadyCallback) store_token_cb,
- NULL);
+ secret_service_store (NULL, EPHY_SYNC_TOKEN_SCHEMA, attributes,
+ NULL, label, secret_value, NULL,
+ (GAsyncReadyCallback) store_token_cb, NULL);
g_free (label);
secret_value_unref (secret_value);
diff --git a/src/ephy-sync-secret.h b/src/ephy-sync-secret.h
index 398afd1..cd1e8b5 100644
--- a/src/ephy-sync-secret.h
+++ b/src/ephy-sync-secret.h
@@ -28,19 +28,17 @@ G_BEGIN_DECLS
const SecretSchema *ephy_sync_secret_get_token_schema (void) G_GNUC_CONST;
-#define EMAIL_KEY "email_utf8"
-#define TOKEN_TYPE_KEY "token_type"
-#define TOKEN_NAME_KEY "token_name"
+#define EMAIL_KEY "email_utf8"
+#define TOKEN_TYPE_KEY "token_type"
+#define TOKEN_NAME_KEY "token_name"
#define EPHY_SYNC_TOKEN_SCHEMA (ephy_sync_secret_get_token_schema ())
-void ephy_sync_secret_forget_all_tokens (void);
-
-void ephy_sync_secret_load_tokens (EphySyncService *sync_service);
-
-void ephy_sync_secret_store_token (const gchar *emailUTF8,
- gchar *value,
- EphySyncServiceTokenType type);
+void ephy_sync_secret_forget_tokens (void);
+void ephy_sync_secret_load_tokens (EphySyncService *service);
+void ephy_sync_secret_store_token (const gchar *email,
+ gchar *value,
+ EphySyncTokenType type);
G_END_DECLS
diff --git a/src/ephy-sync-service.c b/src/ephy-sync-service.c
index 77a3a2b..2e9a366 100644
--- a/src/ephy-sync-service.c
+++ b/src/ephy-sync-service.c
@@ -19,45 +19,47 @@
#include "config.h"
#include "ephy-sync-service.h"
+#include "ephy-bookmark.h"
+#include "ephy-bookmarks-manager.h"
#include "ephy-debug.h"
#include "ephy-settings.h"
+#include "ephy-shell.h"
#include "ephy-sync-crypto.h"
#include "ephy-sync-secret.h"
-#include "ephy-sync-utils.h"
#include <json-glib/json-glib.h>
#include <string.h>
-#define MOZILLA_TOKEN_SERVER_URL "https://token.services.mozilla.com/1.0/sync/1.5"
-#define MOZILLA_FIREFOX_ACCOUNTS_BASE_URL "https://api.accounts.firefox.com/"
-#define MOZILLA_FIREFOX_ACCOUNTS_VERSION "v1/"
-
-#define EMAIL_REGEX "^[a-zA-Z0-9_]([a-zA-Z0-9._]+[a-zA-Z0-9_])?@[a-z0-9.-]+$"
-#define CURRENT_TIME_IN_SECONDS (g_get_real_time () / 1000000)
+#define MOZILLA_TOKEN_SERVER_URL "https://token.services.mozilla.com/1.0/sync/1.5"
+#define MOZILLA_FXA_SERVER_URL "https://api.accounts.firefox.com/v1/"
+#define EPHY_BOOKMARKS_COLLECTION "ephy-bookmarks"
+#define EMAIL_REGEX "^[a-zA-Z0-9_]([a-zA-Z0-9._]+[a-zA-Z0-9_])?@[a-z0-9.-]+$"
struct _EphySyncService {
- GObject parent_instance;
-
- SoupSession *soup_session;
-
- gchar *uid;
- gchar *sessionToken;
- gchar *keyFetchToken;
- gchar *unwrapBKey;
- gchar *kA;
- gchar *kB;
-
- gchar *user_email;
- gint64 last_auth_at;
-
- gboolean is_locked;
- gchar *storage_endpoint;
- gchar *storage_credentials_id;
- gchar *storage_credentials_key;
- gint64 storage_credentials_expiry_time;
- GQueue *storage_queue;
-
- gchar *certificate;
+ GObject parent_instance;
+
+ SoupSession *session;
+ guint sync_frequency;
+
+ gchar *uid;
+ gchar *sessionToken;
+ gchar *keyFetchToken;
+ gchar *unwrapBKey;
+ gchar *kA;
+ gchar *kB;
+
+ gchar *user_email;
+ double sync_time;
+ gint64 auth_at;
+
+ gboolean locked;
+ gchar *storage_endpoint;
+ gchar *storage_credentials_id;
+ gchar *storage_credentials_key;
+ gint64 storage_credentials_expiry_time;
+ GQueue *storage_queue;
+
+ gchar *certificate;
EphySyncCryptoRSAKeyPair *keypair;
};
@@ -111,74 +113,21 @@ storage_server_request_async_data_free (StorageServerRequestAsyncData *data)
g_slice_free (StorageServerRequestAsyncData, data);
}
-static gchar *
-get_audience_for_url (const gchar *url)
-{
- SoupURI *uri;
- const gchar *scheme;
- const gchar *host;
- gchar *port_str;
- guint port;
- gchar *audience;
-
- uri = soup_uri_new (url);
- g_assert (uri != NULL);
-
- scheme = soup_uri_get_scheme (uri);
- host = soup_uri_get_host (uri);
- port = soup_uri_get_port (uri);
- port_str = g_strdup_printf (":%u", port);
-
- /* Even if the url doesn't contain the port, soup_uri_get_port() will return
- * the default port for the url's scheme so we need to check if the port was
- * really present in the url.
- */
- if (g_strstr_len (url, -1, port_str) != NULL)
- audience = g_strdup_printf ("%s://%s:%u", scheme, host, port);
- else
- audience = g_strdup_printf ("%s://%s", scheme, host);
-
- soup_uri_free (uri);
- g_free (port_str);
-
- return audience;
-}
-
-static guchar *
-base64_parse (const gchar *string,
- gsize *out_len)
-{
- gchar *suffix;
- gchar *full;
- guchar *decoded;
- gsize len;
-
- len = ((4 - strlen (string) % 4) % 4);
- suffix = g_strnfill (len, '=');
- full = g_strconcat (string, suffix, NULL);
- decoded = g_base64_decode (full, out_len);
-
- g_free (suffix);
- g_free (full);
-
- return decoded;
-}
-
static void
destroy_session_response_cb (SoupSession *session,
- SoupMessage *message,
+ SoupMessage *msg,
gpointer user_data)
{
JsonParser *parser;
JsonObject *json;
- if (message->status_code == 200) {
+ if (msg->status_code == 200) {
LOG ("Session destroyed");
return;
}
parser = json_parser_new ();
- json_parser_load_from_data (parser, message->response_body->data, -1, NULL);
+ json_parser_load_from_data (parser, msg->response_body->data, -1, NULL);
json = json_node_get_object (json_parser_get_root (parser));
g_warning ("Failed to destroy session: errno: %ld, errmsg: %s",
@@ -188,21 +137,11 @@ destroy_session_response_cb (SoupSession *session,
g_object_unref (parser);
}
-static void
-ephy_sync_service_clear_storage_credentials (EphySyncService *self)
-{
- g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
-
- g_clear_pointer (&self->certificate, g_free);
- g_clear_pointer (&self->storage_endpoint, g_free);
- g_clear_pointer (&self->storage_credentials_id, g_free);
- g_clear_pointer (&self->storage_credentials_key, g_free);
- self->storage_credentials_expiry_time = 0;
-}
-
static gboolean
ephy_sync_service_storage_credentials_is_expired (EphySyncService *self)
{
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), TRUE);
+
if (self->storage_credentials_id == NULL || self->storage_credentials_key == NULL)
return TRUE;
@@ -210,7 +149,7 @@ ephy_sync_service_storage_credentials_is_expired (EphySyncService *self)
return TRUE;
/* Consider a 60 seconds safety interval. */
- return self->storage_credentials_expiry_time < CURRENT_TIME_IN_SECONDS - 60;
+ return self->storage_credentials_expiry_time < ephy_sync_utils_current_time_seconds () - 60;
}
static void
@@ -223,39 +162,33 @@ ephy_sync_service_fxa_hawk_post_async (EphySyncService *self,
SoupSessionCallback callback,
gpointer user_data)
{
- EphySyncCryptoHawkOptions *hawk_options;
- EphySyncCryptoHawkHeader *hawk_header;
- SoupMessage *message;
+ EphySyncCryptoHawkOptions *hoptions;
+ EphySyncCryptoHawkHeader *hheader;
+ SoupMessage *msg;
gchar *url;
const gchar *content_type = "application/json";
- url = g_strdup_printf ("%s%s%s",
- MOZILLA_FIREFOX_ACCOUNTS_BASE_URL,
- MOZILLA_FIREFOX_ACCOUNTS_VERSION,
- endpoint);
- message = soup_message_new (SOUP_METHOD_POST, url);
- soup_message_set_request (message, content_type,
- SOUP_MEMORY_COPY,
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (endpoint != NULL);
+ g_return_if_fail (id != NULL);
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (request_body != NULL);
+
+ url = g_strdup_printf ("%s%s", MOZILLA_FXA_SERVER_URL, endpoint);
+ msg = soup_message_new (SOUP_METHOD_POST, url);
+ soup_message_set_request (msg, content_type, SOUP_MEMORY_COPY,
request_body, strlen (request_body));
- hawk_options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL,
- g_strdup (content_type),
- NULL, NULL, NULL,
- g_strdup (request_body),
- NULL);
- hawk_header = ephy_sync_crypto_compute_hawk_header (url, "POST",
- id,
- key, key_length,
- hawk_options);
- soup_message_headers_append (message->request_headers,
- "authorization", hawk_header->header);
- soup_message_headers_append (message->request_headers,
- "content-type", content_type);
- soup_session_queue_message (self->soup_session, message, callback, user_data);
+ hoptions = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL, content_type,
+ NULL, NULL, NULL, request_body, NULL);
+ hheader = ephy_sync_crypto_compute_hawk_header (url, "POST", id, key, key_length, hoptions);
+ soup_message_headers_append (msg->request_headers, "authorization", hheader->header);
+ soup_message_headers_append (msg->request_headers, "content-type", content_type);
+ soup_session_queue_message (self->session, msg, callback, user_data);
g_free (url);
- ephy_sync_crypto_hawk_options_free (hawk_options);
- ephy_sync_crypto_hawk_header_free (hawk_header);
+ ephy_sync_crypto_hawk_options_free (hoptions);
+ ephy_sync_crypto_hawk_header_free (hheader);
}
static guint
@@ -266,98 +199,87 @@ ephy_sync_service_fxa_hawk_get_sync (EphySyncService *self,
gsize key_length,
JsonNode **node)
{
- EphySyncCryptoHawkHeader *hawk_header;
- SoupMessage *message;
+ EphySyncCryptoHawkHeader *hheader;
+ SoupMessage *msg;
JsonParser *parser;
gchar *url;
- url = g_strdup_printf ("%s%s%s",
- MOZILLA_FIREFOX_ACCOUNTS_BASE_URL,
- MOZILLA_FIREFOX_ACCOUNTS_VERSION,
- endpoint);
- message = soup_message_new (SOUP_METHOD_GET, url);
- hawk_header = ephy_sync_crypto_compute_hawk_header (url, "GET",
- id,
- key, key_length,
- NULL);
- soup_message_headers_append (message->request_headers,
- "authorization", hawk_header->header);
- soup_session_send_message (self->soup_session, message);
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), 0);
+ g_return_val_if_fail (endpoint != NULL, 0);
+ g_return_val_if_fail (id != NULL, 0);
+ g_return_val_if_fail (key != NULL, 0);
+
+ url = g_strdup_printf ("%s%s", MOZILLA_FXA_SERVER_URL, endpoint);
+ msg = soup_message_new (SOUP_METHOD_GET, url);
+ hheader = ephy_sync_crypto_compute_hawk_header (url, "GET", id, key, key_length, NULL);
+ soup_message_headers_append (msg->request_headers, "authorization", hheader->header);
+ soup_session_send_message (self->session, msg);
if (node != NULL) {
parser = json_parser_new ();
- json_parser_load_from_data (parser,
- message->response_body->data,
- -1, NULL);
+ json_parser_load_from_data (parser, msg->response_body->data, -1, NULL);
*node = json_node_copy (json_parser_get_root (parser));
g_object_unref (parser);
}
g_free (url);
- ephy_sync_crypto_hawk_header_free (hawk_header);
+ ephy_sync_crypto_hawk_header_free (hheader);
- return message->status_code;
+ return msg->status_code;
}
static void
ephy_sync_service_send_storage_request (EphySyncService *self,
StorageServerRequestAsyncData *data)
{
- EphySyncCryptoHawkOptions *hawk_options = NULL;
- EphySyncCryptoHawkHeader *hawk_header;
- SoupMessage *message;
+ EphySyncCryptoHawkOptions *hoptions = NULL;
+ EphySyncCryptoHawkHeader *hheader;
+ SoupMessage *msg;
gchar *url;
gchar *if_modified_since = NULL;
gchar *if_unmodified_since = NULL;
const gchar *content_type = "application/json";
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (data != NULL);
+
url = g_strdup_printf ("%s/%s", self->storage_endpoint, data->endpoint);
- message = soup_message_new (data->method, url);
+ msg = soup_message_new (data->method, url);
if (data->request_body != NULL) {
- hawk_options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL,
- g_strdup (content_type),
- NULL, NULL, NULL,
- g_strdup (data->request_body),
- NULL);
- soup_message_set_request (message, content_type,
- SOUP_MEMORY_COPY,
+ hoptions = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL, content_type,
+ NULL, NULL, NULL, data->request_body, NULL);
+ soup_message_set_request (msg, content_type, SOUP_MEMORY_COPY,
data->request_body, strlen (data->request_body));
}
- if (g_strcmp0 (data->method, SOUP_METHOD_POST) == 0) {
- soup_message_headers_append (message->request_headers,
- "content-type", content_type);
- }
+ if (g_strcmp0 (data->method, SOUP_METHOD_POST) == 0)
+ soup_message_headers_append (msg->request_headers, "content-type", content_type);
if (data->modified_since >= 0) {
if_modified_since = g_strdup_printf ("%.2lf", data->modified_since);
- soup_message_headers_append (message->request_headers,
- "X-If-Modified-Since", if_modified_since);
+ soup_message_headers_append (msg->request_headers, "X-If-Modified-Since", if_modified_since);
}
if (data->unmodified_since >= 0) {
if_unmodified_since = g_strdup_printf ("%.2lf", data->unmodified_since);
- soup_message_headers_append (message->request_headers,
- "X-If-Unmodified-Since", if_unmodified_since);
+ soup_message_headers_append (msg->request_headers, "X-If-Unmodified-Since", if_unmodified_since);
}
- hawk_header = ephy_sync_crypto_compute_hawk_header (url, data->method,
- self->storage_credentials_id,
- (guint8 *) self->storage_credentials_key,
- strlen (self->storage_credentials_key),
- hawk_options);
- soup_message_headers_append (message->request_headers,
- "authorization", hawk_header->header);
- soup_session_queue_message (self->soup_session, message,
- data->callback, data->user_data);
+ hheader = ephy_sync_crypto_compute_hawk_header (url, data->method, self->storage_credentials_id,
+ (guint8 *) self->storage_credentials_key,
+ strlen (self->storage_credentials_key),
+ hoptions);
+ soup_message_headers_append (msg->request_headers, "authorization", hheader->header);
+ soup_session_queue_message (self->session, msg, data->callback, data->user_data);
- if (hawk_options != NULL)
- ephy_sync_crypto_hawk_options_free (hawk_options);
+ if (hoptions != NULL)
+ ephy_sync_crypto_hawk_options_free (hoptions);
g_free (url);
g_free (if_modified_since);
g_free (if_unmodified_since);
+ ephy_sync_crypto_hawk_header_free (hheader);
storage_server_request_async_data_free (data);
}
@@ -365,34 +287,34 @@ static gboolean
ephy_sync_service_certificate_is_valid (EphySyncService *self,
const gchar *certificate)
{
- SoupURI *uri;
JsonParser *parser;
JsonObject *json;
JsonObject *principal;
+ SoupURI *uri;
gchar **pieces;
gchar *header;
gchar *payload;
- gchar *uid_email;
- const gchar *algorithm;
+ gchar *uid_email = NULL;
+ const gchar *alg;
const gchar *email;
- gsize header_len;
- gsize payload_len;
+ gsize len;
gboolean retval = FALSE;
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), FALSE);
g_return_val_if_fail (certificate != NULL, FALSE);
- uri = soup_uri_new (MOZILLA_FIREFOX_ACCOUNTS_BASE_URL);
+ uri = soup_uri_new (MOZILLA_FXA_SERVER_URL);
pieces = g_strsplit (certificate, ".", 0);
- header = (gchar *) base64_parse (pieces[0], &header_len);
- payload = (gchar *) base64_parse (pieces[1], &payload_len);
+ header = (gchar *) ephy_sync_crypto_base64_urlsafe_decode (pieces[0], &len, TRUE);
+ payload = (gchar *) ephy_sync_crypto_base64_urlsafe_decode (pieces[1], &len, TRUE);
parser = json_parser_new ();
json_parser_load_from_data (parser, header, -1, NULL);
json = json_node_get_object (json_parser_get_root (parser));
- algorithm = json_object_get_string_member (json, "alg");
+ alg = json_object_get_string_member (json, "alg");
- if (g_str_equal (algorithm, "RS256") == FALSE) {
- g_warning ("Expected algorithm RS256, found %s. Giving up.", algorithm);
+ if (g_strcmp0 (alg, "RS256") != 0) {
+ g_warning ("Expected algorithm RS256, found %s. Giving up.", alg);
goto out;
}
@@ -400,16 +322,14 @@ ephy_sync_service_certificate_is_valid (EphySyncService *self,
json = json_node_get_object (json_parser_get_root (parser));
principal = json_object_get_object_member (json, "principal");
email = json_object_get_string_member (principal, "email");
- uid_email = g_strdup_printf ("%s@%s",
- self->uid,
- soup_uri_get_host (uri));
+ uid_email = g_strdup_printf ("%s@%s", self->uid, soup_uri_get_host (uri));
- if (g_str_equal (uid_email, email) == FALSE) {
+ if (g_strcmp0 (uid_email, email) != 0) {
g_warning ("Expected email %s, found %s. Giving up.", uid_email, email);
goto out;
}
- self->last_auth_at = json_object_get_int_member (json, "fxa-lastAuthAt");
+ self->auth_at = json_object_get_int_member (json, "fxa-lastAuthAt");
retval = TRUE;
out:
@@ -425,7 +345,7 @@ out:
static void
obtain_storage_credentials_response_cb (SoupSession *session,
- SoupMessage *message,
+ SoupMessage *msg,
gpointer user_data)
{
StorageServerRequestAsyncData *data;
@@ -439,7 +359,7 @@ obtain_storage_credentials_response_cb (SoupSession *session,
service = EPHY_SYNC_SERVICE (data->service);
parser = json_parser_new ();
- json_parser_load_from_data (parser, message->response_body->data, -1, NULL);
+ json_parser_load_from_data (parser, msg->response_body->data, -1, NULL);
json = json_node_get_object (json_parser_get_root (parser));
/* FIXME: Since a new Firefox Account password means a new kB, and a new kB
@@ -448,12 +368,13 @@ obtain_storage_credentials_response_cb (SoupSession *session,
* password since the last time he signed in. If this happens, the user needs
* to be asked to sign in again with the new password.
*/
- if (message->status_code == 200) {
+ if (msg->status_code == 200) {
service->storage_endpoint = g_strdup (json_object_get_string_member (json, "api_endpoint"));
service->storage_credentials_id = g_strdup (json_object_get_string_member (json, "id"));
service->storage_credentials_key = g_strdup (json_object_get_string_member (json, "key"));
- service->storage_credentials_expiry_time = json_object_get_int_member (json, "duration") +
CURRENT_TIME_IN_SECONDS;
- } else if (message->status_code == 401) {
+ service->storage_credentials_expiry_time = json_object_get_int_member (json, "duration") +
+ ephy_sync_utils_current_time_seconds ();
+ } else if (msg->status_code == 401) {
array = json_object_get_array_member (json, "errors");
errors = json_node_get_object (json_array_get_element (array, 0));
g_warning ("Failed to talk to the Token Server: %s: %s",
@@ -464,7 +385,7 @@ obtain_storage_credentials_response_cb (SoupSession *session,
} else {
g_warning ("Failed to talk to the Token Server, status code %u. "
"See https://docs.services.mozilla.com/token/apis.html#error-responses",
- message->status_code);
+ msg->status_code);
storage_server_request_async_data_free (data);
goto out;
}
@@ -479,22 +400,20 @@ static void
ephy_sync_service_obtain_storage_credentials (EphySyncService *self,
gpointer user_data)
{
- SoupMessage *message;
- guint8 *kB = NULL;
- gchar *hashed_kB = NULL;
- gchar *client_state = NULL;
- gchar *audience = NULL;
- gchar *assertion = NULL;
- gchar *authorization = NULL;
+ SoupMessage *msg;
+ guint8 *kB;
+ gchar *hashed_kB;
+ gchar *client_state;
+ gchar *audience;
+ gchar *assertion;
+ gchar *authorization;
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
g_return_if_fail (self->certificate != NULL);
g_return_if_fail (self->keypair != NULL);
- audience = get_audience_for_url (MOZILLA_TOKEN_SERVER_URL);
- assertion = ephy_sync_crypto_create_assertion (self->certificate,
- audience,
- 5 * 60,
- self->keypair);
+ audience = ephy_sync_utils_make_audience (MOZILLA_TOKEN_SERVER_URL);
+ assertion = ephy_sync_crypto_create_assertion (self->certificate, audience, 300, self->keypair);
g_return_if_fail (assertion != NULL);
kB = ephy_sync_crypto_decode_hex (self->kB);
@@ -502,16 +421,13 @@ ephy_sync_service_obtain_storage_credentials (EphySyncService *self,
client_state = g_strndup (hashed_kB, EPHY_SYNC_TOKEN_LENGTH);
authorization = g_strdup_printf ("BrowserID %s", assertion);
- message = soup_message_new (SOUP_METHOD_GET, MOZILLA_TOKEN_SERVER_URL);
+ msg = soup_message_new (SOUP_METHOD_GET, MOZILLA_TOKEN_SERVER_URL);
/* We need to add the X-Client-State header so that the Token Server will
* recognize accounts that were previously used to sync Firefox data too.
*/
- soup_message_headers_append (message->request_headers,
- "X-Client-State", client_state);
- soup_message_headers_append (message->request_headers,
- "authorization", authorization);
- soup_session_queue_message (self->soup_session, message,
- obtain_storage_credentials_response_cb, user_data);
+ soup_message_headers_append (msg->request_headers, "X-Client-State", client_state);
+ soup_message_headers_append (msg->request_headers, "authorization", authorization);
+ soup_session_queue_message (self->session, msg, obtain_storage_credentials_response_cb, user_data);
g_free (kB);
g_free (hashed_kB);
@@ -523,7 +439,7 @@ ephy_sync_service_obtain_storage_credentials (EphySyncService *self,
static void
obtain_signed_certificate_response_cb (SoupSession *session,
- SoupMessage *message,
+ SoupMessage *msg,
gpointer user_data)
{
StorageServerRequestAsyncData *data;
@@ -536,10 +452,10 @@ obtain_signed_certificate_response_cb (SoupSession *session,
service = EPHY_SYNC_SERVICE (data->service);
parser = json_parser_new ();
- json_parser_load_from_data (parser, message->response_body->data, -1, NULL);
+ json_parser_load_from_data (parser, msg->response_body->data, -1, NULL);
json = json_node_get_object (json_parser_get_root (parser));
- if (message->status_code != 200) {
+ if (msg->status_code != 200) {
g_warning ("FxA server errno: %ld, errmsg: %s",
json_object_get_int_member (json, "errno"),
json_object_get_string_member (json, "message"));
@@ -568,13 +484,16 @@ static void
ephy_sync_service_obtain_signed_certificate (EphySyncService *self,
gpointer user_data)
{
- EphySyncCryptoProcessedST *processed_st;
- gchar *tokenID;
+ guint8 *tokenID;
+ guint8 *reqHMACkey;
+ guint8 *requestKey;
+ gchar *tokenID_hex;
gchar *public_key_json;
gchar *request_body;
- gchar *n_str;
- gchar *e_str;
+ gchar *n;
+ gchar *e;
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
g_return_if_fail (self->sessionToken != NULL);
if (self->keypair != NULL)
@@ -583,36 +502,30 @@ ephy_sync_service_obtain_signed_certificate (EphySyncService *self,
self->keypair = ephy_sync_crypto_generate_rsa_key_pair ();
g_return_if_fail (self->keypair != NULL);
- processed_st = ephy_sync_crypto_process_session_token (self->sessionToken);
- tokenID = ephy_sync_crypto_encode_hex (processed_st->tokenID, 0);
+ ephy_sync_crypto_process_session_token (self->sessionToken, &tokenID, &reqHMACkey, &requestKey);
+ tokenID_hex = ephy_sync_crypto_encode_hex (tokenID, 0);
- n_str = mpz_get_str (NULL, 10, self->keypair->public.n);
- e_str = mpz_get_str (NULL, 10, self->keypair->public.e);
- public_key_json = ephy_sync_utils_build_json_string ("algorithm", "RS",
- "n", n_str,
- "e", e_str,
- NULL);
+ n = mpz_get_str (NULL, 10, self->keypair->public.n);
+ e = mpz_get_str (NULL, 10, self->keypair->public.e);
+ public_key_json = ephy_sync_utils_build_json_string ("algorithm", "RS", "n", n, "e", e, NULL);
/* Duration is the lifetime of the certificate in milliseconds. The FxA server
* limits the duration to 24 hours. For our purposes, a duration of 30 minutes
* will suffice.
*/
request_body = g_strdup_printf ("{\"publicKey\": %s, \"duration\": %d}",
public_key_json, 30 * 60 * 1000);
- ephy_sync_service_fxa_hawk_post_async (self,
- "certificate/sign",
- tokenID,
- processed_st->reqHMACkey,
- EPHY_SYNC_TOKEN_LENGTH,
- request_body,
- obtain_signed_certificate_response_cb,
- user_data);
-
- ephy_sync_crypto_processed_st_free (processed_st);
+ ephy_sync_service_fxa_hawk_post_async (self, "certificate/sign", tokenID_hex,
+ reqHMACkey, EPHY_SYNC_TOKEN_LENGTH, request_body,
+ obtain_signed_certificate_response_cb, user_data);
+
g_free (tokenID);
+ g_free (reqHMACkey);
+ g_free (requestKey);
+ g_free (tokenID_hex);
g_free (public_key_json);
g_free (request_body);
- g_free (n_str);
- g_free (e_str);
+ g_free (n);
+ g_free (e);
}
static void
@@ -657,10 +570,10 @@ ephy_sync_service_dispose (GObject *object)
{
EphySyncService *self = EPHY_SYNC_SERVICE (object);
- g_clear_object (&self->soup_session);
+ g_clear_object (&self->session);
g_clear_pointer (&self->user_email, g_free);
ephy_sync_service_clear_storage_credentials (self);
- ephy_sync_service_delete_all_tokens (self);
+ ephy_sync_service_clear_tokens (self);
G_OBJECT_CLASS (ephy_sync_service_parent_class)->dispose (object);
}
@@ -679,12 +592,13 @@ ephy_sync_service_init (EphySyncService *self)
{
gchar *email;
- self->soup_session = soup_session_new ();
+ self->session = soup_session_new ();
self->storage_queue = g_queue_new ();
+ self->sync_frequency = 15 * 60;
email = g_settings_get_string (EPHY_SETTINGS_MAIN, EPHY_PREFS_SYNC_USER);
- if (g_str_equal (email, "") == FALSE) {
+ if (g_strcmp0 (email, "") != 0) {
if (g_regex_match_simple (EMAIL_REGEX, email, 0, 0) == TRUE) {
ephy_sync_service_set_user_email (self, email);
ephy_sync_secret_load_tokens (self);
@@ -700,36 +614,19 @@ ephy_sync_service_new (void)
return EPHY_SYNC_SERVICE (g_object_new (EPHY_TYPE_SYNC_SERVICE, NULL));
}
-const gchar *
-ephy_sync_service_token_name_from_type (EphySyncServiceTokenType token_type)
-{
- switch (token_type) {
- case TOKEN_UID:
- return "uid";
- case TOKEN_SESSIONTOKEN:
- return "sessionToken";
- case TOKEN_KEYFETCHTOKEN:
- return "keyFetchToken";
- case TOKEN_UNWRAPBKEY:
- return "unwrapBKey";
- case TOKEN_KA:
- return "kA";
- case TOKEN_KB:
- return "kB";
- default:
- g_assert_not_reached ();
- }
-}
-
gboolean
ephy_sync_service_is_signed_in (EphySyncService *self)
{
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), FALSE);
+
return self->user_email != NULL;
}
gchar *
ephy_sync_service_get_user_email (EphySyncService *self)
{
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), NULL);
+
return self->user_email;
}
@@ -737,14 +634,58 @@ void
ephy_sync_service_set_user_email (EphySyncService *self,
const gchar *email)
{
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+
g_free (self->user_email);
self->user_email = g_strdup (email);
}
+double
+ephy_sync_service_get_sync_time (EphySyncService *self)
+{
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), 0);
+
+ if (self->sync_time != 0)
+ return self->sync_time;
+
+ self->sync_time = g_settings_get_double (EPHY_SETTINGS_MAIN, EPHY_PREFS_SYNC_TIME);
+ return self->sync_time;
+}
+
+
+void
+ephy_sync_service_set_sync_time (EphySyncService *self,
+ double time)
+{
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+
+ self->sync_time = time;
+ g_settings_set_double (EPHY_SETTINGS_MAIN, EPHY_PREFS_SYNC_TIME, time);
+}
+
+guint
+ephy_sync_service_get_sync_frequency (EphySyncService *self)
+{
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), G_MAXUINT);
+
+ return self->sync_frequency;
+}
+
+void
+ephy_sync_service_set_sync_frequency (EphySyncService *self,
+ guint sync_frequency)
+{
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+
+ self->sync_frequency = sync_frequency;
+}
+
gchar *
-ephy_sync_service_get_token (EphySyncService *self,
- EphySyncServiceTokenType type)
+ephy_sync_service_get_token (EphySyncService *self,
+ EphySyncTokenType type)
{
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), NULL);
+
switch (type) {
case TOKEN_UID:
return self->uid;
@@ -764,10 +705,13 @@ ephy_sync_service_get_token (EphySyncService *self,
}
void
-ephy_sync_service_set_token (EphySyncService *self,
- gchar *value,
- EphySyncServiceTokenType type)
+ephy_sync_service_set_token (EphySyncService *self,
+ gchar *value,
+ EphySyncTokenType type)
{
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (value != NULL);
+
switch (type) {
case TOKEN_UID:
g_free (self->uid);
@@ -799,30 +743,47 @@ ephy_sync_service_set_token (EphySyncService *self,
}
void
-ephy_sync_service_set_and_store_tokens (EphySyncService *self,
- gchar *first_value,
- EphySyncServiceTokenType first_type,
+ephy_sync_service_set_and_store_tokens (EphySyncService *self,
+ gchar *value,
+ EphySyncTokenType type,
...)
{
- EphySyncServiceTokenType type;
- gchar *value;
+ EphySyncTokenType next_type;
+ gchar *next_value;
va_list args;
- ephy_sync_service_set_token (self, first_value, first_type);
- ephy_sync_secret_store_token (self->user_email, first_value, first_type);
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (value != NULL);
+
+ ephy_sync_service_set_token (self, value, type);
+ ephy_sync_secret_store_token (self->user_email, value, type);
- va_start (args, first_type);
- while ((value = va_arg (args, gchar *)) != NULL) {
- type = va_arg (args, EphySyncServiceTokenType);
- ephy_sync_service_set_token (self, value, type);
- ephy_sync_secret_store_token (self->user_email, value, type);
+ va_start (args, type);
+ while ((next_value = va_arg (args, gchar *)) != NULL) {
+ next_type = va_arg (args, EphySyncTokenType);
+ ephy_sync_service_set_token (self, next_value, next_type);
+ ephy_sync_secret_store_token (self->user_email, next_value, next_type);
}
va_end (args);
}
void
-ephy_sync_service_delete_all_tokens (EphySyncService *self)
+ephy_sync_service_clear_storage_credentials (EphySyncService *self)
+{
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+
+ g_clear_pointer (&self->certificate, g_free);
+ g_clear_pointer (&self->storage_endpoint, g_free);
+ g_clear_pointer (&self->storage_credentials_id, g_free);
+ g_clear_pointer (&self->storage_credentials_key, g_free);
+ self->storage_credentials_expiry_time = 0;
+}
+
+void
+ephy_sync_service_clear_tokens (EphySyncService *self)
{
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+
g_clear_pointer (&self->uid, g_free);
g_clear_pointer (&self->sessionToken, g_free);
g_clear_pointer (&self->keyFetchToken, g_free);
@@ -835,50 +796,46 @@ void
ephy_sync_service_destroy_session (EphySyncService *self,
const gchar *sessionToken)
{
- EphySyncCryptoProcessedST *processed_st;
- EphySyncCryptoHawkOptions *hawk_options;
- EphySyncCryptoHawkHeader *hawk_header;
- SoupMessage *message;
- gchar *tokenID;
+ EphySyncCryptoHawkOptions *hoptions;
+ EphySyncCryptoHawkHeader *hheader;
+ SoupMessage *msg;
+ guint8 *tokenID;
+ guint8 *reqHMACkey;
+ guint8 *requestKey;
+ gchar *tokenID_hex;
gchar *url;
const gchar *content_type = "application/json";
const gchar *endpoint = "session/destroy";
const gchar *request_body = "{}";
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+
+ if (sessionToken == NULL)
+ sessionToken = ephy_sync_service_get_token (self, TOKEN_SESSIONTOKEN);
g_return_if_fail (sessionToken != NULL);
- url = g_strdup_printf ("%s%s%s",
- MOZILLA_FIREFOX_ACCOUNTS_BASE_URL,
- MOZILLA_FIREFOX_ACCOUNTS_VERSION,
- endpoint);
- processed_st = ephy_sync_crypto_process_session_token (sessionToken);
- tokenID = ephy_sync_crypto_encode_hex (processed_st->tokenID, 0);
+ url = g_strdup_printf ("%s%s", MOZILLA_FXA_SERVER_URL, endpoint);
+ ephy_sync_crypto_process_session_token (sessionToken, &tokenID, &reqHMACkey, &requestKey);
+ tokenID_hex = ephy_sync_crypto_encode_hex (tokenID, 0);
- message = soup_message_new (SOUP_METHOD_POST, url);
- soup_message_set_request (message, content_type,
- SOUP_MEMORY_STATIC,
+ msg = soup_message_new (SOUP_METHOD_POST, url);
+ soup_message_set_request (msg, content_type, SOUP_MEMORY_STATIC,
request_body, strlen (request_body));
- hawk_options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL,
- g_strdup (content_type),
- NULL, NULL, NULL,
- g_strdup (request_body),
- NULL);
- hawk_header = ephy_sync_crypto_compute_hawk_header (url, "POST",
- tokenID,
- processed_st->reqHMACkey,
- EPHY_SYNC_TOKEN_LENGTH,
- hawk_options);
- soup_message_headers_append (message->request_headers,
- "authorization", hawk_header->header);
- soup_message_headers_append (message->request_headers,
- "content-type", content_type);
- soup_session_queue_message (self->soup_session, message,
- destroy_session_response_cb, NULL);
-
- ephy_sync_crypto_hawk_options_free (hawk_options);
- ephy_sync_crypto_hawk_header_free (hawk_header);
- ephy_sync_crypto_processed_st_free (processed_st);
+ hoptions = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL, content_type,
+ NULL, NULL, NULL, request_body, NULL);
+ hheader = ephy_sync_crypto_compute_hawk_header (url, "POST", tokenID_hex,
+ reqHMACkey, EPHY_SYNC_TOKEN_LENGTH,
+ hoptions);
+ soup_message_headers_append (msg->request_headers, "authorization", hheader->header);
+ soup_message_headers_append (msg->request_headers, "content-type", content_type);
+ soup_session_queue_message (self->session, msg, destroy_session_response_cb, NULL);
+
+ ephy_sync_crypto_hawk_options_free (hoptions);
+ ephy_sync_crypto_hawk_header_free (hheader);
+ g_free (tokenID_hex);
g_free (tokenID);
+ g_free (reqHMACkey);
+ g_free (requestKey);
g_free (url);
}
@@ -888,23 +845,30 @@ ephy_sync_service_fetch_sync_keys (EphySyncService *self,
const gchar *keyFetchToken,
const gchar *unwrapBKey)
{
- EphySyncCryptoProcessedKFT *processed_kft = NULL;
- EphySyncCryptoSyncKeys *sync_keys = NULL;
JsonNode *node;
JsonObject *json;
guint8 *unwrapKB;
- gchar *tokenID;
+ guint8 *tokenID;
+ guint8 *reqHMACkey;
+ guint8 *respHMACkey;
+ guint8 *respXORkey;
+ guint8 *kA;
+ guint8 *kB;
+ gchar *tokenID_hex;
guint status_code;
gboolean retval = FALSE;
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), FALSE);
+ g_return_val_if_fail (email != NULL, FALSE);
+ g_return_val_if_fail (keyFetchToken != NULL, FALSE);
+ g_return_val_if_fail (unwrapBKey != NULL, FALSE);
+
unwrapKB = ephy_sync_crypto_decode_hex (unwrapBKey);
- processed_kft = ephy_sync_crypto_process_key_fetch_token (keyFetchToken);
- tokenID = ephy_sync_crypto_encode_hex (processed_kft->tokenID, 0);
- status_code = ephy_sync_service_fxa_hawk_get_sync (self,
- "account/keys",
- tokenID,
- processed_kft->reqHMACkey,
- EPHY_SYNC_TOKEN_LENGTH,
+ ephy_sync_crypto_process_key_fetch_token (keyFetchToken,
+ &tokenID, &reqHMACkey, &respHMACkey, &respXORkey);
+ tokenID_hex = ephy_sync_crypto_encode_hex (tokenID, 0);
+ status_code = ephy_sync_service_fxa_hawk_get_sync (self, "account/keys", tokenID_hex,
+ reqHMACkey, EPHY_SYNC_TOKEN_LENGTH,
&node);
json = json_node_get_object (node);
@@ -915,30 +879,30 @@ ephy_sync_service_fetch_sync_keys (EphySyncService *self,
goto out;
}
- sync_keys = ephy_sync_crypto_retrieve_sync_keys (json_object_get_string_member (json, "bundle"),
- processed_kft->respHMACkey,
- processed_kft->respXORkey,
- unwrapKB);
-
- if (sync_keys == NULL)
- goto out;
+ ephy_sync_crypto_compute_sync_keys (json_object_get_string_member (json, "bundle"),
+ respHMACkey, respXORkey, unwrapKB,
+ &kA, &kB);
/* Everything is okay, save the tokens. */
ephy_sync_service_set_user_email (self, email);
ephy_sync_service_set_and_store_tokens (self,
g_strdup (keyFetchToken), TOKEN_KEYFETCHTOKEN,
g_strdup (unwrapBKey), TOKEN_UNWRAPBKEY,
- ephy_sync_crypto_encode_hex (sync_keys->kA, 0), TOKEN_KA,
- ephy_sync_crypto_encode_hex (sync_keys->kB, 0), TOKEN_KB,
+ ephy_sync_crypto_encode_hex (kA, 0), TOKEN_KA,
+ ephy_sync_crypto_encode_hex (kB, 0), TOKEN_KB,
NULL);
+ g_free (kA);
+ g_free (kB);
retval = TRUE;
out:
- ephy_sync_crypto_processed_kft_free (processed_kft);
- ephy_sync_crypto_sync_keys_free (sync_keys);
json_node_free (node);
- g_free (tokenID);
g_free (unwrapKB);
+ g_free (tokenID);
+ g_free (reqHMACkey);
+ g_free (respHMACkey);
+ g_free (respXORkey);
+ g_free (tokenID_hex);
return retval;
}
@@ -955,16 +919,19 @@ ephy_sync_service_send_storage_message (EphySyncService *self,
{
StorageServerRequestAsyncData *data;
- data = storage_server_request_async_data_new (self, endpoint,
- method, request_body,
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (endpoint != NULL);
+ g_return_if_fail (method != NULL);
+
+ data = storage_server_request_async_data_new (self, endpoint, method, request_body,
modified_since, unmodified_since,
callback, user_data);
/* If there is currently another message being transmitted, then the new
* message has to wait in the queue, otherwise, it is free to go.
*/
- if (self->is_locked == FALSE) {
- self->is_locked = TRUE;
+ if (self->locked == FALSE) {
+ self->locked = TRUE;
ephy_sync_service_issue_storage_request (self, data);
} else {
g_queue_push_tail (self->storage_queue, data);
@@ -976,7 +943,7 @@ ephy_sync_service_release_next_storage_message (EphySyncService *self)
{
g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
/* We should never reach this with the service not being locked. */
- g_assert (self->is_locked == TRUE);
+ g_assert (self->locked == TRUE);
/* If there are other messages waiting in the queue, we release the next one
* and keep the service locked, else, we mark the service as not locked.
@@ -984,5 +951,445 @@ ephy_sync_service_release_next_storage_message (EphySyncService *self)
if (g_queue_is_empty (self->storage_queue) == FALSE)
ephy_sync_service_issue_storage_request (self, g_queue_pop_head (self->storage_queue));
else
- self->is_locked = FALSE;
+ self->locked = FALSE;
+}
+
+static void
+upload_bookmark_response_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ EphySyncService *service;
+ EphyBookmarksManager *manager;
+ EphyBookmark *bookmark;
+ double last_modified;
+
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+ bookmark = EPHY_BOOKMARK (user_data);
+
+ if (msg->status_code == 200) {
+ last_modified = g_ascii_strtod (msg->response_body->data, NULL);
+ ephy_bookmark_set_modified (bookmark, last_modified);
+ ephy_bookmark_set_uploaded (bookmark, TRUE);
+ ephy_bookmarks_manager_save_to_file_async (manager, NULL, NULL, NULL);
+
+ LOG ("Successfully uploaded to server");
+ } else if (msg->status_code == 412) {
+ ephy_sync_service_download_bookmark (service, bookmark);
+ } else {
+ LOG ("Failed to upload to server. Status code: %u, response: %s",
+ msg->status_code, msg->response_body->data);
+ }
+
+ ephy_sync_service_release_next_storage_message (service);
+}
+
+void
+ephy_sync_service_upload_bookmark (EphySyncService *self,
+ EphyBookmark *bookmark,
+ gboolean force)
+{
+ gchar *endpoint;
+ gchar *bso;
+ double modified;
+
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (ephy_sync_service_is_signed_in (self));
+ g_return_if_fail (EPHY_IS_BOOKMARK (bookmark));
+
+ endpoint = g_strdup_printf ("storage/%s/%s",
+ EPHY_BOOKMARKS_COLLECTION,
+ ephy_bookmark_get_id (bookmark));
+ bso = ephy_bookmark_to_bso (bookmark);
+ modified = ephy_bookmark_get_modified (bookmark);
+ ephy_sync_service_send_storage_message (self, endpoint,
+ SOUP_METHOD_PUT, bso, -1,
+ force ? -1 : modified,
+ upload_bookmark_response_cb,
+ bookmark);
+
+ g_free (endpoint);
+ g_free (bso);
+}
+
+static void
+download_bookmark_response_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ EphySyncService *service;
+ EphyBookmarksManager *manager;
+ EphyBookmark *bookmark;
+ GSequenceIter *iter;
+ JsonParser *parser;
+ JsonObject *bso;
+ const gchar *id;
+
+ if (msg->status_code != 200) {
+ LOG ("Failed to download from server. Status code: %u, response: %s",
+ msg->status_code, msg->response_body->data);
+ goto out;
+ }
+
+ parser = json_parser_new ();
+ json_parser_load_from_data (parser, msg->response_body->data, -1, NULL);
+ bso = json_node_get_object (json_parser_get_root (parser));
+ bookmark = ephy_bookmark_from_bso (bso);
+ id = ephy_bookmark_get_id (bookmark);
+
+ /* Overwrite any local bookmark. */
+ manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+ ephy_bookmarks_manager_remove_bookmark (manager,
+ ephy_bookmarks_manager_get_bookmark_by_id (manager, id));
+ ephy_bookmarks_manager_add_bookmark (manager, bookmark);
+
+ /* We have to manually add the tags to the bookmarks manager. */
+ for (iter = g_sequence_get_begin_iter (ephy_bookmark_get_tags (bookmark));
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter))
+ ephy_bookmarks_manager_add_tag (manager, g_sequence_get (iter));
+
+ g_object_unref (parser);
+
+out:
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ ephy_sync_service_release_next_storage_message (service);
+}
+
+void
+ephy_sync_service_download_bookmark (EphySyncService *self,
+ EphyBookmark *bookmark)
+{
+ gchar *endpoint;
+
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (ephy_sync_service_is_signed_in (self));
+ g_return_if_fail (EPHY_IS_BOOKMARK (bookmark));
+
+ endpoint = g_strdup_printf ("storage/%s/%s",
+ EPHY_BOOKMARKS_COLLECTION,
+ ephy_bookmark_get_id (bookmark));
+ ephy_sync_service_send_storage_message (self, endpoint,
+ SOUP_METHOD_GET, NULL, -1, -1,
+ download_bookmark_response_cb, NULL);
+
+ g_free (endpoint);
+}
+
+static void
+delete_bookmark_conditional_response_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ EphySyncService *service;
+ EphyBookmark *bookmark;
+ EphyBookmarksManager *manager;
+
+ bookmark = EPHY_BOOKMARK (user_data);
+ manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+
+ if (msg->status_code == 404) {
+ ephy_bookmarks_manager_remove_bookmark (manager, bookmark);
+ } else if (msg->status_code == 200) {
+ LOG ("The bookmark still exists on the server, don't delete it");
+ } else {
+ LOG ("Failed to delete conditionally. Status code: %u, response: %s",
+ msg->status_code, msg->response_body->data);
+ }
+
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ ephy_sync_service_release_next_storage_message (service);
+}
+
+static void
+delete_bookmark_response_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ EphySyncService *service;
+
+ if (msg->status_code == 200)
+ LOG ("Successfully deleted the bookmark from the server");
+ else
+ LOG ("Failed to delete. Status code: %u, response: %s",
+ msg->status_code, msg->response_body->data);
+
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ ephy_sync_service_release_next_storage_message (service);
+}
+
+void
+ephy_sync_service_delete_bookmark (EphySyncService *self,
+ EphyBookmark *bookmark,
+ gboolean conditional)
+{
+ gchar *endpoint;
+
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (ephy_sync_service_is_signed_in (self));
+ g_return_if_fail (EPHY_IS_BOOKMARK (bookmark));
+
+ endpoint = g_strdup_printf ("storage/%s/%s",
+ EPHY_BOOKMARKS_COLLECTION,
+ ephy_bookmark_get_id (bookmark));
+
+ /* If the bookmark does not exist on the server, delete it from the local
+ * instance too. */
+ if (conditional == TRUE) {
+ ephy_sync_service_send_storage_message (self, endpoint,
+ SOUP_METHOD_GET, NULL, -1, -1,
+ delete_bookmark_conditional_response_cb,
+ bookmark);
+ } else {
+ ephy_sync_service_send_storage_message (self, endpoint,
+ SOUP_METHOD_DELETE, NULL, -1, -1,
+ delete_bookmark_response_cb, NULL);
+ }
+
+ g_free (endpoint);
+}
+
+static void
+sync_bookmarks_first_time_response_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ EphySyncService *service;
+ EphyBookmarksManager *manager;
+ GSequence *bookmarks;
+ GSequenceIter *iter;
+ GHashTable *marked;
+ JsonParser *parser;
+ JsonArray *array;
+ const gchar *timestamp;
+ double server_time;
+
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+ bookmarks = ephy_bookmarks_manager_get_bookmarks (manager);
+ marked = g_hash_table_new (g_direct_hash, g_direct_equal);
+ parser = json_parser_new ();
+ json_parser_load_from_data (parser, msg->response_body->data, -1, NULL);
+
+ if (msg->status_code != 200) {
+ LOG ("Failed to do a first time sync. Status code: %u, response: %s",
+ msg->status_code, msg->response_body->data);
+ goto out;
+ }
+
+ array = json_node_get_array (json_parser_get_root (parser));
+ for (gsize i = 0; i < json_array_get_length (array); i++) {
+ JsonObject *bso = json_array_get_object_element (array, i);
+ EphyBookmark *remote = ephy_bookmark_from_bso (bso);
+ EphyBookmark *local;
+
+ if (remote == NULL)
+ continue;
+
+ local = ephy_bookmarks_manager_get_bookmark_by_id (manager, ephy_bookmark_get_id (remote));
+
+ if (local == NULL) {
+ local = ephy_bookmarks_manager_get_bookmark_by_url (manager, ephy_bookmark_get_url (remote));
+
+ /* If there is no local equivalent of the remote bookmark, then add it to
+ * the local instance together with its tags. */
+ if (local == NULL) {
+ ephy_bookmarks_manager_add_bookmark (manager, remote);
+
+ /* We have to manually add the tags to the bookmarks manager. */
+ for (iter = g_sequence_get_begin_iter (ephy_bookmark_get_tags (remote));
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter))
+ ephy_bookmarks_manager_add_tag (manager, g_sequence_get (iter));
+
+ g_hash_table_add (marked, remote);
+ }
+ /* If there is a local bookmark with the same url as the remote one, then
+ * merge tags into the local one, keep the remote id and upload it to the
+ * server. */
+ else {
+ for (iter = g_sequence_get_begin_iter (ephy_bookmark_get_tags (remote));
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter)) {
+ ephy_bookmark_add_tag (local, g_sequence_get (iter));
+ ephy_bookmarks_manager_add_tag (manager, g_sequence_get (iter));
+ }
+
+ ephy_bookmark_set_id (local, ephy_bookmark_get_id (remote));
+ ephy_sync_service_upload_bookmark (service, local, TRUE);
+ g_object_unref (remote);
+ g_hash_table_add (marked, local);
+ }
+ }
+ /* Having a local bookmark with the same id as the remote one means that the
+ * bookmark has been synced before in the past. Keep the one with the most
+ * recent modified timestamp. */
+ else {
+ if (ephy_bookmark_get_modified (remote) > ephy_bookmark_get_modified (local)) {
+ ephy_bookmarks_manager_remove_bookmark (manager, local);
+ ephy_bookmarks_manager_add_bookmark (manager, remote);
+
+ /* We have to manually add the tags to the bookmarks manager. */
+ for (iter = g_sequence_get_begin_iter (ephy_bookmark_get_tags (remote));
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter))
+ ephy_bookmarks_manager_add_tag (manager, g_sequence_get (iter));
+
+ g_hash_table_add (marked, remote);
+ } else {
+ if (ephy_bookmark_get_modified (local) > ephy_bookmark_get_modified (remote))
+ ephy_sync_service_upload_bookmark (service, local, TRUE);
+
+ g_hash_table_add (marked, local);
+ g_object_unref (remote);
+ }
+ }
+ }
+
+ /* Upload the remaining local bookmarks to the server. */
+ for (iter = g_sequence_get_begin_iter (bookmarks);
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter)) {
+ EphyBookmark *bookmark = g_sequence_get (iter);
+
+ if (g_hash_table_contains (marked, bookmark) == FALSE)
+ ephy_sync_service_upload_bookmark (service, bookmark, TRUE);
+ }
+
+ /* Save changes to file. */
+ ephy_bookmarks_manager_save_to_file_async (manager, NULL, NULL, NULL);
+
+ /* Set the sync time. */
+ timestamp = soup_message_headers_get_one (msg->response_headers, "X-Weave-Timestamp");
+ server_time = g_ascii_strtod (timestamp, NULL);
+ ephy_sync_service_set_sync_time (service, server_time);
+
+out:
+ g_object_unref (parser);
+ g_hash_table_unref (marked);
+
+ ephy_sync_service_release_next_storage_message (service);
+}
+
+static void
+sync_bookmarks_response_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ EphySyncService *service;
+ EphyBookmarksManager *manager;
+ GSequence *bookmarks;
+ GSequenceIter *iter;
+ JsonParser *parser;
+ JsonArray *array;
+ const gchar *timestamp;
+ double server_time;
+
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+ bookmarks = ephy_bookmarks_manager_get_bookmarks (manager);
+ parser = json_parser_new ();
+ json_parser_load_from_data (parser, msg->response_body->data, -1, NULL);
+
+ /* Code 304 indicates that the resource has not been modifiedf. Therefore,
+ * only upload the local bookmarks that were not uploaded. */
+ if (msg->status_code == 304)
+ goto handle_local_bookmarks;
+
+ if (msg->status_code != 200) {
+ LOG ("Failed to sync bookmarks. Status code: %u, response: %s",
+ msg->status_code, msg->response_body->data);
+ goto out;
+ }
+
+ array = json_node_get_array (json_parser_get_root (parser));
+ for (gsize i = 0; i < json_array_get_length (array); i++) {
+ JsonObject *bso = json_array_get_object_element (array, i);
+ EphyBookmark *remote = ephy_bookmark_from_bso (bso);
+ EphyBookmark *local;
+
+ if (remote == NULL)
+ continue;
+
+ local = ephy_bookmarks_manager_get_bookmark_by_id (manager, ephy_bookmark_get_id (remote));
+
+ if (local == NULL) {
+ ephy_bookmarks_manager_add_bookmark (manager, remote);
+
+ /* We have to manually add the tags to the bookmarks manager. */
+ for (iter = g_sequence_get_begin_iter (ephy_bookmark_get_tags (remote));
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter))
+ ephy_bookmarks_manager_add_tag (manager, g_sequence_get (iter));
+ } else {
+ if (ephy_bookmark_get_modified (remote) > ephy_bookmark_get_modified (local)) {
+ ephy_bookmarks_manager_remove_bookmark (manager, local);
+ ephy_bookmarks_manager_add_bookmark (manager, remote);
+
+ /* We have to manually add the tags to the bookmarks manager. */
+ for (iter = g_sequence_get_begin_iter (ephy_bookmark_get_tags (remote));
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter))
+ ephy_bookmarks_manager_add_tag (manager, g_sequence_get (iter));
+ } else {
+ if (ephy_bookmark_get_modified (local) > ephy_bookmark_get_modified (remote))
+ ephy_sync_service_upload_bookmark (service, local, TRUE);
+
+ g_object_unref (remote);
+ }
+ }
+ }
+
+handle_local_bookmarks:
+ for (iter = g_sequence_get_begin_iter (bookmarks);
+ !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter)) {
+ EphyBookmark *bookmark = EPHY_BOOKMARK (g_sequence_get (iter));
+
+ if (ephy_bookmark_is_uploaded (bookmark) == TRUE)
+ ephy_sync_service_delete_bookmark (service, bookmark, TRUE);
+ else
+ ephy_sync_service_upload_bookmark (service, bookmark, FALSE);
+ }
+
+ /* Save changes to file. */
+ ephy_bookmarks_manager_save_to_file_async (manager, NULL, NULL, NULL);
+
+ /* Set the sync time. */
+ timestamp = soup_message_headers_get_one (msg->response_headers, "X-Weave-Timestamp");
+ server_time = g_ascii_strtod (timestamp, NULL);
+ ephy_sync_service_set_sync_time (service, server_time);
+
+out:
+ g_object_unref (parser);
+
+ ephy_sync_service_release_next_storage_message (service);
+}
+
+void
+ephy_sync_service_sync_bookmarks (EphySyncService *self,
+ gboolean first)
+{
+ gchar *endpoint;
+
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (ephy_sync_service_is_signed_in (self));
+
+ endpoint = g_strdup_printf ("storage/%s?full=true", EPHY_BOOKMARKS_COLLECTION);
+
+ if (first == TRUE) {
+ ephy_sync_service_send_storage_message (self, endpoint,
+ SOUP_METHOD_GET, NULL, -1, -1,
+ sync_bookmarks_first_time_response_cb, NULL);
+ } else {
+ ephy_sync_service_send_storage_message (self, endpoint,
+ SOUP_METHOD_GET, NULL,
+ ephy_sync_service_get_sync_time (self), -1,
+ sync_bookmarks_response_cb, NULL);
+ }
+
+ g_free (endpoint);
+}
+
+gboolean
+ephy_sync_service_do_periodical_sync (EphySyncService *self)
+{
+ g_return_val_if_fail (EPHY_IS_SYNC_SERVICE (self), G_SOURCE_REMOVE);
+
+ ephy_sync_service_sync_bookmarks (self, FALSE);
+
+ return G_SOURCE_CONTINUE;
}
diff --git a/src/ephy-sync-service.h b/src/ephy-sync-service.h
index 8dd043b..2bb0561 100644
--- a/src/ephy-sync-service.h
+++ b/src/ephy-sync-service.h
@@ -19,6 +19,9 @@
#ifndef EPHY_SYNC_SERVICE_H
#define EPHY_SYNC_SERVICE_H
+#include "ephy-bookmark.h"
+#include "ephy-sync-utils.h"
+
#include <glib-object.h>
#include <libsoup/soup.h>
@@ -28,48 +31,34 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (EphySyncService, ephy_sync_service, EPHY, SYNC_SERVICE, GObject)
-typedef enum {
- TOKEN_UID,
- TOKEN_SESSIONTOKEN,
- TOKEN_KEYFETCHTOKEN,
- TOKEN_UNWRAPBKEY,
- TOKEN_KA,
- TOKEN_KB
-} EphySyncServiceTokenType;
-
EphySyncService *ephy_sync_service_new (void);
-
-const gchar *ephy_sync_service_token_name_from_type (EphySyncServiceTokenType token_type);
-
gboolean ephy_sync_service_is_signed_in (EphySyncService *self);
-
gchar *ephy_sync_service_get_user_email (EphySyncService *self);
-
void ephy_sync_service_set_user_email (EphySyncService *self,
const gchar *email);
-
-gchar *ephy_sync_service_get_token (EphySyncService *self,
- EphySyncServiceTokenType token_type);
-
-void ephy_sync_service_set_token (EphySyncService *self,
- gchar *token_value,
- EphySyncServiceTokenType token_type);
-
-void ephy_sync_service_set_and_store_tokens (EphySyncService *self,
- gchar *token_value,
- EphySyncServiceTokenType token_type,
+double ephy_sync_service_get_sync_time (EphySyncService *self);
+void ephy_sync_service_set_sync_time (EphySyncService *self,
+ double time);
+guint ephy_sync_service_get_sync_frequency (EphySyncService *self);
+void ephy_sync_service_set_sync_frequency (EphySyncService *self,
+ guint sync_frequency);
+gchar *ephy_sync_service_get_token (EphySyncService *self,
+ EphySyncTokenType type);
+void ephy_sync_service_set_token (EphySyncService *self,
+ gchar *value,
+ EphySyncTokenType type);
+void ephy_sync_service_set_and_store_tokens (EphySyncService *self,
+ gchar *value,
+ EphySyncTokenType type,
...) G_GNUC_NULL_TERMINATED;
-
-void ephy_sync_service_delete_all_tokens (EphySyncService *self);
-
+void ephy_sync_service_clear_storage_credentials (EphySyncService *self);
+void ephy_sync_service_clear_tokens (EphySyncService *self);
void ephy_sync_service_destroy_session (EphySyncService *self,
const gchar *sessionToken);
-
gboolean ephy_sync_service_fetch_sync_keys (EphySyncService *self,
const gchar *email,
const gchar *keyFetchToken,
const gchar *unwrapBKey);
-
void ephy_sync_service_send_storage_message (EphySyncService *self,
gchar *endpoint,
const gchar *method,
@@ -78,8 +67,18 @@ void ephy_sync_service_send_storage_message (EphySyncService
double unmodified_since,
SoupSessionCallback callback,
gpointer user_data);
-
void ephy_sync_service_release_next_storage_message (EphySyncService *self);
+void ephy_sync_service_upload_bookmark (EphySyncService *self,
+ EphyBookmark *bookmark,
+ gboolean force);
+void ephy_sync_service_download_bookmark (EphySyncService *self,
+ EphyBookmark *bookmark);
+void ephy_sync_service_delete_bookmark (EphySyncService *self,
+ EphyBookmark *bookmark,
+ gboolean conditional);
+void ephy_sync_service_sync_bookmarks (EphySyncService *self,
+ gboolean first);
+gboolean ephy_sync_service_do_periodical_sync (EphySyncService *self);
G_END_DECLS
diff --git a/src/ephy-sync-utils.c b/src/ephy-sync-utils.c
index c37f885..702fba7 100644
--- a/src/ephy-sync-utils.c
+++ b/src/ephy-sync-utils.c
@@ -19,24 +19,27 @@
#include "config.h"
#include "ephy-sync-utils.h"
+#include <libsoup/soup.h>
+#include <string.h>
+
gchar *
-ephy_sync_utils_build_json_string (const gchar *first_key,
- const gchar *first_value,
+ephy_sync_utils_build_json_string (const gchar *key,
+ const gchar *value,
...)
{
va_list args;
gchar *json;
- gchar *key;
- gchar *value;
+ gchar *next_key;
+ gchar *next_value;
gchar *tmp;
- json = g_strconcat ("{\"", first_key, "\": \"", first_value, "\"", NULL);
- va_start (args, first_value);
+ json = g_strconcat ("{\"", key, "\": \"", value, "\"", NULL);
+ va_start (args, value);
- while ((key = va_arg (args, gchar *)) != NULL) {
- value = va_arg (args, gchar *);
+ while ((next_key = va_arg (args, gchar *)) != NULL) {
+ next_value = va_arg (args, gchar *);
tmp = json;
- json = g_strconcat (json, ", \"", key, "\": \"", value, "\"", NULL);
+ json = g_strconcat (json, ", \"", next_key, "\": \"", next_value, "\"", NULL);
g_free (tmp);
}
@@ -54,3 +57,117 @@ ephy_sync_utils_create_bso_json (const gchar *id,
{
return ephy_sync_utils_build_json_string ("id", id, "payload", payload, NULL);
}
+
+gchar *
+ephy_sync_utils_make_audience (const gchar *url)
+{
+ SoupURI *uri;
+ const gchar *scheme;
+ const gchar *host;
+ gchar *audience;
+ gchar *port;
+
+ g_return_val_if_fail (url != NULL, NULL);
+
+ uri = soup_uri_new (url);
+ scheme = soup_uri_get_scheme (uri);
+ host = soup_uri_get_host (uri);
+ port = g_strdup_printf (":%u", soup_uri_get_port (uri));
+
+ /* Even if the url doesn't contain the port, soup_uri_get_port() will return
+ * the default port for the url's scheme so we need to check if the port was
+ * really present in the url.
+ */
+ if (g_strstr_len (url, -1, port) != NULL)
+ audience = g_strdup_printf ("%s://%s%s", scheme, host, port);
+ else
+ audience = g_strdup_printf ("%s://%s", scheme, host);
+
+ g_free (port);
+ soup_uri_free (uri);
+
+ return audience;
+}
+
+const gchar *
+ephy_sync_utils_token_name_from_type (EphySyncTokenType type)
+{
+ switch (type) {
+ case TOKEN_UID:
+ return "uid";
+ case TOKEN_SESSIONTOKEN:
+ return "sessionToken";
+ case TOKEN_KEYFETCHTOKEN:
+ return "keyFetchToken";
+ case TOKEN_UNWRAPBKEY:
+ return "unwrapBKey";
+ case TOKEN_KA:
+ return "kA";
+ case TOKEN_KB:
+ return "kB";
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+gchar *
+ephy_sync_utils_find_and_replace (const gchar *src,
+ const gchar *find,
+ const gchar *repl)
+{
+ const gchar *haystack = src;
+ const gchar *needle = NULL;
+ gsize haystack_len = strlen (src);
+ gsize find_len = strlen (find);
+ gsize repl_len = strlen (repl);
+ gsize new_len = 0;
+ gsize skip_len = 0;
+ gchar *out = g_malloc (haystack_len + 1);
+
+ while ((needle = g_strstr_len (haystack, -1, find)) != NULL) {
+ haystack_len += find_len - repl_len;
+ out = g_realloc (out, haystack_len + 1);
+ skip_len = needle - haystack;
+ memcpy (out + new_len, haystack, skip_len);
+ memcpy (out + new_len + skip_len, repl, repl_len);
+ new_len += skip_len + repl_len;
+ haystack = needle + find_len;
+ }
+ strcpy (out + new_len, haystack);
+
+ return out;
+}
+
+guint8 *
+ephy_sync_utils_concatenate_bytes (guint8 *bytes,
+ gsize bytes_len,
+ ...)
+{
+ va_list args;
+ guint8 *next;
+ guint8 *out;
+ gsize next_len;
+ gsize out_len;
+
+ out_len = bytes_len;
+ out = g_malloc (out_len);
+ memcpy (out, bytes, out_len);
+
+ va_start (args, bytes_len);
+ while ((next = va_arg (args, guint8 *)) != NULL) {
+ next_len = va_arg (args, gsize);
+ out = g_realloc (out, out_len + next_len);
+ memcpy (out + out_len, next, next_len);
+ out_len += next_len;
+ }
+
+ va_end (args);
+
+ return out;
+}
+
+gint64
+ephy_sync_utils_current_time_seconds (void)
+{
+ return g_get_real_time () / 1000000;
+}
diff --git a/src/ephy-sync-utils.h b/src/ephy-sync-utils.h
index 8cf72df..2bfc94a 100644
--- a/src/ephy-sync-utils.h
+++ b/src/ephy-sync-utils.h
@@ -21,14 +21,31 @@
#include <glib-object.h>
-G_BEGIN_DECLS
+typedef enum {
+ TOKEN_UID,
+ TOKEN_SESSIONTOKEN,
+ TOKEN_KEYFETCHTOKEN,
+ TOKEN_UNWRAPBKEY,
+ TOKEN_KA,
+ TOKEN_KB
+} EphySyncTokenType;
-gchar *ephy_sync_utils_build_json_string (const gchar *first_key,
- const gchar *first_value,
- ...) G_GNUC_NULL_TERMINATED;
+G_BEGIN_DECLS
-gchar *ephy_sync_utils_create_bso_json (const gchar *id,
- const gchar *payload);
+gchar *ephy_sync_utils_build_json_string (const gchar *key,
+ const gchar *value,
+ ...) G_GNUC_NULL_TERMINATED;
+gchar *ephy_sync_utils_create_bso_json (const gchar *id,
+ const gchar *payload);
+gchar *ephy_sync_utils_make_audience (const gchar *url);
+const gchar *ephy_sync_utils_token_name_from_type (EphySyncTokenType type);
+gchar *ephy_sync_utils_find_and_replace (const gchar *src,
+ const gchar *find,
+ const gchar *repl);
+guint8 *ephy_sync_utils_concatenate_bytes (guint8 *bytes,
+ gsize bytes_len,
+ ...) G_GNUC_NULL_TERMINATED;
+gint64 ephy_sync_utils_current_time_seconds (void);
G_END_DECLS
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
index ecf5f5e..8a58148 100644
--- a/src/prefs-dialog.c
+++ b/src/prefs-dialog.c
@@ -34,7 +34,6 @@
#include "ephy-session.h"
#include "ephy-settings.h"
#include "ephy-shell.h"
-#include "ephy-sync-bookmarks.h"
#include "ephy-sync-secret.h"
#include "ephy-sync-service.h"
#include "clear-data-dialog.h"
@@ -243,7 +242,7 @@ server_message_received_cb (WebKitUserContentManager *manager,
inject_data_to_server (dialog, "message", "login", NULL);
gtk_widget_set_visible (dialog->sync_sign_in_details, FALSE);
- service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
/* Extract tokens. */
data = json_object_get_object_member (detail, "data");
@@ -295,8 +294,13 @@ server_message_received_cb (WebKitUserContentManager *manager,
g_strdup (sessionToken), TOKEN_SESSIONTOKEN,
NULL);
- /* Create our own bookmarks BSO collection on the Storage Server. */
- ephy_sync_bookmarks_create_storage_collection ();
+ /* Do a first time sync. */
+ ephy_sync_service_sync_bookmarks (service, TRUE);
+
+ /* Set a periodical sync. */
+ g_timeout_add_seconds (ephy_sync_service_get_sync_frequency (service),
+ (GSourceFunc) ephy_sync_service_do_periodical_sync,
+ service);
/* Translators: the %s refers to the email of the currently logged in user. */
gtk_label_set_markup (GTK_LABEL (dialog->sync_sign_out_details),
@@ -350,15 +354,14 @@ on_sync_sign_out_button_clicked (GtkWidget *button,
PrefsDialog *dialog)
{
EphySyncService *service;
- gchar *sessionToken;
- service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
- sessionToken = ephy_sync_service_get_token (service, TOKEN_SESSIONTOKEN);
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
/* Destroy session and delete tokens. */
- ephy_sync_service_destroy_session (service, sessionToken);
- ephy_sync_service_delete_all_tokens (service);
- ephy_sync_secret_forget_all_tokens ();
+ ephy_sync_service_destroy_session (service, NULL);
+ ephy_sync_service_clear_storage_credentials (service);
+ ephy_sync_service_clear_tokens (service);
+ ephy_sync_secret_forget_tokens ();
ephy_sync_service_set_user_email (service, NULL);
g_settings_set_string (EPHY_SETTINGS_MAIN, EPHY_PREFS_SYNC_USER, "");
@@ -1452,7 +1455,7 @@ setup_sync_page (PrefsDialog *dialog)
{
EphySyncService *service;
- service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+ service = ephy_shell_get_sync_service (ephy_shell_get_default ());
if (ephy_sync_service_is_signed_in (service) == FALSE) {
setup_fxa_sign_in_view (dialog);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]