-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsessionstore.ts
More file actions
121 lines (100 loc) · 2.95 KB
/
Copy pathsessionstore.ts
File metadata and controls
121 lines (100 loc) · 2.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { Mutex } from 'async-mutex';
import { v4 as uuidv4 } from 'uuid';
const mutex = new Mutex();
const sessionSecondsTimeout = 30 * 60; // 30 minutes
interface Session {
id : string,
username: string
expires : number
}
enum SessionCommand {
GET,
CHECK,
CLEAR_SINGLE,
CLEAR_EXPIRED,
CLEAR_ALL
}
/*
Sessions are referenced in two data structures. A stack and a map
A stack to aid in eliminating older expired sessions
A map (actually just a JavaScript object) for quick lookup of sessions
*/
let sessionsStack : Session[] = [];
let sessionsMap : { [k: string]: Session } = {};
function clearExpired() {
for(let session : (Session|undefined) = sessionsStack.shift();; session = sessionsStack.shift())
{
// If stack empty, stop clearing stack
if(session === undefined)
{
break;
}
// if oldest session (i.e. end of stack) not expired, then stop clearing stack
if(session.expires > Date.now())
{
sessionsStack.unshift(session);
break;
}
// remove reference from map too since that is where we lookup
delete sessionsMap[session.id];
}
}
function clearAll() {
sessionsStack = [];
sessionsMap = {};
}
// Used with login
async function get(user : string) : Promise<string> {
const sessionRef : Session = {
id : `session=${uuidv4()}`,
username : user,
expires : Date.now() + (sessionSecondsTimeout * 1000)
}
sessionsStack.push(sessionRef);
sessionsMap[sessionRef.id] = sessionRef;
return `${sessionRef.id}; Path = /; Expires=${new Date(sessionRef.expires).toUTCString()}`;
}
// Check session
async function check(id : string) : Promise<boolean> {
// check session is there
const session : (Session|undefined) = sessionsMap[id];
if(session !== undefined)
{
return true;
}
return false;
}
async function sessionManager(command : SessionCommand, payload? : string) : Promise<any> {
return await mutex.runExclusive( async function() {
switch(command) {
case SessionCommand.CHECK:
return check(payload as string);
case SessionCommand.GET:
return get(payload as string);
case SessionCommand.CLEAR_SINGLE:
delete sessionsMap[payload as string];
break;
case SessionCommand.CLEAR_EXPIRED:
clearExpired();
break;
case SessionCommand.CLEAR_ALL:
clearAll();
}
});
}
export async function checkSession(session: string) : Promise<boolean> {
return await sessionManager(SessionCommand.CHECK, session) ;
}
export async function getSession(username : string) : Promise<string> {
return await sessionManager(SessionCommand.GET,username) ;
}
export function clearSession(id : string) : void {
sessionManager(SessionCommand.CLEAR_SINGLE, id);
}
export function clearExpiredSessions() : void {
sessionManager(SessionCommand.CLEAR_EXPIRED) ;
}
export function clearAllSessions() : void {
sessionManager(SessionCommand.CLEAR_ALL) ;
}
export default sessionManager;