Plugins/Purple Service/libpurple_extensions/auth_fb.c
branchadium-1.5.11
changeset 6014 fcb71cb71a3d
parent 5941 307f53385811
parent 6013 f8d0dc659e3f
child 6016 325e2ab3406f
equal deleted inserted replaced
5941:307f53385811 6014:fcb71cb71a3d
     1 /*
       
     2  * purple - Jabber Protocol Plugin
       
     3  *
       
     4  * Purple is the legal property of its developers, whose names are too numerous
       
     5  * to list here.  Please refer to the COPYRIGHT file distributed with this
       
     6  * source distribution.
       
     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
       
    19  * along with this program; if not, write to the Free Software
       
    20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
       
    21  *
       
    22  */
       
    23 #include "internal.h"
       
    24 
       
    25 #include "account.h"
       
    26 #include "debug.h"
       
    27 #include "request.h"
       
    28 #include "util.h"
       
    29 #include "xmlnode.h"
       
    30 
       
    31 #include "jabber.h"
       
    32 #include "auth.h"
       
    33 
       
    34 #include "fbapi.h"
       
    35 
       
    36 #define PACKAGE "pidgin"
       
    37 
       
    38 static JabberSaslState
       
    39 fb_handle_challenge(JabberStream *js, xmlnode *packet,
       
    40                             xmlnode **response, char **msg)
       
    41 {
       
    42 	xmlnode *reply = NULL;
       
    43 	gchar *challenge;
       
    44 	guchar *decoded;
       
    45 	gsize decoded_len;
       
    46 	gchar **pairs, *method, *nonce;
       
    47 	gsize i;
       
    48 	GString *request;
       
    49 	gchar *enc_out;
       
    50 
       
    51 	/* Get base64-encoded challenge from XML */
       
    52 	challenge = xmlnode_get_data(packet);
       
    53 	if (challenge == NULL) {
       
    54 		*msg = g_strdup(_("Invalid response from server"));
       
    55 		return JABBER_SASL_STATE_FAIL;
       
    56 	}
       
    57 
       
    58 	/* Decode challenge */
       
    59 	decoded = purple_base64_decode(challenge, &decoded_len);
       
    60 	if (decoded == NULL) {
       
    61 		purple_debug_error("jabber", "X-FACEBOOK-PLATFORM challenge "
       
    62 						   "wasn't valid base64: %s\n", challenge);
       
    63 	
       
    64 		*msg = g_strdup(_("Invalid response from server"));
       
    65 
       
    66 		g_free(challenge);
       
    67 		return JABBER_SASL_STATE_FAIL;
       
    68 	}
       
    69 	g_free(challenge);
       
    70 
       
    71 	/* NULL-terminate the challenge so we can parse it */
       
    72 	challenge = g_strndup((const gchar *)decoded, decoded_len);
       
    73 	g_free(decoded);
       
    74 	purple_debug_misc("jabber", "X-FACEBOOK-PLATFORM decoded "
       
    75 					  "challenge is %s\n", challenge);
       
    76 
       
    77 	/* Get method and nonce */
       
    78 	method = NULL;
       
    79 	nonce = NULL;
       
    80 	pairs = g_strsplit(challenge, "&", 0);
       
    81 	for (i = 0; pairs[i] != NULL; i++) {
       
    82 		if (g_str_has_prefix(pairs[i], "method=")) {
       
    83 			g_free(method);
       
    84 			// TODO: Should url decode this value
       
    85 			method = g_strdup(strchr(pairs[i], '=') + 1);
       
    86 		} else if (g_str_has_prefix(pairs[i], "nonce=")) {
       
    87 			g_free(nonce);
       
    88 			// TODO: Should url decode this value
       
    89 			nonce = g_strdup(strchr(pairs[i], '=') + 1);
       
    90 		}
       
    91 	}
       
    92 	g_strfreev(pairs);
       
    93 	if (!method || !nonce) {
       
    94 		purple_debug_error("jabber", "X-FACEBOOK-PLATFORM challenge "
       
    95 						   "is missing method or nonce: %s\n", challenge);
       
    96 		*msg = g_strdup(_("Invalid response from server"));
       
    97 
       
    98 		g_free(method);
       
    99 		g_free(nonce);
       
   100 		g_free(challenge);
       
   101 		return JABBER_SASL_STATE_FAIL;
       
   102 	}
       
   103 	g_free(challenge);
       
   104 
       
   105 	request = purple_fbapi_construct_request(purple_connection_get_account(js->gc),
       
   106 											 method,
       
   107 											 "v", "1.0",
       
   108 											 "access_token", purple_connection_get_password(js->gc),
       
   109 											 "nonce", nonce,
       
   110 											 NULL);
       
   111 	g_free(method);
       
   112 	g_free(nonce);
       
   113 
       
   114 	purple_debug_misc("jabber", "X-FACEBOOK-PLATFORM response before "
       
   115 					  "encoding is %s\n", request->str);
       
   116 	enc_out = purple_base64_encode((const guchar *)request->str, request->len);
       
   117 	g_string_free(request, TRUE);
       
   118 
       
   119 	reply = xmlnode_new("response");
       
   120 	xmlnode_set_namespace(reply, NS_XMPP_SASL);
       
   121 	xmlnode_insert_data(reply, enc_out, -1);
       
   122 
       
   123 	g_free(enc_out);
       
   124 
       
   125 	*response = reply;
       
   126 
       
   127 	return JABBER_SASL_STATE_CONTINUE;
       
   128 }
       
   129 
       
   130 static JabberSaslState
       
   131 fb_start(JabberStream *js, xmlnode *packet, xmlnode **response, char **error)
       
   132 {
       
   133 	PurpleAccount *account;
       
   134 	const char *username;
       
   135 	gchar **parts;
       
   136 
       
   137 	account = purple_connection_get_account(js->gc);
       
   138 	username = purple_account_get_username(account);
       
   139 
       
   140 	purple_debug_error("auth_fb", "account name is %s", username);
       
   141 
       
   142 	parts = g_strsplit(username, "@", 0);
       
   143 	if (parts[0] && strlen(parts[0]) && g_str_has_prefix(parts[0], "-")) {
       
   144 		/* When connecting with X-FACEBOOK-PLATFORM, the password field must be set to the
       
   145 		 * OAUTH 2.0 session key.
       
   146 		 *
       
   147 		 * X-FACEBOOK-PLATFORM is only valid for a facebook userID, which is prefixed with '-'
       
   148 		 */
       
   149 		xmlnode *auth = xmlnode_new("auth");
       
   150 		xmlnode_set_namespace(auth, "urn:ietf:params:xml:ns:xmpp-sasl");
       
   151 		xmlnode_set_attrib(auth, "mechanism", "X-FACEBOOK-PLATFORM");
       
   152 		
       
   153 		*response = auth;
       
   154 		
       
   155 		g_strfreev(parts);
       
   156 		return JABBER_SASL_STATE_CONTINUE;		
       
   157 	} else {
       
   158 		g_strfreev(parts);
       
   159 		return JABBER_SASL_STATE_FAIL;		
       
   160 	}
       
   161 }
       
   162 
       
   163 static JabberSaslMech fb_mech = {
       
   164 	127, /* priority; gint8 (-128 to 127). higher will be tried sooner if offerred by the server */
       
   165 	"X-FACEBOOK-PLATFORM", /* name */
       
   166 	fb_start,
       
   167 	fb_handle_challenge, /* handle_challenge */
       
   168 	NULL, /* handle_success */
       
   169 	NULL, /* handle_failure */
       
   170 	NULL  /* dispose */
       
   171 };
       
   172 
       
   173 JabberSaslMech *jabber_auth_get_fb_mech(void)
       
   174 {
       
   175 	return &fb_mech;
       
   176 }