[epiphany/wip/ephy-sync: 18/52] Implement login logic



commit c94d9e30c5e55a2b32d702913d9718d12c5482f4
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date:   Sat Jun 25 14:10:22 2016 +0300

    Implement login logic

 src/ephy-sync-service.c |  151 +++++++++++++++++++++++++++++++++++------------
 src/ephy-sync-service.h |    4 +-
 src/ephy-sync-utils.c   |    4 +
 src/ephy-sync-utils.h   |    2 +
 src/prefs-dialog.c      |   29 +++++++--
 5 files changed, 143 insertions(+), 47 deletions(-)
---
diff --git a/src/ephy-sync-service.c b/src/ephy-sync-service.c
index 6f100ef..a074281 100644
--- a/src/ephy-sync-service.c
+++ b/src/ephy-sync-service.c
@@ -28,9 +28,13 @@
 #include <libsoup/soup.h>
 #include <string.h>
 
+#define BASEURL     "https://api.accounts.firefox.com/v1";
+
 struct _EphySyncService {
   GObject parent_instance;
 
+  SoupSession *soup_session;
+
   gchar *user_email;
   GHashTable *tokens;
 };
@@ -44,7 +48,8 @@ ephy_sync_service_finalize (GObject *object)
   EphySyncService *self = EPHY_SYNC_SERVICE (object);
 
   g_free (self->user_email);
-  g_hash_table_destroy (self->tokens);
+  g_clear_object (&self->tokens);
+  g_clear_object (&self->soup_session);
 
   G_OBJECT_CLASS (ephy_sync_service_parent_class)->finalize (object);
 }
@@ -64,6 +69,7 @@ ephy_sync_service_init (EphySyncService *self)
 
   self->tokens = g_hash_table_new_full (NULL, g_str_equal,
                                         NULL, g_free);
+  self->soup_session = soup_session_new ();
 
   sync_user = g_settings_get_string (EPHY_SETTINGS_MAIN,
                                      EPHY_PREFS_SYNC_USER);
@@ -76,17 +82,24 @@ ephy_sync_service_init (EphySyncService *self)
 LOG ("[%d] sync service inited", __LINE__);
 }
 
-static void
-server_response_cb (SoupSession *session,
-                    SoupMessage *message,
-                    gpointer     user_data)
+static SoupMessage *
+synchronous_post_request (EphySyncService *self,
+                          const gchar     *endpoint,
+                          gchar           *request_body)
 {
-  if (message->status_code == 200) {
-LOG ("[%d] response body: %s", __LINE__, message->response_body->data);
-    // TODO: parse response data using JsonParser
-  } else {
-LOG ("[%d] Error response from server: [%u] %s", __LINE__, message->status_code, message->reason_phrase);
-  }
+  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 *
@@ -161,44 +174,92 @@ ephy_sync_service_delete_all_tokens (EphySyncService *self)
 LOG ("[%d] Deleted all tokens", __LINE__);
 }
 
-void
-ephy_sync_service_login (EphySyncService *self)
+gboolean
+ephy_sync_service_login (EphySyncService  *self,
+                         guint            *error_code,
+                         gchar           **error_message)
 {
-  SoupSession *session;
   SoupMessage *message;
+  JsonParser *parser;
+  JsonNode *root;
+  JsonObject *object;
   gchar *request_body;
+  gchar *quickStretchedPW;
   gchar *authPW;
+  gchar *unwrapBKey;
+  gchar *uid;
+  gchar *sessionToken;
+  gchar *keyFetchToken;
 
+  authPW = ephy_sync_service_get_token (self, EPHY_SYNC_TOKEN_AUTHPW);
+  g_return_val_if_fail (authPW, FALSE);
 
-LOG ("[%d] Preparing soup message", __LINE__);
+  request_body = g_strconcat ("{\"authPW\": \"", authPW,
+                              "\", \"email\": \"", self->user_email,
+                              "\"}", NULL);
 
-  session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT,
-                                           "test-json",
-                                           NULL);
-  message = soup_message_new (SOUP_METHOD_POST,
-                              "https://api.accounts.firefox.com/v1/account/login";);
+  message = synchronous_post_request (self,
+                                      "account/login?keys=true",
+                                      request_body);
+LOG ("[%d] status code: %u", __LINE__, message->status_code);
 
