oauth_request.erl 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. -module(oauth_request).
  2. -export([params_string/5]).
  3. -export([url/5]).
  4. -export([header/6]).
  5. % for testing:
  6. -export([plaintext_signature/2]).
  7. -export([hmac_sha1_signature/3]).
  8. -export([hmac_sha1_base_string/3]).
  9. -export([hmac_sha1_normalize/1]).
  10. -export([params_to_header_string/1]).
  11. -import(fmt, [sprintf/2, percent_encode/1]).
  12. -import(lists, [map/2]).
  13. params_string(Method, URL, ExtraParams, Consumer, Tokens) ->
  14. SignedParams = params(Method, URL, ExtraParams, Consumer, Tokens),
  15. params_to_string(SignedParams).
  16. url(Method, URL, ExtraParams, Consumer, Tokens) ->
  17. SignedParams = params(Method, URL, ExtraParams, Consumer, Tokens),
  18. sprintf("%s?%s", [URL, params_to_string(SignedParams)]).
  19. header(Realm, Method, URL, ExtraParams, Consumer, Tokens) ->
  20. SignedParams = params(Method, URL, ExtraParams, Consumer, Tokens),
  21. sprintf("Authorization: OAuth realm=\"%s\", %s", [Realm, params_to_header_string(SignedParams)]).
  22. params(Method, URL, ExtraParams, Consumer, Tokens) ->
  23. {Params, TokenSecret} = oauth_params(Tokens, Consumer, ExtraParams),
  24. [{oauth_signature, signature(Method, URL, Params, Consumer, TokenSecret)}|Params].
  25. oauth_params([], Consumer, ExtraParams) ->
  26. {oauth_params(Consumer, ExtraParams), ""};
  27. oauth_params(Tokens, Consumer, ExtraParams) ->
  28. Params = [proplists:lookup(oauth_token, Tokens)|oauth_params(Consumer, ExtraParams)],
  29. {Params, proplists:get_value(oauth_token_secret, Tokens)}.
  30. oauth_params(Consumer, ExtraParams) ->
  31. proplists_merge([
  32. {oauth_consumer_key, oauth_consumer:key(Consumer)},
  33. {oauth_signature_method, oauth_consumer:signature_method(Consumer)},
  34. {oauth_timestamp, oauth_util:unix_timestamp()},
  35. {oauth_nonce, oauth_util:nonce()},
  36. {oauth_version, "1.0"}
  37. ], ExtraParams).
  38. proplists_merge({K,V}, Merged) ->
  39. case proplists:is_defined(K, Merged) of
  40. true ->
  41. Merged;
  42. false ->
  43. [{K,V}|Merged]
  44. end;
  45. proplists_merge(A, B) ->
  46. lists:foldl(fun proplists_merge/2, A, B).
  47. signature(Method, URL, Params, Consumer, TokenSecret) ->
  48. ConsumerSecret = oauth_consumer:secret(Consumer),
  49. case signature_method(Params) of
  50. "PLAINTEXT" ->
  51. plaintext_signature(ConsumerSecret, TokenSecret);
  52. "HMAC-SHA1" ->
  53. MethodString = string:to_upper(atom_to_list(Method)),
  54. BaseString = hmac_sha1_base_string(MethodString, URL, Params),
  55. hmac_sha1_signature(BaseString, ConsumerSecret, TokenSecret)
  56. end.
  57. signature_method(Params) ->
  58. proplists:get_value(oauth_signature_method, Params).
  59. plaintext_signature(ConsumerSecret, TokenSecret) ->
  60. percent_encode(sprintf("%s&%s", [percent_encode(ConsumerSecret), percent_encode(TokenSecret)])).
  61. hmac_sha1_signature(BaseString, ConsumerSecret, TokenSecret) ->
  62. base64:encode_to_string(crypto:sha_mac(hmac_sha1_key(ConsumerSecret, TokenSecret), BaseString)).
  63. hmac_sha1_key(ConsumerSecret, TokenSecret) ->
  64. sprintf("%s&%s", [percent_encode(ConsumerSecret), percent_encode(TokenSecret)]).
  65. hmac_sha1_base_string(MethodString, URL, Params) ->
  66. string:join(map(fun fmt:percent_encode/1, [MethodString, URL, hmac_sha1_normalize(Params)]), "&").
  67. hmac_sha1_normalize(Params) ->
  68. params_to_string(lists:sort(fun({K,X},{K,Y}) -> X < Y; ({A,_},{B,_}) -> A < B end, Params)).
  69. params_to_string(Params) ->
  70. string:join(map(fun param_to_string/1, Params), "&").
  71. param_to_string({K,V}) ->
  72. sprintf("%s=%s", [percent_encode(K), percent_encode(V)]).
  73. params_to_header_string(Params) ->
  74. string:join(map(fun param_to_header_string/1, Params), ",").
  75. param_to_header_string({K,V}) ->
  76. sprintf("%s=\"%s\"", [percent_encode(K), percent_encode(V)]).