From be28fe7da3e197d91ec00a6c1017c053041f5a85 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Apr 2010 16:12:13 +0100 Subject: Code to calculate OAuth signatures. I hope that after wrapping my mind around all of this the rest is going to be easier.. --- lib/oauth.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 lib/oauth.c (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c new file mode 100644 index 00000000..ef303f14 --- /dev/null +++ b/lib/oauth.c @@ -0,0 +1,106 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple OAuth client (consumer) implementation. * +* * +* Copyright 2010 Wilmer van der Gaast * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +\***************************************************************************/ + +#include +#include +#include +#include +#include "base64.h" +#include "misc.h" +#include "sha1.h" + +#define CONSUMER_KEY "xsDNKJuNZYkZyMcu914uEA" +#define CONSUMER_SECRET "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo" +/* How can it be a secret if it's right here in the source code? No clue... */ + +#define HMAC_BLOCK_SIZE 64 + +struct oauth_state +{ +}; + +static char *oauth_sign( const char *method, const char *url, + const char *params, const char *token_secret ) +{ + sha1_state_t sha1; + uint8_t hash[sha1_hash_size]; + uint8_t key[HMAC_BLOCK_SIZE+1]; + char *s; + int i; + + /* Create K. If our current key is >64 chars we have to hash it, + otherwise just pad. */ + memset( key, 0, HMAC_BLOCK_SIZE ); + i = strlen( CONSUMER_SECRET ) + 1 + token_secret ? strlen( token_secret ) : 0; + if( i > HMAC_BLOCK_SIZE ) + { + sha1_init( &sha1 ); + sha1_append( &sha1, CONSUMER_SECRET, strlen( CONSUMER_SECRET ) ); + sha1_append( &sha1, "&", 1 ); + if( token_secret ) + sha1_append( &sha1, token_secret, strlen( token_secret ) ); + sha1_finish( &sha1, key ); + } + else + { + g_snprintf( key, HMAC_BLOCK_SIZE + 1, "%s&%s", + CONSUMER_SECRET, token_secret ? : "" ); + } + + /* Inner part: H(K XOR 0x36, text) */ + sha1_init( &sha1 ); + + for( i = 0; i < HMAC_BLOCK_SIZE; i ++ ) + key[i] ^= 0x36; + sha1_append( &sha1, key, HMAC_BLOCK_SIZE ); + + /* OAuth: text = method&url¶ms, all http_encoded. */ + sha1_append( &sha1, (const uint8_t*) method, strlen( method ) ); + sha1_append( &sha1, (const uint8_t*) "&", 1 ); + + s = g_new0( char, strlen( url ) * 3 + 1 ); + strcpy( s, url ); + http_encode( s ); + sha1_append( &sha1, (const uint8_t*) s, strlen( s ) ); + sha1_append( &sha1, (const uint8_t*) "&", 1 ); + g_free( s ); + + s = g_new0( char, strlen( params ) * 3 + 1 ); + strcpy( s, params ); + http_encode( s ); + sha1_append( &sha1, (const uint8_t*) s, strlen( s ) ); + g_free( s ); + + sha1_finish( &sha1, hash ); + + /* Final result: H(K XOR 0x5C, inner stuff) */ + sha1_init( &sha1 ); + for( i = 0; i < HMAC_BLOCK_SIZE; i ++ ) + key[i] ^= 0x36 ^ 0x5c; + sha1_append( &sha1, key, HMAC_BLOCK_SIZE ); + sha1_append( &sha1, hash, sha1_hash_size ); + sha1_finish( &sha1, hash ); + + /* base64_encode it and we're done. */ + return base64_encode( hash, sha1_hash_size ); +} -- cgit v1.2.3 From da2efd4eaaf6a87afc35402d96d98d8001e43af7 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Apr 2010 19:57:06 +0100 Subject: Some HTTP stuff. Via gdb I can make this request a token. --- lib/oauth.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 212 insertions(+), 6 deletions(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index ef303f14..6240d514 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -25,9 +25,11 @@ #include #include #include +#include "http_client.h" #include "base64.h" #include "misc.h" #include "sha1.h" +#include "url.h" #define CONSUMER_KEY "xsDNKJuNZYkZyMcu914uEA" #define CONSUMER_SECRET "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo" @@ -35,8 +37,18 @@ #define HMAC_BLOCK_SIZE 64 -struct oauth_state +struct oauth_info; +typedef void (*oauth_cb)( struct oauth_info * ); + +struct oauth_info { + oauth_cb func; + void *data; + + struct http_request *http; + + char *auth_params; + char *token; }; static char *oauth_sign( const char *method, const char *url, @@ -51,19 +63,19 @@ static char *oauth_sign( const char *method, const char *url, /* Create K. If our current key is >64 chars we have to hash it, otherwise just pad. */ memset( key, 0, HMAC_BLOCK_SIZE ); - i = strlen( CONSUMER_SECRET ) + 1 + token_secret ? strlen( token_secret ) : 0; + i = strlen( CONSUMER_SECRET ) + 1 + ( token_secret ? strlen( token_secret ) : 0 ); if( i > HMAC_BLOCK_SIZE ) { sha1_init( &sha1 ); - sha1_append( &sha1, CONSUMER_SECRET, strlen( CONSUMER_SECRET ) ); - sha1_append( &sha1, "&", 1 ); + sha1_append( &sha1, (uint8_t*) CONSUMER_SECRET, strlen( CONSUMER_SECRET ) ); + sha1_append( &sha1, (uint8_t*) "&", 1 ); if( token_secret ) - sha1_append( &sha1, token_secret, strlen( token_secret ) ); + sha1_append( &sha1, (uint8_t*) token_secret, strlen( token_secret ) ); sha1_finish( &sha1, key ); } else { - g_snprintf( key, HMAC_BLOCK_SIZE + 1, "%s&%s", + g_snprintf( (gchar*) key, HMAC_BLOCK_SIZE + 1, "%s&%s", CONSUMER_SECRET, token_secret ? : "" ); } @@ -104,3 +116,197 @@ static char *oauth_sign( const char *method, const char *url, /* base64_encode it and we're done. */ return base64_encode( hash, sha1_hash_size ); } + +static char *oauth_nonce() +{ + unsigned char bytes[9]; + + random_bytes( bytes, sizeof( bytes ) ); + return base64_encode( bytes, sizeof( bytes ) ); +} + +void oauth_params_add( GSList **params, const char *key, const char *value ) +{ + char *item; + + item = g_strdup_printf( "%s=%s", key, value ); + *params = g_slist_insert_sorted( *params, item, (GCompareFunc) strcmp ); +} + +void oauth_params_del( GSList **params, const char *key ) +{ + int key_len = strlen( key ); + GSList *l, *n; + + for( l = *params; l; l = n ) + { + n = l->next; + + if( strncmp( (char*) l->data, key, key_len ) == 0 && + ((char*)l->data)[key_len] == '=' ) + { + g_free( l->data ); + *params = g_slist_remove( *params, l ); + } + } +} + +void oauth_params_set( GSList **params, const char *key, const char *value ) +{ + oauth_params_del( params, key ); + oauth_params_add( params, key, value ); +} + +const char *oauth_params_get( GSList **params, const char *key ) +{ + int key_len = strlen( key ); + GSList *l; + + for( l = *params; l; l = l->next ) + { + if( strncmp( (char*) l->data, key, key_len ) == 0 && + ((char*)l->data)[key_len] == '=' ) + return (const char*) l->data + key_len + 1; + } + + return NULL; +} + +GSList *oauth_params_parse( char *in ) +{ + GSList *ret = NULL; + char *amp, *eq; + + while( in && *in ) + { + eq = strchr( in, '=' ); + if( !eq ) + break; + + *eq = '\0'; + if( ( amp = strchr( eq + 1, '&' ) ) ) + *amp = '\0'; + + oauth_params_add( &ret, in, eq + 1 ); + + *eq = '='; + if( amp == NULL ) + break; + + *amp = '&'; + in = amp + 1; + } + + return ret; +} + +void oauth_params_free( GSList **params ) +{ + while( params && *params ) + { + g_free( (*params)->data ); + *params = g_slist_remove( *params, (*params)->data ); + } +} + +char *oauth_params_string( GSList *params ) +{ + GSList *l; + GString *str = g_string_new( "" ); + + for( l = params; l; l = l->next ) + { + g_string_append( str, l->data ); + if( l->next ) + g_string_append_c( str, '&' ); + } + + return g_string_free( str, FALSE ); +} + +static void *oauth_post_request( const char *url, GSList **params_, http_input_function func, void *data ) +{ + GSList *params = NULL; + char *s, *params_s, *post; + void *req; + url_t url_p; + + if( !url_set( &url_p, url ) ) + { + oauth_params_free( params_ ); + return NULL; + } + + if( params_ ) + params = *params_; + + oauth_params_set( ¶ms, "oauth_consumer_key", CONSUMER_KEY ); + oauth_params_set( ¶ms, "oauth_signature_method", "HMAC-SHA1" ); + + s = g_strdup_printf( "%d", (int) time( NULL ) ); + oauth_params_set( ¶ms, "oauth_timestamp", s ); + g_free( s ); + + s = oauth_nonce(); + oauth_params_set( ¶ms, "oauth_nonce", s ); + g_free( s ); + + oauth_params_set( ¶ms, "oauth_version", "1.0" ); + oauth_params_set( ¶ms, "oauth_callback", "oob" ); + + params_s = oauth_params_string( params ); + oauth_params_free( params_ ); + + s = oauth_sign( "POST", url, params_s, NULL ); + s = g_realloc( s, strlen( s ) * 3 + 1 ); + http_encode( s ); + + post = g_strdup_printf( "%s&oauth_signature=%s", params_s, s ); + g_free( params_s ); + g_free( s ); + + s = g_strdup_printf( "POST %s HTTP/1.0\r\n" + "Host: %s\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: %zd\r\n" + "\r\n" + "%s", url_p.file, url_p.host, strlen( post ), post ); + g_free( post ); + + req = http_dorequest( url_p.host, url_p.port, url_p.proto == PROTO_HTTPS, + s, func, data ); + g_free( s ); + + return req; +} + +void oauth_request_token_done( struct http_request *req ); + +void *oauth_request_token( const char *url, oauth_cb func, void *data ) +{ + struct oauth_info *st = g_new0( struct oauth_info, 1 ); + + st->func = func; + st->data = data; + + return oauth_post_request( url, NULL, oauth_request_token_done, st ); +} + +void oauth_request_token_done( struct http_request *req ) +{ + struct oauth_info *st = req->data; + + st->http = req; + + if( req->status_code == 200 ) + { + GSList *params; + + st->auth_params = g_strdup( req->reply_body ); + params = oauth_params_parse( st->auth_params ); + st->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); + oauth_params_free( ¶ms ); + } + + st->func( st ); +} -- cgit v1.2.3 From 346dfd940c1439f6113c3cf80340791567de5d25 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Apr 2010 20:22:02 +0100 Subject: oauth_access_token() added. I managed to increase the counter on http://twitter.com/oauth_clients/details/127170 . \o/ --- lib/oauth.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 6240d514..bc3974c1 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -252,7 +252,6 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f g_free( s ); oauth_params_set( ¶ms, "oauth_version", "1.0" ); - oauth_params_set( ¶ms, "oauth_callback", "oob" ); params_s = oauth_params_string( params ); oauth_params_free( params_ ); @@ -280,19 +279,22 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f return req; } -void oauth_request_token_done( struct http_request *req ); +static void oauth_request_token_done( struct http_request *req ); void *oauth_request_token( const char *url, oauth_cb func, void *data ) { struct oauth_info *st = g_new0( struct oauth_info, 1 ); + GSList *params = NULL; st->func = func; st->data = data; + oauth_params_add( ¶ms, "oauth_callback", "oob" ); + return oauth_post_request( url, NULL, oauth_request_token_done, st ); } -void oauth_request_token_done( struct http_request *req ) +static void oauth_request_token_done( struct http_request *req ) { struct oauth_info *st = req->data; @@ -308,5 +310,21 @@ void oauth_request_token_done( struct http_request *req ) oauth_params_free( ¶ms ); } - st->func( st ); + //st->func( st ); +} + +static void oauth_access_token_done( struct http_request *req ); + +void *oauth_access_token( const char *url, const char *pin, struct oauth_info *st ) +{ + GSList *params = NULL; + + oauth_params_add( ¶ms, "oauth_token", st->token ); + oauth_params_add( ¶ms, "oauth_verifier", pin ); + + return oauth_post_request( url, ¶ms, oauth_access_token_done, st ); +} + +static void oauth_access_token_done( struct http_request *req ) +{ } -- cgit v1.2.3 From b2bc25c4483f4c2b419d91d479f38c3f07ef4226 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 00:21:00 +0100 Subject: Added a function that generates an OAuth Authorization: HTTP header. --- lib/oauth.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 13 deletions(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index bc3974c1..c166d96a 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -49,6 +49,8 @@ struct oauth_info char *auth_params; char *token; + + char *access_token; }; static char *oauth_sign( const char *method, const char *url, @@ -146,7 +148,7 @@ void oauth_params_del( GSList **params, const char *key ) ((char*)l->data)[key_len] == '=' ) { g_free( l->data ); - *params = g_slist_remove( *params, l ); + *params = g_slist_remove( *params, l->data ); } } } @@ -224,6 +226,24 @@ char *oauth_params_string( GSList *params ) return g_string_free( str, FALSE ); } +static void oauth_add_default_params( GSList **params ) +{ + char *s; + + oauth_params_set( params, "oauth_consumer_key", CONSUMER_KEY ); + oauth_params_set( params, "oauth_signature_method", "HMAC-SHA1" ); + + s = g_strdup_printf( "%d", (int) time( NULL ) ); + oauth_params_set( params, "oauth_timestamp", s ); + g_free( s ); + + s = oauth_nonce(); + oauth_params_set( params, "oauth_nonce", s ); + g_free( s ); + + oauth_params_set( params, "oauth_version", "1.0" ); +} + static void *oauth_post_request( const char *url, GSList **params_, http_input_function func, void *data ) { GSList *params = NULL; @@ -240,18 +260,7 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f if( params_ ) params = *params_; - oauth_params_set( ¶ms, "oauth_consumer_key", CONSUMER_KEY ); - oauth_params_set( ¶ms, "oauth_signature_method", "HMAC-SHA1" ); - - s = g_strdup_printf( "%d", (int) time( NULL ) ); - oauth_params_set( ¶ms, "oauth_timestamp", s ); - g_free( s ); - - s = oauth_nonce(); - oauth_params_set( ¶ms, "oauth_nonce", s ); - g_free( s ); - - oauth_params_set( ¶ms, "oauth_version", "1.0" ); + oauth_add_default_params( ¶ms ); params_s = oauth_params_string( params ); oauth_params_free( params_ ); @@ -327,4 +336,61 @@ void *oauth_access_token( const char *url, const char *pin, struct oauth_info *s static void oauth_access_token_done( struct http_request *req ) { + struct oauth_info *st = req->data; + + if( req->status_code == 200 ) + st->access_token = g_strdup( req->reply_body ); + + //st->func( st ); +} + +char *oauth_http_header( char *access_token, const char *method, const char *url ) +{ + GSList *params, *l; + char *token_secret, *sig, *params_s; + GString *ret = NULL; + + params = oauth_params_parse( access_token ); + if( params == NULL ) + goto err; + token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); + if( token_secret == NULL ) + goto err; + oauth_params_del( ¶ms, "oauth_token_secret" ); + + oauth_add_default_params( ¶ms ); + + params_s = oauth_params_string( params ); + sig = oauth_sign( method, url, params_s, token_secret ); + g_free( params_s ); + sig = g_realloc( sig, strlen( sig ) * 3 + 1 ); + http_encode( sig ); + + ret = g_string_new( "OAuth " ); + for( l = params; l; l = l->next ) + { + char *kv = l->data; + char *eq = strchr( kv, '=' ); + char esc[strlen(kv)*3+1]; + + if( eq == NULL ) + break; /* WTF */ + + strcpy( esc, eq + 1 ); + http_encode( esc ); + + g_string_append_len( ret, kv, eq - kv + 1 ); + g_string_append_c( ret, '"' ); + g_string_append( ret, esc ); + g_string_append( ret, "\", " ); + } + + g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); + +err: + oauth_params_free( ¶ms ); + g_free( sig ); + g_free( token_secret ); + + return ret ? g_string_free( ret, FALSE ) : NULL; } -- cgit v1.2.3 From 508c340d1d12d3ca932001d7ee1dea1a4c81bf02 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 01:42:37 +0100 Subject: Successfully posted a tweet! Twitter's tricky. It returns vars (user_id, screen_name) in the access token that, the way I read the spec, should be included in all subsequent queries. However, stuff only started to work when I dropped those vars. This code's definitely not pretty ATM. Need to clean up now that it actually works. --- lib/oauth.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index c166d96a..6731fe7e 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -174,9 +174,8 @@ const char *oauth_params_get( GSList **params, const char *key ) return NULL; } -GSList *oauth_params_parse( char *in ) +static void oauth_params_parse( GSList **params, char *in ) { - GSList *ret = NULL; char *amp, *eq; while( in && *in ) @@ -189,7 +188,7 @@ GSList *oauth_params_parse( char *in ) if( ( amp = strchr( eq + 1, '&' ) ) ) *amp = '\0'; - oauth_params_add( &ret, in, eq + 1 ); + oauth_params_add( params, in, eq + 1 ); *eq = '='; if( amp == NULL ) @@ -198,8 +197,6 @@ GSList *oauth_params_parse( char *in ) *amp = '&'; in = amp + 1; } - - return ret; } void oauth_params_free( GSList **params ) @@ -311,10 +308,10 @@ static void oauth_request_token_done( struct http_request *req ) if( req->status_code == 200 ) { - GSList *params; + GSList *params = NULL; st->auth_params = g_strdup( req->reply_body ); - params = oauth_params_parse( st->auth_params ); + oauth_params_parse( ¶ms, st->auth_params ); st->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); oauth_params_free( ¶ms ); } @@ -344,13 +341,13 @@ static void oauth_access_token_done( struct http_request *req ) //st->func( st ); } -char *oauth_http_header( char *access_token, const char *method, const char *url ) +char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ) { - GSList *params, *l; - char *token_secret, *sig, *params_s; + GSList *params = NULL, *l; + char *token_secret, *sig, *params_s, *s; GString *ret = NULL; - params = oauth_params_parse( access_token ); + oauth_params_parse( ¶ms, access_token ); if( params == NULL ) goto err; token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); @@ -360,12 +357,6 @@ char *oauth_http_header( char *access_token, const char *method, const char *url oauth_add_default_params( ¶ms ); - params_s = oauth_params_string( params ); - sig = oauth_sign( method, url, params_s, token_secret ); - g_free( params_s ); - sig = g_realloc( sig, strlen( sig ) * 3 + 1 ); - http_encode( sig ); - ret = g_string_new( "OAuth " ); for( l = params; l; l = l->next ) { @@ -385,6 +376,21 @@ char *oauth_http_header( char *access_token, const char *method, const char *url g_string_append( ret, "\", " ); } + if( args ) + oauth_params_parse( ¶ms, args ); + if( ( s = strchr( url, '?' ) ) ) + { + s = g_strdup( s + 1 ); + oauth_params_parse( ¶ms, s + 1 ); + g_free( s ); + } + + params_s = oauth_params_string( params ); + sig = oauth_sign( method, url, params_s, token_secret ); + g_free( params_s ); + sig = g_realloc( sig, strlen( sig ) * 3 + 1 ); + http_encode( sig ); + g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); err: -- cgit v1.2.3 From acba168df90f28fdaee26bc09d621364878dd099 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 22:20:09 +0100 Subject: Moving two public OAuth functions into the header file. --- lib/oauth.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 6731fe7e..7897b760 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -30,6 +30,7 @@ #include "misc.h" #include "sha1.h" #include "url.h" +#include "oauth.h" #define CONSUMER_KEY "xsDNKJuNZYkZyMcu914uEA" #define CONSUMER_SECRET "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo" @@ -37,22 +38,6 @@ #define HMAC_BLOCK_SIZE 64 -struct oauth_info; -typedef void (*oauth_cb)( struct oauth_info * ); - -struct oauth_info -{ - oauth_cb func; - void *data; - - struct http_request *http; - - char *auth_params; - char *token; - - char *access_token; -}; - static char *oauth_sign( const char *method, const char *url, const char *params, const char *token_secret ) { -- cgit v1.2.3 From 713d6111cd754ff9eae4cfa1e6de82c9824d16db Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 22:50:48 +0100 Subject: Twitter module now generates authorize URLs. --- lib/oauth.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 7897b760..828d713d 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -297,11 +297,11 @@ static void oauth_request_token_done( struct http_request *req ) st->auth_params = g_strdup( req->reply_body ); oauth_params_parse( ¶ms, st->auth_params ); - st->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); + st->request_token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); oauth_params_free( ¶ms ); } - //st->func( st ); + st->func( st ); } static void oauth_access_token_done( struct http_request *req ); @@ -310,7 +310,7 @@ void *oauth_access_token( const char *url, const char *pin, struct oauth_info *s { GSList *params = NULL; - oauth_params_add( ¶ms, "oauth_token", st->token ); + oauth_params_add( ¶ms, "oauth_token", st->request_token ); oauth_params_add( ¶ms, "oauth_verifier", pin ); return oauth_post_request( url, ¶ms, oauth_access_token_done, st ); @@ -323,7 +323,7 @@ static void oauth_access_token_done( struct http_request *req ) if( req->status_code == 200 ) st->access_token = g_strdup( req->reply_body ); - //st->func( st ); + st->func( st ); } char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ) -- cgit v1.2.3 From c42e8b907817fc76df4dc3b48d85858555102654 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 23:40:11 +0100 Subject: OAuth, it lives! --- lib/oauth.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 828d713d..7f60f4f5 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -301,6 +301,7 @@ static void oauth_request_token_done( struct http_request *req ) oauth_params_free( ¶ms ); } + st->stage = OAUTH_REQUEST_TOKEN; st->func( st ); } @@ -321,8 +322,19 @@ static void oauth_access_token_done( struct http_request *req ) struct oauth_info *st = req->data; if( req->status_code == 200 ) - st->access_token = g_strdup( req->reply_body ); + { + GSList *params; + const char *token, *token_secret; + + oauth_params_parse( ¶ms, req->reply_body ); + token = oauth_params_get( ¶ms, "oauth_token" ); + token_secret = oauth_params_get( ¶ms, "oauth_token_secret" ); + st->access_token = g_strdup_printf( + "oauth_token=%s&oauth_token_secret=%s", token, token_secret ); + oauth_params_free( ¶ms ); + } + st->stage = OAUTH_ACCESS_TOKEN; st->func( st ); } -- cgit v1.2.3 From 78a2f1e4ac9aeb2c041059eb7a9578d34bd60d50 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 23:47:35 +0100 Subject: Escaping in oauth_nonce(). Not sure if the escaping is entirely right ATM... :-( --- lib/oauth.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 7f60f4f5..9a372082 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -107,9 +107,14 @@ static char *oauth_sign( const char *method, const char *url, static char *oauth_nonce() { unsigned char bytes[9]; + char *ret; random_bytes( bytes, sizeof( bytes ) ); - return base64_encode( bytes, sizeof( bytes ) ); + ret = base64_encode( bytes, sizeof( bytes ) ); + ret = g_realloc( ret, strlen( ret ) * 3 + 1 ); + http_encode( ret ); + + return ret; } void oauth_params_add( GSList **params, const char *key, const char *value ) -- cgit v1.2.3 From ee84bdbc2510fa09bd0f67e14d06e69c2626d0f1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 27 Apr 2010 23:11:11 +0100 Subject: The escaping, I fixed it for you. More expensive code this way and most of the vars don't need escaping. But this shouldn't be so fragile anymore. --- lib/oauth.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 9a372082..0ab94c96 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -100,21 +100,21 @@ static char *oauth_sign( const char *method, const char *url, sha1_append( &sha1, hash, sha1_hash_size ); sha1_finish( &sha1, hash ); - /* base64_encode it and we're done. */ - return base64_encode( hash, sha1_hash_size ); + /* base64_encode + HTTP escape it (both consumers + need it that away) and we're done. */ + s = base64_encode( hash, sha1_hash_size ); + s = g_realloc( s, strlen( s ) * 3 + 1 ); + http_encode( s ); + + return s; } static char *oauth_nonce() { unsigned char bytes[9]; - char *ret; random_bytes( bytes, sizeof( bytes ) ); - ret = base64_encode( bytes, sizeof( bytes ) ); - ret = g_realloc( ret, strlen( ret ) * 3 + 1 ); - http_encode( ret ); - - return ret; + return base64_encode( bytes, sizeof( bytes ) ); } void oauth_params_add( GSList **params, const char *key, const char *value ) @@ -166,7 +166,7 @@ const char *oauth_params_get( GSList **params, const char *key ) static void oauth_params_parse( GSList **params, char *in ) { - char *amp, *eq; + char *amp, *eq, *s; while( in && *in ) { @@ -178,7 +178,10 @@ static void oauth_params_parse( GSList **params, char *in ) if( ( amp = strchr( eq + 1, '&' ) ) ) *amp = '\0'; - oauth_params_add( params, in, eq + 1 ); + s = g_strdup( eq + 1 ); + http_decode( s ); + oauth_params_add( params, in, s ); + g_free( s ); *eq = '='; if( amp == NULL ) @@ -205,7 +208,15 @@ char *oauth_params_string( GSList *params ) for( l = params; l; l = l->next ) { - g_string_append( str, l->data ); + char *s, *eq; + + s = g_malloc( strlen( l->data ) * 3 + 1 ); + strcpy( s, l->data ); + if( ( eq = strchr( s, '=' ) ) ) + http_encode( eq + 1 ); + g_string_append( str, s ); + g_free( s ); + if( l->next ) g_string_append_c( str, '&' ); } @@ -253,9 +264,6 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f oauth_params_free( params_ ); s = oauth_sign( "POST", url, params_s, NULL ); - s = g_realloc( s, strlen( s ) * 3 + 1 ); - http_encode( s ); - post = g_strdup_printf( "%s&oauth_signature=%s", params_s, s ); g_free( params_s ); g_free( s ); @@ -389,11 +397,8 @@ char *oauth_http_header( char *access_token, const char *method, const char *url params_s = oauth_params_string( params ); sig = oauth_sign( method, url, params_s, token_secret ); - g_free( params_s ); - sig = g_realloc( sig, strlen( sig ) * 3 + 1 ); - http_encode( sig ); - g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); + g_free( params_s ); err: oauth_params_free( ¶ms ); -- cgit v1.2.3 From 18dbb20242719f7537ad1a18a9a3befa2eefd502 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 27 Apr 2010 23:42:07 +0100 Subject: Valgrind cleanup. --- lib/oauth.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 0ab94c96..97017043 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -224,6 +224,17 @@ char *oauth_params_string( GSList *params ) return g_string_free( str, FALSE ); } +void oauth_info_free( struct oauth_info *info ) +{ + if( info ) + { + g_free( info->auth_params ); + g_free( info->request_token ); + g_free( info->access_token ); + g_free( info ); + } +} + static void oauth_add_default_params( GSList **params ) { char *s; @@ -285,7 +296,7 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f static void oauth_request_token_done( struct http_request *req ); -void *oauth_request_token( const char *url, oauth_cb func, void *data ) +struct oauth_info *oauth_request_token( const char *url, oauth_cb func, void *data ) { struct oauth_info *st = g_new0( struct oauth_info, 1 ); GSList *params = NULL; @@ -295,7 +306,13 @@ void *oauth_request_token( const char *url, oauth_cb func, void *data ) oauth_params_add( ¶ms, "oauth_callback", "oob" ); - return oauth_post_request( url, NULL, oauth_request_token_done, st ); + if( !oauth_post_request( url, ¶ms, oauth_request_token_done, st ) ) + { + oauth_info_free( st ); + return NULL; + } + + return st; } static void oauth_request_token_done( struct http_request *req ) @@ -315,19 +332,21 @@ static void oauth_request_token_done( struct http_request *req ) } st->stage = OAUTH_REQUEST_TOKEN; - st->func( st ); + if( !st->func( st ) ) + oauth_info_free( st ); } static void oauth_access_token_done( struct http_request *req ); -void *oauth_access_token( const char *url, const char *pin, struct oauth_info *st ) +void oauth_access_token( const char *url, const char *pin, struct oauth_info *st ) { GSList *params = NULL; oauth_params_add( ¶ms, "oauth_token", st->request_token ); oauth_params_add( ¶ms, "oauth_verifier", pin ); - return oauth_post_request( url, ¶ms, oauth_access_token_done, st ); + if( !oauth_post_request( url, ¶ms, oauth_access_token_done, st ) ) + oauth_info_free( st ); } static void oauth_access_token_done( struct http_request *req ) @@ -336,7 +355,7 @@ static void oauth_access_token_done( struct http_request *req ) if( req->status_code == 200 ) { - GSList *params; + GSList *params = NULL; const char *token, *token_secret; oauth_params_parse( ¶ms, req->reply_body ); @@ -349,6 +368,7 @@ static void oauth_access_token_done( struct http_request *req ) st->stage = OAUTH_ACCESS_TOKEN; st->func( st ); + oauth_info_free( st ); } char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ) @@ -357,9 +377,12 @@ char *oauth_http_header( char *access_token, const char *method, const char *url char *token_secret, *sig, *params_s, *s; GString *ret = NULL; + /* First, get the two pieces of info from the access token that we need. */ oauth_params_parse( ¶ms, access_token ); if( params == NULL ) goto err; + + /* Pick out the token secret, we shouldn't include it but use it for signing. */ token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); if( token_secret == NULL ) goto err; @@ -367,6 +390,7 @@ char *oauth_http_header( char *access_token, const char *method, const char *url oauth_add_default_params( ¶ms ); + /* Start building the OAuth header. 'key="value", '... */ ret = g_string_new( "OAuth " ); for( l = params; l; l = l->next ) { @@ -386,6 +410,9 @@ char *oauth_http_header( char *access_token, const char *method, const char *url g_string_append( ret, "\", " ); } + /* Now, before generating the signature, add GET/POST arguments to params + since they should be included in the base signature string (but not in + the HTTP header). */ if( args ) oauth_params_parse( ¶ms, args ); if( ( s = strchr( url, '?' ) ) ) @@ -395,6 +422,7 @@ char *oauth_http_header( char *access_token, const char *method, const char *url g_free( s ); } + /* Append the signature and we're done! */ params_s = oauth_params_string( params ); sig = oauth_sign( method, url, params_s, token_secret ); g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); -- cgit v1.2.3 From 0bff877cf81754283eac52ee49fedc3872cd0d4c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 27 Apr 2010 23:49:58 +0100 Subject: Valgrind-clean now. And decent handling of errors (wrong PIN). --- lib/oauth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 97017043..9fb83922 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -272,7 +272,7 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f oauth_add_default_params( ¶ms ); params_s = oauth_params_string( params ); - oauth_params_free( params_ ); + oauth_params_free( ¶ms ); s = oauth_sign( "POST", url, params_s, NULL ); post = g_strdup_printf( "%s&oauth_signature=%s", params_s, s ); @@ -353,6 +353,8 @@ static void oauth_access_token_done( struct http_request *req ) { struct oauth_info *st = req->data; + st->http = req; + if( req->status_code == 200 ) { GSList *params = NULL; -- cgit v1.2.3 From 85ef57f94436f23447c0d8603b52977824381854 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 30 Apr 2010 23:53:29 +0100 Subject: NULL-initialize two vars that weren't and should. --- lib/oauth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 9fb83922..4a465a2f 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -376,7 +376,7 @@ static void oauth_access_token_done( struct http_request *req ) char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ) { GSList *params = NULL, *l; - char *token_secret, *sig, *params_s, *s; + char *token_secret = NULL, *sig = NULL, *params_s, *s; GString *ret = NULL; /* First, get the two pieces of info from the access token that we need. */ -- cgit v1.2.3 From c2ecadc08daa5163f4c90aef36de0e33d0d44f16 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 1 May 2010 14:53:59 +0100 Subject: Cleaned up OAuth stuff: consumer key/secret should *not* be in lib/oauth.c. Keep it in the Twitter module, and use the oauth_info struct through the whole session to keep all this together. --- lib/oauth.c | 91 ++++++++++++++++++++++++++----------------------------------- 1 file changed, 39 insertions(+), 52 deletions(-) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 4a465a2f..4c93cbf4 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -32,14 +32,10 @@ #include "url.h" #include "oauth.h" -#define CONSUMER_KEY "xsDNKJuNZYkZyMcu914uEA" -#define CONSUMER_SECRET "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo" -/* How can it be a secret if it's right here in the source code? No clue... */ - #define HMAC_BLOCK_SIZE 64 static char *oauth_sign( const char *method, const char *url, - const char *params, const char *token_secret ) + const char *params, struct oauth_info *oi ) { sha1_state_t sha1; uint8_t hash[sha1_hash_size]; @@ -50,20 +46,20 @@ static char *oauth_sign( const char *method, const char *url, /* Create K. If our current key is >64 chars we have to hash it, otherwise just pad. */ memset( key, 0, HMAC_BLOCK_SIZE ); - i = strlen( CONSUMER_SECRET ) + 1 + ( token_secret ? strlen( token_secret ) : 0 ); + i = strlen( oi->sp->consumer_secret ) + 1 + ( oi->token_secret ? strlen( oi->token_secret ) : 0 ); if( i > HMAC_BLOCK_SIZE ) { sha1_init( &sha1 ); - sha1_append( &sha1, (uint8_t*) CONSUMER_SECRET, strlen( CONSUMER_SECRET ) ); + sha1_append( &sha1, (uint8_t*) oi->sp->consumer_secret, strlen( oi->sp->consumer_secret ) ); sha1_append( &sha1, (uint8_t*) "&", 1 ); - if( token_secret ) - sha1_append( &sha1, (uint8_t*) token_secret, strlen( token_secret ) ); + if( oi->token_secret ) + sha1_append( &sha1, (uint8_t*) oi->token_secret, strlen( oi->token_secret ) ); sha1_finish( &sha1, key ); } else { g_snprintf( (gchar*) key, HMAC_BLOCK_SIZE + 1, "%s&%s", - CONSUMER_SECRET, token_secret ? : "" ); + oi->sp->consumer_secret, oi->token_secret ? : "" ); } /* Inner part: H(K XOR 0x36, text) */ @@ -228,18 +224,19 @@ void oauth_info_free( struct oauth_info *info ) { if( info ) { - g_free( info->auth_params ); + g_free( info->auth_url ); g_free( info->request_token ); - g_free( info->access_token ); + g_free( info->token ); + g_free( info->token_secret ); g_free( info ); } } -static void oauth_add_default_params( GSList **params ) +static void oauth_add_default_params( GSList **params, struct oauth_service *sp ) { char *s; - oauth_params_set( params, "oauth_consumer_key", CONSUMER_KEY ); + oauth_params_set( params, "oauth_consumer_key", sp->consumer_key ); oauth_params_set( params, "oauth_signature_method", "HMAC-SHA1" ); s = g_strdup_printf( "%d", (int) time( NULL ) ); @@ -253,7 +250,7 @@ static void oauth_add_default_params( GSList **params ) oauth_params_set( params, "oauth_version", "1.0" ); } -static void *oauth_post_request( const char *url, GSList **params_, http_input_function func, void *data ) +static void *oauth_post_request( const char *url, GSList **params_, http_input_function func, struct oauth_info *oi ) { GSList *params = NULL; char *s, *params_s, *post; @@ -269,12 +266,12 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f if( params_ ) params = *params_; - oauth_add_default_params( ¶ms ); + oauth_add_default_params( ¶ms, oi->sp ); params_s = oauth_params_string( params ); oauth_params_free( ¶ms ); - s = oauth_sign( "POST", url, params_s, NULL ); + s = oauth_sign( "POST", url, params_s, oi ); post = g_strdup_printf( "%s&oauth_signature=%s", params_s, s ); g_free( params_s ); g_free( s ); @@ -288,7 +285,7 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f g_free( post ); req = http_dorequest( url_p.host, url_p.port, url_p.proto == PROTO_HTTPS, - s, func, data ); + s, func, oi ); g_free( s ); return req; @@ -296,17 +293,18 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f static void oauth_request_token_done( struct http_request *req ); -struct oauth_info *oauth_request_token( const char *url, oauth_cb func, void *data ) +struct oauth_info *oauth_request_token( struct oauth_service *sp, oauth_cb func, void *data ) { struct oauth_info *st = g_new0( struct oauth_info, 1 ); GSList *params = NULL; st->func = func; st->data = data; + st->sp = sp; oauth_params_add( ¶ms, "oauth_callback", "oob" ); - if( !oauth_post_request( url, ¶ms, oauth_request_token_done, st ) ) + if( !oauth_post_request( sp->url_request_token, ¶ms, oauth_request_token_done, st ) ) { oauth_info_free( st ); return NULL; @@ -325,28 +323,26 @@ static void oauth_request_token_done( struct http_request *req ) { GSList *params = NULL; - st->auth_params = g_strdup( req->reply_body ); - oauth_params_parse( ¶ms, st->auth_params ); + st->auth_url = g_strdup_printf( "%s?%s", st->sp->url_authorize, req->reply_body ); + oauth_params_parse( ¶ms, req->reply_body ); st->request_token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); oauth_params_free( ¶ms ); } st->stage = OAUTH_REQUEST_TOKEN; - if( !st->func( st ) ) - oauth_info_free( st ); + st->func( st ); } static void oauth_access_token_done( struct http_request *req ); -void oauth_access_token( const char *url, const char *pin, struct oauth_info *st ) +gboolean oauth_access_token( const char *pin, struct oauth_info *st ) { GSList *params = NULL; oauth_params_add( ¶ms, "oauth_token", st->request_token ); oauth_params_add( ¶ms, "oauth_verifier", pin ); - if( !oauth_post_request( url, ¶ms, oauth_access_token_done, st ) ) - oauth_info_free( st ); + return oauth_post_request( st->sp->url_access_token, ¶ms, oauth_access_token_done, st ) != NULL; } static void oauth_access_token_done( struct http_request *req ) @@ -358,39 +354,32 @@ static void oauth_access_token_done( struct http_request *req ) if( req->status_code == 200 ) { GSList *params = NULL; - const char *token, *token_secret; oauth_params_parse( ¶ms, req->reply_body ); - token = oauth_params_get( ¶ms, "oauth_token" ); - token_secret = oauth_params_get( ¶ms, "oauth_token_secret" ); - st->access_token = g_strdup_printf( - "oauth_token=%s&oauth_token_secret=%s", token, token_secret ); + st->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); + st->token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); oauth_params_free( ¶ms ); } st->stage = OAUTH_ACCESS_TOKEN; - st->func( st ); - oauth_info_free( st ); + if( st->func( st ) ) + { + /* Don't need these anymore, but keep the rest. */ + g_free( st->auth_url ); + st->auth_url = NULL; + g_free( st->request_token ); + st->request_token = NULL; + } } -char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ) +char *oauth_http_header( struct oauth_info *oi, const char *method, const char *url, char *args ) { GSList *params = NULL, *l; - char *token_secret = NULL, *sig = NULL, *params_s, *s; + char *sig = NULL, *params_s, *s; GString *ret = NULL; - /* First, get the two pieces of info from the access token that we need. */ - oauth_params_parse( ¶ms, access_token ); - if( params == NULL ) - goto err; - - /* Pick out the token secret, we shouldn't include it but use it for signing. */ - token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); - if( token_secret == NULL ) - goto err; - oauth_params_del( ¶ms, "oauth_token_secret" ); - - oauth_add_default_params( ¶ms ); + oauth_params_add( ¶ms, "oauth_token", oi->token ); + oauth_add_default_params( ¶ms, oi->sp ); /* Start building the OAuth header. 'key="value", '... */ ret = g_string_new( "OAuth " ); @@ -420,20 +409,18 @@ char *oauth_http_header( char *access_token, const char *method, const char *url if( ( s = strchr( url, '?' ) ) ) { s = g_strdup( s + 1 ); - oauth_params_parse( ¶ms, s + 1 ); + oauth_params_parse( ¶ms, s ); g_free( s ); } /* Append the signature and we're done! */ params_s = oauth_params_string( params ); - sig = oauth_sign( method, url, params_s, token_secret ); + sig = oauth_sign( method, url, params_s, oi ); g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); g_free( params_s ); -err: oauth_params_free( ¶ms ); g_free( sig ); - g_free( token_secret ); return ret ? g_string_free( ret, FALSE ) : NULL; } -- cgit v1.2.3 From f4b0911d037c02f8b9190518b5efda4368dcc25b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 1 May 2010 15:10:32 +0100 Subject: Save the credentials again. --- lib/oauth.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'lib/oauth.c') diff --git a/lib/oauth.c b/lib/oauth.c index 4c93cbf4..8012c37a 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -424,3 +424,30 @@ char *oauth_http_header( struct oauth_info *oi, const char *method, const char * return ret ? g_string_free( ret, FALSE ) : NULL; } + +char *oauth_to_string( struct oauth_info *oi ) +{ + GSList *params = NULL; + char *ret; + + oauth_params_add( ¶ms, "oauth_token", oi->token ); + oauth_params_add( ¶ms, "oauth_token_secret", oi->token_secret ); + ret = oauth_params_string( params ); + oauth_params_free( ¶ms ); + + return ret; +} + +struct oauth_info *oauth_from_string( char *in, struct oauth_service *sp ) +{ + struct oauth_info *oi = g_new0( struct oauth_info, 1 ); + GSList *params = NULL; + + oauth_params_parse( ¶ms, in ); + oi->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); + oi->token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); + oauth_params_free( ¶ms ); + oi->sp = sp; + + return oi; +} -- cgit v1.2.3