[epiphany/wip/sync: 24/31] sync-service: Handle missing metaglobal and cryptokeys records



commit ae565fc9de3e37f4349a53c80459c54e5329ed20
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date:   Thu Apr 13 15:07:49 2017 +0300

    sync-service: Handle missing metaglobal and cryptokeys records

 src/sync/ephy-sync-crypto.c  |   41 ++++++++++++
 src/sync/ephy-sync-crypto.h  |    1 +
 src/sync/ephy-sync-service.c |  139 ++++++++++++++++++++++++++++++++++++++----
 3 files changed, 168 insertions(+), 13 deletions(-)
---
diff --git a/src/sync/ephy-sync-crypto.c b/src/sync/ephy-sync-crypto.c
index eb58971..7133bef 100644
--- a/src/sync/ephy-sync-crypto.c
+++ b/src/sync/ephy-sync-crypto.c
@@ -926,6 +926,47 @@ ephy_sync_crypto_derive_key_bundle (const guint8 *key,
 }
 
 char *
+ephy_sync_crypto_generate_crypto_keys (gsize key_len)
+{
+  JsonNode *node;
+  JsonObject *object;
+  JsonArray *array;
+  guint8 *aes_key;
+  guint8 *hmac_key;
+  char *aes_key_b64;
+  char *hmac_key_b64;
+  char *payload;
+
+  aes_key = g_malloc (key_len);
+  ephy_sync_crypto_random_bytes_gen (NULL, key_len, aes_key);
+  aes_key_b64 = g_base64_encode (aes_key, key_len);
+  hmac_key = g_malloc (key_len);
+  ephy_sync_crypto_random_bytes_gen (NULL, key_len, hmac_key);
+  hmac_key_b64 = g_base64_encode (hmac_key, key_len);
+
+  node = json_node_new (JSON_NODE_OBJECT);
+  object = json_object_new ();
+  array = json_array_new ();
+  json_array_add_string_element (array, aes_key_b64);
+  json_array_add_string_element (array, hmac_key_b64);
+  json_object_set_array_member (object, "default", array);
+  json_object_set_object_member (object, "collections", json_object_new ());
+  json_object_set_string_member (object, "collection", "crypto");
+  json_object_set_string_member (object, "id", "keys");
+  json_node_set_object (node, object);
+  payload = json_to_string (node, FALSE);
+
+  json_object_unref (object);
+  json_node_unref (node);
+  g_free (hmac_key_b64);
+  g_free (hmac_key);
+  g_free (aes_key_b64);
+  g_free (aes_key);
+
+  return payload;
+}
+
+char *
 ephy_sync_crypto_decrypt_record (const char          *payload,
                                  SyncCryptoKeyBundle *bundle)
 {
diff --git a/src/sync/ephy-sync-crypto.h b/src/sync/ephy-sync-crypto.h
index ce2b33c..ef3365a 100644
--- a/src/sync/ephy-sync-crypto.h
+++ b/src/sync/ephy-sync-crypto.h
@@ -100,6 +100,7 @@ gboolean                ephy_sync_crypto_compute_sync_keys        (const char
                                                                    gsize                   key_len);
 SyncCryptoKeyBundle    *ephy_sync_crypto_derive_key_bundle        (const guint8           *key,
                                                                    gsize                   key_len);
+char                   *ephy_sync_crypto_generate_crypto_keys     (gsize                   key_len);
 char                   *ephy_sync_crypto_decrypt_record           (const char             *payload,
                                                                    SyncCryptoKeyBundle    *bundle);
 char                   *ephy_sync_crypto_encrypt_record           (const char             *cleartext,
diff --git a/src/sync/ephy-sync-service.c b/src/sync/ephy-sync-service.c
index 2ae7b38..3cfc543 100644
--- a/src/sync/ephy-sync-service.c
+++ b/src/sync/ephy-sync-service.c
@@ -1470,27 +1470,65 @@ ephy_sync_service_report_sign_in_error (EphySyncService *self,
   }
 }
 
+static char *
+ephy_sync_service_upload_crypto_keys_record (EphySyncService *self)
+{
+  SyncCryptoKeyBundle *bundle;
+  JsonNode *node;
+  JsonObject *record;
+  char *payload_clear;
+  char *payload_cipher;
+  char *body;
+  guint8 *master_key;
+
+  g_assert (EPHY_IS_SYNC_SERVICE (self));
+  g_assert (ephy_sync_service_get_secret (self, secrets[MASTER_KEY]));
+
+  node = json_node_new (JSON_NODE_OBJECT);
+  record = json_object_new ();
+  payload_clear = ephy_sync_crypto_generate_crypto_keys (TOKEN_LENGTH);
+  master_key = ephy_sync_crypto_decode_hex (ephy_sync_service_get_secret (self, secrets[MASTER_KEY]));
+  bundle = ephy_sync_crypto_derive_key_bundle (master_key, TOKEN_LENGTH);
+  payload_cipher = ephy_sync_crypto_encrypt_record (payload_clear, bundle);
+  json_object_set_string_member (record, "payload", payload_cipher);
+  json_object_set_string_member (record, "id", "keys");
+  json_node_set_object (node, record);
+  body = json_to_string (node, FALSE);
+
+  ephy_sync_service_queue_storage_request (self, "storage/crypto/keys",
+                                           SOUP_METHOD_PUT, body,
+                                           -1, -1, NULL, NULL);
+
+  g_free (body);
+  g_free (payload_cipher);
+  ephy_sync_crypto_key_bundle_free (bundle);
+  g_free (master_key);
+  json_object_unref (record);
+  json_node_unref (node);
+
+  return payload_clear;
+}
+
 static void
 obtain_crypto_keys_cb (SoupSession *session,
                        SoupMessage *msg,
                        gpointer     user_data)
 {
   EphySyncService *self;
-  SyncCryptoKeyBundle *bundle;
+  SyncCryptoKeyBundle *bundle = NULL;
   JsonObject *json;
-  JsonNode *node;
+  JsonNode *node = NULL;
   GError *error = NULL;
   const char *payload;
   char *crypto_keys;
-  guint8 *kB;
+  guint8 *kB = NULL;
   gboolean is_internal_error = TRUE;
 
   self = ephy_shell_get_sync_service (ephy_shell_get_default ());
 
   if (msg->status_code == 404) {
-    /* TODO: Generate and upload new sync key bundles. */
-    is_internal_error = FALSE;
-    goto out;
+    crypto_keys = ephy_sync_service_upload_crypto_keys_record (self);
+    goto store_secrets;
   }
 
   if (msg->status_code != 200) {
@@ -1527,17 +1565,19 @@ obtain_crypto_keys_cb (SoupSession *session,
     goto free_bundle;
   }
 
-  /* Proceed to store secrets. */
+store_secrets:
   ephy_sync_service_set_secret (self, secrets[CRYPTO_KEYS], crypto_keys);
   ephy_sync_secret_store_secrets (self);
   is_internal_error = FALSE;
 
   g_free (crypto_keys);
 free_bundle:
-  ephy_sync_crypto_key_bundle_free (bundle);
+  if (bundle)
+    ephy_sync_crypto_key_bundle_free (bundle);
   g_free (kB);
 free_node:
-  json_node_unref (node);
+  if (node)
+    json_node_unref (node);
 out:
   if (is_internal_error)
     ephy_sync_service_report_sign_in_error (self,
@@ -1555,22 +1595,94 @@ ephy_sync_service_obtain_crypto_keys (EphySyncService *self)
                                            obtain_crypto_keys_cb, NULL);
 }
 
+static JsonObject *
+make_engine_object (int version)
+{
+  JsonObject *object;
+  char *sync_id;
+
+  object = json_object_new ();
+  sync_id = ephy_sync_crypto_get_random_sync_id ();
+  json_object_set_int_member (object, "version", version);
+  json_object_set_string_member (object, "syncID", sync_id);
+
+  g_free (sync_id);
+
+  return object;
+}
+
+static void
+ephy_sync_service_upload_meta_global_record (EphySyncService *self)
+{
+  JsonNode *node;
+  JsonObject *record;
+  JsonObject *payload;
+  JsonObject *engines;
+  JsonArray *declined;
+  char *sync_id;
+  char *payload_str;
+  char *body;
+
+  g_assert (EPHY_IS_SYNC_SERVICE (self));
+
+  node = json_node_new (JSON_NODE_OBJECT);
+  record = json_object_new ();
+  payload = json_object_new ();
+  engines = json_object_new ();
+  declined = json_array_new ();
+  json_array_add_string_element (declined, "addons");
+  json_array_add_string_element (declined, "prefs");
+  json_array_add_string_element (declined, "tabs");
+  json_object_set_array_member (payload, "declined", declined);
+  json_object_set_object_member (engines, "clients", make_engine_object (1));
+  json_object_set_object_member (engines, "bookmarks", make_engine_object (2));
+  json_object_set_object_member (engines, "history", make_engine_object (1));
+  json_object_set_object_member (engines, "passwords", make_engine_object (1));
+  json_object_set_object_member (engines, "forms", make_engine_object (1));
+  json_object_set_object_member (payload, "engines", engines);
+  json_object_set_int_member (payload, "storageVersion", STORAGE_VERSION);
+  sync_id = ephy_sync_crypto_get_random_sync_id ();
+  json_object_set_string_member (payload, "syncID", sync_id);
+  json_node_set_object (node, payload);
+  payload_str = json_to_string (node, FALSE);
+  json_object_set_string_member (record, "payload", payload_str);
+  json_object_set_string_member (record, "id", "global");
+  json_node_set_object (node, record);
+  body = json_to_string (node, FALSE);
+
+  ephy_sync_service_queue_storage_request (self, "storage/meta/global",
+                                           SOUP_METHOD_PUT, body,
+                                           -1, -1, NULL, NULL);
+
+  g_free (body);
+  g_free (payload_str);
+  g_free (sync_id);
+  json_object_unref (payload);
+  json_object_unref (record);
+  json_node_unref (node);
+}
+
 static void
 check_storage_version_cb (SoupSession *session,
                           SoupMessage *msg,
                           gpointer     user_data)
 {
   EphySyncService *self;
-  JsonParser *parser;
+  JsonParser *parser = NULL;
   JsonObject *json;
   GError *error = NULL;
-  char *payload;
+  char *payload = NULL;
   char *message = NULL;
   int storage_version;
   gboolean is_internal_error = TRUE;
 
   self = ephy_shell_get_sync_service (ephy_shell_get_default ());
 
+  if (msg->status_code == 404) {
+    ephy_sync_service_upload_meta_global_record (self);
+    goto obtain_crypto_keys;
+  }
+
   if (msg->status_code != 200) {
     g_warning ("Failed to check storage version. Status code: %u, response: %s",
                msg->status_code, msg->response_body->data);
@@ -1623,14 +1735,15 @@ check_storage_version_cb (SoupSession *session,
     goto free_payload;
   }
 
-  /* Proceed to obtain the crypto keys. */
+obtain_crypto_keys:
   ephy_sync_service_obtain_crypto_keys (self);
   is_internal_error = FALSE;
 
 free_payload:
   g_free (payload);
 free_parser:
-  g_object_unref (parser);
+  if (parser)
+    g_object_unref (parser);
 out:
   if (is_internal_error) {
     ephy_sync_service_report_sign_in_error (self,


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