libpurple/protocols/gg/oauth/oauth-purple.c

Fri, 01 May 2020 04:42:52 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Fri, 01 May 2020 04:42:52 -0500
changeset 40358
e6fe6fc1f516
parent 40058
8a56f10bd1fb
child 40439
e9838d634d5e
permissions
-rw-r--r--

move all protocols, purple plugins, and purple tests to use purple.h instead of including files individually

/* purple
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * Rewritten from scratch during Google Summer of Code 2012
 * by Tomek Wasilczyk (http://www.wasilczyk.pl).
 *
 * Previously implemented by:
 *  - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
 *  - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
 *  - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 */

#include "oauth-purple.h"
#include "gg.h"

#include "oauth.h"
#include "../utils.h"
#include "../xml.h"

#include <purple.h>

#define GGP_OAUTH_RESPONSE_MAX 10240

typedef struct
{
	PurpleConnection *gc;
	ggp_oauth_request_cb callback;
	gpointer user_data;
	gchar *token;
	gchar *token_secret;

	gchar *sign_method, *sign_url;
} ggp_oauth_data;

static void ggp_oauth_data_free(ggp_oauth_data *data)
{
	g_free(data->token);
	g_free(data->token_secret);
	g_free(data->sign_method);
	g_free(data->sign_url);
	g_free(data);
}

static void
ggp_oauth_access_token_got(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg,
                           gpointer user_data)
{
	ggp_oauth_data *data = user_data;
	gchar *token, *token_secret;
	PurpleXmlNode *xml;
	gboolean succ = TRUE;

	xml = purple_xmlnode_from_str(msg->response_body->data,
	                              msg->response_body->length);
	if (xml == NULL) {
		purple_debug_error("gg", "ggp_oauth_access_token_got: invalid xml");
		ggp_oauth_data_free(data);
		return;
	}

	succ &= ggp_xml_get_string(xml, "oauth_token", &token);
	succ &= ggp_xml_get_string(xml, "oauth_token_secret", &token_secret);
	purple_xmlnode_free(xml);
	if (!succ || strlen(token) < 10) {
		purple_debug_error("gg", "ggp_oauth_access_token_got: invalid xml - "
		                         "token is not present");
		ggp_oauth_data_free(data);
		return;
	}

	if (data->sign_url) {
		PurpleAccount *account;
		gchar *auth;

		purple_debug_misc("gg", "ggp_oauth_access_token_got: got access token, "
		                        "returning signed url");

		account = purple_connection_get_account(data->gc);
		auth = gg_oauth_generate_header(
		        data->sign_method, data->sign_url,
		        purple_account_get_username(account),
		        purple_connection_get_password(data->gc), token, token_secret);
		data->callback(data->gc, auth, data->user_data);
	} else {
		purple_debug_misc(
		        "gg",
		        "ggp_oauth_access_token_got: got access token, returning it");
		data->callback(data->gc, token, data->user_data);
	}

	g_free(token);
	g_free(token_secret);
	ggp_oauth_data_free(data);
}

static void
ggp_oauth_authorization_done(SoupSession *session, SoupMessage *msg,
                             gpointer user_data)
{
	ggp_oauth_data *data = user_data;
	PurpleAccount *account;
	char *auth;
	const char *method = "POST";
	const char *url = "http://api.gadu-gadu.pl/access_token";

	PURPLE_ASSERT_CONNECTION_IS_VALID(data->gc);

	account = purple_connection_get_account(data->gc);

	if (msg->status_code != 302) {
		purple_debug_error("gg",
		                   "ggp_oauth_authorization_done: failed (code = %d)",
		                   msg->status_code);
		ggp_oauth_data_free(data);
		return;
	}

	purple_debug_misc("gg", "ggp_oauth_authorization_done: authorization done, "
	                        "requesting access token...");

	auth = gg_oauth_generate_header(method, url,
	                                purple_account_get_username(account),
	                                purple_connection_get_password(data->gc),
	                                data->token, data->token_secret);

	msg = soup_message_new(method, url);
	// purple_http_request_set_max_len(req, GGP_OAUTH_RESPONSE_MAX);
	soup_message_headers_replace(msg->request_headers, "Authorization", auth);
	soup_session_queue_message(session, msg, ggp_oauth_access_token_got, data);

	g_free(auth);
}

