/soc/2015/jgeboski/facebook: 7c454f51b56b: facebook: handle auth...

James Geboski jgeboski at gmail.com
Mon Jul 27 16:47:06 EDT 2015


Changeset: 7c454f51b56b8d71f4f9ba444c8d60c7848d226e
Author:	 James Geboski <jgeboski at gmail.com>
Date:	 2015-07-27 16:43 -0400
Branch:	 facebook
URL: https://hg.pidgin.im/soc/2015/jgeboski/facebook/rev/7c454f51b56b

Description:

facebook: handle authentication errors

Currently, authentication errors are essentially ignored with ambiguous
error messages. This is due to errors never being fully parsed for the
failure reason. This issue leads to the user being unaware of the cause
as it often breaks long after the password has been changed.

This extends the error parsing as well as refactors some of the error
handling mechanisms.

diffstat:

 libpurple/protocols/facebook/api.c      |  103 ++++++++++++++++++++++++-------
 libpurple/protocols/facebook/api.h      |    3 +-
 libpurple/protocols/facebook/facebook.c |   25 +++----
 3 files changed, 93 insertions(+), 38 deletions(-)

diffs (198 lines):

diff --git a/libpurple/protocols/facebook/api.c b/libpurple/protocols/facebook/api.c
--- a/libpurple/protocols/facebook/api.c
+++ b/libpurple/protocols/facebook/api.c
@@ -306,13 +306,24 @@ fb_api_error_quark(void)
 static gboolean
 fb_api_json_chk(FbApi *api, gconstpointer data, gsize size, JsonNode **node)
 {
+	FbApiError errc = FB_API_ERROR_GENERAL;
 	FbApiPrivate *priv;
-	gboolean success = FALSE;
+	gboolean success = TRUE;
 	gchar *msg = NULL;
+	gchar *str;
 	GError *err = NULL;
 	gint64 code;
+	guint i;
 	JsonNode *root;
 
+	static const gchar *exprs[] = {
+		"$.error.message",
+		"$.error.summary",
+		"$.error_msg",
+		"$.errorCode",
+		"$.failedSend.errorMessage",
+	};
+
 	g_return_val_if_fail(FB_IS_API(api), FALSE);
 	priv = api->priv;
 
@@ -325,37 +336,71 @@ fb_api_json_chk(FbApi *api, gconstpointe
 	root = fb_json_node_new(data, size, &err);
 	FB_API_ERROR_CHK(api, err, return FALSE);
 
-	if (fb_json_node_chk_str(root, "$.error.summary", &msg) ||
-	    fb_json_node_chk_str(root, "$.failedSend.errorMessage", &msg))
+	if (fb_json_node_chk_int(root, "$.error_code", &code) &&
+	    (code == 401))
 	{
-		fb_api_error(api, FB_API_ERROR_GENERAL, "%s", msg);
-	} else if (fb_json_node_chk_int(root, "$.error_code", &code)) {
-		if (!fb_json_node_chk_str(root, "$.error_msg", &msg)) {
-			msg = g_strdup(_("Generic error"));
-		}
+		errc = FB_API_ERROR_AUTH;
+		success = FALSE;
 
-		fb_api_error(api, FB_API_ERROR_GENERAL, "%s", msg);
-	} else if (fb_json_node_chk_str(root, "$.errorCode", &msg)) {
-		if ((g_ascii_strcasecmp(msg, "ERROR_QUEUE_NOT_FOUND") == 0) ||
-		    (g_ascii_strcasecmp(msg, "ERROR_QUEUE_LOST") == 0))
-		{
-			g_free(priv->stoken);
-			priv->stoken = NULL;
-		}
+		g_free(priv->stoken);
+		priv->stoken = NULL;
 
-		fb_api_error(api, FB_API_ERROR_GENERAL, "%s", msg);
-	} else {
-		success = TRUE;
+		g_free(priv->token);
+		priv->token = NULL;
 	}
 
-	if (success && (node != NULL)) {
+	if (fb_json_node_chk_str(root, "$.error.type", &str) &&
+	    (g_ascii_strcasecmp(str, "OAuthException") == 0))
+	{
+		errc = FB_API_ERROR_AUTH;
+		success = FALSE;
+		g_free(str);
+
+		g_free(priv->stoken);
+		priv->stoken = NULL;
+
+		g_free(priv->token);
+		priv->token = NULL;
+
+	}
+
+	if (fb_json_node_chk_str(root, "$.errorCode", &str) && (
+		(g_ascii_strcasecmp(str, "ERROR_QUEUE_NOT_FOUND") == 0) ||
+		(g_ascii_strcasecmp(str, "ERROR_QUEUE_LOST") == 0)))
+	{
+		errc = FB_API_ERROR_AUTH;
+		success = FALSE;
+		g_free(str);
+
+		g_free(priv->stoken);
+		priv->stoken = NULL;
+	}
+
+	for (i = 0; i < G_N_ELEMENTS(exprs); i++) {
+		if (fb_json_node_chk_str(root, exprs[i], &msg)) {
+			success = FALSE;
+			break;
+		}
+	}
+
+	if (!success && (msg == NULL)) {
+		msg = g_strdup(_("Unknown error"));
+	}
+
+	if (msg != NULL) {
+		fb_api_error(api, errc, "%s", msg);
+		json_node_free(root);
+		g_free(msg);
+		return FALSE;
+	}
+
+	if (node != NULL) {
 		*node = root;
 	} else {
 		json_node_free(root);
 	}
 
-	g_free(msg);
-	return success;
+	return TRUE;
 }
 
 static gboolean
@@ -388,11 +433,21 @@ fb_api_http_chk(FbApi *api, PurpleHttpCo
 		              (gint) size, data);
 	}
 
-	if (!fb_http_error_chk(res, &err)) {
+	if ((root == NULL) && fb_http_error_chk(res, &err)) {
+		return TRUE;
+	}
+
+	/* Rudimentary check to prevent wrongful error parsing */
+	if ((size < 2) || (data[0] != '{') || (data[size - 1] != '}')) {
 		FB_API_ERROR_CHK(api, err, return FALSE);
 	}
 
-	return (root == NULL) || fb_api_json_chk(api, data, size, root);
+	if (fb_api_json_chk(api, data, size, root)) {
+		FB_API_ERROR_CHK(api, err, return FALSE);
+		return TRUE;
+	}
+
+	return FALSE;
 }
 
 static PurpleHttpConnection *
diff --git a/libpurple/protocols/facebook/api.h b/libpurple/protocols/facebook/api.h
--- a/libpurple/protocols/facebook/api.h
+++ b/libpurple/protocols/facebook/api.h
@@ -87,7 +87,8 @@ typedef struct _FbApiHttpInfo FbApiHttpI
 
 enum _FbApiError
 {
-	FB_API_ERROR_GENERAL
+	FB_API_ERROR_GENERAL,
+	FB_API_ERROR_AUTH
 };
 
 struct _FbApi
diff --git a/libpurple/protocols/facebook/facebook.c b/libpurple/protocols/facebook/facebook.c
--- a/libpurple/protocols/facebook/facebook.c
+++ b/libpurple/protocols/facebook/facebook.c
@@ -170,23 +170,22 @@ static void
 fb_cb_api_error(FbApi *api, GError *error, gpointer data)
 {
 	FbData *fata = data;
-	gboolean nfatal;
 	PurpleConnection *gc;
-	PurpleConnectionError reason;
+	PurpleConnectionError errc;
 
-	/* Non-fatal errors */
-	nfatal = (error->domain == FB_API_ERROR) ||
-	         (error->domain == FB_MQTT_ERROR);
-
-	/* Non-fatal HTTP errors */
-	nfatal |= (error->domain == FB_HTTP_ERROR) &&
-	          ((error->code < 400) || (error->code > 500));
-
-	reason = (nfatal) ? PURPLE_CONNECTION_ERROR_NETWORK_ERROR
-	                  : PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+	if ((error->domain == FB_HTTP_ERROR) &&
+	    (error->code >= 400) &&
+	    (error->code <= 500))
+	{
+		errc = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+	} else if (g_error_matches(error, FB_API_ERROR, FB_API_ERROR_AUTH)) {
+		errc = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+	} else {
+		errc = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
+	}
 
 	gc = fb_data_get_connection(fata);
-	purple_connection_error(gc, reason, error->message);
+	purple_connection_error(gc, errc, error->message);
 }
 
 static void



More information about the Commits mailing list