[epiphany/wip/ephy-sync: 9/48] sync-crypto: Add function to compute Hawk headers



commit 1a3e053cb2742283319071cb8a987c2499561c7f
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date:   Sun Jun 26 18:50:40 2016 +0300

    sync-crypto: Add function to compute Hawk headers

 src/ephy-sync-crypto.c  |  412 +++++++++++++++++++++++++++++++++++++++++++++++
 src/ephy-sync-crypto.h  |   81 ++++++++--
 src/ephy-sync-service.c |  134 ++++++++++++----
 src/ephy-sync-utils.c   |   36 ++++
 src/ephy-sync-utils.h   |    4 +
 5 files changed, 622 insertions(+), 45 deletions(-)
---
diff --git a/src/ephy-sync-crypto.c b/src/ephy-sync-crypto.c
index 00480cf..64e560d 100644
--- a/src/ephy-sync-crypto.c
+++ b/src/ephy-sync-crypto.c
@@ -18,10 +18,318 @@
 
 #include "ephy-sync-crypto.h"
 
+#include <libsoup/soup.h>
 #include <nettle/hmac.h>
 #include <nettle/pbkdf2.h>
+#include <nettle/sha2.h>
 #include <string.h>
 
+#define HAWK_VERSION  1
+
+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 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 void
+ephy_sync_crypto_hawk_artifacts_free (EphySyncCryptoHawkArtifacts *hawk_artifacts)
+{
+  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);
+}
+
+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)
+{
+  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);
+
+  return new;
+}
+
+static gchar *
+normalize_string (const gchar                 *mac_type,
+                  EphySyncCryptoHawkArtifacts *artifacts)
+{
+  gchar *host;
+  gchar *info;
+  gchar *method;
+  gchar *n_ext = NULL;
+  gchar *normalized;
+  gchar *tmp;
+
+  g_return_val_if_fail (mac_type, NULL);
+  g_return_val_if_fail (artifacts, NULL);
+
+  info = g_strdup_printf ("hawk.%d.%s", HAWK_VERSION, mac_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 : "",
+                          NULL);
+
+  if (artifacts->ext && strlen (artifacts->ext) > 0) {
+    tmp = find_and_replace_string (artifacts->ext, "\\", "\\\\");
+    n_ext = find_and_replace_string (tmp, "\n", "\\n");
+    g_free (tmp);
+  }
+
+  tmp = normalized;
+  normalized = g_strconcat (normalized, "\n",
+                            n_ext ? n_ext : "", "\n",
+                            artifacts->app ? artifacts->app : "",
+                            artifacts->app ? "\n" : "",
+                            artifacts->app && artifacts->dlg ? artifacts->dlg : "",
+                            artifacts->app && artifacts->dlg ? "\n" : "",
+                            NULL);
+
+  g_free (host);
+  g_free (info);
+  g_free (method);
+  g_free (n_ext);
+  g_free (tmp);
+
+  return normalized;
+}
+
+static gchar *
+parse_content_type (const gchar *content_type)
+{
+  gchar **tokens;
+  gchar *retval;
+
+  tokens = g_strsplit (content_type, ";", -1);
+  retval = g_ascii_strdown (g_strstrip (tokens[0]), -1);
+  g_strfreev (tokens);
+
+  return retval;
+}
+
+static gchar *
+calculate_payload_hash (const gchar *payload,
+                        const gchar *content_type)
+{
+  struct sha256_ctx ctx;
+  guint8 *digest;
+  gchar *content;
+  gchar *update;
+  gchar *retval;
+
+  g_return_val_if_fail (payload, NULL);
+  g_return_val_if_fail (content_type, NULL);
+
+  content = parse_content_type (content_type);
+  update = g_strdup_printf ("hawk.%d.payload\n%s\n%s\n",
+                            HAWK_VERSION,
+                            content,
+                            payload);
+  digest = g_malloc (SHA256_DIGEST_SIZE);
+
+  sha256_init (&ctx);
+  sha256_update (&ctx, strlen (update), (guint8 *) update);
+  sha256_digest (&ctx, SHA256_DIGEST_SIZE, digest);
+  retval = g_base64_encode (digest, SHA256_DIGEST_SIZE);
+
+  g_free (content);
+  g_free (update);
+  g_free (digest);
+
+  return retval;
+}
+
+static gchar *
+calculate_mac (const gchar                 *mac_type,
+               guint8                      *key,
+               gsize                        key_length,
+               EphySyncCryptoHawkArtifacts *artifacts)
+{
+  struct hmac_sha256_ctx ctx;
+  guint8 *digest;
+  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);
+
+  normalized = normalize_string (mac_type, artifacts);
+  digest = g_malloc (SHA256_DIGEST_SIZE);
+
+  hmac_sha256_set_key (&ctx, key_length, key);
+  hmac_sha256_update (&ctx, strlen (normalized), (guint8 *) normalized);
+  hmac_sha256_digest (&ctx, SHA256_DIGEST_SIZE, digest);
+  mac = g_base64_encode (digest, SHA256_DIGEST_SIZE);
+
+  g_free (normalized);
+  g_free (digest);
+
+  return mac;
+}
+
+static gchar *
+append_token_to_header (gchar       *header,
+                        const gchar *token_name,
+                        gchar       *token_value)
+{
+  gchar *new_header;
+  gchar *tmp;
+
+  tmp = header;
+  new_header = g_strconcat (header, ", ",
+                            token_name, "=\"",
+                            token_value, "\"",
+                            NULL);
+  g_free (tmp);
+
+  return new_header;
+}
+
+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;
+}
+
+void
+ephy_sync_crypto_hawk_options_free (EphySyncCryptoHawkOptions *hawk_options)
+{
+  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);
+}
+
+void
+ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader *hawk_header)
+{
+  g_free (hawk_header->header);
+  ephy_sync_crypto_hawk_artifacts_free (hawk_header->artifacts);
+
+  g_slice_free (EphySyncCryptoHawkHeader, hawk_header);
+}
+
 /*
  * Runs 1000 iterations of PBKDF2.
  * Uses sha256 as hash function.
@@ -94,3 +402,107 @@ ephy_sync_crypto_hkdf (guint8 *in,
   g_free (tmp);
   g_free (prk);
 }
+
+EphySyncCryptoHawkHeader *
+ephy_sync_crypto_compute_hawk_header (const gchar               *url,
+                                      const gchar               *method,
+                                      const gchar               *id,
+                                      guint8                    *key,
+                                      gsize                      key_length,
+                                      EphySyncCryptoHawkOptions *options)
+{
+  EphySyncCryptoHawkArtifacts *artifacts;
+  SoupURI *uri;
+  gboolean has_options;
+  const gchar *hostname;
+  const gchar *resource;
+  gchar *hash;
+  gchar *header;
+  gchar *mac;
+  gchar *nonce;
+  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);
+
+  has_options = options != NULL;
+  ts = g_get_real_time () / 1000000;
+
+  timestamp = has_options ? options->timestamp : NULL;
+  if (timestamp) {
+    gchar *local_time_offset;
+    gint64 offset;
+
+    local_time_offset = has_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 : 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);
+  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);
+  }
+
+  artifacts = ephy_sync_crypto_hawk_artifacts_new (has_options ? options->app : NULL,
+                                                   has_options ? options->dlg : NULL,
+                                                   has_options ? options->ext : NULL,
+                                                   hash,
+                                                   g_strdup (hostname),
+                                                   g_strdup (method),
+                                                   nonce,
+                                                   g_strdup_printf ("%u", port),
+                                                   g_strdup (resource),
+                                                   g_strdup_printf ("%ld", ts));
+
+  mac = calculate_mac ("header", key, key_length, 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->ext && 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);
+
+    g_free (h_ext);
+    g_free (tmp_ext);
+  }
+
+  header = append_token_to_header (header, "mac", mac);
+
+  if (artifacts->app) {
+    header = append_token_to_header (header, "app", artifacts->app);
+
+    if (artifacts->dlg)
+      header = append_token_to_header (header, "dlg", artifacts->dlg);
+  }
+
+  return ephy_sync_crypto_hawk_header_new (header, artifacts);
+}
diff --git a/src/ephy-sync-crypto.h b/src/ephy-sync-crypto.h
index ec4cd3a..7afb73d 100644
--- a/src/ephy-sync-crypto.h
+++ b/src/ephy-sync-crypto.h
@@ -23,21 +23,72 @@
 
 G_BEGIN_DECLS
 
-void ephy_sync_crypto_pbkdf2_1k (guint8 *key,
-                                 gsize   key_length,
-                                 guint8 *salt,
-                                 gsize   salt_length,
-                                 guint8 *out,
-                                 gsize   out_length);
-
-void ephy_sync_crypto_hkdf      (guint8 *in,
-                                 gsize   in_length,
-                                 guint8 *salt,
-                                 gsize   salt_length,
-                                 guint8 *info,
-                                 gsize   info_length,
-                                 guint8 *out,
-                                 gsize   out_length);
+typedef struct {
+  gchar *app;
+  gchar *dlg;
+  gchar *ext;
+  gchar *content_type;
+  gchar *hash;
+  gchar *local_time_offset;
+  gchar *nonce;
+  gchar *payload;
+  gchar *timestamp;
+} EphySyncCryptoHawkOptions;
+
+typedef struct {
+  gchar *app;
+  gchar *dlg;
+  gchar *ext;
+  gchar *hash;
+  gchar *host;
+  gchar *method;
+  gchar *nonce;
+  gchar *port;
+  gchar *resource;
+  gchar *ts;
+} EphySyncCryptoHawkArtifacts;
+
+typedef struct {
+  gchar *header;
+  EphySyncCryptoHawkArtifacts *artifacts;
+} EphySyncCryptoHawkHeader;
+
+void                       ephy_sync_crypto_pbkdf2_1k           (guint8 *key,
+                                                                 gsize   key_length,
+                                                                 guint8 *salt,
+                                                                 gsize   salt_length,
+                                                                 guint8 *out,
+                                                                 gsize   out_length);
+
+void                       ephy_sync_crypto_hkdf                (guint8 *in,
+                                                                 gsize   in_length,
+                                                                 guint8 *salt,
+                                                                 gsize   salt_length,
+                                                                 guint8 *info,
+                                                                 gsize   info_length,
+                                                                 guint8 *out,
+                                                                 gsize   out_length);
+
+EphySyncCryptoHawkHeader  *ephy_sync_crypto_compute_hawk_header (const gchar               *url,
+                                                                 const gchar               *method,
+                                                                 const gchar               *id,
+                                                                 guint8                    *key,
+                                                                 gsize                      key_length,
+                                                                 EphySyncCryptoHawkOptions *options);
+
+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);
 
 G_END_DECLS
 
diff --git a/src/ephy-sync-service.c b/src/ephy-sync-service.c
index a074281..04910e1 100644
--- a/src/ephy-sync-service.c
+++ b/src/ephy-sync-service.c
@@ -28,7 +28,8 @@
 #include <libsoup/soup.h>
 #include <string.h>
 
-#define BASEURL     "https://api.accounts.firefox.com/v1";
+#define FXA_BASEURL   "https://api.accounts.firefox.com/";
+#define FXA_VERSION   "v1/"
 
 struct _EphySyncService {
   GObject parent_instance;
@@ -42,13 +43,107 @@ struct _EphySyncService {
 
 G_DEFINE_TYPE (EphySyncService, ephy_sync_service, G_TYPE_OBJECT);
 
+static SoupMessage *
+synchronous_hawk_get_request (EphySyncService *self,
+                              const gchar     *endpoint,
+                              const gchar     *id,
+                              guint8          *key,
+                              gsize            key_length)
+{
+  EphySyncCryptoHawkHeader *hawk_header;
+  SoupMessage *message;
+  gchar *url;
+
+  url = g_strdup_printf ("%s%s%s", FXA_BASEURL, FXA_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);
+LOG ("[%d] Sending synchronous HAWK GET request to %s endpoint", __LINE__, endpoint);
+  soup_session_send_message (self->soup_session, message);
+
+  g_free (url);
+  ephy_sync_crypto_hawk_header_free (hawk_header);
+
+  return message;
+}
+
+static SoupMessage *
+synchronous_hawk_post_request (EphySyncService *self,
+                               const gchar     *endpoint,
+                               const gchar     *id,
+                               guint8          *key,
+                               gsize            key_length,
+                               gchar           *request_body)
+{
+  EphySyncCryptoHawkHeader *hawk_header;
+  EphySyncCryptoHawkOptions *hawk_options;
+  SoupMessage *message;
+  gchar *url;
+
+  url = g_strdup_printf ("%s%s%s", FXA_BASEURL, FXA_VERSION, endpoint);
+  message = soup_message_new (SOUP_METHOD_POST, url);
+  soup_message_set_request (message,
+                            "application/json",
+                            SOUP_MEMORY_TAKE,
+                            request_body,
+                            strlen (request_body));
+  hawk_options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL,
+                                                    g_strdup ("application/json"),
+                                                    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", "application/json");
+LOG ("[%d] Sending synchronous HAWK POST request to %s endpoint", __LINE__, endpoint);
+  soup_session_send_message (self->soup_session, message);
+
+  g_free (url);
+  ephy_sync_crypto_hawk_options_free (hawk_options);
+  ephy_sync_crypto_hawk_header_free (hawk_header);
+
+  return message;
+}
+
+static SoupMessage *
+synchronous_fxa_post_request (EphySyncService *self,
+                              const gchar     *endpoint,
+                              gchar           *request_body)
+{
+  SoupMessage *message;
+  gchar *url;
+
+  url = g_strdup_printf ("%s%s%s", FXA_BASEURL, FXA_VERSION, endpoint);
+  message = soup_message_new (SOUP_METHOD_POST, url);
+  soup_message_set_request (message,
+                            "application/json",
+                            SOUP_MEMORY_TAKE,
+                            request_body,
+                            strlen (request_body));
+LOG ("[%d] Sending synchronous POST request to %s endpoint", __LINE__, endpoint);
+  soup_session_send_message (self->soup_session, message);
+
+  g_free (url);
+
+  return message;
+}
+
 static void
 ephy_sync_service_finalize (GObject *object)
 {
   EphySyncService *self = EPHY_SYNC_SERVICE (object);
 
   g_free (self->user_email);
-  g_clear_object (&self->tokens);
+  g_hash_table_destroy (self->tokens);
   g_clear_object (&self->soup_session);
 
   G_OBJECT_CLASS (ephy_sync_service_parent_class)->finalize (object);
@@ -67,7 +162,7 @@ ephy_sync_service_init (EphySyncService *self)
 {
   gchar *sync_user = NULL;
 
-  self->tokens = g_hash_table_new_full (NULL, g_str_equal,
+  self->tokens = g_hash_table_new_full (g_str_hash, g_str_equal,
                                         NULL, g_free);
   self->soup_session = soup_session_new ();
 
@@ -82,26 +177,6 @@ ephy_sync_service_init (EphySyncService *self)
 LOG ("[%d] sync service inited", __LINE__);
 }
 
-static SoupMessage *
-synchronous_post_request (EphySyncService *self,
-                          const gchar     *endpoint,
-                          gchar           *request_body)
-{
-  SoupMessage *message;
-
-  message = soup_message_new (SOUP_METHOD_POST,
-                              g_strdup_printf ("%s/%s", BASEURL, endpoint));
-  soup_message_set_request (message,
-                            "application/json",
-                            SOUP_MEMORY_TAKE,
-                            request_body,
-                            strlen (request_body));
-LOG ("[%d] Sending synchronous POST request to %s endpoint", __LINE__, endpoint);
-  soup_session_send_message (self->soup_session, message);
-
-  return message;
-}
-
 EphySyncService *
 ephy_sync_service_new (void)
 {
@@ -194,13 +269,12 @@ ephy_sync_service_login (EphySyncService  *self,
   authPW = ephy_sync_service_get_token (self, EPHY_SYNC_TOKEN_AUTHPW);
   g_return_val_if_fail (authPW, FALSE);
 
-  request_body = g_strconcat ("{\"authPW\": \"", authPW,
-                              "\", \"email\": \"", self->user_email,
-                              "\"}", NULL);
-
-  message = synchronous_post_request (self,
-                                      "account/login?keys=true",
-                                      request_body);
+  request_body = ephy_sync_utils_build_json_string ("authPW", authPW,
+                                                    "email", self->user_email,
+                                                    NULL);
+  message = synchronous_fxa_post_request (self,
+                                          "account/login?keys=true",
+                                          request_body);
 LOG ("[%d] status code: %u", __LINE__, message->status_code);
 
   parser = json_parser_new ();
diff --git a/src/ephy-sync-utils.c b/src/ephy-sync-utils.c
index 68d2f36..c307b0b 100644
--- a/src/ephy-sync-utils.c
+++ b/src/ephy-sync-utils.c
@@ -93,6 +93,42 @@ ephy_sync_utils_token_name_from_type (EphySyncTokenType token_type)
   }
 }
 
+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;
+}
+
 /* FIXME: Only for debugging, remove when no longer needed */
 void
 ephy_sync_utils_display_hex (const gchar *data_name,
diff --git a/src/ephy-sync-utils.h b/src/ephy-sync-utils.h
index d3eeae6..9e33850 100644
--- a/src/ephy-sync-utils.h
+++ b/src/ephy-sync-utils.h
@@ -46,6 +46,10 @@ guint8      *ephy_sync_utils_decode_hex           (const gchar *hex_string);
 
 const gchar *ephy_sync_utils_token_name_from_type (EphySyncTokenType token_type);
 
+gchar       *ephy_sync_utils_build_json_string    (const gchar *first_key,
+                                                   const gchar *first_value,
+                                                   ...) G_GNUC_NULL_TERMINATED;
+
 /* FIXME: Only for debugging, remove when no longer needed */
 void         ephy_sync_utils_display_hex          (const gchar *data_name,
                                                    guint8      *data,


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