diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2013-05-25 11:36:34 +0100 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2013-05-25 11:36:34 +0100 |
commit | c1538088cc9d9a0bb573fcf4a31248acd26254e2 (patch) | |
tree | da9658c6eafa99fbb6e4e4cf3b2f042c952e8327 | |
parent | be9f3f1b0e84c358d93291ea5d4f91580cbd1ec5 (diff) |
Fix OAuth2 error reporting.
-rw-r--r-- | lib/oauth2.c | 75 | ||||
-rw-r--r-- | lib/oauth2.h | 5 | ||||
-rw-r--r-- | protocols/jabber/sasl.c | 6 |
3 files changed, 65 insertions, 21 deletions
diff --git a/lib/oauth2.c b/lib/oauth2.c index 6921a6d5..69ce9d58 100644 --- a/lib/oauth2.c +++ b/lib/oauth2.c @@ -1,9 +1,9 @@ /***************************************************************************\ * * * BitlBee - An IRC to IM gateway * -* Simple OAuth client (consumer) implementation. * +* Simple OAuth2 client (consumer) implementation. * * * -* Copyright 2010-2012 Wilmer van der Gaast <wilmer@gaast.net> * +* Copyright 2010-2013 Wilmer van der Gaast <wilmer@gaast.net> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -21,11 +21,28 @@ * * \***************************************************************************/ +/* Out of protest, I should rename this file. OAuth2 is a pathetic joke, and + of all things, DEFINITELY NOT A STANDARD. The only thing various OAuth2 + implementations have in common is that name, wrongfully stolen from + a pretty nice standard called OAuth 1.0a. That, and the fact that they + use JSON. Wait, no, Facebook's version doesn't use JSON. For some of its + responses. + + Apparently too many people were too retarded to comprehend the elementary + bits of crypto in OAuth 1.0a (took me one afternoon to implement) so + the standard was replaced with what comes down to a complicated scheme + around what's really just application-specific passwords. + + And then a bunch of mostly incompatible implementations. Great work, guys. + + http://hueniverse.com/2012/07/oauth-2-0-and-the-road-to-hell/ */ + #include <glib.h> #include "http_client.h" #include "oauth2.h" #include "oauth.h" #include "json.h" +#include "json_util.h" #include "url.h" char *oauth2_url( const struct oauth2_service *sp ) @@ -98,10 +115,35 @@ int oauth2_access_token( const struct oauth2_service *sp, return req != NULL; } +static char* oauth2_parse_error( json_value *e ) +{ + /* This does a reasonable job with some of the flavours of error + responses I've seen. Because apparently it's not standardised. */ + + if( e->type == json_object ) + { + /* Facebook style */ + const char *msg = json_o_str( e, "message" ); + const char *type = json_o_str( e, "type" ); + json_value *code_o = json_o_get( e, "code" ); + int code = 0; + + if( code_o && code_o->type == json_integer ) + code = code_o->u.integer; + + return g_strdup_printf( "Error %d: %s", code, msg ? msg : type ? type : "Unknown error" ); + } + else if( e->type == json_string ) + { + return g_strdup( e->u.string.ptr ); + } + return NULL; +} + static void oauth2_access_token_done( struct http_request *req ) { struct oauth2_access_token_data *cb_data = req->data; - char *atoken = NULL, *rtoken = NULL; + char *atoken = NULL, *rtoken = NULL, *error = NULL; char *content_type; if( getenv( "BITLBEE_DEBUG" ) && req->reply_body ) @@ -109,24 +151,22 @@ static void oauth2_access_token_done( struct http_request *req ) content_type = get_rfc822_header( req->reply_headers, "Content-Type", 0 ); - if( req->status_code != 200 ) - { - } - else if( content_type && strstr( content_type, "application/json" ) ) + if( content_type && ( strstr( content_type, "application/json" ) || + strstr( content_type, "text/javascript" ) ) ) { json_value *js = json_parse( req->reply_body ); if( js && js->type == json_object ) { - int i; - - for( i = 0; i < js->u.object.length; i ++ ) + JSON_O_FOREACH( js, k, v ) { - if( js->u.object.values[i].value->type != json_string ) + if( strcmp( k, "error" ) == 0 ) + error = oauth2_parse_error( v ); + if( v->type != json_string ) continue; - if( strcmp( js->u.object.values[i].name, "access_token" ) == 0 ) - atoken = g_strdup( js->u.object.values[i].value->u.string.ptr ); - if( strcmp( js->u.object.values[i].name, "refresh_token" ) == 0 ) - rtoken = g_strdup( js->u.object.values[i].value->u.string.ptr ); + if( strcmp( k, "access_token" ) == 0 ) + atoken = g_strdup( v->u.string.ptr ); + if( strcmp( k, "refresh_token" ) == 0 ) + rtoken = g_strdup( v->u.string.ptr ); } } json_value_free( js ); @@ -143,10 +183,13 @@ static void oauth2_access_token_done( struct http_request *req ) } if( getenv( "BITLBEE_DEBUG" ) ) printf( "Extracted atoken=%s rtoken=%s\n", atoken, rtoken ); + if( !atoken && !rtoken && !error ) + error = g_strdup( "Unusuable response" ); - cb_data->func( cb_data->data, atoken, rtoken ); + cb_data->func( cb_data->data, atoken, rtoken, error ); g_free( content_type ); g_free( atoken ); g_free( rtoken ); + g_free( error ); g_free( cb_data ); } diff --git a/lib/oauth2.h b/lib/oauth2.h index c8d18963..b3811f49 100644 --- a/lib/oauth2.h +++ b/lib/oauth2.h @@ -3,7 +3,7 @@ * BitlBee - An IRC to IM gateway * * Simple OAuth2 client (consumer) implementation. * * * -* Copyright 2010-2011 Wilmer van der Gaast <wilmer@gaast.net> * +* Copyright 2010-2013 Wilmer van der Gaast <wilmer@gaast.net> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -24,7 +24,8 @@ /* Implementation mostly based on my experience with writing the previous OAuth module, and from http://code.google.com/apis/accounts/docs/OAuth2.html . */ -typedef void (*oauth2_token_callback)( gpointer data, const char *atoken, const char *rtoken ); +typedef void (*oauth2_token_callback)( gpointer data, const char *atoken, + const char *rtoken, const char *error ); struct oauth2_service { diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c index 450b5b28..12111fc7 100644 --- a/protocols/jabber/sasl.c +++ b/protocols/jabber/sasl.c @@ -482,7 +482,7 @@ static gboolean sasl_oauth2_remove_contact( gpointer data, gint fd, b_input_cond return FALSE; } -static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token ); +static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token, const char *error ); int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ) { @@ -513,7 +513,7 @@ int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token ) refresh_token, sasl_oauth2_got_token, ic ); } -static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token ) +static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token, const char *error ) { struct im_connection *ic = data; struct jabber_data *jd; @@ -526,7 +526,7 @@ static void sasl_oauth2_got_token( gpointer data, const char *access_token, cons if( access_token == NULL ) { - imcb_error( ic, "OAuth failure (missing access token)" ); + imcb_error( ic, "OAuth failure (%s)", error ); imc_logout( ic, TRUE ); return; } |