[epiphany/wip/sync-rebase: 11/74] ephy-sync: Implement the new sign in method
- From: Gabriel - Cristian Ivascu <gabrielivascu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany/wip/sync-rebase: 11/74] ephy-sync: Implement the new sign in method
- Date: Thu, 29 Sep 2016 17:43:43 +0000 (UTC)
commit 49cb51504ad84de2342fe5a51a42557329ddb7fb
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date: Fri Jul 15 18:22:23 2016 +0300
ephy-sync: Implement the new sign in method
src/ephy-sync-crypto.c | 145 +++++++---------
src/ephy-sync-crypto.h | 65 ++++----
src/ephy-sync-service.c | 242 +++++++++-----------------
src/ephy-sync-service.h | 19 ++-
src/ephy-sync-utils.c | 15 +--
src/ephy-sync-utils.h | 7 +-
src/prefs-dialog.c | 387 ++++++++++++++++++++++++++---------------
src/resources/prefs-dialog.ui | 169 +++++++------------
8 files changed, 502 insertions(+), 547 deletions(-)
---
diff --git a/src/ephy-sync-crypto.c b/src/ephy-sync-crypto.c
index 01e9b27..37a9743 100644
--- a/src/ephy-sync-crypto.c
+++ b/src/ephy-sync-crypto.c
@@ -21,7 +21,6 @@
#include <libsoup/soup.h>
#include <nettle/hmac.h>
-#include <nettle/pbkdf2.h>
#include <nettle/sha2.h>
#include <string.h>
@@ -96,21 +95,6 @@ ephy_sync_crypto_hawk_header_new (gchar *header,
return hawk_header;
}
-static EphySyncCryptoStretchedCredentials *
-ephy_sync_crypto_stretched_credentials_new (guint8 *quickStretchedPW,
- guint8 *authPW,
- guint8 *unwrapBKey)
-{
- EphySyncCryptoStretchedCredentials *stretched_credentials;
-
- stretched_credentials = g_slice_new (EphySyncCryptoStretchedCredentials);
- stretched_credentials->quickStretchedPW = quickStretchedPW;
- stretched_credentials->authPW = authPW;
- stretched_credentials->unwrapBKey = unwrapBKey;
-
- return stretched_credentials;
-}
-
static EphySyncCryptoProcessedKFT *
ephy_sync_crypto_processed_kft_new (guint8 *tokenID,
guint8 *reqHMACkey,
@@ -128,6 +112,21 @@ ephy_sync_crypto_processed_kft_new (guint8 *tokenID,
return processed_kft;
}
+static EphySyncCryptoProcessedST *
+ephy_sync_crypto_processed_st_new (guint8 *tokenID,
+ guint8 *reqHMACkey,
+ guint8 *requestKey)
+{
+ EphySyncCryptoProcessedST *processed_st;
+
+ processed_st = g_slice_new (EphySyncCryptoProcessedST);
+ processed_st->tokenID = tokenID;
+ processed_st->reqHMACkey = reqHMACkey;
+ processed_st->requestKey = requestKey;
+
+ return processed_st;
+}
+
static EphySyncCryptoSyncKeys *
ephy_sync_crypto_sync_keys_new (guint8 *kA,
guint8 *kB,
@@ -192,18 +191,6 @@ ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader *hawk_header)
}
void
-ephy_sync_crypto_stretched_credentials_free (EphySyncCryptoStretchedCredentials *stretched_credentials)
-{
- g_return_if_fail (stretched_credentials != NULL);
-
- g_free (stretched_credentials->quickStretchedPW);
- g_free (stretched_credentials->authPW);
- g_free (stretched_credentials->unwrapBKey);
-
- g_slice_free (EphySyncCryptoStretchedCredentials, stretched_credentials);
-}
-
-void
ephy_sync_crypto_processed_kft_free (EphySyncCryptoProcessedKFT *processed_kft)
{
g_return_if_fail (processed_kft != NULL);
@@ -217,6 +204,18 @@ ephy_sync_crypto_processed_kft_free (EphySyncCryptoProcessedKFT *processed_kft)
}
void
+ephy_sync_crypto_processed_st_free (EphySyncCryptoProcessedST *processed_st)
+{
+ g_return_if_fail (processed_st != NULL);
+
+ g_free (processed_st->tokenID);
+ g_free (processed_st->reqHMACkey);
+ g_free (processed_st->requestKey);
+
+ g_slice_free (EphySyncCryptoProcessedST, processed_st);
+}
+
+void
ephy_sync_crypto_sync_keys_free (EphySyncCryptoSyncKeys *sync_keys)
{
g_return_if_fail (sync_keys != NULL);
@@ -468,21 +467,6 @@ append_token_to_header (gchar *header,
}
/*
- * Runs 1000 iterations of PBKDF2.
- * Uses sha256 as hash function.
- */
-static void
-pbkdf2_1k (guint8 *key,
- gsize key_length,
- guint8 *salt,
- gsize salt_length,
- guint8 *out,
- gsize out_length)
-{
- pbkdf2_hmac_sha256 (key_length, key, 1000, salt_length, salt, out_length, out);
-}
-
-/*
* HMAC-based Extract-and-Expand Key Derivation Function.
* Uses sha256 as hash function.
* https://tools.ietf.org/html/rfc5869
@@ -540,46 +524,6 @@ hkdf (guint8 *in,
g_free (prk);
}
-EphySyncCryptoStretchedCredentials *
-ephy_sync_crypto_stretch (const gchar *emailUTF8,
- const gchar *passwordUTF8)
-{
- gchar *salt_stretch;
- gchar *info_auth;
- gchar *info_unwrap;
- guint8 *quickStretchedPW;
- guint8 *authPW;
- guint8 *unwrapBKey;
-
- salt_stretch = ephy_sync_utils_kwe ("quickStretch", emailUTF8);
- quickStretchedPW = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- pbkdf2_1k ((guint8 *) passwordUTF8, strlen (passwordUTF8),
- (guint8 *) salt_stretch, strlen (salt_stretch),
- quickStretchedPW, EPHY_SYNC_TOKEN_LENGTH);
-
- info_auth = ephy_sync_utils_kw ("authPW");
- authPW = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- hkdf (quickStretchedPW, EPHY_SYNC_TOKEN_LENGTH,
- NULL, 0,
- (guint8 *) info_auth, strlen (info_auth),
- authPW, EPHY_SYNC_TOKEN_LENGTH);
-
- info_unwrap = ephy_sync_utils_kw ("unwrapBkey");
- unwrapBKey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
- hkdf (quickStretchedPW, EPHY_SYNC_TOKEN_LENGTH,
- NULL, 0,
- (guint8 *) info_unwrap, strlen (info_unwrap),
- unwrapBKey, EPHY_SYNC_TOKEN_LENGTH);
-
- g_free (salt_stretch);
- g_free (info_unwrap);
- g_free (info_auth);
-
- return ephy_sync_crypto_stretched_credentials_new (quickStretchedPW,
- authPW,
- unwrapBKey);
-}
-
EphySyncCryptoProcessedKFT *
ephy_sync_crypto_process_key_fetch_token (const gchar *keyFetchToken)
{
@@ -635,6 +579,41 @@ ephy_sync_crypto_process_key_fetch_token (const gchar *keyFetchToken)
respXORkey);
}
+EphySyncCryptoProcessedST *
+ephy_sync_crypto_process_session_token (const gchar *sessionToken)
+{
+ guint8 *st;
+ guint8 *out;
+ guint8 *tokenID;
+ guint8 *reqHMACkey;
+ guint8 *requestKey;
+ gchar *info;
+
+ st = ephy_sync_utils_decode_hex (sessionToken);
+ info = ephy_sync_utils_kw ("sessionToken");
+ out = g_malloc (3 * EPHY_SYNC_TOKEN_LENGTH);
+
+ hkdf (st, EPHY_SYNC_TOKEN_LENGTH,
+ NULL, 0,
+ (guint8 *) info, strlen (info),
+ out, 3 * EPHY_SYNC_TOKEN_LENGTH);
+
+ tokenID = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ reqHMACkey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ requestKey = g_malloc (EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (tokenID, out, EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (reqHMACkey, out + EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
+ memcpy (requestKey, out + 2 * EPHY_SYNC_TOKEN_LENGTH, EPHY_SYNC_TOKEN_LENGTH);
+
+ g_free (st);
+ g_free (out);
+ g_free (info);
+
+ return ephy_sync_crypto_processed_st_new (tokenID,
+ reqHMACkey,
+ requestKey);
+}
+
EphySyncCryptoSyncKeys *
ephy_sync_crypto_retrieve_sync_keys (const gchar *bundle,
guint8 *respHMACkey,
diff --git a/src/ephy-sync-crypto.h b/src/ephy-sync-crypto.h
index 2e3c789..33846ad 100644
--- a/src/ephy-sync-crypto.h
+++ b/src/ephy-sync-crypto.h
@@ -54,12 +54,6 @@ typedef struct {
} EphySyncCryptoHawkHeader;
typedef struct {
- guint8 *quickStretchedPW;
- guint8 *authPW;
- guint8 *unwrapBKey;
-} EphySyncCryptoStretchedCredentials;
-
-typedef struct {
guint8 *tokenID;
guint8 *reqHMACkey;
guint8 *respHMACkey;
@@ -67,47 +61,52 @@ typedef struct {
} EphySyncCryptoProcessedKFT;
typedef struct {
+ guint8 *tokenID;
+ guint8 *reqHMACkey;
+ guint8 *requestKey;
+} EphySyncCryptoProcessedST;
+
+typedef struct {
guint8 *kA;
guint8 *kB;
guint8 *wrapKB;
} EphySyncCryptoSyncKeys;
-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 *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_options_free (EphySyncCryptoHawkOptions
*hawk_options);
-void ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader
*hawk_header);
+void ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader *hawk_header);
-void ephy_sync_crypto_stretched_credentials_free
(EphySyncCryptoStretchedCredentials *stretched_credentials);
+void ephy_sync_crypto_processed_kft_free (EphySyncCryptoProcessedKFT
*processed_kft);
-void ephy_sync_crypto_processed_kft_free (EphySyncCryptoProcessedKFT
*processed_kft);
+void ephy_sync_crypto_processed_st_free (EphySyncCryptoProcessedST
*processed_st);
-void ephy_sync_crypto_sync_keys_free (EphySyncCryptoSyncKeys
*sync_keys);
+void ephy_sync_crypto_sync_keys_free (EphySyncCryptoSyncKeys *sync_keys);
-EphySyncCryptoStretchedCredentials *ephy_sync_crypto_stretch (const gchar *emailUTF8,
- const gchar *passwordUTF8);
+EphySyncCryptoProcessedKFT *ephy_sync_crypto_process_key_fetch_token (const gchar *keyFetchToken);
-EphySyncCryptoProcessedKFT *ephy_sync_crypto_process_key_fetch_token (const gchar
*keyFetchToken);
+EphySyncCryptoProcessedST *ephy_sync_crypto_process_session_token (const gchar *sessionToken);
-EphySyncCryptoSyncKeys *ephy_sync_crypto_retrieve_sync_keys (const gchar *bundle,
- guint8 *respHMACkey,
- guint8 *respXORkey,
- guint8 *unwrapBKey);
+EphySyncCryptoSyncKeys *ephy_sync_crypto_retrieve_sync_keys (const gchar *bundle,
+ guint8 *respHMACkey,
+ guint8 *respXORkey,
+ guint8 *unwrapBKey);
-EphySyncCryptoHawkHeader *ephy_sync_crypto_compute_hawk_header (const gchar
*url,
- const gchar
*method,
- const gchar
*id,
- guint8
*key,
- gsize
key_length,
- EphySyncCryptoHawkOptions
*options);
+EphySyncCryptoHawkHeader *ephy_sync_crypto_compute_hawk_header (const gchar *url,
+ const gchar *method,
+ const gchar *id,
+ guint8 *key,
+ gsize key_length,
+ EphySyncCryptoHawkOptions *options);
G_END_DECLS
diff --git a/src/ephy-sync-service.c b/src/ephy-sync-service.c
index aa4f4f3..56651e2 100644
--- a/src/ephy-sync-service.c
+++ b/src/ephy-sync-service.c
@@ -43,15 +43,8 @@ struct _EphySyncService {
GHashTable *tokens;
};
-
G_DEFINE_TYPE (EphySyncService, ephy_sync_service, G_TYPE_OBJECT);
-static void
-save_and_store_tokens (EphySyncService *self,
- gchar *token_value,
- EphySyncTokenType token_type,
- ...) G_GNUC_NULL_TERMINATED;
-
static guint
synchronous_hawk_get_request (EphySyncService *self,
const gchar *endpoint,
@@ -77,12 +70,14 @@ LOG ("[%d] Sending synchronous HAWK GET request to %s endpoint", __LINE__, endpo
soup_session_send_message (self->soup_session, message);
LOG ("[%d] Got response from server: %u", __LINE__, message->status_code);
- json_parser_load_from_data (self->parser,
- message->response_body->data,
- -1, NULL);
- root = json_parser_get_root (self->parser);
- g_assert (JSON_NODE_HOLDS_OBJECT (root));
- *jobject = json_node_get_object (root);
+ if (jobject != NULL) {
+ json_parser_load_from_data (self->parser,
+ message->response_body->data,
+ -1, NULL);
+ root = json_parser_get_root (self->parser);
+ g_assert (JSON_NODE_HOLDS_OBJECT (root));
+ *jobject = json_node_get_object (root);
+ }
g_free (url);
ephy_sync_crypto_hawk_header_free (hawk_header);
@@ -129,12 +124,14 @@ LOG ("[%d] Sending synchronous HAWK POST request to %s endpoint", __LINE__, endp
soup_session_send_message (self->soup_session, message);
LOG ("[%d] Got response from server: %u", __LINE__, message->status_code);
- json_parser_load_from_data (self->parser,
- message->response_body->data,
- -1, NULL);
- root = json_parser_get_root (self->parser);
- g_assert (JSON_NODE_HOLDS_OBJECT (root));
- *jobject = json_node_get_object (root);
+ if (jobject != NULL) {
+ json_parser_load_from_data (self->parser,
+ message->response_body->data,
+ -1, NULL);
+ root = json_parser_get_root (self->parser);
+ g_assert (JSON_NODE_HOLDS_OBJECT (root));
+ *jobject = json_node_get_object (root);
+ }
g_free (url);
ephy_sync_crypto_hawk_options_free (hawk_options);
@@ -143,61 +140,6 @@ LOG ("[%d] Got response from server: %u", __LINE__, message->status_code);
return message->status_code;
}
-static guint
-synchronous_fxa_post_request (EphySyncService *self,
- const gchar *endpoint,
- gchar *request_body,
- JsonObject **jobject)
-{
- SoupMessage *message;
- JsonNode *root;
- 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);
-LOG ("[%d] Got response from server: %u", __LINE__, message->status_code);
-
- json_parser_load_from_data (self->parser,
- message->response_body->data,
- -1, NULL);
- root = json_parser_get_root (self->parser);
- g_assert (JSON_NODE_HOLDS_OBJECT (root));
- *jobject = json_node_get_object (root);
-
- g_free (url);
-
- return message->status_code;
-}
-
-static void
-save_and_store_tokens (EphySyncService *self,
- gchar *token_value,
- EphySyncTokenType token_type,
- ...)
-{
- EphySyncTokenType type;
- gchar *value;
- va_list args;
-
- ephy_sync_service_save_token (self, token_value, token_type);
- ephy_sync_secret_store_token (self->user_email, token_value, token_type);
-
- va_start (args, token_type);
- while ((value = va_arg (args, gchar *)) != NULL) {
- type = va_arg (args, EphySyncTokenType);
- ephy_sync_service_save_token (self, value, type);
- ephy_sync_secret_store_token (self->user_email, value, type);
- }
- va_end (args);
-}
-
static void
ephy_sync_service_finalize (GObject *object)
{
@@ -255,10 +197,10 @@ ephy_sync_service_get_user_email (EphySyncService *self)
void
ephy_sync_service_set_user_email (EphySyncService *self,
- const gchar *emailUTF8)
+ const gchar *email)
{
g_free (self->user_email);
- self->user_email = g_strdup (emailUTF8);
+ self->user_email = g_strdup (email);
}
gchar *
@@ -293,15 +235,25 @@ LOG ("[%d] Saved token %s with value %s", __LINE__, token_name, token_value);
}
void
-ephy_sync_service_delete_token (EphySyncService *self,
- EphySyncTokenType token_type)
+ephy_sync_service_save_store_tokens (EphySyncService *self,
+ gchar *token_value,
+ EphySyncTokenType token_type,
+ ...)
{
- const gchar *token_name;
+ EphySyncTokenType type;
+ gchar *value;
+ va_list args;
- token_name = ephy_sync_utils_token_name_from_type (token_type);
- g_hash_table_remove (self->tokens, token_name);
+ ephy_sync_service_save_token (self, token_value, token_type);
+ ephy_sync_secret_store_token (self->user_email, token_value, token_type);
-LOG ("[%d] Deleted token %s", __LINE__, token_name);
+ va_start (args, token_type);
+ while ((value = va_arg (args, gchar *)) != NULL) {
+ type = va_arg (args, EphySyncTokenType);
+ ephy_sync_service_save_token (self, value, type);
+ ephy_sync_secret_store_token (self->user_email, value, type);
+ }
+ va_end (args);
}
void
@@ -313,57 +265,48 @@ LOG ("[%d] Deleted all tokens", __LINE__);
}
gboolean
-ephy_sync_service_login (EphySyncService *self,
- const gchar *emailUTF8,
- const gchar *passwordUTF8,
- gchar **error_message)
+ephy_sync_service_destroy_session (EphySyncService *self,
+ const gchar *sessionToken)
+{
+ EphySyncCryptoProcessedST *processed_st;
+ gchar *tokenID;
+ guint status_code;
+
+ g_return_val_if_fail (sessionToken != NULL, FALSE);
+
+ processed_st = ephy_sync_crypto_process_session_token (sessionToken);
+ tokenID = ephy_sync_utils_encode_hex (processed_st->tokenID, 0);
+
+ /* FIXME: Do this asynchronously, there is no need to wait for this. */
+ status_code = synchronous_hawk_post_request (self,
+ "session/destroy",
+ tokenID,
+ processed_st->reqHMACkey,
+ EPHY_SYNC_TOKEN_LENGTH,
+ g_strdup ("{}"),
+ NULL);
+
+ g_free (tokenID);
+ ephy_sync_crypto_processed_st_free (processed_st);
+
+ return status_code == STATUS_OK;
+}
+
+gboolean
+ephy_sync_service_fetch_sync_keys (EphySyncService *self,
+ const gchar *email,
+ const gchar *keyFetchToken,
+ const gchar *unwrapBKey)
{
- EphySyncCryptoStretchedCredentials *stretched_credentials = NULL;
EphySyncCryptoProcessedKFT *processed_kft = NULL;
EphySyncCryptoSyncKeys *sync_keys = NULL;
JsonObject *jobject;
- gchar *request_body;
- gchar *tokenID = NULL;
- gchar *authPW = NULL;
- gchar *unwrapBKey = NULL;
- gchar *uid = NULL;
- gchar *sessionToken = NULL;
- gchar *keyFetchToken = NULL;
- gchar *kA = NULL;
- gchar *kB = NULL;
- gchar *wrapKB = NULL;
+ guint8 *unwrapKB;
+ gchar *tokenID;
guint status_code;
gboolean retval = FALSE;
- stretched_credentials = ephy_sync_crypto_stretch (emailUTF8, passwordUTF8);
- authPW = ephy_sync_utils_encode_hex (stretched_credentials->authPW, 0);
- request_body = ephy_sync_utils_build_json_string ("authPW", authPW,
- "email", emailUTF8,
- NULL);
- status_code = synchronous_fxa_post_request (self,
- "account/login?keys=true",
- request_body,
- &jobject);
- if (status_code != STATUS_OK) {
- g_warning ("FxA server errno: %ld, errmsg: %s",
- json_object_get_int_member (jobject, "errno"),
- json_object_get_string_member (jobject, "message"));
- *error_message = g_strdup_printf ("%s.",
- json_object_get_string_member (jobject, "message"));
- g_free (authPW);
- goto out;
- } else if (json_object_get_boolean_member (jobject, "verified") == FALSE) {
- g_warning ("Firefox Account not verified");
- *error_message = g_strdup (_("Account not verified!"));
- g_free (authPW);
- goto out;
- }
-
- uid = g_strdup (json_object_get_string_member (jobject, "uid"));
- sessionToken = g_strdup (json_object_get_string_member (jobject, "sessionToken"));
- keyFetchToken = g_strdup (json_object_get_string_member (jobject, "keyFetchToken"));
-
- /* Proceed with key fetching */
+ unwrapKB = ephy_sync_utils_decode_hex (unwrapBKey);
processed_kft = ephy_sync_crypto_process_key_fetch_token (keyFetchToken);
tokenID = ephy_sync_utils_encode_hex (processed_kft->tokenID, 0);
status_code = synchronous_hawk_get_request (self,
@@ -376,52 +319,35 @@ ephy_sync_service_login (EphySyncService *self,
g_warning ("FxA server errno: %ld, errmsg: %s",
json_object_get_int_member (jobject, "errno"),
json_object_get_string_member (jobject, "message"));
- /* Translators: the %s refers to the error message. */
- *error_message = g_strdup_printf (_("Failed to retrieve keys: %s. Please try again."),
- json_object_get_string_member (jobject, "message"));
- g_free (authPW);
- g_free (uid);
- g_free (sessionToken);
- g_free (keyFetchToken);
goto out;
}
sync_keys = ephy_sync_crypto_retrieve_sync_keys (json_object_get_string_member (jobject, "bundle"),
processed_kft->respHMACkey,
processed_kft->respXORkey,
- stretched_credentials->unwrapBKey);
- if (sync_keys == NULL) {
- *error_message = g_strdup (_("Something went wrong, please try again."));
- g_free (authPW);
- g_free (uid);
- g_free (sessionToken);
- g_free (keyFetchToken);
+ unwrapKB);
+
+ if (sync_keys == NULL)
goto out;
- }
- /* Everything okay, save and store tokens */
- ephy_sync_service_set_user_email (self, emailUTF8);
- unwrapBKey = ephy_sync_utils_encode_hex (stretched_credentials->unwrapBKey, 0);
- kA = ephy_sync_utils_encode_hex (sync_keys->kA, 0);
- kB = ephy_sync_utils_encode_hex (sync_keys->kB, 0);
- wrapKB = ephy_sync_utils_encode_hex (sync_keys->wrapKB, 0);
- save_and_store_tokens (self,
- authPW, EPHY_SYNC_TOKEN_AUTHPW,
- unwrapBKey, EPHY_SYNC_TOKEN_UNWRAPBKEY,
- uid, EPHY_SYNC_TOKEN_UID,
- sessionToken, EPHY_SYNC_TOKEN_SESSIONTOKEN,
- keyFetchToken, EPHY_SYNC_TOKEN_KEYFETCHTOKEN,
- kA, EPHY_SYNC_TOKEN_KA,
- kB, EPHY_SYNC_TOKEN_KB,
- wrapKB, EPHY_SYNC_TOKEN_WRAPKB,
- NULL);
+ /* Everything is okay, save the tokens. */
+ ephy_sync_service_set_user_email (self, email);
+ ephy_sync_service_save_store_tokens (self,
+ g_strdup (keyFetchToken), EPHY_SYNC_TOKEN_KEYFETCHTOKEN,
+ g_strdup (unwrapBKey), EPHY_SYNC_TOKEN_UNWRAPBKEY,
+ ephy_sync_utils_encode_hex (sync_keys->kA, 0), EPHY_SYNC_TOKEN_KA,
+ ephy_sync_utils_encode_hex (sync_keys->kB, 0), EPHY_SYNC_TOKEN_KB,
+ NULL);
retval = TRUE;
+LOG ("kA: %s", ephy_sync_utils_encode_hex (sync_keys->kA, 0));
+LOG ("kB: %s", ephy_sync_utils_encode_hex (sync_keys->kB, 0));
+
out:
- ephy_sync_crypto_stretched_credentials_free (stretched_credentials);
ephy_sync_crypto_processed_kft_free (processed_kft);
ephy_sync_crypto_sync_keys_free (sync_keys);
g_free (tokenID);
+ g_free (unwrapKB);
return retval;
}
diff --git a/src/ephy-sync-service.h b/src/ephy-sync-service.h
index ffe63eb..9bc1a95 100644
--- a/src/ephy-sync-service.h
+++ b/src/ephy-sync-service.h
@@ -34,7 +34,7 @@ EphySyncService *ephy_sync_service_new (void);
gchar *ephy_sync_service_get_user_email (EphySyncService *self);
void ephy_sync_service_set_user_email (EphySyncService *self,
- const gchar *emailUTF8);
+ const gchar *email);
gchar *ephy_sync_service_get_token (EphySyncService *self,
EphySyncTokenType token_type);
@@ -43,15 +43,20 @@ void ephy_sync_service_save_token (EphySyncService *self,
gchar *token_value,
EphySyncTokenType token_type);
-void ephy_sync_service_delete_token (EphySyncService *self,
- EphySyncTokenType token_type);
+void ephy_sync_service_save_store_tokens (EphySyncService *self,
+ gchar *token_value,
+ EphySyncTokenType token_type,
+ ...) G_GNUC_NULL_TERMINATED;
void ephy_sync_service_delete_all_tokens (EphySyncService *self);
-gboolean ephy_sync_service_login (EphySyncService *self,
- const gchar *emailUTF8,
- const gchar *passwordUTF8,
- gchar **error_message);
+gboolean ephy_sync_service_destroy_session (EphySyncService *self,
+ const gchar *sessionToken);
+
+gboolean ephy_sync_service_fetch_sync_keys (EphySyncService *self,
+ const gchar *email,
+ const gchar *keyFetchToken,
+ const gchar *unwrapBKey);
G_END_DECLS
diff --git a/src/ephy-sync-utils.c b/src/ephy-sync-utils.c
index 784b78e..d6b4425 100644
--- a/src/ephy-sync-utils.c
+++ b/src/ephy-sync-utils.c
@@ -31,13 +31,6 @@ ephy_sync_utils_kw (const gchar *name)
}
gchar *
-ephy_sync_utils_kwe (const gchar *name,
- const gchar *emailUTF8)
-{
- return g_strconcat ("identity.mozilla.com/picl/v1/", name, ":", emailUTF8, NULL);
-}
-
-gchar *
ephy_sync_utils_encode_hex (guint8 *data,
gsize data_length)
{
@@ -81,22 +74,18 @@ const gchar *
ephy_sync_utils_token_name_from_type (EphySyncTokenType token_type)
{
switch (token_type) {
- case EPHY_SYNC_TOKEN_AUTHPW:
- return "authPW";
- case EPHY_SYNC_TOKEN_UNWRAPBKEY:
- return "unwrapBKey";
case EPHY_SYNC_TOKEN_UID:
return "uid";
case EPHY_SYNC_TOKEN_SESSIONTOKEN:
return "sessionToken";
case EPHY_SYNC_TOKEN_KEYFETCHTOKEN:
return "keyFetchToken";
+ case EPHY_SYNC_TOKEN_UNWRAPBKEY:
+ return "unwrapBKey";
case EPHY_SYNC_TOKEN_KA:
return "kA";
case EPHY_SYNC_TOKEN_KB:
return "kB";
- case EPHY_SYNC_TOKEN_WRAPKB:
- return "wrapKB";
default:
g_assert_not_reached ();
}
diff --git a/src/ephy-sync-utils.h b/src/ephy-sync-utils.h
index a0ee2ec..501437f 100644
--- a/src/ephy-sync-utils.h
+++ b/src/ephy-sync-utils.h
@@ -26,21 +26,16 @@ G_BEGIN_DECLS
#define EPHY_SYNC_TOKEN_LENGTH 32
typedef enum {
- EPHY_SYNC_TOKEN_AUTHPW,
- EPHY_SYNC_TOKEN_UNWRAPBKEY,
EPHY_SYNC_TOKEN_UID,
EPHY_SYNC_TOKEN_SESSIONTOKEN,
EPHY_SYNC_TOKEN_KEYFETCHTOKEN,
+ EPHY_SYNC_TOKEN_UNWRAPBKEY,
EPHY_SYNC_TOKEN_KA,
EPHY_SYNC_TOKEN_KB,
- EPHY_SYNC_TOKEN_WRAPKB
} EphySyncTokenType;
gchar *ephy_sync_utils_kw (const gchar *name);
-gchar *ephy_sync_utils_kwe (const gchar *name,
- const gchar *emailUTF8);
-
gchar *ephy_sync_utils_encode_hex (guint8 *data,
gsize data_length);
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
index 633e809..33465f2 100644
--- a/src/prefs-dialog.c
+++ b/src/prefs-dialog.c
@@ -43,10 +43,20 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
+#include <JavaScriptCore/JavaScript.h>
+#include <json-glib/json-glib.h>
#include <string.h>
#define DOWNLOAD_BUTTON_WIDTH 8
+static const gchar *fxa_url = "https://accounts.firefox.com/signin?service=sync&context=fx_ios_v1";
+static const gchar *JSScript = "\"use strict\";"
+ "function handleAccountsCommand(evt) {"
+ " let j = {type: evt.type, detail: evt.detail};"
+ "
window.webkit.messageHandlers.accountsCommandHandler.postMessage(JSON.stringify(j));"
+ "};"
+ "window.addEventListener(\"FirefoxAccountsCommand\", handleAccountsCommand);";
+
enum {
COL_LANG_NAME,
COL_LANG_CODE
@@ -98,18 +108,16 @@ struct _PrefsDialog {
GHashTable *iso_3166_table;
/* sync */
- GtkWidget *sync_top_box;
GtkWidget *sync_authenticate_box;
- GtkWidget *sync_login_grid;
- GtkWidget *sync_logout_box;
- GtkWidget *sync_email_entry;
- GtkWidget *sync_password_entry;
- GtkWidget *sync_login_button;
- GtkWidget *sync_logout_button;
- GtkWidget *sync_logout_details_label;
- GtkWidget *sync_email_details_label;
- GtkWidget *sync_password_details_label;
- GtkWidget *sync_extra_details_label;
+ GtkWidget *sync_sign_in_box;
+ GtkWidget *sync_sign_in_details;
+ GtkWidget *sync_sign_out_box;
+ GtkWidget *sync_sign_out_details;
+ GtkWidget *sync_sign_out_button;
+
+ WebKitWebView *fxa_web_view;
+ WebKitUserContentManager *fxa_manager;
+ WebKitUserScript *fxa_script;
};
enum {
@@ -137,121 +145,257 @@ prefs_dialog_finalize (GObject *object)
g_hash_table_destroy (dialog->iso_639_table);
g_hash_table_destroy (dialog->iso_3166_table);
+ if (dialog->fxa_web_view != NULL) {
+ webkit_user_content_manager_unregister_script_message_handler (dialog->fxa_manager,
+ "accountsCommandHandler");
+ webkit_user_script_unref (dialog->fxa_script);
+ }
+
G_OBJECT_CLASS (prefs_dialog_parent_class)->finalize (object);
}
static void
-on_manage_cookies_button_clicked (GtkWidget *button,
- PrefsDialog *dialog)
+inject_data_to_server (PrefsDialog *dialog,
+ const gchar *type,
+ const gchar *status,
+ const gchar *data)
{
- EphyCookiesDialog *cookies_dialog;
+ gchar *json;
+ gchar *script;
- cookies_dialog = ephy_cookies_dialog_new ();
+ if (data == NULL)
+ json = g_strdup_printf ("{'type': '%s', 'content': {'status': '%s'}}",
+ type, status);
+ else
+ json = g_strdup_printf ("{'type': '%s', 'content': {'status': '%s', 'data': %s}}",
+ type, status, data);
- gtk_window_set_transient_for (GTK_WINDOW (cookies_dialog), GTK_WINDOW (dialog));
- gtk_window_set_modal (GTK_WINDOW (cookies_dialog), TRUE);
- gtk_window_present (GTK_WINDOW (cookies_dialog));
+ script = g_strdup_printf ("window.postMessage(%s, '%s');", json, fxa_url);
+
+ /* No callback, we don't expect any response from the server. */
+ webkit_web_view_run_javascript (dialog->fxa_web_view,
+ script,
+ NULL, NULL, NULL);
+
+ g_free (json);
+ g_free (script);
}
-static void
-on_manage_passwords_button_clicked (GtkWidget *button,
- PrefsDialog *dialog)
+static gboolean
+sync_fxa_load_sign_in_url (PrefsDialog *dialog)
{
- EphyPasswordsDialog *passwords_dialog;
-
- passwords_dialog = ephy_passwords_dialog_new ();
+ webkit_web_view_load_uri (dialog->fxa_web_view, fxa_url);
- gtk_window_set_transient_for (GTK_WINDOW (passwords_dialog), GTK_WINDOW (dialog));
- gtk_window_set_modal (GTK_WINDOW (passwords_dialog), TRUE);
- gtk_window_present (GTK_WINDOW (passwords_dialog));
+ return G_SOURCE_REMOVE;
}
static void
-on_sync_login_button_clicked (GtkWidget *button,
- PrefsDialog *dialog)
+server_message_received_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *result,
+ PrefsDialog *dialog)
{
- EphySyncService *sync_service;
- const gchar *emailUTF8;
- const gchar *passwordUTF8;
- gboolean login_ok;
- gchar *error_message = 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));
-
- if (emailUTF8 && !emailUTF8[0]) {
- gtk_label_set_markup (GTK_LABEL (dialog->sync_email_details_label),
- _("<span fgcolor='#e6780b'>Please insert your email</span>"));
- return;
+ EphySyncService *service;
+ GError *error = NULL;
+ JsonParser *parser;
+ JsonNode *root;
+ JsonObject *object;
+ JsonObject *detail;
+ JsonObject *data;
+ gchar *json_string;
+ const gchar *type;
+ const gchar *command;
+ const gchar *uid;
+ const gchar *email;
+ const gchar *sessionToken;
+ const gchar *keyFetchToken;
+ const gchar *unwrapBKey;
+ gboolean verified;
+
+ json_string = ephy_embed_utils_get_js_result_as_string (result);
+ parser = json_parser_new ();
+
+ if (json_parser_load_from_data (parser, json_string, -1, &error) == FALSE) {
+ g_warning ("Error loading JSON: %s", error->message);
+ g_error_free (error);
+ goto out;
}
- if (passwordUTF8 && !passwordUTF8[0]) {
- gtk_label_set_markup (GTK_LABEL (dialog->sync_password_details_label),
- _("<span fgcolor='#e6780b'>Please insert your password</span>"));
- return;
+ root = json_parser_get_root (parser);
+ object = json_node_get_object (root);
+ type = json_object_get_string_member (object, "type");
+
+ /* The only message type we can receive is FirefoxAccountsCommand. */
+ if (g_str_equal (type, "FirefoxAccountsCommand") == FALSE) {
+ g_warning ("Unknown command type: %s", type);
+ goto out;
}
-LOG ("[%d] email: %s", __LINE__, emailUTF8);
-LOG ("[%d] password: %s", __LINE__, passwordUTF8);
-
- sync_service = ephy_shell_get_global_sync_service ();
- login_ok = ephy_sync_service_login (sync_service,
- emailUTF8,
- passwordUTF8,
- &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;
+ detail = json_object_get_object_member (object, "detail");
+ command = json_object_get_string_member (detail, "command");
+
+ if (g_str_equal (command, "loaded")) {
+ LOG ("Loaded Firefox Sign In iframe");
+ } else if (g_str_equal (command, "can_link_account")) {
+ /* We need to confirm a relink. */
+ inject_data_to_server (dialog, "message", "can_link_account", "{'ok': true}");
+ } else if (g_str_equal (command, "login")) {
+ inject_data_to_server (dialog, "message", "login", NULL);
+ gtk_widget_set_visible (dialog->sync_sign_in_details, FALSE);
+
+ service = ephy_shell_get_global_sync_service ();
+
+ /* Extract tokens. */
+ data = json_object_get_object_member (detail, "data");
+ verified = json_object_get_boolean_member (data, "verified");
+ email = json_object_get_string_member (data, "email");
+ uid = json_object_get_string_member (data, "uid");
+ sessionToken = json_object_get_string_member (data, "sessionToken");
+ keyFetchToken = json_object_get_string_member (data, "keyFetchToken");
+ unwrapBKey = json_object_get_string_member (data, "unwrapBKey");
+
+ /* Cannot retrieve the sync keys without keyFetchToken or unwrapBKey. */
+ if (keyFetchToken == NULL || unwrapBKey == NULL) {
+ g_warning ("Ignoring login with keyFetchToken or unwrapBKey missing!"
+ "Cannot retrieve sync keys with one of them missing.");
+ ephy_sync_service_destroy_session (service, sessionToken);
+ gtk_label_set_markup (GTK_LABEL (dialog->sync_sign_in_details),
+ _("<span fgcolor='#e6780b'>Something went wrong, please try again.</span>"));
+ gtk_widget_set_visible (dialog->sync_sign_in_details, TRUE);
+ g_timeout_add_seconds (3, (GSourceFunc) sync_fxa_load_sign_in_url, dialog);
+ goto out;
+ }
+
+ /* Cannot retrieve the sync keys if account is not verified. */
+ if (verified == FALSE) {
+ g_warning ("Attempt to operate on an unverified account, giving up.");
+ ephy_sync_service_destroy_session (service, sessionToken);
+ gtk_label_set_markup (GTK_LABEL (dialog->sync_sign_in_details),
+ _("<span fgcolor='#e6780b'>Please verify your account before you sign
in.</span>"));
+ gtk_widget_set_visible (dialog->sync_sign_in_details, TRUE);
+ g_timeout_add_seconds (3, (GSourceFunc) sync_fxa_load_sign_in_url, dialog);
+ goto out;
+ }
+
+ /* We cannot sync without the sync keys. */
+ if (ephy_sync_service_fetch_sync_keys (service, email, keyFetchToken, unwrapBKey) == FALSE) {
+ g_warning ("Failed to retrieve the sync keys, giving up.");
+ ephy_sync_service_destroy_session (service, sessionToken);
+ gtk_label_set_markup (GTK_LABEL (dialog->sync_sign_in_details),
+ _("<span fgcolor='#e6780b'>Something went wrong, please try again.</span>"));
+ gtk_widget_set_visible (dialog->sync_sign_in_details, TRUE);
+ g_timeout_add_seconds (3, (GSourceFunc) sync_fxa_load_sign_in_url, dialog);
+ goto out;
+ }
+
+ /* Everything is okay, save the tokens. */
+ g_settings_set_string (EPHY_SETTINGS_MAIN, EPHY_PREFS_SYNC_USER, email);
+ ephy_sync_service_save_store_tokens (service,
+ g_strdup (uid), EPHY_SYNC_TOKEN_UID,
+ g_strdup (sessionToken), EPHY_SYNC_TOKEN_SESSIONTOKEN,
+ NULL);
+
+ /* 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));
+ gtk_container_remove (GTK_CONTAINER (dialog->sync_authenticate_box),
+ dialog->sync_sign_in_box);
+ gtk_box_pack_start (GTK_BOX (dialog->sync_authenticate_box),
+ dialog->sync_sign_out_box,
+ TRUE, TRUE, 0);
+ } else if (g_str_equal (command, "session_status")) {
+ /* We are not signed in at this time, which we signal by returning an error. */
+ inject_data_to_server (dialog, "message", "error", NULL);
+ } else if (g_str_equal (command, "sign_out")) {
+ /* We are not signed in at this time. We should never get a sign out message! */
+ inject_data_to_server (dialog, "message", "error", NULL);
}
- 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));
- gtk_container_remove (GTK_CONTAINER (dialog->sync_authenticate_box),
- dialog->sync_login_grid);
- gtk_box_pack_start (GTK_BOX (dialog->sync_authenticate_box),
- dialog->sync_logout_box,
- TRUE, TRUE, 0);
+out:
+ g_free (json_string);
+ g_object_unref (parser);
}
static void
-on_sync_logout_button_clicked (GtkWidget *button,
- PrefsDialog *dialog)
+setup_fxa_sign_in_view (PrefsDialog *dialog)
{
- EphySyncService *sync_service;
+ dialog->fxa_script = webkit_user_script_new (JSScript,
+ WEBKIT_USER_CONTENT_INJECT_TOP_FRAME,
+ WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END,
+ NULL, NULL);
+ dialog->fxa_manager = webkit_user_content_manager_new ();
+ webkit_user_content_manager_add_script (dialog->fxa_manager, dialog->fxa_script);
+ g_signal_connect (dialog->fxa_manager,
+ "script-message-received::accountsCommandHandler",
+ G_CALLBACK (server_message_received_cb),
+ dialog);
+ webkit_user_content_manager_register_script_message_handler (dialog->fxa_manager,
+ "accountsCommandHandler");
- sync_service = ephy_shell_get_global_sync_service ();
+ dialog->fxa_web_view = WEBKIT_WEB_VIEW (webkit_web_view_new_with_user_content_manager
(dialog->fxa_manager));
+ gtk_widget_set_visible (GTK_WIDGET (dialog->fxa_web_view), TRUE);
+ gtk_widget_set_size_request (GTK_WIDGET (dialog->fxa_web_view), 450, 450);
+ webkit_web_view_load_uri (dialog->fxa_web_view, fxa_url);
- gtk_entry_set_text (GTK_ENTRY (dialog->sync_email_entry), "");
- gtk_entry_set_text (GTK_ENTRY (dialog->sync_password_entry), "");
+ gtk_widget_set_visible (dialog->sync_sign_in_details, FALSE);
+ gtk_container_add (GTK_CONTAINER (dialog->sync_sign_in_box),
+ GTK_WIDGET (dialog->fxa_web_view));
+}
+
+static void
+on_sync_sign_out_button_clicked (GtkWidget *button,
+ PrefsDialog *dialog)
+{
+ EphySyncService *service;
+ gchar *sessionToken;
+
+ service = ephy_shell_get_global_sync_service ();
+ sessionToken = ephy_sync_service_get_token (service, EPHY_SYNC_TOKEN_SESSIONTOKEN);
- /* TODO: Call session/destroy endpoint */
+ /* Destroy session and delete tokens. */
+ if (ephy_sync_service_destroy_session (service, sessionToken) == FALSE)
+ g_warning ("Failed to destroy session");
- ephy_sync_service_delete_all_tokens (sync_service);
+ ephy_sync_service_delete_all_tokens (service);
ephy_sync_secret_forget_all_tokens ();
+ g_settings_set_string (EPHY_SETTINGS_MAIN, EPHY_PREFS_SYNC_USER, "");
+
+ /* Show sign in box. */
+ if (dialog->fxa_web_view == NULL)
+ setup_fxa_sign_in_view (dialog);
+ else
+ webkit_web_view_load_uri (dialog->fxa_web_view, fxa_url);
- g_settings_set_string (EPHY_SETTINGS_MAIN,
- EPHY_PREFS_SYNC_USER,
- "");
gtk_container_remove (GTK_CONTAINER (dialog->sync_authenticate_box),
- dialog->sync_logout_box);
+ dialog->sync_sign_out_box);
gtk_box_pack_start (GTK_BOX (dialog->sync_authenticate_box),
- dialog->sync_login_grid,
+ dialog->sync_sign_in_box,
TRUE, TRUE, 0);
-LOG ("[%d] logged out", __LINE__);
+}
+
+static void
+on_manage_cookies_button_clicked (GtkWidget *button,
+ PrefsDialog *dialog)
+{
+ EphyCookiesDialog *cookies_dialog;
+
+ cookies_dialog = ephy_cookies_dialog_new ();
+
+ gtk_window_set_transient_for (GTK_WINDOW (cookies_dialog), GTK_WINDOW (dialog));
+ gtk_window_set_modal (GTK_WINDOW (cookies_dialog), TRUE);
+ gtk_window_present (GTK_WINDOW (cookies_dialog));
+}
+
+static void
+on_manage_passwords_button_clicked (GtkWidget *button,
+ PrefsDialog *dialog)
+{
+ EphyPasswordsDialog *passwords_dialog;
+
+ passwords_dialog = ephy_passwords_dialog_new ();
+
+ gtk_window_set_transient_for (GTK_WINDOW (passwords_dialog), GTK_WINDOW (dialog));
+ gtk_window_set_modal (GTK_WINDOW (passwords_dialog), TRUE);
+ gtk_window_present (GTK_WINDOW (passwords_dialog));
}
static void
@@ -300,23 +444,16 @@ prefs_dialog_class_init (PrefsDialogClass *klass)
gtk_widget_class_bind_template_child (widget_class, PrefsDialog, enable_spell_checking_checkbutton);
/* sync */
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_top_box);
gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_authenticate_box);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_login_grid);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_logout_box);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_email_entry);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_password_entry);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_login_button);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_logout_button);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_logout_details_label);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_email_details_label);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_password_details_label);
- gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_extra_details_label);
+ gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_sign_in_box);
+ gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_sign_in_details);
+ gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_sign_out_box);
+ gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_sign_out_details);
+ gtk_widget_class_bind_template_child (widget_class, PrefsDialog, sync_sign_out_button);
gtk_widget_class_bind_template_callback (widget_class, on_manage_cookies_button_clicked);
gtk_widget_class_bind_template_callback (widget_class, on_manage_passwords_button_clicked);
- gtk_widget_class_bind_template_callback (widget_class, on_sync_login_button_clicked);
- gtk_widget_class_bind_template_callback (widget_class, on_sync_logout_button_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, on_sync_sign_out_button_clicked);
}
static void
@@ -1309,48 +1446,22 @@ setup_language_page (PrefsDialog *dialog)
static void
setup_sync_page (PrefsDialog *dialog)
{
- GtkWidget *sync_main_label;
- GtkWidget *sync_secondary_label;
gchar *sync_user = NULL;
gboolean logged_in;
- sync_main_label = gtk_label_new (NULL);
- gtk_widget_set_visible (sync_main_label, TRUE);
- gtk_widget_set_halign (sync_main_label, GTK_ALIGN_START);
- gtk_label_set_markup (GTK_LABEL (sync_main_label),
- _("Log in with your "
- "<a href=\"https://www.mozilla.org/en-US/firefox/accounts/\" "
- "title=\"Get a Firefox Account\">Firefox Account</a> "
- "and have your data synced across all your devices.\n"));
-
- sync_secondary_label = gtk_label_new (NULL);
- gtk_widget_set_visible (sync_secondary_label, TRUE);
- gtk_widget_set_halign (sync_secondary_label, GTK_ALIGN_START);
- gtk_label_set_markup (GTK_LABEL (sync_secondary_label),
- _("Note that you must own an <b>already verified account</b> "
- "to be able to login."));
-
- gtk_box_pack_start (GTK_BOX (dialog->sync_top_box),
- sync_main_label,
- TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (dialog->sync_top_box),
- sync_secondary_label,
- TRUE, TRUE, 0);
-
sync_user = g_settings_get_string (EPHY_SETTINGS_MAIN, EPHY_PREFS_SYNC_USER);
logged_in = sync_user && sync_user[0];
- if (logged_in) {
-LOG ("[%d] Setup sync page, already logged in as %s", __LINE__, sync_user);
+ if (logged_in == FALSE) {
+ setup_fxa_sign_in_view (dialog);
gtk_container_remove (GTK_CONTAINER (dialog->sync_authenticate_box),
- dialog->sync_login_grid);
- /* 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>"), sync_user));
+ dialog->sync_sign_out_box);
} else {
-LOG ("[%d] Setup sync page, not logged in", __LINE__);
gtk_container_remove (GTK_CONTAINER (dialog->sync_authenticate_box),
- dialog->sync_logout_box);
+ 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>"), sync_user));
}
}
diff --git a/src/resources/prefs-dialog.ui b/src/resources/prefs-dialog.ui
index b035cbf..e0ab0de 100644
--- a/src/resources/prefs-dialog.ui
+++ b/src/resources/prefs-dialog.ui
@@ -762,8 +762,24 @@
<object class="GtkBox" id="sync_top_box">
<property name="visible">True</property>
<property name="orientation">vertical</property>
- <property name="spacing">0</property>
<property name="margin-start">12</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="use-markup">True</property>
+ <property name="label" translatable="yes">Sign in with your <b>Firefox
Account</b> and have your data synced across all your devices.</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="use-markup">True</property>
+ <property name="label" translatable="yes">Note that you must own an already
<b>verified</b> account to be able to login.</property>
+ </object>
+ </child>
</object>
</child>
</object>
@@ -776,7 +792,7 @@
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
- <object class="GtkBox" id="sync_authenticate_box">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
@@ -791,122 +807,57 @@
</object>
</child>
<child>
- <object class="GtkGrid" id="sync_login_grid">
- <property name="visible">True</property>
- <property name="margin-start">12</property>
- <property name="row-spacing">6</property>
- <property name="column-spacing">12</property>
- <child>
- <object class="GtkEntry" id="sync_email_entry">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="max-length">80</property>
- <property name="width_request">230</property>
- <property name="activates-default">True</property>
- <property name="placeholder-text">Email</property>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="sync_email_details_label">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="use-markup">True</property>
- <property name="label" translatable="yes"></property>
- </object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="sync_password_entry">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="max-length">80</property>
- <property name="width_request">230</property>
- <property name="activates-default">True</property>
- <property name="visibility">False</property>
- <property name="caps-lock-warning">True</property>
- <property name="placeholder-text">Password</property>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="sync_password_details_label">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="use-markup">True</property>
- <property name="label" translatable="yes"></property>
- </object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="sync_login_button">
- <property name="label" translatable="yes">_Login</property>
- <property name="visible">True</property>
- <property name="use-underline">True</property>
- <property name="halign">start</property>
- <property name="width-request">100</property>
- <signal name="clicked" handler="on_sync_login_button_clicked"/>
- <style>
- <class name="suggested-action"/>
- <class name="text-button"/>
- </style>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="sync_extra_details_label">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="use-markup">True</property>
- <property name="label" translatable="yes"></property>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">3</property>
- </packing>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkBox" id="sync_logout_box">
+ <object class="GtkBox" id="sync_authenticate_box">
<property name="visible">True</property>
<property name="orientation">vertical</property>
- <property name="spacing">12</property>
<property name="margin-start">12</property>
<child>
- <object class="GtkLabel" id="sync_logout_details_label">
+ <object class="GtkBox" id="sync_sign_in_box">
<property name="visible">True</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes"></property>
+ <property name="orientation">vertical</property>
+ <property name="halign">center</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="sync_sign_in_details">
+ <property name="visible">False</property>
+ <property name="halign">start</property>
+ </object>
+ </child>
</object>
</child>
<child>
- <object class="GtkButton" id="sync_logout_button">
- <property name="label" translatable="yes">Lo_gout</property>
+ <object class="GtkBox" id="sync_sign_out_box">
<property name="visible">True</property>
- <property name="use-underline">True</property>
- <property name="halign">start</property>
- <property name="width-request">100</property>
- <signal name="clicked" handler="on_sync_logout_button_clicked"/>
- <style>
- <class name="destructive-action"/>
- <class name="text-button"/>
- </style>
+ <property name="orientation">vertical</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkLabel" id="sync_sign_out_details">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes"></property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Sign out if you wish to stop
syncing data.</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="sync_sign_out_button">
+ <property name="label" translatable="yes">Sign _out</property>
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ <property name="halign">start</property>
+ <property name="width-request">100</property>
+ <signal name="clicked" handler="on_sync_sign_out_button_clicked"/>
+ <style>
+ <class name="destructive-action"/>
+ <class name="text-button"/>
+ </style>
+ </object>
+ </child>
</object>
</child>
</object>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]