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

branch
soc.2008.masterpassword
changeset 34106
1b0c94670bcc
parent 33351
bd15903d0d89
child 34108
7a07b6857540
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/gg/oauth/oauth-purple.c	Wed Aug 22 18:19:53 2012 -0400
@@ -0,0 +1,283 @@
+/* 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 "oauth.h"
+#include "../utils.h"
+#include "../xml.h"
+
+#include <debug.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);
+
+static void ggp_oauth_request_token_got(PurpleUtilFetchUrlData *url_data,
+	gpointer user_data, const gchar *url_text, gsize len,
+	const gchar *error_message);
+
+static void ggp_oauth_authorization_done(PurpleUtilFetchUrlData *url_data,
+	gpointer user_data, const gchar *url_text, gsize len,
+	const gchar *error_message);
+
+static void ggp_oauth_access_token_got(PurpleUtilFetchUrlData *url_data,
+	gpointer user_data, const gchar *url_text, gsize len,
+	const gchar *error_message);
+
+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);
+}
+
+void ggp_oauth_request(PurpleConnection *gc, ggp_oauth_request_cb callback,
+	gpointer user_data, const gchar *sign_method, const gchar *sign_url)
+{
+	PurpleAccount *account = purple_connection_get_account(gc);
+	char *auth;
+	const char *method = "POST";
+	const char *url = "http://api.gadu-gadu.pl/request_token";
+	gchar *request;
+	ggp_oauth_data *data;
+
+	g_return_if_fail((method == NULL) == (url == NULL));
+
+	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);
+	request = g_strdup_printf(
+		"POST /request_token HTTP/1.1\r\n"
+		"Host: api.gadu-gadu.pl\r\n"
+		"%s\r\n"
+		"Content-Length: 0\r\n"
+		"\r\n",
+		auth);
+	free(auth);
+
+	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);
+
+	purple_util_fetch_url_request(account, url, FALSE, NULL, TRUE, request,
+		FALSE, GGP_OAUTH_RESPONSE_MAX, ggp_oauth_request_token_got,
+		data);
+
+	g_free(request);
+}
+
+static void ggp_oauth_request_token_got(PurpleUtilFetchUrlData *url_data,
+	gpointer user_data, const gchar *url_text, gsize len,
+	const gchar *error_message)
+{
+	ggp_oauth_data *data = user_data;
+	PurpleAccount *account;
+	xmlnode *xml;
+	gchar *request, *request_data;
+	gboolean succ = TRUE;
+
+	if (!PURPLE_CONNECTION_IS_VALID(data->gc))
+	{
+		ggp_oauth_data_free(data);
+		return;
+	}
+	account = purple_connection_get_account(data->gc);
+
+	if (len == 0)
+	{
+		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 = xmlnode_from_str(url_text, -1);
+	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);
+	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));
+	request = g_strdup_printf(
+		"POST /authorize HTTP/1.1\r\n"
+		"Host: login.gadu-gadu.pl\r\n"
+		"Content-Length: %zu\r\n"
+		"Content-Type: application/x-www-form-urlencoded\r\n"
+		"\r\n%s",
+		strlen(request_data), request_data);
+	g_free(request_data);
+
+	// we don't need any results, nor 302 redirection
+	purple_util_fetch_url_request(account,
+		"https://login.gadu-gadu.pl/authorize", FALSE, NULL, TRUE,
+		request, FALSE, 0,
+		ggp_oauth_authorization_done, data);
+
+	g_free(request);
+}
+
+static void ggp_oauth_authorization_done(PurpleUtilFetchUrlData *url_data,
+	gpointer user_data, const gchar *url_text, gsize len,
+	const gchar *error_message)
+{
+	ggp_oauth_data *data = user_data;
+	PurpleAccount *account;
+	char *auth;
+	const char *url = "http://api.gadu-gadu.pl/access_token";
+	gchar *request;
+	
+	if (!PURPLE_CONNECTION_IS_VALID(data->gc))
+	{
+		ggp_oauth_data_free(data);
+		return;
+	}
+	account = purple_connection_get_account(data->gc);
+
+	purple_debug_misc("gg", "ggp_oauth_authorization_done: "
+		"authorization done, requesting access token...\n");
+
+	auth = gg_oauth_generate_header("POST", url,
+		purple_account_get_username(account),
+		purple_connection_get_password(data->gc),
+		data->token, data->token_secret);
+
+	request = g_strdup_printf(
+		"POST /access_token HTTP/1.1\r\n"
+		"Host: api.gadu-gadu.pl\r\n"
+		"%s\r\n"
+		"Content-Length: 0\r\n"
+		"\r\n",
+		auth);
+	free(auth);
+	
+	purple_util_fetch_url_request(account, url, FALSE, NULL, TRUE, request,
+		FALSE, GGP_OAUTH_RESPONSE_MAX, ggp_oauth_access_token_got,
+		data);
+
+	g_free(request);
+}
+
+static void ggp_oauth_access_token_got(PurpleUtilFetchUrlData *url_data,
+	gpointer user_data, const gchar *url_text, gsize len,
+	const gchar *error_message)
+{
+	ggp_oauth_data *data = user_data;
+	gchar *token, *token_secret;
+	xmlnode *xml;
+	gboolean succ = TRUE;
+
+	xml = xmlnode_from_str(url_text, -1);
+	if (xml == NULL)
+	{
+		purple_debug_error("gg", "ggp_oauth_access_token_got: "
+			"invalid xml\n");
+		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);
+	xmlnode_free(xml);
+	if (!succ || strlen(token) < 10)
+	{
+		purple_debug_error("gg", "ggp_oauth_access_token_got: "
+			"invalid xml - token is not present\n");
+		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\n");
+		
+		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\n");
+		data->callback(data->gc, token, data->user_data);
+	}
+
+	g_free(token);
+	g_free(token_secret);
+	ggp_oauth_data_free(data);
+}

mercurial