PageRenderTime 39ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/src/middleware/ewgi_session/ewgi_session_cookie_store.erl

http://github.com/skarab/ewgi
Erlang | 130 lines | 93 code | 13 blank | 24 comment | 1 complexity | 7f02cf5aa7f8b3318c7b7d636446c0bc MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. %% @author Hunter Morris <hunter.morris@smarkets.com>
  2. %% @author Davide Marquês <nesrait@gmail.com>
  3. %% @copyright 2009 Smarkets Limited.
  4. %%
  5. %% @doc Cookie-based session store.
  6. %% Based on smak_auth_cookie by Hunter Morris.
  7. %% @end
  8. %%
  9. %% Licensed under the MIT license:
  10. %% http://www.opensource.org/licenses/mit-license.php
  11. -module(ewgi_session_cookie_store).
  12. -author('Hunter Morris <hunter.morris@smarkets.com>').
  13. -author('Davide Marquês <nesrait@gmail.com>').
  14. %% Session Store API
  15. -export([load_session/2, store_session/2, delete_session/2]).
  16. %% Usage examples
  17. -export([create_example/1, delete_example/1]).
  18. -import(ewgi_util_cookie, [cookie_headers/5, cookie_safe_encode/1, cookie_safe_decode/1]).
  19. -include("ewgi.hrl").
  20. -define(DEFAULT_COOKIE_NAME, "session_id").
  21. -define(ENCODER, ewgi_util_crypto).
  22. -define(MAX_LENGTH, 4096).
  23. %%====================================================================
  24. %% Session Store API
  25. %%====================================================================
  26. -spec load_session(ewgi_context(), list()) -> ewgi_context().
  27. load_session(Ctx, [CookieName, _CookiePath, _SecureCookie, Timeout, IncludeIp, Key]=Args) ->
  28. case ewgi_api:get_header_value("cookie", Ctx) of
  29. undefined ->
  30. ewgi_session:new_session(Ctx);
  31. Cookies ->
  32. CookieValues = ewgi_util_cookie:parse_cookie(Cookies),
  33. case proplists:get_value(CookieName, CookieValues) of
  34. undefined ->
  35. ewgi_session:new_session(Ctx);
  36. SessionCookie ->
  37. case decode_cookie_contents(SessionCookie, Key) of
  38. {error,_} = _Error ->
  39. %% DISPLAY ERROR!?
  40. ewgi_session:new_session(Ctx);
  41. Session ->
  42. case ewgi_session:init_session(Ctx, Session, Timeout, IncludeIp) of
  43. invalid_session ->
  44. %% DISPLAY ERROR!?
  45. Ctx_2 = ?MODULE:delete_session(Ctx, Args),
  46. ewgi_session:new_session(Ctx_2);
  47. Ctx_2 ->
  48. Ctx_2
  49. end
  50. end
  51. end
  52. end.
  53. -spec store_session(ewgi_context(), list()) -> ewgi_context().
  54. store_session(Ctx, [CookieName, CookiePath, SecureCookie, _Timeout, IncludeIp, Key]) ->
  55. Updated = ewgi_session:session_updated(Ctx),
  56. if Updated ->
  57. Session = ewgi_session:get_session(Ctx, IncludeIp),
  58. case ?ENCODER:encode(Key, term_to_binary(Session), ?MAX_LENGTH) of
  59. {error, _} = _Error ->
  60. %% TODO: report this? To whom?
  61. Ctx;
  62. EncryptedVal ->
  63. CookieVal = cookie_safe_encode(EncryptedVal),
  64. cookie_headers(Ctx, CookieName, CookieVal, CookiePath, SecureCookie)
  65. end;
  66. true -> %% nothing to do!
  67. Ctx
  68. end.
  69. delete_session(Ctx, [CookieName, CookiePath, SecureCookie, _Timeout, _IncludeIp, _Key]) ->
  70. cookie_headers(Ctx, CookieName, [], CookiePath, SecureCookie).
  71. %%====================================================================
  72. %% example functions on how to use the session middleware
  73. %%====================================================================
  74. -define(COOKIE_SIGNING_KEY, <<"ABCDEFGHIJKLMNOP">>).
  75. -define(COOKIE_PATH, "/").
  76. -define(SECURE_COOKIE, false).
  77. -define(INCLUDE_IP, true).
  78. -define(SESSION_TIMEOUT, 15 * 60 * 1000). %% 15 minutes
  79. -define(COOKIE_STORE_ARGS, [
  80. "cookie_session_id",
  81. ?COOKIE_PATH,
  82. ?SECURE_COOKIE,
  83. ?SESSION_TIMEOUT,
  84. ?INCLUDE_IP,
  85. ?COOKIE_SIGNING_KEY
  86. ]).
  87. create_example(Ctx) ->
  88. SessionApp = fun ewgi_session:session_create_app/1,
  89. Ctx1 = ?MODULE:load_session(Ctx, ?COOKIE_STORE_ARGS),
  90. Ctx2 = SessionApp(Ctx1),
  91. ?MODULE:store_session(Ctx2, ?COOKIE_STORE_ARGS).
  92. delete_example(Ctx) ->
  93. SessionApp = fun ewgi_session:session_delete_app/1,
  94. Ctx1 = ?MODULE:load_session(Ctx, ?COOKIE_STORE_ARGS),
  95. Ctx2 = SessionApp(Ctx1),
  96. ?MODULE:store_session(Ctx2, ?COOKIE_STORE_ARGS).
  97. %%====================================================================
  98. %% Internal functions
  99. %%====================================================================
  100. -spec decode_cookie_contents(string(), list()) -> any() | {'error', any()}.
  101. decode_cookie_contents(Cookie0, Key) ->
  102. case cookie_safe_decode(Cookie0) of
  103. <<>> ->
  104. {error, {decode_cookie_contents, no_data}};
  105. Cookie when is_binary(Cookie) ->
  106. case ?ENCODER:decode(Key, Cookie) of
  107. {error, _} = Error ->
  108. Error;
  109. Content when is_binary(Content) ->
  110. case (catch(binary_to_term(Content))) of
  111. {'EXIT', Error} ->
  112. {error, {decode_cookie_contents, Error}};
  113. Session ->
  114. Session
  115. end
  116. end
  117. end.