forked from ITwrxOrg/Forget-Me-Not
149 lines
4.5 KiB
Nim
149 lines
4.5 KiB
Nim
#[Copyright 2025 ITwrx.
|
|
This file is part of Simple Site Manager.
|
|
Simple Site Manager is released under the GNU Affero General Public License 3.0.
|
|
See COPYING or <https://www.gnu.org/licenses/> for details.]#
|
|
|
|
import std/[cgi, strtabs, cookies, sysrand, base64]
|
|
import guildenstern/[httpserver], sqliteral
|
|
import "../models/session", "db", "global"
|
|
|
|
#[type
|
|
Session* = object
|
|
sessionId*, csrfToken*: string
|
|
id*, userId*: int]#
|
|
type
|
|
User* = object
|
|
email*, password*: string
|
|
id*: int
|
|
|
|
proc getSessionBySessionId*(sessionId: string): Session =
|
|
{.gcsafe.}:
|
|
var session: Session
|
|
for row in db1.rows(SelectSessionBySessionId, sessionId):
|
|
session.id = row.getInt(0)
|
|
session.sessionId = row.getString(1)
|
|
session.userId = row.getInt(2)
|
|
session.csrfToken = row.getString(3)
|
|
return session
|
|
|
|
proc createUserSession*(userSession: Session) =
|
|
{.gcsafe.}:
|
|
db1.transaction:
|
|
discard db1.insert(InsertUserSession, userSession.sessionId, userSession.userId, userSession.csrfToken)
|
|
|
|
proc deleteSession*(sessionId: string) =
|
|
{.gcsafe.}:
|
|
db1.transaction:
|
|
db1.exec(DeleteSessionBySessionId, sessionId)
|
|
|
|
#Both form and auth have this template. The form.nim copy is exported.
|
|
template formInput(input: string): untyped =
|
|
readData(getBody()).getOrDefault(input)
|
|
|
|
proc getSessionIdFromCookies*(): string =
|
|
{.gcsafe.}:
|
|
let cookieString = http.headers.getOrDefault("cookie")
|
|
let allCookies = parseCookies(cookieString)
|
|
if allCookies.hasKey(APP_NAME & "_session"):
|
|
return allCookies[APP_NAME & "_session"]
|
|
else:
|
|
return ""
|
|
|
|
proc setVisitorCsrfToken*(): string =
|
|
{.gcsafe.}:
|
|
#create csrf token.
|
|
var csrfToken = $urandom(32)
|
|
csrfToken = base64.encode(csrfToken)
|
|
#delete old VisitorSessions, as they are just the one time use CSRF Tokens.
|
|
#may need to be redesigned for better multiuser robustness if it's deleting other users' unused tokens.
|
|
#deleteVisitorSessions()
|
|
#create session in db.
|
|
var visitorSession: Session
|
|
visitorSession.csrfToken = csrfToken
|
|
discard createVisitorSession(visitorSession)
|
|
return csrfToken
|
|
|
|
proc getUserPageCsrfToken*(): string =
|
|
{.gcsafe.}:
|
|
var sessionId: string
|
|
var userSession: Session
|
|
sessionId = getSessionIdFromCookies()
|
|
userSession = getSessionBySessionId(sessionId)
|
|
return userSession.csrfToken
|
|
|
|
proc newCsrfToken*(): string =
|
|
{.gcsafe.}:
|
|
#create csrf token.
|
|
var csrfToken = $urandom(32)
|
|
csrfToken = base64.encode(csrfToken)
|
|
return csrfToken
|
|
|
|
#[proc fCsrfToken*(): string =
|
|
{.gcsafe.}:
|
|
let sessionId = getSessionIdFromCookies()
|
|
let userSession = getUserSessionBySessionId(sessionId)
|
|
result = userSession.csrfToken]#
|
|
|
|
proc isValidVisitorCsrfToken*(csrfToken: string): bool =
|
|
#our previoulsy self-generated, valid csrfToken from the DB.
|
|
let visitorSessionCsrfToken = getSessionByCsrfToken(csrfToken).csrfToken
|
|
if visitorSessionCsrfToken.len > 0 and csrfToken == visitorSessionCsrfToken:
|
|
return true
|
|
else:
|
|
return false
|
|
|
|
proc isValidUserCsrfToken*(csrfToken: string): bool =
|
|
var sessionId: string
|
|
var userSession: Session
|
|
sessionId = getSessionIdFromCookies()
|
|
userSession = getSessionBySessionId(sessionId)
|
|
if userSession.csrfToken == csrfToken:
|
|
return true
|
|
else:
|
|
return false
|
|
|
|
proc isAuthdAdmin*(): bool =
|
|
{.gcsafe.}:
|
|
#get sessionId from request's cookie and see if it exists in session DB.
|
|
var sessionId: string
|
|
sessionId = getSessionIdFromCookies()
|
|
if sessionId.len() > 0:
|
|
var userSession: Session
|
|
try:
|
|
userSession = getSessionBySessionId(sessionId)
|
|
if userSession.id > 0:
|
|
return true
|
|
else:
|
|
return false
|
|
except Exception as e:
|
|
echo e.msg
|
|
return false
|
|
else:
|
|
return false
|
|
|
|
#adds CSRF checking for POST requests.
|
|
proc isAuthdAdminPost*(): bool =
|
|
{.gcsafe.}:
|
|
#get sessionId from request's cookie and see if it exists in session DB.
|
|
#var sessionId{.threadvar.}: string
|
|
var sessionId: string
|
|
sessionId = getSessionIdFromCookies()
|
|
if sessionId.len() > 0:
|
|
try:
|
|
let userSession = getSessionBySessionId(sessionId)
|
|
if userSession.id > 0:
|
|
return true
|
|
else:
|
|
return false
|
|
except Exception as e:
|
|
echo e.msg
|
|
return false
|
|
else:
|
|
return false
|
|
|
|
template ifAuthAdminPost*(procName: untyped): untyped =
|
|
if isAuthdAdminPost() == true:
|
|
procName
|
|
else:
|
|
reply(Http302, [location("/login")])
|