PageRenderTime 211ms CodeModel.GetById 80ms app.highlight 15ms RepoModel.GetById 35ms 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
  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
 12-module(ewgi_session_cookie_store).
 13-author('Hunter Morris <hunter.morris@smarkets.com>').
 14-author('Davide Marquês <nesrait@gmail.com>').
 15
 16%% Session Store API
 17-export([load_session/2, store_session/2, delete_session/2]).
 18
 19%% Usage examples
 20-export([create_example/1, delete_example/1]).
 21
 22-import(ewgi_util_cookie, [cookie_headers/5, cookie_safe_encode/1, cookie_safe_decode/1]).
 23
 24-include("ewgi.hrl").
 25
 26-define(DEFAULT_COOKIE_NAME, "session_id").
 27-define(ENCODER, ewgi_util_crypto).
 28-define(MAX_LENGTH, 4096).
 29
 30%%====================================================================
 31%% Session Store API
 32%%====================================================================
 33-spec load_session(ewgi_context(), list()) -> ewgi_context().
 34load_session(Ctx, [CookieName, _CookiePath, _SecureCookie, Timeout, IncludeIp, Key]=Args) ->
 35    case ewgi_api:get_header_value("cookie", Ctx) of
 36	undefined ->
 37	    ewgi_session:new_session(Ctx);
 38	Cookies ->
 39	    CookieValues = ewgi_util_cookie:parse_cookie(Cookies),
 40	    case proplists:get_value(CookieName, CookieValues) of
 41		undefined ->
 42		    ewgi_session:new_session(Ctx);
 43		SessionCookie ->
 44		    case decode_cookie_contents(SessionCookie, Key) of
 45			{error,_} = _Error ->
 46			    %% DISPLAY ERROR!?
 47			    ewgi_session:new_session(Ctx);
 48			Session ->
 49			    case ewgi_session:init_session(Ctx, Session, Timeout, IncludeIp) of
 50				invalid_session ->
 51				    %% DISPLAY ERROR!?
 52				    Ctx_2 = ?MODULE:delete_session(Ctx, Args),
 53				    ewgi_session:new_session(Ctx_2);
 54				Ctx_2 ->
 55				    Ctx_2
 56			    end
 57		    end
 58	    end
 59    end.
 60
 61-spec store_session(ewgi_context(), list()) -> ewgi_context().
 62store_session(Ctx, [CookieName, CookiePath, SecureCookie, _Timeout, IncludeIp, Key]) ->
 63    Updated = ewgi_session:session_updated(Ctx),
 64    if Updated ->
 65	    Session = ewgi_session:get_session(Ctx, IncludeIp),
 66	    case ?ENCODER:encode(Key, term_to_binary(Session), ?MAX_LENGTH) of
 67		{error, _} = _Error ->
 68		    %% TODO: report this? To whom?
 69		    Ctx;
 70		EncryptedVal ->
 71		    CookieVal = cookie_safe_encode(EncryptedVal),
 72		    cookie_headers(Ctx, CookieName, CookieVal, CookiePath, SecureCookie)
 73	    end;
 74       true -> %% nothing to do!
 75	    Ctx
 76    end.
 77
 78delete_session(Ctx,  [CookieName, CookiePath, SecureCookie, _Timeout, _IncludeIp, _Key]) ->
 79    cookie_headers(Ctx, CookieName, [], CookiePath, SecureCookie).
 80
 81%%====================================================================
 82%% example functions on how to use the session middleware
 83%%====================================================================
 84-define(COOKIE_SIGNING_KEY, <<"ABCDEFGHIJKLMNOP">>).
 85-define(COOKIE_PATH, "/").
 86-define(SECURE_COOKIE, false).
 87-define(INCLUDE_IP, true).
 88-define(SESSION_TIMEOUT, 15 * 60 * 1000). %% 15 minutes
 89-define(COOKIE_STORE_ARGS, [
 90			    "cookie_session_id",
 91				?COOKIE_PATH,
 92			    ?SECURE_COOKIE,
 93			    ?SESSION_TIMEOUT,
 94			    ?INCLUDE_IP,
 95			    ?COOKIE_SIGNING_KEY
 96			   ]).
 97
 98create_example(Ctx) ->
 99    SessionApp = fun ewgi_session:session_create_app/1,
100    Ctx1 = ?MODULE:load_session(Ctx, ?COOKIE_STORE_ARGS),
101    Ctx2 = SessionApp(Ctx1),
102    ?MODULE:store_session(Ctx2, ?COOKIE_STORE_ARGS).
103
104delete_example(Ctx) ->
105    SessionApp = fun ewgi_session:session_delete_app/1,
106    Ctx1 = ?MODULE:load_session(Ctx, ?COOKIE_STORE_ARGS),
107    Ctx2 = SessionApp(Ctx1),
108    ?MODULE:store_session(Ctx2, ?COOKIE_STORE_ARGS).
109
110%%====================================================================
111%% Internal functions
112%%====================================================================
113-spec decode_cookie_contents(string(), list()) -> any() | {'error', any()}.
114decode_cookie_contents(Cookie0, Key) ->
115    case cookie_safe_decode(Cookie0) of
116        <<>> ->
117	    {error, {decode_cookie_contents, no_data}};
118        Cookie when is_binary(Cookie) ->
119	    case ?ENCODER:decode(Key, Cookie) of
120		{error, _} = Error ->
121		    Error;
122		Content when is_binary(Content) ->
123		    case (catch(binary_to_term(Content))) of
124			{'EXIT', Error} ->
125			    {error, {decode_cookie_contents, Error}};
126			Session ->
127			    Session
128		    end
129	    end
130    end.