change labels, remove empty lines, show phishing warning on copy
[claws.git] / src / oauth2.c
blob2ea840474b42a4f65f31569c31b72ad4529fe067
1 /*
2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2021 the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #include "claws-features.h"
23 #endif
25 #include <glib.h>
26 #ifdef ENABLE_NLS
27 #include <glib/gi18n.h>
28 #else
29 #define _(a) (a)
30 #define N_(a) (a)
31 #endif
32 #include <stdio.h>
33 #include <string.h>
34 #include <errno.h>
36 #include "oauth2.h"
37 #include "md5.h"
38 #include "utils.h"
39 #include "log.h"
40 #include "time.h"
41 #include "common/passcrypt.h"
43 //Yahoo requires token requests to send POST header Authorization: Basic
44 //where the password is Base64 encoding of client_id:client_secret
46 static gchar *OAUTH2info[4][17]={
47 {"accounts.google.com",
48 "",
49 ".",
50 "urn:ietf:wg:oauth:2.0:oob",
51 "/o/oauth2/auth",
52 "/o/oauth2/token",
53 "/o/oauth2/token",
54 "code",
55 "https://mail.google.com",
56 "authorization_code",
57 "refresh_token",
58 "",
59 "",
60 "",
61 "",
62 "",
63 ""},
64 {"login.microsoftonline.com",
65 "",
66 "",
67 "https://login.microsoftonline.com/common/oauth2/nativeclient",
68 "/common/oauth2/v2.0/authorize",
69 "/common/oauth2/v2.0/token",
70 "/common/oauth2/v2.0/token",
71 "code",
72 "wl.imap offline_access",
73 "authorization_code",
74 "refresh_token",
75 "common",
76 "",
77 "offline",
78 "wl.imap offline_access",
79 "fragment",
80 ""},
81 {"login.microsoftonline.com",
82 "",
83 "",
84 "https://login.microsoftonline.com/common/oauth2/nativeclient",
85 "/common/oauth2/v2.0/authorize",
86 "/common/oauth2/v2.0/token",
87 "/common/oauth2/v2.0/token",
88 "code",
89 "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send",
90 "authorization_code",
91 "refresh_token",
92 "common",
93 "",
94 "offline",
95 "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send",
96 "fragment",
97 ""},
98 {"api.login.yahoo.com",
99 "",
100 ".",
101 "oob",
102 "/oauth2/request_auth",
103 "/oauth2/get_token",
104 "/oauth2/get_token",
105 "code",
107 "authorization_code",
108 "refresh_token",
114 "1"}
117 static gchar *OAUTH2CodeMarker[5][2] = {
118 {"",""},
119 {"google_begin_mark","google_end_mark"}, /* Not used since token avalable to user to copy in browser window */
120 {"#code=","&session_state"},
121 {"#code=","&session_state"},
122 {"yahoo_begin_mark","yahoo_end_mark"} /* Not used since token avalable to user to copy in browser window */
125 static gint oauth2_post_request (gchar *buf, gchar *host, gchar *resource, gchar *header, gchar *body);
126 static gint oauth2_filter_refresh (gchar *json, gchar *refresh_token);
127 static gint oauth2_filter_access (gchar *json, gchar *access_token, gint *expiry);
128 static gint oauth2_contact_server (SockInfo *sock, gchar *request, gchar *response);
131 static gint oauth2_post_request (gchar *buf, gchar *host, gchar *resource, gchar *header, gchar *body)
133 gint len;
135 len = strlen(body);
136 if (header[0])
137 return snprintf(buf, OAUTH2BUFSIZE, "POST %s HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: text/html,application/json\r\nContent-Length: %i\r\nHost: %s\r\nConnection: close\r\nUser-Agent: ClawsMail\r\n%s\r\n\r\n%s", resource, len, host, header, body);
138 else
139 return snprintf(buf, OAUTH2BUFSIZE, "POST %s HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: text/html,application/json\r\nContent-Length: %i\r\nHost: %s\r\nConnection: close\r\nUser-Agent: ClawsMail\r\n\r\n%s", resource, len, host, body);
142 static gint oauth2_filter_access (gchar *json, gchar *access_token, gint *expiry)
144 GMatchInfo *matchInfo;
145 GRegex *regex;
147 regex = g_regex_new ("\"access_token\": ?\"(.*?)\",?", 0, 0, NULL);
148 g_regex_match (regex, json, 0, &matchInfo);
149 if (g_match_info_matches (matchInfo))
150 g_stpcpy (access_token,g_match_info_fetch (matchInfo, 1));
151 else{
152 g_match_info_free (matchInfo);
153 return (-1);
156 g_match_info_free (matchInfo);
158 regex = g_regex_new ("\"expires_in\": ?([0-9]*),?", 0, 0, NULL);
159 g_regex_match (regex, json, 0, &matchInfo);
160 if (g_match_info_matches (matchInfo)){
161 // Reduce available token life to avoid attempting connections with (near) expired tokens
162 *expiry = (g_get_real_time () / G_USEC_PER_SEC) + atoi(g_match_info_fetch (matchInfo, 1)) - 120;
163 }else{
164 g_match_info_free (matchInfo);
165 return (-2);
168 g_match_info_free (matchInfo);
170 return(0);
173 static gint oauth2_filter_refresh (gchar *json, gchar *refresh_token)
175 GMatchInfo *matchInfo;
176 GRegex *regex;
178 regex = g_regex_new ("\"refresh_token\": ?\"(.*?)\",?", 0, 0, NULL);
179 g_regex_match (regex, json, 0, &matchInfo);
180 if (g_match_info_matches (matchInfo))
181 g_stpcpy (refresh_token,g_match_info_fetch (matchInfo, 1));
182 else{
183 g_match_info_free (matchInfo);
184 return (-1);
187 g_match_info_free (matchInfo);
189 return(0);
192 static gchar* oauth2_get_token_from_response(Oauth2Service provider, const gchar* response) {
193 gchar* token = NULL;
195 debug_print("Auth response: %s\n", response);
196 if (provider == OAUTH2AUTH_YAHOO || provider == OAUTH2AUTH_GOOGLE) {
197 /* Providers which display auth token in browser for users to copy */
198 token = g_strdup(response);
199 } else {
200 gchar* start = g_strstr_len(response, strlen(response), OAUTH2CodeMarker[provider][0]);
201 start += strlen(OAUTH2CodeMarker[provider][0]);
202 if (start == NULL)
203 return NULL;
204 gchar* stop = g_strstr_len(response, strlen(response), OAUTH2CodeMarker[provider][1]);
205 if (stop == NULL)
206 return NULL;
207 token = g_strndup(start, stop - start);
210 return token;
213 int oauth2_obtain_tokens (Oauth2Service provider, OAUTH2Data *OAUTH2Data, const gchar *authcode)
215 gchar *request;
216 gchar *response;
217 gchar *body;
218 gchar *header;
219 gchar *tmp_hd;
220 gchar *access_token;
221 gchar *refresh_token;
222 gint expiry = 0;
223 gint ret;
224 SockInfo *sock;
225 gchar *client_id;
226 gchar *client_secret;
227 gchar *token = NULL;
229 gint i;
231 i = (int)provider - 1;
232 if (i < 0 || i > (OAUTH2AUTH_LAST-1))
233 return (1);
235 token = oauth2_get_token_from_response(provider, authcode);
236 debug_print("Auth token: %s\n", token);
237 if (token == NULL) {
238 log_message(LOG_PROTOCOL, _("OAuth2 missing authorization code\n"));
239 return (1);
242 sock = sock_connect(OAUTH2info[i][OA2_BASE_URL], 443);
243 if (sock == NULL) {
244 log_message(LOG_PROTOCOL, _("OAuth2 connection error\n"));
245 g_free(token);
246 return (1);
248 sock->ssl_cert_auto_accept = TRUE;
249 sock_set_nonblocking_mode(sock, FALSE);
250 sock_set_io_timeout(10);
251 sock->gnutls_priority = "NORMAL:!VERS-SSL3.0:!VERS-TLS1.0:!VERS-TLS1.1";
252 if (ssl_init_socket(sock) == FALSE) {
253 log_message(LOG_PROTOCOL, _("OAuth2 SSL/TLS connection error\n"));
254 g_free(token);
255 return (1);
258 refresh_token = g_malloc(OAUTH2BUFSIZE+1);
259 access_token = g_malloc(OAUTH2BUFSIZE+1);
260 request = g_malloc(OAUTH2BUFSIZE+1);
261 response = g_malloc(OAUTH2BUFSIZE+1);
262 body = g_malloc(OAUTH2BUFSIZE+1);
264 if(OAUTH2Data->custom_client_id)
265 client_id = g_strdup(OAUTH2Data->custom_client_id);
266 else
267 client_id = oauth2_decode(OAUTH2info[i][OA2_CLIENT_ID]);
269 body = g_strconcat ("client_id=", g_uri_escape_string (client_id, NULL, FALSE),
270 "&code=",g_uri_escape_string (token, NULL, FALSE), NULL);
271 g_free(token);
273 if(OAUTH2info[i][OA2_CLIENT_SECRET][0]){
274 //Only allow custom client secret if the service provider would usually expect a client secret
275 if(OAUTH2Data->custom_client_secret)
276 client_secret = g_strdup(OAUTH2Data->custom_client_secret);
277 else
278 client_secret = oauth2_decode(OAUTH2info[i][OA2_CLIENT_SECRET]);
279 body = g_strconcat (body, "&client_secret=", g_uri_escape_string (client_secret, NULL, FALSE), NULL);
280 }else{
281 client_secret = g_strconcat ("", NULL);
284 if(OAUTH2info[i][OA2_REDIRECT_URI][0])
285 body = g_strconcat (body, "&redirect_uri=",g_uri_escape_string (OAUTH2info[i][OA2_REDIRECT_URI], NULL, FALSE), NULL);
286 if(OAUTH2info[i][OA2_GRANT_TYPE_ACCESS][0])
287 body = g_strconcat (body, "&grant_type=", g_uri_escape_string (OAUTH2info[i][OA2_GRANT_TYPE_ACCESS], NULL, FALSE), NULL);
288 if(OAUTH2info[i][OA2_TENANT][0])
289 body = g_strconcat (body, "&tenant=", g_uri_escape_string (OAUTH2info[i][OA2_TENANT], NULL, FALSE), NULL);
290 if(OAUTH2info[i][OA2_SCOPE_FOR_ACCESS][0])
291 body = g_strconcat (body, "&scope=", g_uri_escape_string (OAUTH2info[i][OA2_SCOPE_FOR_ACCESS], NULL, FALSE), NULL);
292 if(OAUTH2info[i][OA2_STATE][0])
293 body = g_strconcat (body, "&state=", g_uri_escape_string (OAUTH2info[i][OA2_STATE], NULL, FALSE), NULL);
295 if(OAUTH2info[i][OA2_HEADER_AUTH_BASIC][0]){
296 tmp_hd = g_strconcat(client_id, ":", client_secret, NULL);
297 header = g_strconcat ("Authorization: Basic ", g_base64_encode (tmp_hd, strlen(tmp_hd)), NULL);
298 g_free(tmp_hd);
299 }else{
300 header = g_strconcat ("", NULL);
303 oauth2_post_request (request, OAUTH2info[i][OA2_BASE_URL], OAUTH2info[i][OA2_ACCESS_RESOURCE], header, body);
304 ret = oauth2_contact_server (sock, request, response);
306 if(oauth2_filter_access (response, access_token, &expiry) == 0){
307 OAUTH2Data->access_token = access_token;
308 OAUTH2Data->expiry = expiry;
309 OAUTH2Data->expiry_str = g_strdup_printf ("%i", expiry);
310 ret = 0;
311 log_message(LOG_PROTOCOL, _("OAuth2 access token obtained\n"));
312 }else{
313 log_message(LOG_PROTOCOL, _("OAuth2 access token not obtained\n"));
314 debug_print("OAuth2 - request: %s\n Response: %s", request, response);
315 ret = 1;
318 if(oauth2_filter_refresh (response, refresh_token) == 0){
319 OAUTH2Data->refresh_token = refresh_token;
320 log_message(LOG_PROTOCOL, _("OAuth2 refresh token obtained\n"));
321 }else{
322 log_message(LOG_PROTOCOL, _("OAuth2 refresh token not obtained\n"));
325 sock_close(sock, TRUE);
326 g_free(body);
327 g_free(header);
328 g_free(request);
329 g_free(response);
330 g_free(client_id);
331 g_free(client_secret);
333 return (ret);
336 gint oauth2_use_refresh_token (Oauth2Service provider, OAUTH2Data *OAUTH2Data)
339 gchar *request;
340 gchar *response;
341 gchar *body;
342 gchar *header;
343 gchar *tmp_hd;
344 gchar *access_token;
345 gint expiry = 0;
346 gint ret;
347 SockInfo *sock;
348 gchar *client_id;
349 gchar *client_secret;
351 gint i;
353 i = (int)provider - 1;
354 if (i < 0 || i > (OAUTH2AUTH_LAST-1))
355 return (1);
357 sock = sock_connect(OAUTH2info[i][OA2_BASE_URL], 443);
358 if (sock == NULL) {
359 log_message(LOG_PROTOCOL, _("OAuth2 connection error\n"));
360 return (1);
362 sock->ssl_cert_auto_accept = TRUE;
363 sock_set_nonblocking_mode(sock, FALSE);
364 sock_set_io_timeout(10);
365 sock->gnutls_priority = "NORMAL:!VERS-SSL3.0:!VERS-TLS1.0:!VERS-TLS1.1";
366 if (ssl_init_socket(sock) == FALSE) {
367 log_message(LOG_PROTOCOL, _("OAuth2 SSL connection error\n"));
368 return (1);
371 access_token = g_malloc(OAUTH2BUFSIZE+1);
372 request = g_malloc(OAUTH2BUFSIZE+1);
373 response = g_malloc(OAUTH2BUFSIZE+1);
374 body = g_malloc(OAUTH2BUFSIZE+1);
376 if(OAUTH2Data->custom_client_id)
377 client_id = g_strdup(OAUTH2Data->custom_client_id);
378 else
379 client_id = oauth2_decode(OAUTH2info[i][OA2_CLIENT_ID]);
381 body = g_strconcat ("client_id=", g_uri_escape_string (client_id, NULL, FALSE),
382 "&refresh_token=",OAUTH2Data->refresh_token, NULL);
384 if(OAUTH2info[i][OA2_CLIENT_SECRET][0]){
385 //Only allow custom client secret if the service provider would usually expect a client secret
386 if(OAUTH2Data->custom_client_secret)
387 client_secret = g_strdup(OAUTH2Data->custom_client_secret);
388 else
389 client_secret = oauth2_decode(OAUTH2info[i][OA2_CLIENT_SECRET]);
390 body = g_strconcat (body, "&client_secret=", g_uri_escape_string (client_secret, NULL, FALSE), NULL);
391 }else{
392 client_secret = g_strconcat ("", NULL);
395 if(OAUTH2info[i][OA2_GRANT_TYPE_REFRESH][0])
396 body = g_strconcat (body, "&grant_type=", g_uri_escape_string (OAUTH2info[i][OA2_GRANT_TYPE_REFRESH], NULL, FALSE), NULL);
397 if(OAUTH2info[i][OA2_SCOPE_FOR_ACCESS][0])
398 body = g_strconcat (body, "&scope=", g_uri_escape_string (OAUTH2info[i][OA2_SCOPE_FOR_ACCESS], NULL, FALSE), NULL);
399 if(OAUTH2info[i][OA2_STATE][0])
400 body = g_strconcat (body, "&state=", g_uri_escape_string (OAUTH2info[i][OA2_STATE], NULL, FALSE), NULL);
402 if(OAUTH2info[i][OA2_HEADER_AUTH_BASIC][0]){
403 tmp_hd = g_strconcat(client_id, ":", client_secret, NULL);
404 header = g_strconcat ("Authorization: Basic ", g_base64_encode (tmp_hd, strlen(tmp_hd)), NULL);
405 g_free(tmp_hd);
406 }else{
407 header = g_strconcat ("", NULL);
410 oauth2_post_request (request, OAUTH2info[i][OA2_BASE_URL], OAUTH2info[i][OA2_REFRESH_RESOURCE], header, body);
411 ret = oauth2_contact_server (sock, request, response);
413 if(oauth2_filter_access (response, access_token, &expiry) == 0){
414 OAUTH2Data->access_token = access_token;
415 OAUTH2Data->expiry = expiry;
416 OAUTH2Data->expiry_str = g_strdup_printf ("%i", expiry);
417 ret = 0;
418 log_message(LOG_PROTOCOL, _("OAuth2 access token obtained\n"));
419 }else{
420 log_message(LOG_PROTOCOL, _("OAuth2 access token not obtained\n"));
421 debug_print("OAuth2 - request: %s\n Response: %s", request, response);
422 ret = 1;
425 debug_print("OAuth2 - access token: %s\n", access_token);
426 debug_print("OAuth2 - access token expiry: %i\n", expiry);
428 sock_close(sock, TRUE);
429 g_free(body);
430 g_free(header);
431 g_free(request);
432 g_free(response);
433 g_free(client_id);
434 g_free(client_secret);
436 return (ret);
439 static gint oauth2_contact_server (SockInfo *sock, gchar *request, gchar *response)
441 gint len;
442 gint ret;
443 gchar *token;
444 gint toread = OAUTH2BUFSIZE;
445 time_t startplus = time(NULL);
447 len = strlen(request);
449 startplus += 10;
451 if (sock_write (sock, request, len+1) < 0) {
452 log_message(LOG_PROTOCOL, _("OAuth2 socket write error\n"));
453 return (1);
456 token = g_strconcat ("", NULL);
457 do {
459 ret = sock_read (sock, response, OAUTH2BUFSIZE);
460 if (ret < 0 && errno == EAGAIN)
461 continue;
462 if (ret < 0)
463 break;
464 if (ret == 0)
465 break;
467 toread -= ret;
468 token = g_strconcat(token, response, NULL);
469 } while ((toread > 0) && (time(NULL) < startplus));
471 if(time(NULL) >= startplus)
472 log_message(LOG_PROTOCOL, _("OAuth2 socket timeout error\n"));
474 g_free(token);
476 return (0);
479 gint oauth2_authorisation_url (Oauth2Service provider, gchar **url, const gchar *custom_client_id)
481 gint i;
482 const gchar *client_id;
484 i = (int)provider - 1;
485 if (i < 0 || i > (OAUTH2AUTH_LAST-1))
486 return (1);
488 if(custom_client_id)
489 client_id = custom_client_id;
490 else
491 client_id = oauth2_decode(OAUTH2info[i][OA2_CLIENT_ID]);
493 *url = g_strconcat ("https://", OAUTH2info[i][OA2_BASE_URL],OAUTH2info[i][OA2_AUTH_RESOURCE], "?client_id=",
494 g_uri_escape_string (client_id, NULL, FALSE), NULL);
496 if(OAUTH2info[i][OA2_REDIRECT_URI][0])
497 *url = g_strconcat (*url, "&redirect_uri=", g_uri_escape_string (OAUTH2info[i][OA2_REDIRECT_URI], NULL, FALSE), NULL);
498 if(OAUTH2info[i][OA2_RESPONSE_TYPE][0])
499 *url = g_strconcat (*url, "&response_type=",g_uri_escape_string (OAUTH2info[i][OA2_RESPONSE_TYPE], NULL, FALSE), NULL);
500 if(OAUTH2info[i][OA2_SCOPE_FOR_AUTH][0])
501 *url = g_strconcat (*url, "&scope=", g_uri_escape_string (OAUTH2info[i][OA2_SCOPE_FOR_AUTH], NULL, FALSE), NULL);
502 if(OAUTH2info[i][OA2_TENANT][0])
503 *url = g_strconcat (*url, "&tenant=", g_uri_escape_string (OAUTH2info[i][OA2_TENANT], NULL, FALSE), NULL);
504 if(OAUTH2info[i][OA2_RESPONSE_MODE][0])
505 *url = g_strconcat (*url, "&response_mode=", g_uri_escape_string (OAUTH2info[i][OA2_RESPONSE_MODE], NULL, FALSE), NULL);
506 if(OAUTH2info[i][OA2_STATE][0])
507 *url = g_strconcat (*url, "&state=", g_uri_escape_string (OAUTH2info[i][OA2_STATE], NULL, FALSE), NULL);
509 return (0);
512 gint oauth2_check_passwds (PrefsAccount *ac_prefs)
514 gchar *uid = g_strdup_printf("%d", ac_prefs->account_id);
515 gint expiry;
516 OAUTH2Data *OAUTH2Data = g_malloc(sizeof(* OAUTH2Data));
517 gint ret;
519 oauth2_init (OAUTH2Data);
521 OAUTH2Data->custom_client_id = ac_prefs->oauth2_client_id;
522 OAUTH2Data->custom_client_secret = ac_prefs->oauth2_client_secret;
524 if(passwd_store_has_password(PWS_ACCOUNT, uid, PWS_ACCOUNT_OAUTH2_EXPIRY)) {
525 expiry = atoi(passwd_store_get_account(ac_prefs->account_id, PWS_ACCOUNT_OAUTH2_EXPIRY));
526 if (expiry > (g_get_real_time () / G_USEC_PER_SEC)){
527 g_free(OAUTH2Data);
528 log_message(LOG_PROTOCOL, _("OAuth2 access token still fresh\n"));
529 return (0);
533 if(passwd_store_has_password(PWS_ACCOUNT, uid, PWS_ACCOUNT_OAUTH2_REFRESH)) {
534 log_message(LOG_PROTOCOL, _("OAuth2 obtaining access token using refresh token\n"));
535 OAUTH2Data->refresh_token = passwd_store_get_account(ac_prefs->account_id, PWS_ACCOUNT_OAUTH2_REFRESH);
536 ret = oauth2_use_refresh_token (ac_prefs->oauth2_provider, OAUTH2Data);
537 }else if (passwd_store_has_password(PWS_ACCOUNT, uid, PWS_ACCOUNT_OAUTH2_AUTH)) {
538 log_message(LOG_PROTOCOL, _("OAuth2 trying for fresh access token with authorization code\n"));
539 ret = oauth2_obtain_tokens (ac_prefs->oauth2_provider, OAUTH2Data,
540 passwd_store_get_account(ac_prefs->account_id, PWS_ACCOUNT_OAUTH2_AUTH));
541 }else{
542 ret = 1;
545 if (ret){
546 log_message(LOG_PROTOCOL, _("OAuth2 access token not obtained\n"));
547 }else{
548 passwd_store_set_account(ac_prefs->account_id, PWS_ACCOUNT_RECV, OAUTH2Data->access_token, FALSE);
549 if (ac_prefs->use_smtp_auth && ac_prefs->smtp_auth_type == SMTPAUTH_OAUTH2)
550 passwd_store_set_account(ac_prefs->account_id, PWS_ACCOUNT_SEND, OAUTH2Data->access_token, FALSE);
551 passwd_store_set_account(ac_prefs->account_id, PWS_ACCOUNT_OAUTH2_EXPIRY, OAUTH2Data->expiry_str, FALSE);
552 log_message(LOG_PROTOCOL, _("OAuth2 access token updated\n"));
555 g_free(OAUTH2Data);
557 return (ret);
560 /* returns allocated string which must be freed */
561 guchar* oauth2_decode(const gchar *in)
563 guchar *tmp;
564 gsize len;
566 tmp = g_base64_decode(in, &len);
567 passcrypt_decrypt(tmp, len);
568 return tmp;
571 /* For testing */
572 void oauth2_encode(const gchar *in)
574 guchar *tmp = g_strdup(in);
575 guchar *tmp2 = g_strdup(in);
576 gchar *result;
577 gsize len = strlen(in);
579 passcrypt_encrypt(tmp, len);
580 result = g_base64_encode(tmp, len);
581 tmp2 = oauth2_decode(result);
583 log_message(LOG_PROTOCOL, _("OAuth2 original: %s\n"), in);
584 log_message(LOG_PROTOCOL, _("OAuth2 encoded: %s\n"), result);
585 log_message(LOG_PROTOCOL, _("OAuth2 decoded: %s\n\n"), tmp2);
587 g_free(tmp);
588 g_free(tmp2);
589 g_free(result);
592 gint oauth2_init (OAUTH2Data *OAUTH2Data)
594 OAUTH2Data->refresh_token = NULL;
595 OAUTH2Data->access_token = NULL;
596 OAUTH2Data->expiry_str = NULL;
597 OAUTH2Data->expiry = 0;
598 OAUTH2Data->custom_client_id = NULL;
599 OAUTH2Data->custom_client_secret = NULL;
601 return (0);