js_session.erl 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. -module(js_session).
  2. -author('Maxim Sokhatsky').
  3. -include_lib("n2o/include/wf.hrl").
  4. -include_lib("kvs/include/user.hrl").
  5. -include_lib("stdlib/include/ms_transform.hrl").
  6. -export(?SESSION_API).
  7. -compile(export_all).
  8. -record(state, {unique, node}).
  9. init(State,Ctx) -> {ok,State,Ctx}.
  10. finish(State,Ctx) -> {ok,State,Ctx}.
  11. ensure_sid(State, Ctx) ->
  12. SessionUser = wf:cookie_req(<<"n2o-name">>,?REQ),
  13. SessionId = wf:cookie_req(<<"n2o-sid">>, ?REQ),
  14. wf:info(?MODULE,"Session Init n2o-sid: ~p",[SessionId]),
  15. {{D1,D2,D3},{T1,T2,T3}} = calendar:now_to_datetime(now()),
  16. Till = {{D1,D2,D3+1},{T1,T2,T3}},
  17. TTL = 24 * 60 * 60, % 1 day TTL
  18. SessionCookie = case lookup_ets({SessionId,<<"auth">>}) of
  19. undefined ->
  20. CookieValue = case kvs:get(user,SessionUser) of
  21. {ok,User} ->
  22. SS = lists:keyfind(n2o,1,User#user.tokens),
  23. case SS of
  24. {n2o,SessionId} -> SessionId;
  25. _ -> new_cookie_value() end;
  26. _ -> new_cookie_value() end,
  27. Cookie = {{CookieValue,<<"auth">>},<<"/">>,now(),{TTL,Till},new},
  28. ets:insert(cookies,Cookie),
  29. wf:info(?MODULE,"Cookie New: ~p",[Cookie]),
  30. Cookie;
  31. {{Session,Key},Path,Issued,{_TTL,_Till},Status} ->
  32. case expired(Issued,{_TTL,_Till}) of
  33. false ->
  34. Cookie = {{Session,Key},Path,Issued,{_TTL,_Till},Status},
  35. wf:info(?MODULE,"Cookie Same: ~p",[Cookie]),
  36. Cookie;
  37. true -> Cookie = {{new_cookie_value(),<<"auth">>},<<"/">>,now(),{TTL,Till},new},
  38. ets:insert(cookies,Cookie),
  39. wf:info(?MODULE,"Cookie Expired: ~p",[Cookie]),
  40. Cookie end;
  41. _ -> error_logger:info_msg("Cookie Error"), skip
  42. end,
  43. {{ID,_},_,_,_,_} = SessionCookie,
  44. put(session_id,ID),
  45. wf:info(?MODULE,"State: ~p",[SessionCookie]),
  46. {ok, State, Ctx#context{session=SessionCookie}}.
  47. expired(_Issued,{_TTL,Till}) -> false. % Till < calendar:now_to_datetime(now()).
  48. lookup_ets(Key) ->
  49. Res = ets:lookup(cookies,Key),
  50. wf:info(?MODULE,"Lookup ETS: ~p",[{Res,Key}]),
  51. case Res of
  52. [] -> undefined;
  53. [Value] -> Value;
  54. Values -> Values end.
  55. clear() -> clear(session_id()).
  56. clear(Session) ->
  57. [ ets:delete(cookies,X) || X <- ets:select(cookies,
  58. ets:fun2ms(fun(A) when (element(1,element(1,A)) == Session) -> element(1,A) end)) ].
  59. cookie_expire(SecondsToLive) ->
  60. Seconds = calendar:datetime_to_gregorian_seconds(calendar:local_time()),
  61. DateTime = calendar:gregorian_seconds_to_datetime(Seconds + SecondsToLive),
  62. httpd_util:rfc1123_date(DateTime).
  63. ttl() -> 60*60*24*30.
  64. session_id() -> get(session_id).
  65. new_cookie_value() ->
  66. SessionKey = base64:encode(erlang:md5(term_to_binary({now(), make_ref()}))),
  67. wf:wire(wf:f("document.cookie='~s=~s; path=/; expires=~s';",
  68. [wf:to_list(session_cookie_name()),
  69. wf:to_list(SessionKey),
  70. cookie_expire(ttl())])),
  71. SessionKey.
  72. new_cookie_value(SessionKey) ->
  73. wf:info(?MODULE,wf:f("document.cookie='~s=~s; path=/; expires=~s';",
  74. [wf:to_list(session_cookie_name()),
  75. wf:to_list(SessionKey),
  76. cookie_expire(ttl())]),[]),
  77. SessionKey.
  78. new_state() -> #state{unique=new_cookie_value()}.
  79. session_cookie_name() -> <<"n2o-sid">>.
  80. set_value(Key, Value) -> ets:insert(cookies,{{session_id(),Key},Value}), Value.
  81. get_value(Key, DefaultValue) ->
  82. Res = case lookup_ets({session_id(),Key}) of
  83. undefined -> DefaultValue;
  84. {_,Value} -> Value end,
  85. wf:info(?MODULE,"Session Lookup Key ~p Value ~p",[Key,Res]),
  86. Res.