| 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" |