func DB.GetUserIdFromSession(session) { DB.Lock(); var dbCon = DB.Open(); var exec = Sqlite.Exec(dbCon,$"SELECT * FROM sessions WHERE key = {Sqlite.Escape(session)};"); if(TypeOf(exec) == "List" && exec.Length == 1) { var expiry = 0; const expires = ParseLong(exec[0].expires); if(TypeIsLong(expires) && expires != 0) { const whenItExpires = ParseLong(expires); const currentTime = DateTime.NowEpoch ?? 0; if(whenItExpires != 0 && currentTime < whenItExpires && (whenItExpires - currentTime) < (DB.Expires-3600)) { expiry = currentTime + DB.Expires; Sqlite.Exec(dbCon, $"UPDATE sessions SET expires = {expiry} WHERE key = {Sqlite.Escape(session)};"); } else if(whenItExpires != 0 && currentTime >= whenItExpires) { Sqlite.Exec(dbCon, $"DELETE FROM sessions WHERE key = {Sqlite.Escape(session)};"); Sqlite.Close(dbCon); DB.Unlock(); return null; } } Sqlite.Close(dbCon); DB.Unlock(); return { accountId = ParseLong(exec[0].accountId), expiry }; } Sqlite.Close(dbCon); DB.Unlock(); return null; } func DB.GetSessionFromBearer(ctx) { var auth = ctx.RequestHeaders.TryGetFirst("Authorization"); if(TypeOf(auth) == "String") { auth=auth.Split(" ",true,2); if(auth.Length < 2) return null; if(auth[0] != "Bearer") return null; var uid = DB.GetUserIdFromSession(auth[1]); if(TypeIsDictionary(uid)) return auth[1]; } return null; } func DB.GetSession(ctx) { var cookie = ctx.RequestHeaders.TryGetFirst("Cookie"); if(TypeOf(cookie) == "String") { each(var part : cookie.Split("; ")) { if(part.Length > 0) { var cookieKV = part.Split("=",true,2); if(cookieKV.Length == 2 && cookieKV[0] == "Session") { var session = cookieKV[1]; var sessionObj = DB.GetUserIdFromSession(session); if(TypeIsDictionary(sessionObj)) { if(sessionObj.expiry > 0) { ctx.WithHeader("Set-Cookie",$"Session={session}; SameSite=Lax; Expires={new DateTime(sessionObj.expiry).ToHttpDate()}"); } return session; } } } } } return null; } func DB.CreateSession(userId, doesExpire, name) { const now = DateTime.NowEpoch; const expiryTime = doesExpire ? (DB.Expires + now) : 0; DB.Lock(); var dbCon = DB.Open(); var rand = Net.Http.UrlEncode(Crypto.Base64Encode(Crypto.RandomBytes(32, "CPKG"))); Sqlite.Exec(dbCon,$"INSERT INTO sessions (accountId,key, expires, created, name) VALUES ({userId},{Sqlite.Escape(rand)},{Sqlite.Escape(expiryTime)},{Sqlite.Escape(now)}, {Sqlite.Escape(name)});"); Sqlite.Close(dbCon); DB.Unlock(); return rand; } func DB.DestroySession(session) { if(TypeOf(session) != "String") return false; DB.Lock(); var dbCon = DB.Open(); var res = Sqlite.Exec(dbCon, $"DELETE FROM sessions WHERE key = {Sqlite.Escape(session)};"); Sqlite.Close(dbCon); DB.Unlock(); if(TypeOf(res) == "String") return false; return true; }