static void
ggp_oauth_request_token_got(SoupSession *session, SoupMessage *msg,
                            gpointer user_data)
{
	ggp_oauth_data *data = user_data;
	PurpleAccount *account;
	PurpleXmlNode *xml;
	gchar *request_data;
	gboolean succ = TRUE;

	PURPLE_ASSERT_CONNECTION_IS_VALID(data->gc);

	account = purple_connection_get_account(data->gc);

	if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
		purple_debug_error("gg", "ggp_oauth_request_token_got: "
			"requested token not received\n");
		ggp_oauth_data_free(data);
		return;
	}

	purple_debug_misc("gg", "ggp_oauth_request_token_got: "
		"got request token, doing authorization...\n");

	xml = purple_xmlnode_from_str(msg->response_body->data,
	                              msg->response_body->length);
	if (xml == NULL) {
		purple_debug_error("gg", "ggp_oauth_request_token_got: "
			"invalid xml\n");
		ggp_oauth_data_free(data);
		return;
	}

	succ &= ggp_xml_get_string(xml, "oauth_token", &data->token);
	succ &= ggp_xml_get_string(xml, "oauth_token_secret",
		&data->token_secret);
	purple_xmlnode_free(xml);
	if (!succ) {
		purple_debug_error("gg", "ggp_oauth_request_token_got: "
			"invalid xml - token is not present\n");
		ggp_oauth_data_free(data);
		return;
	}

	request_data = g_strdup_printf(
		"callback_url=http://www.mojageneracja.pl&request_token=%s&"
		"uin=%s&password=%s", data->token,
		purple_account_get_username(account),
		purple_connection_get_password(data->gc));

	msg = soup_message_new("POST", "https://login.gadu-gadu.pl/authorize");
	// purple_http_request_set_max_len(msg, GGP_OAUTH_RESPONSE_MAX);
	/* we don't need any results, nor 302 redirection */
	soup_message_set_flags(msg, SOUP_MESSAGE_NO_REDIRECT);
	soup_message_set_request(msg, "application/x-www-form-urlencoded",
	                         SOUP_MEMORY_TAKE, request_data, -1);
	soup_session_queue_message(session, msg, ggp_oauth_authorization_done,
	                           data);
}

void
ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback,
                  gpointer user_data, const gchar *sign_method,
                  const gchar *sign_url)
{
	GGPInfo *info = purple_connection_get_protocol_data(gc);
	PurpleAccount *account = purple_connection_get_account(gc);
	SoupMessage *msg;
	char *auth;
	const char *method = "POST";
	const char *url = "http://api.gadu-gadu.pl/request_token";
	ggp_oauth_data *data;

	purple_debug_misc("gg", "ggp_oauth_request: requesting token...\n");

	auth = gg_oauth_generate_header(
	        method, url, purple_account_get_username(account),
	        purple_connection_get_password(gc), NULL, NULL);

	data = g_new0(ggp_oauth_data, 1);
	data->gc = gc;
	data->callback = callback;
	data->user_data = user_data;
	data->sign_method = g_strdup(sign_method);
	data->sign_url = g_strdup(sign_url);

	msg = soup_message_new(method, url);
	// purple_http_request_set_max_len(req, GGP_OAUTH_RESPONSE_MAX);
	soup_message_headers_replace(msg->request_headers, "Authorization", auth);
	soup_session_queue_message(info->http, msg, ggp_oauth_request_token_got,
	                           data);

	g_free(auth);
}

mercurial