-  authPW = ephy_sync_service_get_token (self, EPHY_SYNC_TOKEN_AUTHPW);
-  g_assert (authPW != NULL);
+  parser = json_parser_new ();
+  json_parser_load_from_data (parser, message->response_body->data, -1, NULL);
+  root = json_parser_get_root (parser);
+  g_assert (JSON_NODE_HOLDS_OBJECT (root));
+  object = json_node_get_object (root);
 
-  request_body = g_strconcat ("{\"authPW\": \"",
-                              authPW,
-                              "\", \"email\": \"",
-                              self->user_email,
-                              "\"}",
-                              NULL);
+  if (message->status_code != 200) {
+    *error_message = g_strdup (json_object_get_string_member (object, "message"));
+    *error_code = json_object_get_int_member (object, "errno");
 
-  soup_message_set_request (message,
-                            "application/json",
-                            SOUP_MEMORY_COPY,
-                            request_body,
-                            strlen (request_body));
+LOG ("[%d] errno: %u, errmsg: %s", __LINE__, *error_code, *error_message);
+
+    ephy_sync_service_delete_all_tokens (self);
+    ephy_sync_service_set_user_email (self, NULL);
 
-  soup_session_queue_message (session, message, server_response_cb, NULL);
-LOG ("[%d] Queued the soup message", __LINE__);
+    return FALSE;
+  }
 
-  // TODO: find a way to safely free request_body
-  // TODO: find a way to safely destroy session, message
+  /* Extract uid, sesionToken, keyFetchToken */
+  uid = g_strdup (json_object_get_string_member (object, "uid"));
+  sessionToken = g_strdup (json_object_get_string_member (object, "sessionToken"));
+  keyFetchToken = g_strdup (json_object_get_string_member (object, "keyFetchToken"));
+
+  /* Save tokens in memory */
+  ephy_sync_service_save_token (self,
+                                EPHY_SYNC_TOKEN_UID,
+                                uid);
+  ephy_sync_service_save_token (self,
+                                EPHY_SYNC_TOKEN_SESSIONTOKEN,
+                                sessionToken);
+  ephy_sync_service_save_token (self,
+                                EPHY_SYNC_TOKEN_KEYFETCHTOKEN,
+                                keyFetchToken);
+
+  /* Store tokens on disk */
+  quickStretchedPW = ephy_sync_service_get_token (self, EPHY_SYNC_TOKEN_QUICKSTRETCHEDPW);
+  unwrapBKey = ephy_sync_service_get_token (self, EPHY_SYNC_TOKEN_UNWRAPBKEY);
+  ephy_sync_secret_store_token (self->user_email,
+                                EPHY_SYNC_TOKEN_AUTHPW,
+                                authPW);
+  ephy_sync_secret_store_token (self->user_email,
+                                EPHY_SYNC_TOKEN_KEYFETCHTOKEN,
+                                keyFetchToken);
+  ephy_sync_secret_store_token (self->user_email,
+                                EPHY_SYNC_TOKEN_SESSIONTOKEN,
+                                sessionToken);
+  ephy_sync_secret_store_token (self->user_email,
+                                EPHY_SYNC_TOKEN_UID,
+                                uid);
+  ephy_sync_secret_store_token (self->user_email,
+                                EPHY_SYNC_TOKEN_UNWRAPBKEY,
+                                unwrapBKey);
+  ephy_sync_secret_store_token (self->user_email,
+                                EPHY_SYNC_TOKEN_QUICKSTRETCHEDPW,
+                                quickStretchedPW);
+
+  return TRUE;
 }
 
 void
