Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • lib/oauth2.c

    rca8037e r3bda2c2  
    22*                                                                           *
    33*  BitlBee - An IRC to IM gateway                                           *
    4 *  Simple OAuth2 client (consumer) implementation.                          *
     4*  Simple OAuth client (consumer) implementation.                           *
    55*                                                                           *
    6 *  Copyright 2010-2013 Wilmer van der Gaast <wilmer@gaast.net>              *
     6*  Copyright 2010-2011 Wilmer van der Gaast <wilmer@gaast.net>              *
    77*                                                                           *
    88*  This program is free software; you can redistribute it and/or modify     *
     
    2222\***************************************************************************/
    2323
    24 /* Out of protest, I should rename this file. OAuth2 is a pathetic joke, and
    25    of all things, DEFINITELY NOT A STANDARD. The only thing various OAuth2
    26    implementations have in common is that name, wrongfully stolen from
    27    a pretty nice standard called OAuth 1.0a. That, and the fact that they
    28    use JSON. Wait, no, Facebook's version doesn't use JSON. For some of its
    29    responses.
    30    
    31    Apparently too many people were too retarded to comprehend the elementary
    32    bits of crypto in OAuth 1.0a (took me one afternoon to implement) so
    33    the standard was replaced with what comes down to a complicated scheme
    34    around what's really just application-specific passwords.
    35    
    36    And then a bunch of mostly incompatible implementations. Great work, guys.
    37    
    38    http://hueniverse.com/2012/07/oauth-2-0-and-the-road-to-hell/ */
    39 
    4024#include <glib.h>
    4125#include "http_client.h"
    4226#include "oauth2.h"
    4327#include "oauth.h"
    44 #include "json.h"
    45 #include "json_util.h"
    4628#include "url.h"
    4729
     
    6244};
    6345
     46static char *oauth2_json_dumb_get( const char *json, const char *key );
    6447static void oauth2_access_token_done( struct http_request *req );
    6548
     
    9679                             "Content-Type: application/x-www-form-urlencoded\r\n"
    9780                             "Content-Length: %zd\r\n"
     81                             "Connection: close\r\n"
    9882                             "\r\n"
    9983                             "%s", url_p.file, url_p.host, strlen( args_s ), args_s );
     
    11599}
    116100
    117 static char* oauth2_parse_error( json_value *e )
    118 {
    119         /* This does a reasonable job with some of the flavours of error
    120            responses I've seen. Because apparently it's not standardised. */
    121        
    122         if( e->type == json_object )
    123         {
    124                 /* Facebook style */
    125                 const char *msg = json_o_str( e, "message" );
    126                 const char *type = json_o_str( e, "type" );
    127                 json_value *code_o = json_o_get( e, "code" );
    128                 int code = 0;
    129                
    130                 if( code_o && code_o->type == json_integer )
    131                         code = code_o->u.integer;
    132                
    133                 return g_strdup_printf( "Error %d: %s", code, msg ? msg : type ? type : "Unknown error" );
    134         }
    135         else if( e->type == json_string )
    136         {
    137                 return g_strdup( e->u.string.ptr );
    138         }
    139         return NULL;
    140 }
    141 
    142101static void oauth2_access_token_done( struct http_request *req )
    143102{
    144103        struct oauth2_access_token_data *cb_data = req->data;
    145         char *atoken = NULL, *rtoken = NULL, *error = NULL;
     104        char *atoken = NULL, *rtoken = NULL;
    146105        char *content_type;
    147106       
     
    151110        content_type = get_rfc822_header( req->reply_headers, "Content-Type", 0 );
    152111       
    153         if( content_type && ( strstr( content_type, "application/json" ) ||
    154                               strstr( content_type, "text/javascript" ) ) )
     112        if( req->status_code != 200 )
    155113        {
    156                 json_value *js = json_parse( req->reply_body );
    157                 if( js && js->type == json_object )
    158                 {
    159                         JSON_O_FOREACH( js, k, v )
    160                         {
    161                                 if( strcmp( k, "error" ) == 0 )
    162                                         error = oauth2_parse_error( v );
    163                                 if( v->type != json_string )
    164                                         continue;
    165                                 if( strcmp( k, "access_token" ) == 0 )
    166                                         atoken = g_strdup( v->u.string.ptr );
    167                                 if( strcmp( k, "refresh_token" ) == 0 )
    168                                         rtoken = g_strdup( v->u.string.ptr );
    169                         }
    170                 }
    171                 json_value_free( js );
     114        }
     115        else if( content_type && strstr( content_type, "application/json" ) )
     116        {
     117                atoken = oauth2_json_dumb_get( req->reply_body, "access_token" );
     118                rtoken = oauth2_json_dumb_get( req->reply_body, "refresh_token" );
    172119        }
    173120        else
     
    183130        if( getenv( "BITLBEE_DEBUG" ) )
    184131                printf( "Extracted atoken=%s rtoken=%s\n", atoken, rtoken );
    185         if( !atoken && !rtoken && !error )
    186                 error = g_strdup( "Unusuable response" );
    187132       
    188         cb_data->func( cb_data->data, atoken, rtoken, error );
     133        cb_data->func( cb_data->data, atoken, rtoken );
    189134        g_free( content_type );
    190135        g_free( atoken );
    191136        g_free( rtoken );
    192         g_free( error );
    193137        g_free( cb_data );
    194138}
     139
     140/* Super dumb. I absolutely refuse to use/add a complete json parser library
     141   (adding a new dependency to BitlBee for the first time in.. 6 years?) just
     142   to parse 100 bytes of data. So I have to do my own parsing because OAuth2
     143   dropped support for XML. (GRRR!) This is very dumb and for example won't
     144   work for integer values, nor will it strip/handle backslashes. */
     145static char *oauth2_json_dumb_get( const char *json, const char *key )
     146{
     147        int is_key = 0; /* 1 == reading key, 0 == reading value */
     148        int found_key = 0;
     149               
     150        while( json && *json )
     151        {
     152                /* Grab strings and see if they're what we're looking for. */
     153                if( *json == '"' || *json == '\'' )
     154                {
     155                        char q = *json;
     156                        const char *str_start;
     157                        json ++;
     158                        str_start = json;
     159                       
     160                        while( *json )
     161                        {
     162                                /* \' and \" are not string terminators. */
     163                                if( *json == '\\' && json[1] == q )
     164                                        json ++;
     165                                /* But without a \ it is. */
     166                                else if( *json == q )
     167                                        break;
     168                                json ++;
     169                        }
     170                        if( *json == '\0' )
     171                                return NULL;
     172                       
     173                        if( is_key && strncmp( str_start, key, strlen( key ) ) == 0 )
     174                        {
     175                                found_key = 1;
     176                        }
     177                        else if( !is_key && found_key )
     178                        {
     179                                char *ret = g_memdup( str_start, json - str_start + 1 );
     180                                ret[json-str_start] = '\0';
     181                                return ret;
     182                        }
     183                       
     184                }
     185                else if( *json == '{' || *json == ',' )
     186                {
     187                        found_key = 0;
     188                        is_key = 1;
     189                }
     190                else if( *json == ':' )
     191                        is_key = 0;
     192               
     193                json ++;
     194        }
     195       
     196        return NULL;
     197}
Note: See TracChangeset for help on using the changeset viewer.