source: lib/oauth2.c @ e1c926f

Last change on this file since e1c926f was 39a939c, checked in by Wilmer van der Gaast <wilmer@…>, at 2011-07-31T14:55:00Z

oauth2 changes to address http://twitter.com/Wilmer/status/96715400124968960

  • Property mode set to 100644
File size: 6.1 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Simple OAuth client (consumer) implementation.                           *
5*                                                                           *
6*  Copyright 2010-2011 Wilmer van der Gaast <wilmer@gaast.net>              *
7*                                                                           *
8*  This program is free software; you can redistribute it and/or modify     *
9*  it under the terms of the GNU General Public License as published by     *
10*  the Free Software Foundation; either version 2 of the License, or        *
11*  (at your option) any later version.                                      *
12*                                                                           *
13*  This program 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            *
16*  GNU General Public License for more details.                             *
17*                                                                           *
18*  You should have received a copy of the GNU General Public License along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24#include <glib.h>
25#include "http_client.h"
26#include "oauth2.h"
27#include "oauth.h"
28#include "url.h"
29
30struct oauth2_service oauth2_service_google =
31{
32        "https://accounts.google.com/o/oauth2/auth",
33        "https://accounts.google.com/o/oauth2/token",
34        "urn:ietf:wg:oauth:2.0:oob",
35        "783993391592.apps.googleusercontent.com",
36        "k5_EV4EQ7jEVCEk3WBwEFfuW",
37};
38struct oauth2_service oauth2_service_facebook =
39{
40        "https://www.facebook.com/dialog/oauth",
41        "https://graph.facebook.com/oauth/access_token",
42        "http://www.bitlbee.org/main.php/fb.html",
43        "126828914005625",
44        "4b100f0f244d620bf3f15f8b217d4c32",
45};
46
47char *oauth2_url( const struct oauth2_service *sp, const char *scope )
48{
49        return g_strconcat( sp->auth_url,
50                            "?scope=", scope,
51                            "&response_type=code"
52                            "&redirect_uri=", sp->redirect_url, 
53                            "&client_id=", sp->consumer_key,
54                            NULL );
55}
56
57struct oauth2_access_token_data
58{
59        oauth2_token_callback func;
60        gpointer data;
61};
62
63static char *oauth2_json_dumb_get( const char *json, const char *key );
64static void oauth2_access_token_done( struct http_request *req );
65
66int oauth2_access_token( const struct oauth2_service *sp,
67                         const char *auth_type, const char *auth,
68                         oauth2_token_callback func, gpointer data )
69{
70        GSList *args = NULL;
71        char *args_s, *s;
72        url_t url_p;
73        struct http_request *req;
74        struct oauth2_access_token_data *cb_data;
75       
76        if( !url_set( &url_p, sp->token_url ) )
77                return 0;
78       
79        oauth_params_add( &args, "client_id", sp->consumer_key );
80        oauth_params_add( &args, "client_secret", sp->consumer_secret );
81        oauth_params_add( &args, "grant_type", auth_type );
82        if( strcmp( auth_type, OAUTH2_AUTH_CODE ) == 0 )
83        {
84                oauth_params_add( &args, "redirect_uri", sp->redirect_url );
85                oauth_params_add( &args, "code", auth );
86        }
87        else
88        {
89                oauth_params_add( &args, "refresh_token", auth );
90        }
91        args_s = oauth_params_string( args );
92        oauth_params_free( &args );
93       
94        s = g_strdup_printf( "POST %s HTTP/1.0\r\n"
95                             "Host: %s\r\n"
96                             "Content-Type: application/x-www-form-urlencoded\r\n"
97                             "Content-Length: %zd\r\n"
98                             "Connection: close\r\n"
99                             "\r\n"
100                             "%s", url_p.file, url_p.host, strlen( args_s ), args_s );
101        g_free( args_s );
102       
103        cb_data = g_new0( struct oauth2_access_token_data, 1 );
104        cb_data->func = func;
105        cb_data->data = data;
106       
107        req = http_dorequest( url_p.host, url_p.port, url_p.proto == PROTO_HTTPS,
108                              s, oauth2_access_token_done, cb_data );
109       
110        g_free( s );
111       
112        if( req == NULL )
113                g_free( cb_data );
114       
115        return req != NULL;
116}
117
118static void oauth2_access_token_done( struct http_request *req )
119{
120        struct oauth2_access_token_data *cb_data = req->data;
121        char *atoken = NULL, *rtoken = NULL;
122       
123        if( req->status_code == 200 )
124        {
125                atoken = oauth2_json_dumb_get( req->reply_body, "access_token" );
126                rtoken = oauth2_json_dumb_get( req->reply_body, "refresh_token" );
127        }
128        cb_data->func( cb_data->data, atoken, rtoken );
129        g_free( atoken );
130        g_free( rtoken );
131        g_free( cb_data );
132}
133
134/* Super dumb. I absolutely refuse to use/add a complete json parser library
135   (adding a new dependency to BitlBee for the first time in.. 6 years?) just
136   to parse 100 bytes of data. So I have to do my own parsing because OAuth2
137   dropped support for XML. (GRRR!) This is very dumb and for example won't
138   work for integer values, nor will it strip/handle backslashes. */
139static char *oauth2_json_dumb_get( const char *json, const char *key )
140{
141        int is_key; /* 1 == reading key, 0 == reading value */
142        int found_key = 0;
143               
144        while( json && *json )
145        {
146                /* Grab strings and see if they're what we're looking for. */
147                if( *json == '"' || *json == '\'' )
148                {
149                        char q = *json;
150                        const char *str_start;
151                        json ++;
152                        str_start = json;
153                       
154                        while( *json )
155                        {
156                                /* \' and \" are not string terminators. */
157                                if( *json == '\\' && json[1] == q )
158                                        json ++;
159                                /* But without a \ it is. */
160                                else if( *json == q )
161                                        break;
162                                json ++;
163                        }
164                        if( *json == '\0' )
165                                return NULL;
166                       
167                        if( is_key && strncmp( str_start, key, strlen( key ) ) == 0 )
168                        {
169                                found_key = 1;
170                        }
171                        else if( !is_key && found_key )
172                        {
173                                char *ret = g_memdup( str_start, json - str_start + 1 );
174                                ret[json-str_start] = '\0';
175                                return ret;
176                        }
177                       
178                }
179                else if( *json == '{' || *json == ',' )
180                {
181                        found_key = 0;
182                        is_key = 1;
183                }
184                else if( *json == ':' )
185                        is_key = 0;
186               
187                json ++;
188        }
189       
190        return NULL;
191}
Note: See TracBrowser for help on using the repository browser.