[epiphany/wip/sync-rebase: 50/86] ephy-sync: Prepare the ground for sync



commit be577882553329967a0fec414bfd42c8a0793482
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date:   Fri Jul 29 16:51:34 2016 +0300

    ephy-sync: Prepare the ground for sync
    
    Add sync-bookmarks and sync-utils modules.
    
    Add function to convert bookmark to BSO.

 src/Makefile.am               |    4 +
 src/bookmarks/ephy-bookmark.c |  124 ++++++++++++++++++++--
 src/bookmarks/ephy-bookmark.h |    8 ++
 src/ephy-sync-bookmarks.c     |  124 ++++++++++++++++++++++
 src/ephy-sync-bookmarks.h     |   36 +++++++
 src/ephy-sync-crypto.c        |  193 ++++++++++++++++++++++-------------
 src/ephy-sync-crypto.h        |   24 +++-
 src/ephy-sync-service.c       |  229 ++++++++++++----------------------------
 src/ephy-sync-service.h       |   54 ++++++----
 src/ephy-sync-utils.c         |   56 ++++++++++
 src/ephy-sync-utils.h         |   35 ++++++
 src/prefs-dialog.c            |   10 +-
 12 files changed, 620 insertions(+), 277 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index ddc4d80..2341708 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -44,12 +44,16 @@ 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                      \
        ephy-sync-secret.h                      \
        ephy-sync-service.c                     \
        ephy-sync-service.h                     \
+       ephy-sync-utils.c                       \
+       ephy-sync-utils.h                       \
        ephy-window.c                           \
        ephy-window.h                           \
        languages.h                             \
diff --git a/src/bookmarks/ephy-bookmark.c b/src/bookmarks/ephy-bookmark.c
index d872c9d..dbcc956 100644
--- a/src/bookmarks/ephy-bookmark.c
+++ b/src/bookmarks/ephy-bookmark.c
@@ -20,7 +20,12 @@
 
 #include "ephy-bookmark.h"
 
+#include "ephy-shell.h"
+#include "ephy-sync-crypto.h"
+#include "ephy-sync-utils.h"
+
 #include <json-glib/json-glib.h>
+#include <string.h>
 
 struct _EphyBookmark {
   GObject      parent_instance;
@@ -29,6 +34,9 @@ struct _EphyBookmark {
   char        *title;
   GSequence   *tags;
   gint64       time_added;
+
+  char        *id;
+  double       modified;
 };
 
 static JsonSerializableIface *serializable_iface = NULL;
@@ -184,32 +192,70 @@ ephy_bookmark_class_init (EphyBookmarkClass *klass)
 static void
 ephy_bookmark_init (EphyBookmark *self)
 {
+  self->id = ephy_sync_crypto_generate_random_string (12);
 }
 
 static JsonNode *
 ephy_bookmark_json_serializable_serialize_property (JsonSerializable *serializable,
-                                                    const gchar *property_name,
+                                                    const gchar *name,
                                                     const GValue *value,
                                                     GParamSpec *pspec)
 {
-  return serializable_iface->serialize_property (serializable,
-                                                 property_name,
-                                                 value,
-                                                 pspec);
+  JsonNode *node = NULL;
+
+  if (g_strcmp0 (name, "tags") == 0) {
+    GSequence *tags;
+    GSequenceIter *iter;
+    JsonArray *array;
+
+    node = json_node_new (JSON_NODE_ARRAY);
+    array = json_array_new ();
+    tags = g_value_get_pointer (value);
+
+    for (iter = g_sequence_get_begin_iter (tags);
+         !g_sequence_iter_is_end (iter);
+         iter = g_sequence_iter_next (iter)) {
+      json_array_add_string_element (array, g_sequence_get (iter));
+    }
+
+    json_node_set_array (node, array);
+  } else {
+    node = serializable_iface->serialize_property (serializable, name,
+                                                   value, pspec);
+  }
+
+  return node;
 }
 
 static gboolean
 ephy_bookmark_json_serializable_deserialize_property (JsonSerializable *serializable,
-                                                      const gchar *property_name,
+                                                      const gchar *name,
                                                       GValue *value,
                                                       GParamSpec *pspec,
-                                                      JsonNode *property_node)
+                                                      JsonNode *node)
 {
-  return serializable_iface->deserialize_property (serializable,
-                                                   property_name,
-                                                   value,
-                                                   pspec,
-                                                   property_node);
+  if (g_strcmp0 (name, "tags") == 0) {
+    GSequence *tags;
+    JsonArray *array;
+    const char *tag;
+
+    g_assert (JSON_NODE_HOLDS_ARRAY (node));
+    array = json_node_get_array (node);
+    tags = g_sequence_new (g_free);
+
+    for (gsize i = 0; i < json_array_get_length (array); i++) {
+      tag = json_node_get_string (json_array_get_element (array, i));
+      g_sequence_insert_sorted (tags, g_strdup (tag),
+                                (GCompareDataFunc)ephy_bookmark_tags_compare, NULL);
+    }
+
+    g_value_set_pointer (value, tags);
+  } else {
+    serializable_iface->deserialize_property (serializable, name,
+                                              value, pspec, node);
+  }
+
+  return TRUE;
 }
 
 static void
