1 /***************************************************************************\
3 * BitlBee - An IRC to IM gateway *
4 * Simple OAuth client (consumer) implementation. *
6 * Copyright 2010-2011 Wilmer van der Gaast <wilmer@gaast.net> *
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. *
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. *
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. *
22 \***************************************************************************/
25 #include "http_client.h"
30 char *oauth2_url( const struct oauth2_service
*sp
)
32 return g_strconcat( sp
->auth_url
,
35 "&redirect_uri=", sp
->redirect_url
,
36 "&client_id=", sp
->consumer_key
,
40 struct oauth2_access_token_data
42 oauth2_token_callback func
;
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
)
56 struct http_request
*req
;
57 struct oauth2_access_token_data
*cb_data
;
59 if( !url_set( &url_p
, sp
->token_url
) )
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
);
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"
79 "Content-Type: application/x-www-form-urlencoded\r\n"
80 "Content-Length: %zd\r\n"
81 "Connection: close\r\n"
83 "%s", url_p
.file
, url_p
.host
, strlen( args_s
), args_s
);
86 cb_data
= g_new0( struct oauth2_access_token_data
, 1 );
90 req
= http_dorequest( url_p
.host
, url_p
.port
, url_p
.proto
== PROTO_HTTPS
,
91 s
, oauth2_access_token_done
, cb_data
);
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" );
122 /* Facebook use their own odd format here, seems to be URL-encoded. */
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
);
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 */
149 while( json
&& *json
)
151 /* Grab strings and see if they're what we're looking for. */
152 if( *json
== '"' || *json
== '\'' )
155 const char *str_start
;
161 /* \' and \" are not string terminators. */
162 if( *json
== '\\' && json
[1] == q
)
164 /* But without a \ it is. */
165 else if( *json
== q
)
172 if( is_key
&& strncmp( str_start
, key
, strlen( key
) ) == 0 )
176 else if( !is_key
&& found_key
)
178 char *ret
= g_memdup( str_start
, json
- str_start
+ 1 );
179 ret
[json
-str_start
] = '\0';
184 else if( *json
== '{' || *json
== ',' )
189 else if( *json
== ':' )