@@ -191,15 +191,35 @@ int OAuthClient::httpRequest(const char* method, const char* path, const char* c
191
191
url += _ip[3 ];
192
192
}
193
193
194
- url += path;
194
+ const char * queryParams = NULL ;
195
+ const char * bodyParams = NULL ;
196
+
197
+ // split the path from query params if necessary
198
+ char * questionMark = strchr (path, ' ?' );
199
+ if (questionMark != NULL ) {
200
+ queryParams = (questionMark + 1 );
201
+
202
+ const char * temp = path;
203
+
204
+ while (temp != questionMark) {
205
+ url += *temp++;
206
+ }
207
+ } else {
208
+ url += path;
209
+ }
210
+
211
+ if (strcmp (contentType, " application/x-www-form-urlencoded" ) == 0 ) {
212
+ // only use the body as params if the body is URL encoded
213
+ bodyParams = body;
214
+ }
195
215
196
216
unsigned long time = 0 ;
197
217
198
218
if (_onGetTimeCallback) {
199
219
time = _onGetTimeCallback ();
200
220
}
201
221
202
- String signature = calculateSignature (method, url.c_str (), time, body );
222
+ String signature = calculateSignature (method, url.c_str (), time, queryParams, bodyParams );
203
223
String authorization = calculateOauthAuthorization (signature, time);
204
224
205
225
_httpClient.beginRequest ();
@@ -237,29 +257,120 @@ String OAuthClient::createNonce() {
237
257
return n;
238
258
}
239
259
240
- String OAuthClient::calculateSignature (const char * method, const char * url, unsigned long time, const char * body)
260
+ static int strcmp_pointer (const void * a, const void * b) {
261
+ return strcmp (*(const char **)a, *(const char **)b);
262
+ }
263
+
264
+ String OAuthClient::calculateSignature (const char * method, const char * url, unsigned long time, const char * queryParams, const char * bodyParams)
241
265
{
266
+ // This function is long due to the complexity of the OAuth signature.
267
+ // It must collect all the parameters from the oauth, query, and body params,
268
+ // then sort the param key values lexographically. After these steps the
269
+ // signature can be calculated.
270
+
271
+ // calculate the OAuth params
272
+ String oauthParams;
273
+
274
+ oauthParams += " oauth_consumer_key=" ;
275
+ oauthParams += _consumerKey;
276
+ oauthParams += " &oauth_nonce=" ;
277
+ oauthParams += _nonce;
278
+ oauthParams += " &oauth_signature_method=HMAC-SHA1&oauth_timestamp=" ;
279
+ oauthParams += String (time);
280
+ oauthParams += " &oauth_token=" ;
281
+ oauthParams += _accessToken;
282
+ oauthParams += " &oauth_version=1.0" ;
283
+
284
+ // calculate the length of all of the params
285
+ int paramsLength = oauthParams.length ();
286
+ int queryParamsLength = strlen (queryParams);
287
+ int bodyParamsLength = strlen (bodyParams);
288
+
289
+ if (queryParams) {
290
+ paramsLength += (1 + queryParamsLength);
291
+ }
292
+
293
+ if (bodyParams) {
294
+ paramsLength += (1 + bodyParamsLength);
295
+ }
296
+
297
+ // copy the parameters to a buffer
298
+ char params[paramsLength + 1 ];
299
+ char * temp = params;
300
+
301
+ temp = strcpy (temp, oauthParams.c_str ());
302
+ temp += oauthParams.length ();
303
+
304
+ if (queryParams) {
305
+ *temp++ = ' &' ;
306
+ strcpy (temp, queryParams);
307
+ temp += queryParamsLength;
308
+ }
309
+
310
+ if (bodyParams) {
311
+ *temp++ = ' &' ;
312
+ strcpy (temp, bodyParams);
313
+ temp += bodyParamsLength;
314
+ }
315
+
316
+ *temp = ' \0 ' ;
317
+
318
+ // caculate the number of parameters
319
+ int numParams = 0 ;
320
+ for (int i = 0 ; i < paramsLength; i++) {
321
+ if (params[i] == ' =' ) {
322
+ numParams++;
323
+ }
324
+ }
325
+
326
+ // collect the keys of the parameters to an array
327
+ // and also replace the = and & characters with \0
328
+ // this will help with the sorting later
329
+ const char * paramKeys[numParams];
330
+ int paramIndex = 0 ;
331
+ const char * lastKey = params;
332
+
333
+ temp = params;
334
+ while (1 ) {
335
+ char c = *temp;
336
+
337
+ if (c == ' \0 ' ) {
338
+ break ;
339
+ } else if (c == ' =' ) {
340
+ paramKeys[paramIndex++] = lastKey;
341
+
342
+ *temp = ' \0 ' ;
343
+ } else if (c == ' &' ) {
344
+ lastKey = (temp + 1 );
345
+
346
+ *temp = ' \0 ' ;
347
+ }
348
+
349
+ temp++;
350
+ }
351
+
352
+ // sort the param keys
353
+ qsort (paramKeys, numParams, sizeof (uintptr_t ), strcmp_pointer);
354
+
355
+ // calculate the signature
242
356
SHA1.beginHmac (_signingKey);
243
357
SHA1.print (method);
244
358
SHA1.print (" &" );
245
359
SHA1.print (URLEncoder.encode (url));
246
360
SHA1.print (" &" );
361
+ for (int i = 0 ; i < numParams; i++) {
362
+ const char * paramKey = paramKeys[i];
363
+ int keyLength = strlen (paramKey);
364
+ const char * paramValue = paramKey + keyLength + 1 ;
365
+
366
+ SHA1.print (URLEncoder.encode (paramKey));
367
+ SHA1.print (URLEncoder.encode (" =" ));
368
+ SHA1.print (URLEncoder.encode (paramValue));
247
369
248
- SHA1.print (URLEncoder.encode (" oauth_consumer_key=" ));
249
- SHA1.print (URLEncoder.encode (_consumerKey));
250
- SHA1.print (URLEncoder.encode (" &" ));
251
- SHA1.print (URLEncoder.encode (" oauth_nonce=" ));
252
- SHA1.print (URLEncoder.encode (_nonce));
253
- SHA1.print (URLEncoder.encode (" &" ));
254
- SHA1.print (URLEncoder.encode (" oauth_signature_method=HMAC-SHA1&" ));
255
- SHA1.print (URLEncoder.encode (" oauth_timestamp=" ));
256
- SHA1.print (URLEncoder.encode (String (time)));
257
- SHA1.print (URLEncoder.encode (" &" ));
258
- SHA1.print (URLEncoder.encode (" oauth_token=" ));
259
- SHA1.print (URLEncoder.encode (_accessToken));
260
- SHA1.print (URLEncoder.encode (" &" ));
261
- SHA1.print (URLEncoder.encode (" oauth_version=1.0&" ));
262
- SHA1.print (URLEncoder.encode (body));
370
+ if ((i + 1 ) < numParams) {
371
+ SHA1.print (URLEncoder.encode (" &" ));
372
+ }
373
+ }
263
374
SHA1.endHmac ();
264
375
265
376
int rawSignatureLength = SHA1.available ();
@@ -283,21 +394,15 @@ String OAuthClient::calculateOauthAuthorization(const String& signature, unsigne
283
394
authorization += " OAuth " ;
284
395
authorization += " oauth_consumer_key=\" " ;
285
396
authorization += _consumerKey;
286
- authorization += " \" ," ;
287
- authorization += " oauth_nonce=\" " ;
397
+ authorization += " \" ,oauth_nonce=\" " ;
288
398
authorization += _nonce;
289
- authorization += " \" ," ;
290
- authorization += " oauth_signature=\" " ;
399
+ authorization += " \" ,oauth_signature=\" " ;
291
400
authorization += signature;
292
- authorization += " \" ," ;
293
- authorization += " oauth_signature_method=\" HMAC-SHA1\" ," ;
294
- authorization += " oauth_timestamp=\" " ;
401
+ authorization += " \" ,oauth_signature_method=\" HMAC-SHA1\" ,oauth_timestamp=\" " ;
295
402
authorization += timestamp;
296
- authorization += " \" ," ;
297
- authorization += " oauth_token=\" " ;
403
+ authorization += " \" ,oauth_token=\" " ;
298
404
authorization += _accessToken;
299
- authorization += " \" ," ;
300
- authorization += " oauth_version=\" 1.0\" " ;
405
+ authorization += " \" ,oauth_version=\" 1.0\" " ;
301
406
302
407
return authorization;
303
408
}
0 commit comments