source: lib/oauth.c @ da2efd4

Last change on this file since da2efd4 was da2efd4, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-25T18:57:06Z

Some HTTP stuff. Via gdb I can make this request a token.

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Simple OAuth client (consumer) implementation.                           *
5*                                                                           *
6*  Copyright 2010 Wilmer van der Gaast <wilmer@gaast.net>                   *
7*                                                                           *
8*  This library is free software; you can redistribute it and/or            *
9*  modify it under the terms of the GNU Lesser General Public               *
10*  License as published by the Free Software Foundation, version            *
11*  2.1.                                                                     *
12*                                                                           *
13*  This library is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        *
16*  Lesser General Public License for more details.                          *
17*                                                                           *
18*  You should have received a copy of the GNU Lesser General Public License *
19*  along with this library; if not, write to the Free Software Foundation,  *
20*  Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA           *
21*                                                                           *
22\***************************************************************************/
23
24#include <glib.h>
25#include <gmodule.h>
26#include <stdlib.h>
27#include <string.h>
28#include "http_client.h"
29#include "base64.h"
30#include "misc.h"
31#include "sha1.h"
32#include "url.h"
33
34#define CONSUMER_KEY "xsDNKJuNZYkZyMcu914uEA"
35#define CONSUMER_SECRET "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo"
36/* How can it be a secret if it's right here in the source code? No clue... */
37
38#define HMAC_BLOCK_SIZE 64
39
40struct oauth_info;
41typedef void (*oauth_cb)( struct oauth_info * );
42
43struct oauth_info
44{
45        oauth_cb func;
46        void *data;
47       
48        struct http_request *http;
49       
50        char *auth_params;
51        char *token;
52};
53
54static char *oauth_sign( const char *method, const char *url,
55                         const char *params, const char *token_secret )
56{
57        sha1_state_t sha1;
58        uint8_t hash[sha1_hash_size];
59        uint8_t key[HMAC_BLOCK_SIZE+1];
60        char *s;
61        int i;
62       
63        /* Create K. If our current key is >64 chars we have to hash it,
64           otherwise just pad. */
65        memset( key, 0, HMAC_BLOCK_SIZE );
66        i = strlen( CONSUMER_SECRET ) + 1 + ( token_secret ? strlen( token_secret ) : 0 );
67        if( i > HMAC_BLOCK_SIZE )
68        {
69                sha1_init( &sha1 );
70                sha1_append( &sha1, (uint8_t*) CONSUMER_SECRET, strlen( CONSUMER_SECRET ) );
71                sha1_append( &sha1, (uint8_t*) "&", 1 );
72                if( token_secret )
73                        sha1_append( &sha1, (uint8_t*) token_secret, strlen( token_secret ) );
74                sha1_finish( &sha1, key );
75        }
76        else
77        {
78                g_snprintf( (gchar*) key, HMAC_BLOCK_SIZE + 1, "%s&%s",
79                            CONSUMER_SECRET, token_secret ? : "" );
80        }
81       
82        /* Inner part: H(K XOR 0x36, text) */
83        sha1_init( &sha1 );
84       
85        for( i = 0; i < HMAC_BLOCK_SIZE; i ++ )
86                key[i] ^= 0x36;
87        sha1_append( &sha1, key, HMAC_BLOCK_SIZE );
88       
89        /* OAuth: text = method&url&params, all http_encoded. */
90        sha1_append( &sha1, (const uint8_t*) method, strlen( method ) );
91        sha1_append( &sha1, (const uint8_t*) "&", 1 );
92       
93        s = g_new0( char, strlen( url ) * 3 + 1 );
94        strcpy( s, url );
95        http_encode( s );
96        sha1_append( &sha1, (const uint8_t*) s, strlen( s ) );
97        sha1_append( &sha1, (const uint8_t*) "&", 1 );
98        g_free( s );
99       
100        s = g_new0( char, strlen( params ) * 3 + 1 );
101        strcpy( s, params );
102        http_encode( s );
103        sha1_append( &sha1, (const uint8_t*) s, strlen( s ) );
104        g_free( s );
105       
106        sha1_finish( &sha1, hash );
107       
108        /* Final result: H(K XOR 0x5C, inner stuff) */
109        sha1_init( &sha1 );
110        for( i = 0; i < HMAC_BLOCK_SIZE; i ++ )
111                key[i] ^= 0x36 ^ 0x5c;
112        sha1_append( &sha1, key, HMAC_BLOCK_SIZE );
113        sha1_append( &sha1, hash, sha1_hash_size );
114        sha1_finish( &sha1, hash );
115       
116        /* base64_encode it and we're done. */
117        return base64_encode( hash, sha1_hash_size );
118}
119
120static char *oauth_nonce()
121{
122        unsigned char bytes[9];
123       
124        random_bytes( bytes, sizeof( bytes ) );
125        return base64_encode( bytes, sizeof( bytes ) );
126}
127
128void oauth_params_add( GSList **params, const char *key, const char *value )
129{
130        char *item;
131       
132        item = g_strdup_printf( "%s=%s", key, value );
133        *params = g_slist_insert_sorted( *params, item, (GCompareFunc) strcmp );
134}
135
136void oauth_params_del( GSList **params, const char *key )
137{
138        int key_len = strlen( key );
139        GSList *l, *n;
140       
141        for( l = *params; l; l = n )
142        {
143                n = l->next;
144               
145                if( strncmp( (char*) l->data, key, key_len ) == 0 &&
146                    ((char*)l->data)[key_len] == '=' )
147                {
148                        g_free( l->data );
149                        *params = g_slist_remove( *params, l );
150                }
151        }
152}
153
154void oauth_params_set( GSList **params, const char *key, const char *value )
155{
156        oauth_params_del( params, key );
157        oauth_params_add( params, key, value );
158}
159
160const char *oauth_params_get( GSList **params, const char *key )
161{
162        int key_len = strlen( key );
163        GSList *l;
164       
165        for( l = *params; l; l = l->next )
166        {
167                if( strncmp( (char*) l->data, key, key_len ) == 0 &&
168                    ((char*)l->data)[key_len] == '=' )
169                        return (const char*) l->data + key_len + 1;
170        }
171       
172        return NULL;
173}
174
175GSList *oauth_params_parse( char *in )
176{
177        GSList *ret = NULL;
178        char *amp, *eq;
179       
180        while( in && *in )
181        {
182                eq = strchr( in, '=' );
183                if( !eq )
184                        break;
185               
186                *eq = '\0';
187                if( ( amp = strchr( eq + 1, '&' ) ) )
188                        *amp = '\0';
189               
190                oauth_params_add( &ret, in, eq + 1 );
191               
192                *eq = '=';
193                if( amp == NULL )
194                        break;
195               
196                *amp = '&';
197                in = amp + 1;
198        }
199       
200        return ret;
201}
202
203void oauth_params_free( GSList **params )
204{
205        while( params && *params )
206        {
207                g_free( (*params)->data );
208                *params = g_slist_remove( *params, (*params)->data );
209        }
210}
211
212char *oauth_params_string( GSList *params )
213{
214        GSList *l;
215        GString *str = g_string_new( "" );
216       
217        for( l = params; l; l = l->next )
218        {
219                g_string_append( str, l->data );
220                if( l->next )
221                        g_string_append_c( str, '&' );
222        }
223       
224        return g_string_free( str, FALSE );
225}
226
227static void *oauth_post_request( const char *url, GSList **params_, http_input_function func, void *data )
228{
229        GSList *params = NULL;
230        char *s, *params_s, *post;
231        void *req;
232        url_t url_p;
233       
234        if( !url_set( &url_p, url ) )
235        {
236                oauth_params_free( params_ );
237                return NULL;
238        }
239       
240        if( params_ )
241                params = *params_;
242       
243        oauth_params_set( &params, "oauth_consumer_key", CONSUMER_KEY );
244        oauth_params_set( &params, "oauth_signature_method", "HMAC-SHA1" );
245       
246        s = g_strdup_printf( "%d", (int) time( NULL ) );
247        oauth_params_set( &params, "oauth_timestamp", s );
248        g_free( s );
249       
250        s = oauth_nonce();
251        oauth_params_set( &params, "oauth_nonce", s );
252        g_free( s );
253       
254        oauth_params_set( &params, "oauth_version", "1.0" );
255        oauth_params_set( &params, "oauth_callback", "oob" );
256       
257        params_s = oauth_params_string( params );
258        oauth_params_free( params_ );
259       
260        s = oauth_sign( "POST", url, params_s, NULL );
261        s = g_realloc( s, strlen( s ) * 3 + 1 );
262        http_encode( s );
263       
264        post = g_strdup_printf( "%s&oauth_signature=%s", params_s, s );
265        g_free( params_s );
266        g_free( s );
267       
268        s = g_strdup_printf( "POST %s HTTP/1.0\r\n"
269                             "Host: %s\r\n"
270                             "Content-Type: application/x-www-form-urlencoded\r\n"
271                             "Content-Length: %zd\r\n"
272                             "\r\n"
273                             "%s", url_p.file, url_p.host, strlen( post ), post );
274        g_free( post );
275       
276        req = http_dorequest( url_p.host, url_p.port, url_p.proto == PROTO_HTTPS,
277                              s, func, data );
278        g_free( s );
279       
280        return req;
281}
282
283void oauth_request_token_done( struct http_request *req );
284
285void *oauth_request_token( const char *url, oauth_cb func, void *data )
286{
287        struct oauth_info *st = g_new0( struct oauth_info, 1 );
288       
289        st->func = func;
290        st->data = data;
291       
292        return oauth_post_request( url, NULL, oauth_request_token_done, st );
293}
294
295void oauth_request_token_done( struct http_request *req )
296{
297        struct oauth_info *st = req->data;
298       
299        st->http = req;
300       
301        if( req->status_code == 200 )
302        {
303                GSList *params;
304               
305                st->auth_params = g_strdup( req->reply_body );
306                params = oauth_params_parse( st->auth_params );
307                st->token = g_strdup( oauth_params_get( &params, "oauth_token" ) );
308                oauth_params_free( &params );
309        }
310       
311        st->func( st );
312}
Note: See TracBrowser for help on using the repository browser.