fix: sessions not expiring

This commit is contained in:
Massimo Melina 2020-05-10 00:16:56 +02:00
parent 8ff8a9ca22
commit 82de213059

132
main.pas
View File

@ -29,10 +29,11 @@ uses
Windows, Messages, SysUtils, Forms, Menus, Graphics, Controls, ComCtrls, Dialogs, math, Windows, Messages, SysUtils, Forms, Menus, Graphics, Controls, ComCtrls, Dialogs, math,
registry, ExtCtrls, shellapi, ImgList, ToolWin, StdCtrls, strutils, AppEvnts, types, registry, ExtCtrls, shellapi, ImgList, ToolWin, StdCtrls, strutils, AppEvnts, types,
winsock, clipbrd, shlobj, activex, Buttons, FileCtrl, dateutils, iniFiles, Classes, winsock, clipbrd, shlobj, activex, Buttons, FileCtrl, dateutils, iniFiles, Classes,
System.ImageList, system.Generics.Collections,
// 3rd part libs. ensure you have all of these, the same version reported in dev-notes.txt // 3rd part libs. ensure you have all of these, the same version reported in dev-notes.txt
OverbyteIcsWSocket, OverbyteIcsHttpProt, OverbyteicsMD5, GIFimage, regexpr, OverbyteIcsZLibHigh, OverbyteIcsZLibObj, OverbyteIcsWSocket, OverbyteIcsHttpProt, OverbyteicsMD5, GIFimage, regexpr, OverbyteIcsZLibHigh, OverbyteIcsZLibObj,
// rejetto libs // rejetto libs
HSlib, traylib, monoLib, progFrmLib, classesLib, System.ImageList; HSlib, traylib, monoLib, progFrmLib, classesLib;
const const
VERSION = '2.4rc5'; VERSION = '2.4rc5';
@ -290,6 +291,19 @@ type
size: int64; size: int64;
end; end;
Tsession = class
vars: THashedStringList;
created, ttl, expires: Tdatetime;
public
id: string;
constructor create(const sid:string='');
destructor Destroy; override;
procedure setVar(const k,v:string);
function getVar(const k:string):string;
procedure keepAlive();
end;
Tsessions = Tdictionary<string,Tsession>;
TconnData = class // data associated to a client connection TconnData = class // data associated to a client connection
private private
FlastFile: Tfile; FlastFile: Tfile;
@ -337,8 +351,7 @@ type
bytes: integer; bytes: integer;
since: Tdatetime; since: Tdatetime;
end; end;
sessionID: string; session: Tsession;
session,
vars, // defined by {.set.} vars, // defined by {.set.}
urlvars, // as $_GET in php urlvars, // as $_GET in php
postVars // as $_POST in php postVars // as $_POST in php
@ -352,8 +365,6 @@ type
property lastFile:Tfile read FlastFile write setLastFile; property lastFile:Tfile read FlastFile write setLastFile;
constructor create(conn:ThttpConn); constructor create(conn:ThttpConn);
destructor Destroy; override; destructor Destroy; override;
function sessionGet(k:string):string;
procedure sessionSet(k, v:string);
procedure disconnect(reason:string); procedure disconnect(reason:string);
procedure logout(); procedure logout();
end; // Tconndata end; // Tconndata
@ -1083,7 +1094,7 @@ uses
var var
globalLimiter: TspeedLimiter; globalLimiter: TspeedLimiter;
ip2obj: THashedStringList; ip2obj: THashedStringList;
sessions: THashedStringList; sessions: Tsessions;
addToFolder: string; // default folder where to add items from the command line addToFolder: string; // default folder where to add items from the command line
lastDialogFolder: string; // stores last for open dialog, to make it persistent lastDialogFolder: string; // stores last for open dialog, to make it persistent
clock: integer; // program ticks (tenths of second) clock: integer; // program ticks (tenths of second)
@ -2257,6 +2268,53 @@ if assigned(mainFrm) then
mainfrm.visible:=userInteraction.bakVisible; mainfrm.visible:=userInteraction.bakVisible;
end; // reenableUserInteraction end; // reenableUserInteraction
function getNewSID():string;
begin result:=replaceStr(base64encode(str_(now())+str_(random())), '=','') end;
constructor Tsession.create(const sid:string='');
begin
id:=sid;
if id = '' then
id:=getNewSID();
sessions.Add(id, self);
created:=now();
ttl:=1; // days
keepAlive();
end;
destructor Tsession.Destroy;
var
o: Tobject;
cd: TconnData;
begin
for o in srv.conns do
begin
cd:=ThttpConn(o).data;
if cd.session = self then
cd.session:=NIL;
end;
sessions.remove(id);
freeAndNIL(vars);
end;
procedure Tsession.keepAlive();
begin expires:=now() + ttl end;
function Tsession.getVar(const k:string):string;
begin
try result:=vars.values[k];
except result:=''
end;
end; // sessionGet
procedure Tsession.setVar(const k, v:string);
begin
if vars= NIL then
vars:=THashedStringList.create;
vars.addPair(k,v);
end;
constructor TconnData.create(conn:ThttpConn); constructor TconnData.create(conn:ThttpConn);
begin begin
conn.data:=self; conn.data:=self;
@ -2304,29 +2362,11 @@ end; // disconnect
procedure TconnData.logout(); procedure TconnData.logout();
begin begin
freeAndNIL(session); freeAndNIL(session);
sessions.delete(sessions.IndexOf(sessionID));
sessionID:='';
usr:=''; usr:='';
pwd:=''; pwd:='';
conn.delCookie(SESSION_COOKIE); conn.delCookie(SESSION_COOKIE);
end; // logout end; // logout
function Tconndata.sessionGet(k:string):string;
begin
try result:=session.values[k];
except result:='' end;
end; // sessionGet
procedure Tconndata.sessionSet(k, v:string);
begin
if session = NIL then
begin
session:=THashedStringList.create;
sessions.addObject(sessionID, session);
end;
session.values[k]:=v;
end; // sessionSet
// we'll automatically free and previous temporary object // we'll automatically free and previous temporary object
procedure TconnData.setLastFile(f:Tfile); procedure TconnData.setLastFile(f:Tfile);
begin begin
@ -4479,9 +4519,6 @@ else if tplLast <> 0 then
end; end;
end; // keepTplUpdated end; // keepTplUpdated
function getNewSID():string;
begin result:=replaceStr(base64encode(str_(now())+str_(random())), '=','') end;
procedure setNewTplFile(fn:string); procedure setNewTplFile(fn:string);
begin begin
tplFilename:=fn; tplFilename:=fn;
@ -4825,21 +4862,29 @@ var
end; end;
procedure sessionSetup(); procedure sessionSetup();
var
sid: string;
begin begin
if (data = NIL) or assigned(data.session) then exit; if data = NIL then
data.sessionID:=conn.getCookie(SESSION_COOKIE); exit;
if data.sessionID = '' then if data.session = NIL then
begin begin
data.sessionID:=getNewSID(); sid:=conn.getCookie(SESSION_COOKIE);
conn.setCookie(SESSION_COOKIE, data.sessionID, ['path','/'], 'HttpOnly'); // the session is site-wide, even if this request was related to a folder if sid = '' then
begin
data.session:=Tsession.create();
conn.setCookie(SESSION_COOKIE, data.session.id, ['path','/'], 'HttpOnly'); // the session is site-wide, even if this request was related to a folder
end end
else else
try data.session:=sessions.objects[sessions.indexOf(data.sessionID)] as ThashedStringList try data.session:=sessions[sid]
except end; except data.session:=Tsession.create(sid) // probably expired
end;
end;
data.session.keepAlive();
if data.usr = '' then if data.usr = '' then
begin begin
data.usr:=data.sessionGet('user'); data.usr:=data.session.getVar('user');
data.pwd:=data.sessionGet('password'); data.pwd:=data.session.getVar('password');
end; end;
if (data.usr = '') and (conn.request.user > '') then if (data.usr = '') and (conn.request.user > '') then
begin begin
@ -5229,17 +5274,17 @@ var
In such case we would not be able to calculate pwd+sessionID because we'd had no clear pwd. In such case we would not be able to calculate pwd+sessionID because we'd had no clear pwd.
By relying on md5(pwd) instead of pwd, we will avoid such problem. } By relying on md5(pwd) instead of pwd, we will avoid such problem. }
s:=data.postVars.values['__PASSWORD_MD5']; s:=data.postVars.values['__PASSWORD_MD5'];
if (s > '') and (s = strMD5(strMD5(data.account.pwd)+data.sessionID)) if (s > '') and (s = strMD5(strMD5(data.account.pwd)+data.session.id))
or (data.postVars.values['__PASSWORD'] = data.account.pwd) then or (data.postVars.values['__PASSWORD'] = data.account.pwd) then
begin begin
s:='ok'; s:='ok';
data.pwd:=data.account.pwd; data.pwd:=data.account.pwd;
data.sessionSet('user', data.usr); data.session.setVar('user', data.usr);
data.sessionSet('password', data.pwd); data.session.setVar('password', data.pwd);
end end
else else
begin begin
s:='bad password'; s:='bad password'; //TODO shouldn't this change http code?
data.account:=NIL; data.account:=NIL;
data.usr:=''; data.usr:='';
end; end;
@ -7740,7 +7785,12 @@ var
end; // every10minutes end; // every10minutes
procedure everyMinute(); procedure everyMinute();
var
sess: Tsession;
begin begin
for sess in sessions.values do
if now_ > sess.expires then
sess.free;
if updateDailyChk.Checked then if updateDailyChk.Checked then
autoCheckUpdates(); autoCheckUpdates();
// purge icons older than 5 minutes, because sometimes icons change // purge icons older than 5 minutes, because sometimes icons change
@ -12439,7 +12489,7 @@ filelistTpl:=Ttpl.create(getRes('filelistTpl'));
globalLimiter:=TspeedLimiter.create(); globalLimiter:=TspeedLimiter.create();
ip2obj:=THashedStringList.create(); ip2obj:=THashedStringList.create();
etags:=THashedStringList.create(); etags:=THashedStringList.create();
sessions:=THashedStringList.create(); sessions:=Tsessions.create();
ipsEverConnected:=THashedStringList.create(); ipsEverConnected:=THashedStringList.create();
ipsEverConnected.sorted:=TRUE; ipsEverConnected.sorted:=TRUE;
ipsEverConnected.duplicates:=dupIgnore; ipsEverConnected.duplicates:=dupIgnore;