Scan media entities as well, not just url entities. This should expand more
[bitlbee.git] / lib / oauth2.c
blob87965d04e9b01bd585bd450456646ba9f211d94a
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 \***************************************************************************/
24 #include <glib.h>
25 #include "http_client.h"
26 #include "oauth2.h"
27 #include "oauth.h"
28 #include "url.h"
30 char *oauth2_url( const struct oauth2_service *sp )
32 return g_strconcat( sp->auth_url,
33 "?scope=", sp->scope,
34 "&response_type=code"
35 "&redirect_uri=", sp->redirect_url,
36 "&client_id=", sp->consumer_key,
37 NULL );
40 struct oauth2_access_token_data
42 oauth2_token_callback func;
43 gpointer data;
46 static char *oauth2_json_dumb_get( const char *json, const char *key );
47 static void oauth2_access_token_done( struct http_request *req );
49 int oauth2_access_token( const struct oauth2_service *sp,
50 const char *auth_type, const char *auth,
51 oauth2_token_callback func, gpointer data )
53 GSList *args = NULL;
54 char *args_s, *s;
55 url_t url_p;
56 struct http_request *req;
57 struct oauth2_access_token_data *cb_data;
59 if( !url_set( &url_p, sp->token_url ) )
60 return 0;
62 oauth_params_add( &args, "client_id", sp->consumer_key );
63 oauth_params_add( &args, "client_secret", sp->consumer_secret );
64 oauth_params_add( &args, "grant_type", auth_type );
65 if( strcmp( auth_type, OAUTH2_AUTH_CODE ) == 0 )
67 oauth_params_add( &args, "redirect_uri", sp->redirect_url );
68 oauth_params_add( &args, "code", auth );
70 else
72 oauth_params_add( &args, "refresh_token", auth );
74 args_s = oauth_params_string( args );
75 oauth_params_free( &args );
77 s = g_strdup_printf( "POST %s HTTP/1.0\r\n"
78 "Host: %s\r\n"
79 "Content-Type: application/x-www-form-urlencoded\r\n"
80 "Content-Length: %zd\r\n"
81 "Connection: close\r\n"
82 "\r\n"
83 "%s", url_p.file, url_p.host, strlen( args_s ), args_s );
84 g_free( args_s );
86 cb_data = g_new0( struct oauth2_access_token_data, 1 );
87 cb_data->func = func;
88 cb_data->data = data;
90 req = http_dorequest( url_p.host, url_p.port, url_p.proto == PROTO_HTTPS,
91 s, oauth2_access_token_done, cb_data );
93 g_free( s );
95 if( req == NULL )
96 g_free( cb_data );
98 return req != NULL;
101 static void oauth2_access_token_done( struct http_request *req )
103 struct oauth2_access_token_data *cb_data = req->data;
104 char *atoken = NULL, *rtoken = NULL;
105 const char *content_type;
107 if( getenv( "BITLBEE_DEBUG" ) && req->reply_body )
108 printf( "%s\n", req->reply_body );
110 content_type = get_rfc822_header( req->reply_headers, "Content-Type", 0 );
112 if( req->status_code != 200 )
115 else if( content_type && strstr( content_type, "application/json" ) )
117 atoken = oauth2_json_dumb_get( req->reply_body, "access_token" );
118 rtoken = oauth2_json_dumb_get( req->reply_body, "refresh_token" );
120 else
122 /* Facebook use their own odd format here, seems to be URL-encoded. */
123 GSList *p_in = NULL;
125 oauth_params_parse( &p_in, req->reply_body );
126 atoken = g_strdup( oauth_params_get( &p_in, "access_token" ) );
127 rtoken = g_strdup( oauth_params_get( &p_in, "refresh_token" ) );
128 oauth_params_free( &p_in );
130 if( getenv( "BITLBEE_DEBUG" ) )
131 printf( "Extracted atoken=%s rtoken=%s\n", atoken, rtoken );
133 cb_data->func( cb_data->data, atoken, rtoken );
134 g_free( atoken );
135 g_free( rtoken );
136 g_free( cb_data );
139 /* Super dumb. I absolutely refuse to use/add a complete json parser library
140 (adding a new dependency to BitlBee for the first time in.. 6 years?) just
141 to parse 100 bytes of data. So I have to do my own parsing because OAuth2
142 dropped support for XML. (GRRR!) This is very dumb and for example won't
143 work for integer values, nor will it strip/handle backslashes. */
144 static char *oauth2_json_dumb_get( const char *json, const char *key )
146 int is_key = 0; /* 1 == reading key, 0 == reading value */
147 int found_key = 0;
149 while( json && *json )
151 /* Grab strings and see if they're what we're looking for. */
152 if( *json == '"' || *json == '\'' )
154 char q = *json;
155 const char *str_start;
156 json ++;
157 str_start = json;
159 while( *json )
161 /* \' and \" are not string terminators. */
162 if( *json == '\\' && json[1] == q )
163 json ++;
164 /* But without a \ it is. */
165 else if( *json == q )
166 break;
167 json ++;
169 if( *json == '\0' )
170 return NULL;
172 if( is_key && strncmp( str_start, key, strlen( key ) ) == 0 )
174 found_key = 1;
176 else if( !is_key && found_key )
178 char *ret = g_memdup( str_start, json - str_start + 1 );
179 ret[json-str_start] = '\0';
180 return ret;
184 else if( *json == '{' || *json == ',' )
186 found_key = 0;
187 is_key = 1;
189 else if( *json == ':' )
190 is_key = 0;
192 json ++;
195 return NULL;