@@ -213,8 +274,6 @@ ephy_sync_service_stretch (EphySyncService *self,
   guint8 *authPW;
   guint8 *unwrapBKey;
 
-  g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
-
   salt_stretch = ephy_sync_utils_kwe ("quickStretch", emailUTF8);
   quickStretchedPW = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
   ephy_sync_crypto_pbkdf2_1k ((guint8 *) passwordUTF8,
@@ -248,6 +307,20 @@ ephy_sync_utils_display_hex ("quickStretchedPW", quickStretchedPW, EPHY_SYNC_TOK
 
 LOG ("[%d] Stretching done", __LINE__);
 
+  ephy_sync_service_set_user_email (self, emailUTF8);
+  ephy_sync_service_save_token (self,
+                                EPHY_SYNC_TOKEN_QUICKSTRETCHEDPW,
+                                ephy_sync_utils_encode_hex (quickStretchedPW,
+                                                            EPHY_SYNC_TOKEN_LENGTH));
+  ephy_sync_service_save_token (self,
+                                EPHY_SYNC_TOKEN_AUTHPW,
+                                ephy_sync_utils_encode_hex (authPW,
+                                                            EPHY_SYNC_TOKEN_LENGTH));
+  ephy_sync_service_save_token (self,
+                                EPHY_SYNC_TOKEN_UNWRAPBKEY,
+                                ephy_sync_utils_encode_hex (unwrapBKey,
+                                                            EPHY_SYNC_TOKEN_LENGTH));
+
   g_free (salt_stretch);
   g_free (info_unwrap);
   g_free (info_auth);
diff --git a/src/ephy-sync-service.h b/src/ephy-sync-service.h
index e467c83..2631971 100644
--- a/src/ephy-sync-service.h
+++ b/src/ephy-sync-service.h
@@ -52,7 +52,9 @@ void             ephy_sync_service_stretch           (EphySyncService *self,
                                                       const gchar     *emailUTF8,
                                                       const gchar     *passwordUTF8);
 
-void             ephy_sync_service_login             (EphySyncService *self);
+gboolean         ephy_sync_service_login             (EphySyncService  *self,
+                                                      guint            *error_code,
+                                                      gchar           **error_message);
 
 G_END_DECLS
 
diff --git a/src/ephy-sync-utils.c b/src/ephy-sync-utils.c
index 152dddb..68d2f36 100644
--- a/src/ephy-sync-utils.c
+++ b/src/ephy-sync-utils.c
@@ -78,8 +78,12 @@ ephy_sync_utils_token_name_from_type (EphySyncTokenType token_type)
   switch (token_type) {
   case EPHY_SYNC_TOKEN_AUTHPW:
     return "authPw";
+  case EPHY_SYNC_TOKEN_KEYFETCHTOKEN:
+    return "keyFetchToken";
   case EPHY_SYNC_TOKEN_SESSIONTOKEN:
     return "sessionToken";
+  case EPHY_SYNC_TOKEN_UID:
+    return "uid";
   case EPHY_SYNC_TOKEN_UNWRAPBKEY:
     return "unwrapBKey";
   case EPHY_SYNC_TOKEN_QUICKSTRETCHEDPW:
diff --git a/src/ephy-sync-utils.h b/src/ephy-sync-utils.h
index ea0b6f5..d3eeae6 100644
--- a/src/ephy-sync-utils.h
+++ b/src/ephy-sync-utils.h
@@ -27,7 +27,9 @@ G_BEGIN_DECLS
 
 typedef enum {
   EPHY_SYNC_TOKEN_AUTHPW,
+  EPHY_SYNC_TOKEN_KEYFETCHTOKEN,
   EPHY_SYNC_TOKEN_SESSIONTOKEN,
+  EPHY_SYNC_TOKEN_UID,
   EPHY_SYNC_TOKEN_UNWRAPBKEY,
   EPHY_SYNC_TOKEN_QUICKSTRETCHEDPW
 } EphySyncTokenType;
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
index c25455a..452d8ee 100644
--- a/src/prefs-dialog.c
+++ b/src/prefs-dialog.c
@@ -35,6 +35,7 @@
 #include "ephy-session.h"
 #include "ephy-settings.h"
 #include "ephy-shell.h"
+#include "ephy-sync-service.h"
 #include "clear-data-dialog.h"
 #include "cookies-dialog.h"
 #include "languages.h"
@@ -169,12 +170,16 @@ static void
 on_sync_login_button_clicked (GtkWidget   *button,
                               PrefsDialog *dialog)
 {
+  EphySyncService *sync_service;
   const gchar *emailUTF8;
   const gchar *passwordUTF8;
+  gboolean login_ok;
+  guint error_code = 0;
+  gchar *error_message = NULL;
 
-  gtk_label_set_markup (GTK_LABEL (dialog->sync_email_details_label), NULL);
-  gtk_label_set_markup (GTK_LABEL (dialog->sync_password_details_label), NULL);
-  gtk_label_set_markup (GTK_LABEL (dialog->sync_extra_details_label), NULL);
+  gtk_label_set_markup (GTK_LABEL (dialog->sync_email_details_label), "");
+  gtk_label_set_markup (GTK_LABEL (dialog->sync_password_details_label), "");
+  gtk_label_set_markup (GTK_LABEL (dialog->sync_extra_details_label), "");
 
   emailUTF8 = gtk_entry_get_text (GTK_ENTRY (dialog->sync_email_entry));
   passwordUTF8 = gtk_entry_get_text (GTK_ENTRY (dialog->sync_password_entry));
@@ -182,28 +187,38 @@ on_sync_login_button_clicked (GtkWidget   *button,
   if (emailUTF8 && !emailUTF8[0]) {
     gtk_label_set_markup (GTK_LABEL (dialog->sync_email_details_label),
                           _("<span fgcolor='#e6780b'>Please insert your email</span>"));
-LOG ("[%d] empty email field", __LINE__);
     return;
   }
 
   if (passwordUTF8 && !passwordUTF8[0]) {
     gtk_label_set_markup (GTK_LABEL (dialog->sync_password_details_label),
                           _("<span fgcolor='#e6780b'>Please insert your password</span>"));
-LOG ("[%d] empty password field", __LINE__);
     return;
   }
 
 LOG ("[%d] email: %s", __LINE__, emailUTF8);
 LOG ("[%d] password: %s", __LINE__, passwordUTF8);
 
-  /* TODO: Call /account/login endpoint and handle server response */
+  sync_service = ephy_shell_get_global_sync_service ();
+  ephy_sync_service_stretch (sync_service, emailUTF8, passwordUTF8);
+  login_ok = ephy_sync_service_login (sync_service, &error_code, &error_message);
+
+  if (login_ok == FALSE) {
+    /* Translators: the %s refers to the error message. */
+    gtk_label_set_markup (GTK_LABEL (dialog->sync_extra_details_label),
+                          g_strdup_printf (_("<span fgcolor='#e6780b'>Error: %s</span>"),
+                                           error_message));
+    g_free (error_message);
+    return;
+  }
 
   g_settings_set_string (EPHY_SETTINGS_MAIN,
                          EPHY_PREFS_SYNC_USER,
                          emailUTF8);
   /* Translators: the %s refers to the email of the currently logged in user. */
   gtk_label_set_markup (GTK_LABEL (dialog->sync_logout_details_label),
-                        g_strdup_printf (_("Currently logged in as <b>%s</b>"), emailUTF8));
+                        g_strdup_printf (_("Currently logged in as <b>%s</b>"),
+                                         emailUTF8));
   gtk_container_remove (GTK_CONTAINER (dialog->sync_authenticate_box),
                         dialog->sync_login_grid);
   gtk_box_pack_start (GTK_BOX (dialog->sync_authenticate_box),


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