@@ -288,6 +334,31 @@ ephy_bookmark_get_title (EphyBookmark *bookmark)
   return bookmark->title;
 }
 
+const char *
+ephy_bookmark_get_id (EphyBookmark *self)
+{
+  g_return_val_if_fail (EPHY_IS_BOOKMARK (self), NULL);
+
+  return self->id;
+}
+
+void
+ephy_bookmark_set_modified (EphyBookmark *self,
+                            double        modified)
+{
+  g_return_if_fail (EPHY_IS_BOOKMARK (self));
+
+  self->modified = modified;
+}
+
+double
+ephy_bookmark_get_modified (EphyBookmark *self)
+{
+  g_return_val_if_fail (EPHY_IS_BOOKMARK (self), -1);
+
+  return self->modified;
+}
+
 void
 ephy_bookmark_add_tag (EphyBookmark *self,
                        const char   *tag)
@@ -391,3 +462,32 @@ ephy_bookmark_tags_compare (const char *tag1, const char *tag2)
 
   return result;
 }
+
+char *
+ephy_bookmark_to_bso (EphyBookmark *self)
+{
+  EphySyncService *service;
+  guint8 *encrypted;
+  guint8 *sync_key;
+  char *serialized;
+  char *payload;
+  char *bso;
+  gsize length;
+
+  g_return_val_if_fail (EPHY_IS_BOOKMARK (self), NULL);
+
+  service = ephy_shell_get_global_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,
+                                        (guint8 *)serialized, strlen (serialized), &length);
+  payload = ephy_sync_crypto_base64_urlsafe_encode (encrypted, length, FALSE);
+  bso = ephy_sync_utils_create_bso_json (self->id, payload);
+
+  g_free (sync_key);
+  g_free (serialized);
+  g_free (encrypted);
+  g_free (payload);
+
+  return bso;
+}
diff --git a/src/bookmarks/ephy-bookmark.h b/src/bookmarks/ephy-bookmark.h
index 8a44c03..76508bd 100644
--- a/src/bookmarks/ephy-bookmark.h
+++ b/src/bookmarks/ephy-bookmark.h
@@ -42,6 +42,12 @@ void                 ephy_bookmark_set_title           (EphyBookmark *self,
                                                         const char   *title);
 const char          *ephy_bookmark_get_title           (EphyBookmark *self);
 
