Browse Source

n2o_session to n4u_session

221V 3 years ago
parent
commit
0bc9712442
7 changed files with 196 additions and 134 deletions
  1. 1 1
      ebin/n4u.app
  2. 0 127
      src/handlers/n2o_session.erl
  3. 190 0
      src/handlers/n4u_session.erl
  4. 1 1
      src/n4u_cx.erl
  5. 1 1
      src/n4u_sup.erl
  6. 1 1
      src/protocols/n4u_nitrogen.erl
  7. 2 3
      src/wf.erl

+ 1 - 1
ebin/n4u.app

@@ -2,7 +2,7 @@
   {description, "N4U WebSocket Application Server"},
   {description, "N4U WebSocket Application Server"},
   {vsn, "4.4.20"},
   {vsn, "4.4.20"},
   {applications, [kernel, stdlib, asn1, public_key, ssl, crypto, ranch, cowboy, fs, active, sh, gproc, nitro]},
   {applications, [kernel, stdlib, asn1, public_key, ssl, crypto, ranch, cowboy, fs, active, sh, gproc, nitro]},
-  {modules, [n2o, n4u_app, n4u_sup, n4u_async, n2o_xhr, n4u_cx, n2o_cowboy, n2o_multipart, n2o_static, n2o_stream, n4u_document, n2o_proto, n2o_relay, n4u_error, n4u_io, n4u_log, n4u_mq, n4u_pickle, n4u_query, n4u_secret, n2o_session, n4u_syn, n4u_client, n4u_file, n4u_heart, n4u_http, n4u_nitrogen, n4u_text, wf, wf_convert, wf_utils]},
+  {modules, [n2o, n4u_app, n4u_sup, n4u_async, n2o_xhr, n4u_cx, n2o_cowboy, n2o_multipart, n2o_static, n2o_stream, n4u_document, n2o_proto, n2o_relay, n4u_error, n4u_io, n4u_log, n4u_mq, n4u_pickle, n4u_query, n4u_secret, n4u_session, n4u_syn, n4u_client, n4u_file, n4u_heart, n4u_http, n4u_nitrogen, n4u_text, wf, wf_convert, wf_utils]},
   {registered, [n4u_sup]},
   {registered, [n4u_sup]},
   {mod, {n4u_app, []}},
   {mod, {n4u_app, []}},
   {env, []}
   {env, []}

+ 0 - 127
src/handlers/n2o_session.erl

