pidgin/pidgin

facebook: handle authentication errors
facebook
2015-07-27, James Geboski
7c454f51b56b
Parents f80258f7ce6f
Children e1fa48ad1f89
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.
--- a/libpurple/protocols/facebook/api.c Sun Jul 26 16:51:03 2015 -0400
+++ b/libpurple/protocols/facebook/api.c Mon Jul 27 16:43:41 2015 -0400
@@ -306,13 +306,24 @@
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 @@
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;
+
+ g_free(priv->stoken);
+ priv->stoken = NULL;
+
+ g_free(priv->token);
+ priv->token = NULL;
+ }
- 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;
- }
+ 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);
- fb_api_error(api, FB_API_ERROR_GENERAL, "%s", msg);
- } else {
- success = TRUE;
+ g_free(priv->stoken);
+ priv->stoken = NULL;
+
+ g_free(priv->token);
+ priv->token = NULL;
+
}
- if (success && (node != 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 @@
(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 *
--- a/libpurple/protocols/facebook/api.h Sun Jul 26 16:51:03 2015 -0400
+++ b/libpurple/protocols/facebook/api.h Mon Jul 27 16:43:41 2015 -0400
@@ -87,7 +87,8 @@
enum _FbApiError
{
- FB_API_ERROR_GENERAL
+ FB_API_ERROR_GENERAL,
+ FB_API_ERROR_AUTH
};
struct _FbApi
--- a/libpurple/protocols/facebook/facebook.c Sun Jul 26 16:51:03 2015 -0400
+++ b/libpurple/protocols/facebook/facebook.c Mon Jul 27 16:43:41 2015 -0400
@@ -170,23 +170,22 @@
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