+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_add_tag             (EphyBookmark *self,
                                                         const char   *tag);
 void                 ephy_bookmark_remove_tag          (EphyBookmark *self,
@@ -55,4 +61,6 @@ int                  ephy_bookmark_bookmarks_sort_func (EphyBookmark *bookmark1,
 int                  ephy_bookmark_tags_compare        (const char *tag1,
                                                         const char *tag2);
 
+char                *ephy_bookmark_to_bso              (EphyBookmark *self);
+
 G_END_DECLS
diff --git a/src/ephy-sync-bookmarks.c b/src/ephy-sync-bookmarks.c
new file mode 100644
index 0000000..9344b72
--- /dev/null
+++ b/src/ephy-sync-bookmarks.c
@@ -0,0 +1,124 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2016 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "ephy-sync-bookmarks.h"
+
+#include "ephy-debug.h"
+#include "ephy-shell.h"
+#include "ephy-sync-utils.h"
+
+#define EPHY_BOOKMARKS_DUMMY_BSO   "000000000000"
+#define EPHY_BOOKMARKS_COLLECTION  "ephy-bookmarks"
+
+static void
+create_bso_collection_response_cb (SoupSession *session,
+                                   SoupMessage *message,
+                                   gpointer     user_data)
+{
+  EphySyncService *service;
+  gchar *endpoint;
+
+  service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+
+  /* Status code 412 means the BSO already exists. Since we will delete it
+   * anyway, we don't treat this as an error.
+   */
+  if (message->status_code != 200 && message->status_code != 412) {
+    g_warning ("Failed to add dummy BSO to collection, status code: %u, response: %s",
+               message->status_code, message->response_body->data);
+    return;
+  }
+
+  /* The EPHY_BOOKMARKS_COLLECTION collection is now created. We can safely
+   * delete the dummy BSO that we've uploaded. No need to check for response.
+   */
+  endpoint = g_strdup_printf ("storage/%s/%s", EPHY_BOOKMARKS_COLLECTION, EPHY_BOOKMARKS_DUMMY_BSO);
+  ephy_sync_service_send_storage_message (service, endpoint, SOUP_METHOD_DELETE,
+                                          NULL, -1, -1, NULL, NULL);
+  g_free (endpoint);
+}
+
+void
+ephy_sync_bookmarks_create_storage_collection (void)
+{
+  EphySyncService *service;
+  gchar *endpoint;
+  gchar *bso;
+
+  service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+  endpoint = g_strdup_printf ("storage/%s/%s", EPHY_BOOKMARKS_COLLECTION, EPHY_BOOKMARKS_DUMMY_BSO);
+  bso = ephy_sync_utils_create_bso_json (EPHY_BOOKMARKS_DUMMY_BSO, EPHY_BOOKMARKS_DUMMY_BSO);
+
+  /* Send a dummy BSO to the Storage Server so it will create the
+   * EPHY_BOOKMARKS_COLLECTION collection if it doesn't exist already.
+   * In the response callback we will delete the dummy BSO.
+   */
+  ephy_sync_service_send_storage_message (service, endpoint, SOUP_METHOD_PUT,
+                                          bso, -1, 0,
+                                          create_bso_collection_response_cb, NULL);
+
+  g_free (endpoint);
+  g_free (bso);
+}
+
+static void
+server_response_default_cb (SoupSession *session,
+                            SoupMessage *message,
+                            gpointer     user_data)
+{
+  LOG ("Server response:");
+  LOG ("status_code: %u", message->status_code);
+  LOG ("response_body: %s", message->response_body->data);
+  LOG ("Retry-After: %s", soup_message_headers_get_one (message->response_headers, "Retry-After"));
+  LOG ("X-Weave-Backoff: %s", soup_message_headers_get_one (message->response_headers, "X-Weave-Backoff"));
+  LOG ("X-Last-Modified: %s", soup_message_headers_get_one (message->response_headers, "X-Last-Modified"));
+  LOG ("X-Weave-Timestamp: %s", soup_message_headers_get_one (message->response_headers, 
"X-Weave-Timestamp"));
+  LOG ("X-Weave-Records: %s", soup_message_headers_get_one (message->response_headers, "X-Weave-Records"));
+  LOG ("X-Weave-Next-Offset: %s", soup_message_headers_get_one (message->response_headers, 
"X-Weave-Next-Offset"));
+  LOG ("X-Weave-Quota-Remaining: %s", soup_message_headers_get_one (message->response_headers, 
"X-Weave-Quota-Remaining"));
+  LOG ("X-Weave-Alert: %s", soup_message_headers_get_one (message->response_headers, "X-Weave-Alert"));
+}
+
+void
+ephy_sync_bookmarks_check_storage_collection (void)
+{
+  EphySyncService *service;
+  gchar *endpoint;
+
+  service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+  endpoint = g_strdup_printf ("storage/%s", EPHY_BOOKMARKS_COLLECTION);
+  ephy_sync_service_send_storage_message (service, endpoint,
+                                          SOUP_METHOD_GET, NULL, -1, -1,
+                                          server_response_default_cb, NULL);
+  g_free (endpoint);
+}
+
+void
+ephy_sync_bookmarks_delete_storage_collection (void)
+{
+  EphySyncService *service;
+  gchar *endpoint;
+
+  service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+  endpoint = g_strdup_printf ("storage/%s", EPHY_BOOKMARKS_COLLECTION);
+  ephy_sync_service_send_storage_message (service, endpoint,
+                                          SOUP_METHOD_DELETE, NULL, -1, -1,
+                                          server_response_default_cb, NULL);
+  g_free (endpoint);
+}
diff --git a/src/ephy-sync-bookmarks.h b/src/ephy-sync-bookmarks.h
new file mode 100644
index 0000000..47f0ccc
--- /dev/null
+++ b/src/ephy-sync-bookmarks.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2016 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EPHY_SYNC_BOOKMARKS_H
+#define EPHY_SYNC_BOOKMARKS_H
+
+#include "ephy-sync-service.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void ephy_sync_bookmarks_create_storage_collection (void);
+
+void ephy_sync_bookmarks_check_storage_collection  (void);
+
+void ephy_sync_bookmarks_delete_storage_collection (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ephy-sync-crypto.c b/src/ephy-sync-crypto.c
index 1e6f213..a194360 100644
--- a/src/ephy-sync-crypto.c
+++ b/src/ephy-sync-crypto.c
@@ -264,37 +264,6 @@ kw (const gchar *name)
   return g_strconcat ("identity.mozilla.com/picl/v1/", name, NULL);
 }
 
-static gchar *
-base64_urlsafe_strip (guint8 *data,
-                      gsize   data_length)
-{
-  gchar *encoded;
-  gchar *base64;
-  gsize start;
-  gssize end;
-
-  base64 = g_base64_encode (data, data_length);
-
-  start = 0;
-  while (start < strlen (base64) && base64[start] == '=')
-    start++;
-
-  end = strlen (base64) - 1;
-  while (end >= 0 && base64[end] == '=')
-    end--;
-
-  encoded = g_strndup (base64 + start, end - start + 1);
-
-  /* Replace '+' with '-' */
-  g_strcanon (encoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/", '-');
-  /* Replace '/' with '_' */
-  g_strcanon (encoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-", '_');
-
-  g_free (base64);
-
-  return encoded;
-}
-
 static guint8 *
 xor (guint8 *a,
      guint8 *b,
@@ -328,26 +297,6 @@ are_equal (guint8 *a,
 }
 
 static gchar *
-generate_random_string (gsize length)
-{
-  guchar *bytes;
-  gchar *base64_string;
-  gchar *string;
-
-  bytes = g_malloc (length);
-  for (gsize i = 0; i < length; i++)
-    bytes[i] = g_random_int ();
-
-  base64_string = g_base64_encode (bytes, length);
-  string = g_strndup (base64_string, length);
-
-  g_free (bytes);
-  g_free (base64_string);
-
-  return string;
-}
-
-static gchar *
 find_and_replace_string (const gchar *src,
                          const gchar *find,
                          const gchar *repl)
@@ -636,6 +585,22 @@ random_func (void   *ctx,
     dst[i] = g_random_int ();
 }
 
+static void
+base64_to_base64_urlsafe (gchar *text)
+{
+  /* Replace '+' with '-' and '/' with '_' */
+  g_strcanon (text, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=/", '-');
+  g_strcanon (text, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=-", '_');
+}
+
+static void
+base64_urlsafe_to_base64 (gchar *text)
+{
+  /* Replace '-' with '+' and '_' with '/' */
+  g_strcanon (text, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=_", '+');
+  g_strcanon (text, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+", '/');
+}
+
 EphySyncCryptoProcessedKFT *
 ephy_sync_crypto_process_key_fetch_token (const gchar *keyFetchToken)
 {
@@ -820,7 +785,7 @@ ephy_sync_crypto_compute_hawk_header (const gchar               *url,
   }
 
   nonce = has_options ? options->nonce : NULL;
-  nonce = nonce ? nonce : generate_random_string (6);
+  nonce = nonce ? nonce : ephy_sync_crypto_generate_random_string (6);
   hash = has_options ? options->hash : NULL;
   payload = has_options ? options->payload : NULL;
 
@@ -934,8 +899,8 @@ ephy_sync_crypto_create_assertion (const gchar              *certificate,
 
   expires_at = g_get_real_time () / 1000 + duration * 1000;
   body = g_strdup_printf ("{\"exp\": %lu, \"aud\": \"%s\"}", expires_at, audience);
-  body_b64 = base64_urlsafe_strip ((guint8 *) body, strlen (body));
-  header_b64 = base64_urlsafe_strip ((guint8 *) header, strlen (header));
+  body_b64 = ephy_sync_crypto_base64_urlsafe_encode ((guint8 *) body, strlen (body), TRUE);
+  header_b64 = ephy_sync_crypto_base64_urlsafe_encode ((guint8 *) header, strlen (header), TRUE);
   to_sign = g_strdup_printf ("%s.%s", header_b64, body_b64);
 
   mpz_init (signature);
@@ -958,7 +923,7 @@ ephy_sync_crypto_create_assertion (const gchar              *certificate,
     goto out;
   }
 
-  sig_b64 = base64_urlsafe_strip (sig, count);
+  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);
 
@@ -976,36 +941,120 @@ out:
   return assertion;
 }
 
+gchar *
+ephy_sync_crypto_generate_random_string (gsize length)
+{
+  guchar *bytes;
+  gchar *base64_string;
+  gchar *string;
+
+  bytes = g_malloc (length);
+  for (gsize i = 0; i < length; i++)
+    bytes[i] = g_random_int ();
+
+  base64_string = g_base64_encode (bytes, length);
+  base64_to_base64_urlsafe (base64_string);
+  string = g_strndup (base64_string, length);
+
+  g_free (bytes);
+  g_free (base64_string);
+
+  return string;
+}
+
+gchar *
+ephy_sync_crypto_base64_urlsafe_encode (guint8   *data,
+                                        gsize     data_length,
+                                        gboolean  strip)
+{
+  gchar *encoded;
+  gchar *base64;
+  gsize start;
+  gssize end;
+
+  base64 = g_base64_encode (data, data_length);
+
+  if (strip == FALSE) {
+    base64_to_base64_urlsafe (base64);
+    return base64;
+  }
+
+  /* Strip all the '=' */
+  start = 0;
+  while (start < strlen (base64) && base64[start] == '=')
+    start++;
+
+  end = strlen (base64) - 1;
+  while (end >= 0 && base64[end] == '=')
+    end--;
+
+  encoded = g_strndup (base64 + start, end - start + 1);
+  base64_to_base64_urlsafe (encoded);
+
+  g_free (base64);
+
+  return encoded;
+}
+
 guint8 *
-ephy_sync_crypto_encode_aes_256 (const guint8 *key,
-                                 const guint8 *data,
-                                 gsize         data_length)
+ephy_sync_crypto_base64_urlsafe_decode (gchar *text,
+                                        gsize *out_length)
 {
-  struct aes256_ctx aes;
-  guint8 *out;
+  guint8 *decoded;
+  gchar *text_copy;
 
-  g_assert (data_length % AES_BLOCK_SIZE == 0);
+  text_copy = g_strdup (text);
+  base64_urlsafe_to_base64 (text_copy);
+  decoded = g_base64_decode (text_copy, out_length);
 
-  out = g_malloc (data_length);
-  aes256_set_encrypt_key (&aes, key);
-  aes256_encrypt (&aes, data_length, out, data);
+  g_free (text_copy);
 
-  return out;
+  return decoded;
 }
 
 guint8 *
-ephy_sync_crypto_decode_aes_256 (const guint8 *key,
-                                 const guint8 *data,
-                                 gsize         data_length)
+ephy_sync_crypto_aes_256 (EphySyncCryptoAES256Mode  mode,
+                          const guint8             *key,
+                          const guint8             *data,
+                          gsize                     data_length,
+                          gsize                    *out_length)
 {
   struct aes256_ctx aes;
+  gsize padded_length;
+  guint8 *padded_data;
   guint8 *out;
 
-  g_assert (data_length % AES_BLOCK_SIZE == 0);
+  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 (out_length != NULL)
+    *out_length = padded_length;
 
-  out = g_malloc (data_length);
-  aes256_set_decrypt_key (&aes, key);
-  aes256_decrypt (&aes, data_length, out, data);
+  g_free (padded_data);
 
   return out;
 }
diff --git a/src/ephy-sync-crypto.h b/src/ephy-sync-crypto.h
index 902f285..4cf1adb 100644
--- a/src/ephy-sync-crypto.h
+++ b/src/ephy-sync-crypto.h
@@ -26,6 +26,11 @@ G_BEGIN_DECLS
 
 #define EPHY_SYNC_TOKEN_LENGTH 32
 
+typedef enum {
+  AES_256_MODE_ENCRYPT,
+  AES_256_MODE_DECRYPT
+} EphySyncCryptoAES256Mode;
+
 typedef struct {
   gchar *app;
   gchar *dlg;
@@ -125,13 +130,20 @@ gchar                      *ephy_sync_crypto_create_assertion        (const gcha
                                                                       guint64                   duration,
                                                                       EphySyncCryptoRSAKeyPair *keypair);
 
-guint8                     *ephy_sync_crypto_encode_aes_256          (const guint8 *key,
-                                                                      const guint8 *data,
-                                                                      gsize         data_length);
+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_decode_aes_256          (const guint8 *key,
-                                                                      const guint8 *data,
-                                                                      gsize         data_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);
diff --git a/src/ephy-sync-service.c b/src/ephy-sync-service.c
index 425ce28..657a3ec 100644
--- a/src/ephy-sync-service.c
+++ b/src/ephy-sync-service.c
@@ -23,21 +23,17 @@
 #include "ephy-settings.h"
 #include "ephy-sync-crypto.h"
 #include "ephy-sync-secret.h"
+#include "ephy-sync-utils.h"
 
 #include <json-glib/json-glib.h>
-#include <libsoup/soup.h>
 #include <string.h>
 
-#define EPHY_BOOKMARKS_DUMMY_BSO       "000000000000"
-#define EPHY_BOOKMARKS_BSO_COLLECTION  "ephy-bookmarks"
-
 #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-z0-9]([a-z0-9.]+[a-z0-9])?@[a-z0-9.-]+$"
 #define CURRENT_TIME_IN_SECONDS  (g_get_real_time () / 1000000)
-#define HTTP_STATUS_OK           200
 
 struct _EphySyncService {
   GObject parent_instance;
@@ -68,28 +64,23 @@ struct _EphySyncService {
 G_DEFINE_TYPE (EphySyncService, ephy_sync_service, G_TYPE_OBJECT);
 
 typedef struct {
-  EphySyncService *service;
-  gchar *endpoint;
-  const gchar *method;
-  gchar *request_body;
-  gint64 modified_since;
-  gint64 unmodified_since;
-  SoupSessionCallback callback;
-  gpointer user_data;
+  EphySyncService     *service;
+  gchar               *endpoint;
+  const gchar         *method;
+  gchar               *request_body;
+  double               modified_since;
+  double               unmodified_since;
+  SoupSessionCallback  callback;
+  gpointer             user_data;
 } StorageServerRequestAsyncData;
 
-static gchar *
-build_json_string (const gchar *first_key,
-                   const gchar *first_value,
-                   ...) G_GNUC_NULL_TERMINATED;
-
 static StorageServerRequestAsyncData *
 storage_server_request_async_data_new (EphySyncService     *service,
                                        gchar               *endpoint,
                                        const gchar         *method,
                                        gchar               *request_body,
-                                       gint64               modified_since,
-                                       gint64               unmodified_since,
+                                       double               modified_since,
+                                       double               unmodified_since,
                                        SoupSessionCallback  callback,
                                        gpointer             user_data)
 {
@@ -121,35 +112,6 @@ storage_server_request_async_data_free (StorageServerRequestAsyncData *data)
 }
 
 static gchar *
-build_json_string (const gchar *first_key,
-                   const gchar *first_value,
-                   ...)
-{
-  va_list args;
-  gchar *json;
-  gchar *key;
-  gchar *value;
-  gchar *tmp;
-
-  json = g_strconcat ("{\"", first_key, "\": \"", first_value, "\"", NULL);
-  va_start (args, first_value);
-
-  while ((key = va_arg (args, gchar *)) != NULL) {
-    value = va_arg (args, gchar *);
-    tmp = json;
-    json = g_strconcat (json, ", \"", key, "\": \"", value, "\"", NULL);
-    g_free (tmp);
-  }
-
-  va_end (args);
-  tmp = json;
-  json = g_strconcat (json, "}", NULL);
-  g_free (tmp);
-
-  return json;
-}
-
-static gchar *
 get_audience_for_url (const gchar *url)
 {
   SoupURI *uri;
@@ -210,7 +172,7 @@ destroy_session_response_cb (SoupSession *session,
   JsonParser *parser;
   JsonObject *json;
 
-  if (message->status_code == HTTP_STATUS_OK) {
+  if (message->status_code == 200) {
     LOG ("Session destroyed");
     return;
   }
@@ -357,13 +319,13 @@ ephy_sync_service_send_storage_request (EphySyncService               *self,
   }
 
   if (data->modified_since >= 0) {
-    if_modified_since = g_strdup_printf ("%ld", data->modified_since);
+    if_modified_since = g_strdup_printf ("%.2lf", data->modified_since);
     soup_message_headers_append (message->request_headers,
                                  "X-If-Modified-Since", if_modified_since);
   }
 
   if (data->unmodified_since >= 0) {
-    if_unmodified_since = g_strdup_printf ("%ld", data->unmodified_since);
+    if_unmodified_since = g_strdup_printf ("%.2lf", data->unmodified_since);
     soup_message_headers_append (message->request_headers,
                                  "X-If-Unmodified-Since", if_unmodified_since);
   }
@@ -485,7 +447,7 @@ 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 == HTTP_STATUS_OK) {
+  if (message->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"));
@@ -580,7 +542,7 @@ obtain_signed_certificate_response_cb (SoupSession *session,
   json_parser_load_from_data (parser, message->response_body->data, -1, NULL);
   json = json_node_get_object (json_parser_get_root (parser));
 
-  if (message->status_code != HTTP_STATUS_OK) {
+  if (message->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"));
@@ -629,10 +591,10 @@ ephy_sync_service_obtain_signed_certificate (EphySyncService *self,
 
   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 = build_json_string ("algorithm", "RS",
-                                       "n", n_str,
-                                       "e", e_str,
-                                       NULL);
+  public_key_json = ephy_sync_utils_build_json_string ("algorithm", "RS",
+                                                       "n", n_str,
+                                                       "e", e_str,
+                                                       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.
@@ -657,88 +619,6 @@ ephy_sync_service_obtain_signed_certificate (EphySyncService *self,
 }
 
 static void
-ephy_sync_service_send_storage_message (EphySyncService     *self,
-                                        gchar               *endpoint,
-                                        const gchar         *method,
-                                        gchar               *request_body,
-                                        gint64               modified_since,
-                                        gint64               unmodified_since,
-                                        SoupSessionCallback  callback,
-                                        gpointer             user_data)
-{
-  StorageServerRequestAsyncData *data;
-
-  data = storage_server_request_async_data_new (self, endpoint,
-                                                method, request_body,
-                                                modified_since, unmodified_since,
-                                                callback, user_data);
-
-  if (ephy_sync_service_storage_credentials_is_expired (self) == FALSE) {
-    ephy_sync_service_send_storage_request (self, data);
-    return;
-  }
-
-  /* If we are currently obtaining the storage credentials for another message,
-   * then the new message is enqueued and will be sent after the credentials are
-   * retrieved.
-   */
-  if (self->is_obtaining_storage_credentials == TRUE) {
-    g_queue_push_tail (self->storage_message_queue, data);
-    return;
-  }
-
-  /* This message is the one that will obtain the storage credentials. */
-  self->is_obtaining_storage_credentials = TRUE;
-
-  /* Drop the old certificate and storage credentials. */
-  g_clear_pointer (&self->certificate, 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;
-
-  /* The only purpose of certificates is to obtain a signed BrowserID that is
-   * needed to talk to the Token Server. From the Token Server we will obtain
-   * the credentials needed to talk to the Storage Server. Since both
-   * ephy_sync_service_obtain_signed_certificate() and
-   * ephy_sync_service_obtain_storage_credentials() complete asynchronously, we
-   * need to entrust them the task of sending the request to the Storage Server.
-   */
-  ephy_sync_service_obtain_signed_certificate (self, data);
-}
-
-static void
-create_bookmarks_bso_collection_response_cb (SoupSession *session,
-                                             SoupMessage *message,
-                                             gpointer     user_data)
-{
-  EphySyncService *service;
-  gchar *endpoint;
-
-  service = EPHY_SYNC_SERVICE (user_data);
-
-  /* Status code 412 means the BSO already exists. Since we will delete it
-   * anyway, we don't treat this as an error.
-   */
-  if (message->status_code != HTTP_STATUS_OK && message->status_code != 412) {
-    g_warning ("Failed to add dummy BSO to collection, status code: %u, response: %s",
-               message->status_code, message->response_body->data);
-    return;
-  }
-
-  /* The EPHY_BOOKMARKS_BSO_COLLECTION collection is now created. We can safely
-   * delete the dummy BSO that we've uploaded. No need to check for response.
-   */
-  endpoint = g_strdup_printf ("storage/%s/%s",
-                              EPHY_BOOKMARKS_BSO_COLLECTION,
-                              EPHY_BOOKMARKS_DUMMY_BSO);
-  ephy_sync_service_send_storage_message (service,
-                                          endpoint, SOUP_METHOD_DELETE,
-                                          NULL, -1, -1,
-                                          NULL, NULL);
-  g_free (endpoint);
-}
-
-static void
 ephy_sync_service_finalize (GObject *object)
 {
   EphySyncService *self = EPHY_SYNC_SERVICE (object);
@@ -823,6 +703,12 @@ ephy_sync_service_token_name_from_type (EphySyncServiceTokenType token_type)
   }
 }
 
+gboolean
+ephy_sync_service_is_signed_in (EphySyncService *self)
+{
+  return self->user_email != NULL;
+}
+
 gchar *
 ephy_sync_service_get_user_email (EphySyncService *self)
 {
@@ -1004,7 +890,7 @@ ephy_sync_service_fetch_sync_keys (EphySyncService *self,
                                                      &node);
   json = json_node_get_object (node);
 
-  if (status_code != HTTP_STATUS_OK) {
+  if (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"));
@@ -1040,28 +926,51 @@ out:
 }
 
 void
-ephy_sync_service_create_bookmarks_bso_collection (EphySyncService *self)
+ephy_sync_service_send_storage_message (EphySyncService     *self,
+                                        gchar               *endpoint,
+                                        const gchar         *method,
+                                        gchar               *request_body,
+                                        double               modified_since,
+                                        double               unmodified_since,
+                                        SoupSessionCallback  callback,
+                                        gpointer             user_data)
 {
-  gchar *endpoint;
-  gchar *request_body;
+  StorageServerRequestAsyncData *data;
 
-  endpoint = g_strdup_printf ("storage/%s/%s",
-                              EPHY_BOOKMARKS_BSO_COLLECTION,
-                              EPHY_BOOKMARKS_DUMMY_BSO);
-  request_body = build_json_string ("id", EPHY_BOOKMARKS_DUMMY_BSO,
-                                    "payload", EPHY_BOOKMARKS_DUMMY_BSO,
-                                    NULL);
+  data = storage_server_request_async_data_new (self, endpoint,
+                                                method, request_body,
+                                                modified_since, unmodified_since,
+                                                callback, user_data);
 
-  /* Send a dummy BSO to the Storage Server so it will create the
-   * EPHY_BOOKMARKS_BSO_COLLECTION collection if it doesn't exist already.
-   * In the response callback we will delete the dummy BSO.
+  if (ephy_sync_service_storage_credentials_is_expired (self) == FALSE) {
+    ephy_sync_service_send_storage_request (self, data);
+    return;
+  }
+
+  /* If we are currently obtaining the storage credentials for another message,
+   * then the new message is enqueued and will be sent after the credentials are
+   * retrieved.
    */
-  ephy_sync_service_send_storage_message (self,
-                                          endpoint, SOUP_METHOD_PUT,
-                                          request_body, -1, 0,
-                                          create_bookmarks_bso_collection_response_cb,
-                                          self);
+  if (self->is_obtaining_storage_credentials == TRUE) {
+    g_queue_push_tail (self->storage_message_queue, data);
+    return;
+  }
 
-  g_free (endpoint);
-  g_free (request_body);
+  /* This message is the one that will obtain the storage credentials. */
+  self->is_obtaining_storage_credentials = TRUE;
+
+  /* Drop the old certificate and storage credentials. */
+  g_clear_pointer (&self->certificate, 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;
+
+  /* The only purpose of certificates is to obtain a signed BrowserID that is
+   * needed to talk to the Token Server. From the Token Server we will obtain
+   * the credentials needed to talk to the Storage Server. Since both
+   * ephy_sync_service_obtain_signed_certificate() and
+   * ephy_sync_service_obtain_storage_credentials() complete asynchronously, we
+   * need to entrust them the task of sending the request to the Storage Server.
+   */
+  ephy_sync_service_obtain_signed_certificate (self, data);
 }
diff --git a/src/ephy-sync-service.h b/src/ephy-sync-service.h
index 0cbcf63..6623bad 100644
--- a/src/ephy-sync-service.h
+++ b/src/ephy-sync-service.h
@@ -20,6 +20,7 @@
 #define EPHY_SYNC_SERVICE_H
 
 #include <glib-object.h>
+#include <libsoup/soup.h>
 
 G_BEGIN_DECLS
 
@@ -36,38 +37,47 @@ typedef enum {
   TOKEN_KB
 } EphySyncServiceTokenType;
 
-EphySyncService *ephy_sync_service_new                             (void);
+EphySyncService *ephy_sync_service_new                  (void);
 
-const gchar     *ephy_sync_service_token_name_from_type            (EphySyncServiceTokenType token_type);
+const gchar     *ephy_sync_service_token_name_from_type (EphySyncServiceTokenType token_type);
 
-gchar           *ephy_sync_service_get_user_email                  (EphySyncService *self);
+gboolean         ephy_sync_service_is_signed_in         (EphySyncService *self);
 
-void             ephy_sync_service_set_user_email                  (EphySyncService *self,
-                                                                    const gchar     *email);
+gchar           *ephy_sync_service_get_user_email       (EphySyncService *self);
 
-gchar           *ephy_sync_service_get_token                       (EphySyncService          *self,
-                                                                    EphySyncServiceTokenType  token_type);
+void             ephy_sync_service_set_user_email       (EphySyncService *self,
+                                                         const gchar     *email);
 
-void             ephy_sync_service_set_token                       (EphySyncService          *self,
-                                                                    gchar                    *token_value,
-                                                                    EphySyncServiceTokenType  token_type);
+gchar           *ephy_sync_service_get_token            (EphySyncService          *self,
+                                                         EphySyncServiceTokenType  token_type);
 
-void             ephy_sync_service_set_and_store_tokens            (EphySyncService          *self,
-                                                                    gchar                    *token_value,
-                                                                    EphySyncServiceTokenType  token_type,
-                                                                    ...) G_GNUC_NULL_TERMINATED;
+void             ephy_sync_service_set_token            (EphySyncService          *self,
+                                                         gchar                    *token_value,
+                                                         EphySyncServiceTokenType  token_type);
 
-void             ephy_sync_service_delete_all_tokens               (EphySyncService *self);
+void             ephy_sync_service_set_and_store_tokens (EphySyncService          *self,
+                                                         gchar                    *token_value,
+                                                         EphySyncServiceTokenType  token_type,
+                                                         ...) G_GNUC_NULL_TERMINATED;
 
-void             ephy_sync_service_destroy_session                 (EphySyncService *self,
-                                                                    const gchar     *sessionToken);
+void             ephy_sync_service_delete_all_tokens    (EphySyncService *self);
 
-gboolean         ephy_sync_service_fetch_sync_keys                 (EphySyncService *self,
-                                                                    const gchar     *email,
-                                                                    const gchar     *keyFetchToken,
-                                                                    const gchar     *unwrapBKey);
+void             ephy_sync_service_destroy_session      (EphySyncService *self,
+                                                         const gchar     *sessionToken);
 
-void             ephy_sync_service_create_bookmarks_bso_collection (EphySyncService *self);
+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,
+                                                         gchar               *request_body,
+                                                         double               modified_since,
+                                                         double               unmodified_since,
+                                                         SoupSessionCallback  callback,
+                                                         gpointer             user_data);
 
 G_END_DECLS
 
diff --git a/src/ephy-sync-utils.c b/src/ephy-sync-utils.c
new file mode 100644
index 0000000..c37f885
--- /dev/null
+++ b/src/ephy-sync-utils.c
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2016 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "ephy-sync-utils.h"
+
+gchar *
+ephy_sync_utils_build_json_string (const gchar *first_key,
+                                   const gchar *first_value,
+                                   ...)
+{
+  va_list args;
+  gchar *json;
+  gchar *key;
+  gchar *value;
+  gchar *tmp;
+
+  json = g_strconcat ("{\"", first_key, "\": \"", first_value, "\"", NULL);
+  va_start (args, first_value);
+
+  while ((key = va_arg (args, gchar *)) != NULL) {
+    value = va_arg (args, gchar *);
+    tmp = json;
+    json = g_strconcat (json, ", \"", key, "\": \"", value, "\"", NULL);
+    g_free (tmp);
+  }
+
+  va_end (args);
+  tmp = json;
+  json = g_strconcat (json, "}", NULL);
+  g_free (tmp);
+
+  return json;
+}
+
+gchar *
+ephy_sync_utils_create_bso_json (const gchar *id,
+                                 const gchar *payload)
+{
+  return ephy_sync_utils_build_json_string ("id", id, "payload", payload, NULL);
+}
diff --git a/src/ephy-sync-utils.h b/src/ephy-sync-utils.h
new file mode 100644
index 0000000..8cf72df
--- /dev/null
+++ b/src/ephy-sync-utils.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2016 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EPHY_SYNC_UTILS_H
+#define EPHY_SYNC_UTILS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+gchar *ephy_sync_utils_build_json_string (const gchar *first_key,
+                                          const gchar *first_value,
+                                          ...) G_GNUC_NULL_TERMINATED;
+
+gchar *ephy_sync_utils_create_bso_json   (const gchar *id,
+                                          const gchar *payload);
+
+G_END_DECLS
+
+#endif
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
index dd54fcd..ecf5f5e 100644
--- a/src/prefs-dialog.c
+++ b/src/prefs-dialog.c
@@ -34,6 +34,7 @@
 #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"
@@ -295,7 +296,7 @@ server_message_received_cb (WebKitUserContentManager *manager,
                                             NULL);
 
     /* Create our own bookmarks BSO collection on the Storage Server. */
-    ephy_sync_service_create_bookmarks_bso_collection (service);
+    ephy_sync_bookmarks_create_storage_collection ();
 
     /* Translators: the %s refers to the email of the currently logged in user. */
     gtk_label_set_markup (GTK_LABEL (dialog->sync_sign_out_details),
@@ -1450,12 +1451,10 @@ static void
 setup_sync_page (PrefsDialog *dialog)
 {
   EphySyncService *service;
-  gchar *email = NULL;
 
   service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
-  email = ephy_sync_service_get_user_email (service);
 
-  if (email == NULL) {
+  if (ephy_sync_service_is_signed_in (service) == FALSE) {
     setup_fxa_sign_in_view (dialog);
     gtk_container_remove (GTK_CONTAINER (dialog->sync_authenticate_box),
                           dialog->sync_sign_out_box);
@@ -1464,7 +1463,8 @@ setup_sync_page (PrefsDialog *dialog)
                           dialog->sync_sign_in_box);
     /* Translators: the %s refers to the email of the currently logged in user. */
     gtk_label_set_markup (GTK_LABEL (dialog->sync_sign_out_details),
-                          g_strdup_printf (_("Currently logged in as <b>%s</b>"), email));
+                          g_strdup_printf (_("Currently logged in as <b>%s</b>"),
+                                           ephy_sync_service_get_user_email (service)));
   }
 }
 


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