@@ -1,127 +0,0 @@
--module(n2o_session).
--include_lib("n4u/include/n4u.hrl").
--include_lib("stdlib/include/ms_transform.hrl").
--compile([export_all, nowarn_export_all]).
-
-finish(State,Ctx) -> {ok,State,Ctx}.
-init(State,Ctx) -> case wf:config(n2o,auto_session) of
-                        disabled -> {ok,State,Ctx};
-                        _ -> n2o_session:ensure_sid(State,Ctx,[]) end.
-
-ensure_sid(State, Ctx, []) -> ensure_sid(State, Ctx, site);
-ensure_sid(State, Ctx, From) ->
-    SessionId   = wf:cookie_req(session_cookie_name(From), Ctx#cx.req),
-    wf:info(?MODULE,"Ensure SID ~p-sid=~p~n",[From,SessionId]),
-    session_sid(State, Ctx, SessionId, From).
-
-session_sid(SID, Source) -> session_sid([], ?CTX, SID, Source).
-session_sid(State, Ctx, SessionId, From) ->
-    wf:info(?MODULE,"Session Init ~p: ~p",[From,SessionId]),
-    Lookup = lookup_ets({SessionId,<<"auth">>}),
-    NewTill = till(calendar:local_time(), ttl()),
-    SessionCookie = case Lookup of
-        undefined ->
-            CookieValue = case SessionId of
-                undefined -> case wf:qc(wf:config(n2o,transfer_session,<<"csid">>),Ctx) of
-                    undefined -> new_cookie_value(From);
-                    Csid -> new_cookie_value(Csid, From) end;
-                _ -> new_cookie_value(SessionId,From) end,
-            Cookie = {{CookieValue,<<"auth">>},<<"/">>,os:timestamp(),NewTill,new},
-            ets:insert(cookies,Cookie),
-            wf:info(?MODULE,"Auth Cookie New: ~p~n",[Cookie]),
-            Cookie;
-        {{Session,Key},Path,Issued,Till,Status} ->
-            case expired(Issued,Till) of
-                false ->
-                    Cookie = {{Session,Key},Path,Issued,Till,Status},
-                    wf:info(?MODULE,"Auth Cookie Same: ~p",[Cookie]),
-                    Cookie;
-                true ->
-                    Cookie = {{new_cookie_value(From),<<"auth">>},<<"/">>,os:timestamp(),NewTill,new},
-                    clear(Session),
-                    ets:insert(cookies,Cookie),
-                    wf:info(?MODULE,"Auth Cookie Expired in Session ~p~n",[Session]),
-                    Cookie end;
-        What -> wf:info(?MODULE,"Auth Cookie Error: ~p",[What]), What
-    end,
-    {{ID,_},_,_,_,_} = SessionCookie,
-    put(session_id,ID),
-    wf:info(?MODULE,"State: ~p",[SessionCookie]),
-    {ok, State, Ctx#cx{session=SessionCookie}}.
-
-expired(_Issued,Till) -> Till < calendar:local_time().
-
-lookup_ets(Key) ->
-    Res = ets:lookup(cookies,Key),
-    %wf:info(?MODULE,"Lookup ETS: ~p",[{Res,Key}]),
-    case Res of
-         [] -> undefined;
-         [Value] -> Value;
-         Values -> Values end.
-
-clear() -> clear(session_id()).
-clear(Session) ->
-    [ ets:delete(cookies,X) || X <- ets:select(cookies,
-        ets:fun2ms(fun(A) when (element(1,element(1,A)) == Session) -> element(1,A) end)) ].
-
-cookie_expire(SecondsToLive) ->
-    Seconds = calendar:datetime_to_gregorian_seconds(calendar:local_time()),
-    DateTime = calendar:gregorian_seconds_to_datetime(Seconds + SecondsToLive),
-    cow_date:rfc2109(DateTime).
-
-ttl() -> wf:config(n2o,ttl,60*15).
-
-till(Now,TTL) ->
-    calendar:gregorian_seconds_to_datetime(
-        calendar:datetime_to_gregorian_seconds(Now) + TTL).
-
-session_id() -> get(session_id).
-
-new_sid() ->
-    wf_convert:hex(binary:part(crypto:hmac(wf:config(n4u, hmac, sha256),
-         n4u_secret:secret(),term_to_binary(os:timestamp())),0,16)).
-
-new_cookie_value(From) -> new_cookie_value(new_sid(), From).
-new_cookie_value(undefined, From) -> new_cookie_value(new_sid(), From);
-new_cookie_value(SessionKey, From) ->
-    F = wf:f("document.cookie='~s=~s; path=/; expires=~s';",
-                [wf:to_list(session_cookie_name(From)),
-                 wf:to_list(SessionKey),
-                 cookie_expire(2147483647)]),
-    io:format("Cookie: ~p~n",[F]),
-    wf:wire(F),
-    % NOTE: Infinity-expire cookie will allow to clean up all session cookies
-    %       by request from browser so we don't need to sweep them on server.
-    %       Actually we should anyway to cleanup outdated cookies
-    %       that will never be requested.
-    SessionKey.
-
-session_cookie_name([]) -> session_cookie_name(site);
-session_cookie_name(From) -> wf:to_binary([wf:to_binary(From), <<"-sid">>]).
-
-set_session_value(Session, Key, Value) ->
-    Till = till(calendar:local_time(), ttl()),
-    ets:insert(cookies,{{Session,Key},<<"/">>,os:timestamp(),Till,Value}),
-    Value.
-
-set_value(Key, Value) ->
-    NewTill = till(calendar:local_time(), ttl()),
-    ets:insert(cookies,{{session_id(),Key},<<"/">>,os:timestamp(),NewTill,Value}),
-    Value.
-
-invalidate_sessions() ->
-    ets:foldl(fun(X,A) -> {Sid,Key} = element(1,X), n2o_session:get_value(Sid,Key,undefined), A end, 0, cookies).
-
-get_value(Key, DefaultValue) ->
-    get_value(session_id(), Key, DefaultValue).
-
-get_value(SID, Key, DefaultValue) ->
-    Res = case lookup_ets({SID,Key}) of
-               undefined -> DefaultValue;
-               {{SID,Key},_,Issued,Till,Value} -> case expired(Issued,Till) of
-                       false -> Value;
-                       true -> ets:delete(cookies,{SID,Key}), DefaultValue end end,
-    %wf:info(?MODULE,"Session Lookup Key ~p Value ~p",[Key,Res]),
-    Res.
-
-remove_value(Key) -> ets:delete(cookies,Key).

+ 190 - 0
src/handlers/n4u_session.erl

@@ -0,0 +1,190 @@
+-module(n4u_session).
+
+-include_lib("n4u/include/n4u.hrl").
+-include_lib("stdlib/include/ms_transform.hrl"). % todo read how this works
+
+-export([init/2, finish/2]).
+-export([ensure_sid/3, session_sid/2, session_sid/4, expired/2,
+  lookup_ets/1, clear/0, clear/1, cookie_expire/1, ttl/0, till/2,
+  new_sid/0, new_cookie_value/1, new_cookie_value/2,
+  session_cookie_name/1, set_session_value/3, set_value/2,
+  invalidate_sessions/0, get_value/2, get_value/3, remove_value/1]).
+% todo check where used
+
+
+init(State, Ctx) ->
+  case application:get_env(n4u, auto_session, "") of
+    disabled -> {ok, State, Ctx};
+    _ -> ?MODULE:ensure_sid(State, Ctx, [])
+  end.
+
+
+finish(State, Ctx) -> {ok, State, Ctx}.
+
+
+ensure_sid(State, Ctx, []) -> ensure_sid(State, Ctx, site);
+
+ensure_sid(State, Ctx, From) ->
+  Cookie_Name = nitro:to_atom(session_cookie_name(From)),
+  Session_Id = wf:cookie_req(Cookie_Name, Ctx#cx.req),
+  wf:info(?MODULE, "Ensure SID ~p-sid=~p~n", [From, Session_Id]),
+  session_sid(State, Ctx, Session_Id, From).
+
+
+session_sid(SID, Source) -> session_sid([], ?CTX, SID, Source).
+
+session_sid(State, Ctx, Session_Id, From) ->
+  wf:info(?MODULE, "Session Init ~p: ~p~n", [From, Session_Id]),
+  Lookup = lookup_ets({Session_Id, <<"auth">>}),
+  New_Till = till(calendar:local_time(), ttl()),
+  
+  Session_Cookie = case Lookup of
+    undefined ->
+      
+      Cookie_Value = case Session_Id of
+        undefined ->
+          case wf:qc(application:get_env(n4u, transfer_session, <<"csid">>), Ctx) of
+            undefined -> new_cookie_value(From);
+            Csid -> new_cookie_value(Csid, From)
+          end;
+        
+        _ ->
+          new_cookie_value(Session_Id, From)
+      end,
+      
+      Cookie = {{Cookie_Value, <<"auth">>}, <<"/">>, os:timestamp(), New_Till, new},
+      ets:insert(cookies, Cookie),
+      wf:info(?MODULE, "Auth Cookie New: ~p~n", [Cookie]),
+      Cookie;
+      
+    {{Session, Key}, Path, Issued, Till, Status} ->
+      case expired(Issued, Till) of
+        false ->
+          Cookie = {{Session, Key}, Path, Issued, Till, Status},
+          wf:info(?MODULE, "Auth Cookie Same: ~p~n", [Cookie]),
+          Cookie;
+        true ->
+          Cookie = {{new_cookie_value(From), <<"auth">>}, <<"/">>, os:timestamp(), New_Till, new},
+          clear(Session),
+          ets:insert(cookies, Cookie),
+          wf:info(?MODULE, "Auth Cookie Expired in Session ~p~n", [Session]),
+          Cookie
+      end;
+      
+    What ->
+      wf:info(?MODULE, "Auth Cookie Error: ~p~n", [What]),
+      What
+  end,
+  
+  {{ID, _}, _, _, _, _} = Session_Cookie,
+  erlang:put(session_id, ID),
+  wf:info(?MODULE, "State: ~p~n", [Session_Cookie]),
+  {ok, State, Ctx#cx{session = Session_Cookie}}.
+
+
+expired(_Issued, Till) ->
+  Till < calendar:local_time().
+
+
+lookup_ets(Key) ->
+  Res = ets:lookup(cookies, Key),
+  %wf:info(?MODULE, "Lookup ETS: ~p", [{Res, Key}]),
+  case Res of
+    [] -> undefined;
+    [Value] -> Value;
+    Values -> Values
+  end.
+
+
+clear() -> clear(erlang:get(session_id)).
+
+clear(Session) ->
+  [ets:delete(cookies, X) || X <- ets:select(cookies, ets:fun2ms(fun(A) 
+      when (erlang:element(1, erlang:element(1, A)) == Session) -> erlang:element(1, A) end))].
+
+
+cookie_expire(Seconds_To_Live) ->
+  Seconds = calendar:datetime_to_gregorian_seconds(calendar:local_time()),
+  DateTime = calendar:gregorian_seconds_to_datetime(Seconds + Seconds_To_Live),
+  cow_date:rfc2109(DateTime).
+
+
+ttl() -> application:get_env(n4u, ttl, 60 * 15).
+
+
+till(Now, TTL) ->
+  calendar:gregorian_seconds_to_datetime(
+    calendar:datetime_to_gregorian_seconds(Now) + TTL).
+
+
+new_sid() ->
+  nitro:hex(binary:part(
+    crypto:mac(application:get_env(n4u, mac_type, hmac),
+               application:get_env(n4u, mac_subtype, sha256),
+               n4u_secret:secret(),
+               erlang:term_to_binary(os:timestamp())),
+    0, 16)).
+
+
+new_cookie_value(From) -> new_cookie_value(new_sid(), From).
+
+new_cookie_value(undefined, From) -> new_cookie_value(new_sid(), From);
+new_cookie_value(Session_Key, From) ->
+  F = nitro:f("document.cookie='~s=~s; path=/; expires=~s';",
+    [nitro:to_list(session_cookie_name(From)),
+     nitro:to_list(Session_Key),
+     cookie_expire(2147483647)]),
+  wf:info(?MODULE, "Cookie: ~p~n", [F]),
+  nitro:wire(F),
+  % NOTE: Infinity-expire cookie will allow to clean up all session cookies
+  %       by request from browser so we don't need to sweep them on server.
+  %       Actually we should anyway to cleanup outdated cookies
+  %       that will never be requested.
+  Session_Key.
+
+
+session_cookie_name([]) -> session_cookie_name(site);
+session_cookie_name(From) -> nitro:to_binary([nitro:to_binary(From), <<"-sid">>]).
+
+
+set_session_value(Session, Key, Value) ->
+  Till = till(calendar:local_time(), ttl()),
+  ets:insert(cookies, {{Session, Key}, <<"/">>, os:timestamp(), Till, Value}),
+  Value.
+
+
+set_value(Key, Value) ->
+  New_Till = till(calendar:local_time(), ttl()),
+  ets:insert(cookies, {{erlang:get(session_id), Key}, <<"/">>, os:timestamp(), New_Till, Value}),
+  Value.
+
+
+invalidate_sessions() ->
+  ets:foldl(fun(X, A) ->
+    {Sid, Key} = erlang:element(1, X),
+    ?MODULE:get_value(Sid, Key, undefined),
+    A
+    end, 0, cookies).
+
+
+get_value(Key, Default_Value) ->
+  get_value(erlang:get(session_id), Key, Default_Value).
+
+
+get_value(SID, Key, Default_Value) ->
+  Res = case lookup_ets({SID, Key}) of
+    undefined -> Default_Value;
+    {{SID, Key}, _, Issued, Till, Value} ->
+      case expired(Issued, Till) of
+        false -> Value;
+        true ->
+          ets:delete(cookies, {SID, Key}),
+          Default_Value
+      end
+  end,
+  %wf:info(?MODULE, "Session Lookup Key ~p Value ~p~n", [Key, Res]),
+  Res.
+
+
+remove_value(Key) -> ets:delete(cookies, Key).
+

+ 1 - 1
src/n4u_cx.erl

@@ -61,6 +61,6 @@ fold(Fun, Handlers, Ctx) ->
 init_context(Req) ->
 init_context(Req) ->
   #cx{actions=[], module=index, path=[], req=Req, params=[],
   #cx{actions=[], module=index, path=[], req=Req, params=[],
       handlers= [ {'query', application:get_env(n4u, 'query', n4u_query)},
       handlers= [ {'query', application:get_env(n4u, 'query', n4u_query)},
-                  {session, application:get_env(n4u, session, n2o_session)},
+                  {session, application:get_env(n4u, session, n4u_session)},
                   {route,   application:get_env(n4u, route,   n2o_dynroute)} ]}.
                   {route,   application:get_env(n4u, route,   n2o_dynroute)} ]}.
 
 

+ 1 - 1
src/n4u_sup.erl

@@ -50,6 +50,6 @@ proc({timer, ping}, #handler{state=Timer}=Async) ->
     _ -> erlang:cancel_timer(Timer)
     _ -> erlang:cancel_timer(Timer)
   end,
   end,
   wf:info(?MODULE, "n4u Timer: ~p~n", [ping]),
   wf:info(?MODULE, "n4u Timer: ~p~n", [ping]),
-  (application:get_env(n4u, session, n2o_session)):invalidate_sessions(),
+  (application:get_env(n4u, session, n4u_session)):invalidate_sessions(),
   wf:invalidate_cache(),
   wf:invalidate_cache(),
   {reply, ok, Async#handler{state=timer_restart(ping())}}.
   {reply, ok, Async#handler{state=timer_restart(ping())}}.

+ 1 - 1
src/protocols/n4u_nitrogen.erl

@@ -31,7 +31,7 @@ info({init, Rest}, Req, State) ->
       UserCx = try Module:event(init),
       UserCx = try Module:event(init),
         case application:get_env(n4u, auto_session, "") of
         case application:get_env(n4u, auto_session, "") of
           disabled -> skip;
           disabled -> skip;
-          _ -> n2o_session:ensure_sid([], ?CTX, [])
+          _ -> n4u_session:ensure_sid([], ?CTX, [])
         end
         end
       catch E2:R2:Stk2 ->
       catch E2:R2:Stk2 ->
         wf:error(?MODULE, "init: E:R:Stk: ~p ~p~n ~p~n", [E2, R2, Stk2]),
         wf:error(?MODULE, "init: E:R:Stk: ~p ~p~n ~p~n", [E2, R2, Stk2]),

+ 2 - 3
src/wf.erl

@@ -109,21 +109,20 @@ error_page(Class,Error) -> ?ERRORING:error_page(Class, Error).
 % Session handling wf:session wf:user wf:role
 % Session handling wf:session wf:user wf:role
 
 
 -ifndef(SESSION).
 -ifndef(SESSION).
--define(SESSION, (wf:config(n2o,session,n2o_session))).
+-define(SESSION, (application:get_env(n4u, session, n4u_session))).
 -endif.
 -endif.
 
 
 session(Key) -> ?SESSION:get_value(Key,undefined).
 session(Key) -> ?SESSION:get_value(Key,undefined).
 session(Key, Value) -> ?SESSION:set_value(Key, Value).
 session(Key, Value) -> ?SESSION:set_value(Key, Value).
 session_default(Key, DefaultValue) -> ?SESSION:get_value(Key, DefaultValue).
 session_default(Key, DefaultValue) -> ?SESSION:get_value(Key, DefaultValue).
 clear_session() -> ?SESSION:clear().
 clear_session() -> ?SESSION:clear().
-session_id() -> ?SESSION:session_id().
 user() -> wf:session(<<"user">>).
 user() -> wf:session(<<"user">>).
 user(User) -> wf:session(<<"user">>,User).
 user(User) -> wf:session(<<"user">>,User).
 clear_user() -> wf:session(<<"user">>,undefined).
 clear_user() -> wf:session(<<"user">>,undefined).
 logout() -> clear_user(), clear_session().
 logout() -> clear_user(), clear_session().
 invalidate_cache() -> ets:foldl(fun(X, _A) -> wf:cache(element(1,X)) end, 0, caching).
 invalidate_cache() -> ets:foldl(fun(X, _A) -> wf:cache(element(1,X)) end, 0, caching).
 cache(Key, undefined) -> ets:delete(caching,Key);
 cache(Key, undefined) -> ets:delete(caching,Key);
-cache(Key, Value) -> ets:insert(caching,{Key,n2o_session:till(calendar:local_time(), n2o_session:ttl()),Value}), Value.
+cache(Key, Value) -> ets:insert(caching, {Key, n4u_session:till(calendar:local_time(), n4u_session:ttl()), Value}), Value.
 cache(Key, Value, Till) -> ets:insert(caching,{Key,Till,Value}), Value.
 cache(Key, Value, Till) -> ets:insert(caching,{Key,Till,Value}), Value.
 cache(Key) ->
 cache(Key) ->
     Res = ets:lookup(caching,Key),
     Res = ets:lookup(caching,Key),