comparison libpurple/protocols/oscar/clientlogin.c @ 28255:79c14adf9669

Change purple_url_encode() to not encode . _ - ~ because it's not necessary. Also use capital letters instead of lowercase. RFC3986 says capital letters are a SHOULD and that lowercase letters should be equivalent. AOL's clientlogin authentication requires both of these changes for our signature to match up with the signature generated on AOL's side. Original I had implemented an oscar-specific version of our url encode function with these two changes, but I'm pretty sure it's safe to make this in purple_url_encode(). It looks like it's almost always used to encode pieces of URLs. MSN uses it for a few other things... I tested setting those characters in your friendly name and it works fine.
author Mark Doliner <mark@kingant.net>
date Fri, 11 Sep 2009 18:17:03 +0000
parents 2987756bc600
children 17617d892bc4
comparison
equal deleted inserted replaced
28254:a7f47621ad53 28255:79c14adf9669
60 od->icq ? "prpl-icq-clientkey" : "prpl-aim-clientkey", 60 od->icq ? "prpl-icq-clientkey" : "prpl-aim-clientkey",
61 DEFAULT_CLIENT_KEY); 61 DEFAULT_CLIENT_KEY);
62 } 62 }
63 63
64 /** 64 /**
65 * This is similar to purple_url_encode() except that it follows
66 * RFC3986 a little more closely by not encoding - . _ and ~
67 * It also uses capital letters as hex characters because capital
68 * letters are required by AOL. The RFC says that capital letters
69 * are a SHOULD and that URLs that use capital letters are
70 * equivalent to URLs that use small letters.
71 *
72 * TODO: Check if purple_url_encode() can be replaced with this
73 * version without breaking anything.
74 */
75 static const char *oscar_auth_url_encode(const char *str)
76 {
77 const char *iter;
78 static char buf[BUF_LEN];
79 char utf_char[6];
80 guint i, j = 0;
81
82 g_return_val_if_fail(str != NULL, NULL);
83 g_return_val_if_fail(g_utf8_validate(str, -1, NULL), NULL);
84
85 iter = str;
86 for (; *iter && j < (BUF_LEN - 1) ; iter = g_utf8_next_char(iter)) {
87 gunichar c = g_utf8_get_char(iter);
88 /* If the character is an ASCII character and is alphanumeric
89 * no need to escape */
90 if ((c < 128 && isalnum(c)) || c =='-' || c == '.' || c == '_' || c == '~') {
91 buf[j++] = c;
92 } else {
93 int bytes = g_unichar_to_utf8(c, utf_char);
94 for (i = 0; i < bytes; i++) {
95 if (j > (BUF_LEN - 4))
96 break;
97 sprintf(buf + j, "%%%02X", utf_char[i] & 0xff);
98 j += 3;
99 }
100 }
101 }
102
103 buf[j] = '\0';
104
105 return buf;
106 }
107
108 /**
109 * @return A null-terminated base64 encoded version of the HMAC 65 * @return A null-terminated base64 encoded version of the HMAC
110 * calculated using the given key and data. 66 * calculated using the given key and data.
111 */ 67 */
112 static gchar *hmac_sha256(const char *key, const char *message) 68 static gchar *hmac_sha256(const char *key, const char *message)
113 { 69 {
132 static gchar *generate_signature(const char *method, const char *url, const char *parameters, const char *session_key) 88 static gchar *generate_signature(const char *method, const char *url, const char *parameters, const char *session_key)
133 { 89 {
134 char *encoded_url, *signature_base_string, *signature; 90 char *encoded_url, *signature_base_string, *signature;
135 const char *encoded_parameters; 91 const char *encoded_parameters;
136 92
137 encoded_url = g_strdup(oscar_auth_url_encode(url)); 93 encoded_url = g_strdup(purple_url_encode(url));
138 encoded_parameters = oscar_auth_url_encode(parameters); 94 encoded_parameters = purple_url_encode(parameters);
139 signature_base_string = g_strdup_printf("%s&%s&%s", 95 signature_base_string = g_strdup_printf("%s&%s&%s",
140 method, encoded_url, encoded_parameters); 96 method, encoded_url, encoded_parameters);
141 g_free(encoded_url); 97 g_free(encoded_url);
142 98
143 signature = hmac_sha256(session_key, signature_base_string); 99 signature = hmac_sha256(session_key, signature_base_string);
307 query_string = g_strdup_printf("a=%s" 263 query_string = g_strdup_printf("a=%s"
308 "&f=xml" 264 "&f=xml"
309 "&k=%s" 265 "&k=%s"
310 "&ts=%" PURPLE_TIME_T_MODIFIER 266 "&ts=%" PURPLE_TIME_T_MODIFIER
311 "&useTLS=0", 267 "&useTLS=0",
312 oscar_auth_url_encode(token), get_client_key(od), hosttime); 268 purple_url_encode(token), get_client_key(od), hosttime);
313 signature = generate_signature("GET", URL_START_OSCAR_SESSION, 269 signature = generate_signature("GET", URL_START_OSCAR_SESSION,
314 query_string, session_key); 270 query_string, session_key);
315 url = g_strdup_printf(URL_START_OSCAR_SESSION "?%s&sig_sha256=%s", 271 url = g_strdup_printf(URL_START_OSCAR_SESSION "?%s&sig_sha256=%s",
316 query_string, signature); 272 query_string, signature);
317 g_free(query_string); 273 g_free(query_string);
551 507
552 /* Construct the body of the HTTP POST request */ 508 /* Construct the body of the HTTP POST request */
553 body = g_string_new(""); 509 body = g_string_new("");
554 g_string_append_printf(body, "devId=%s", get_client_key(od)); 510 g_string_append_printf(body, "devId=%s", get_client_key(od));
555 g_string_append_printf(body, "&f=xml"); 511 g_string_append_printf(body, "&f=xml");
556 g_string_append_printf(body, "&pwd=%s", oscar_auth_url_encode(password)); 512 g_string_append_printf(body, "&pwd=%s", purple_url_encode(password));
557 g_string_append_printf(body, "&s=%s", oscar_auth_url_encode(username)); 513 g_string_append_printf(body, "&s=%s", purple_url_encode(username));
558 g_free(password); 514 g_free(password);
559 515
560 /* Construct an HTTP POST request */ 516 /* Construct an HTTP POST request */
561 request = g_string_new("POST /auth/clientLogin HTTP/1.0\r\n" 517 request = g_string_new("POST /auth/clientLogin HTTP/1.0\r\n"
562 "Connection: close\r\n" 518 "Connection: close\r\n"