#[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 for details.]# import guildenstern/httpserver import nimword, jsony import std/[base64, sysrand] import "../helpers/form", "../helpers/validation", "../helpers/auth", "../helpers/global", "../models/user", "../models/session" proc loginPostHandler*() = try: var cookieHeader1, cookieHeader2: string let email = formInput("email") let password = formInput("password") #validate form inputs vInput("email", @["required", "string", "email", "max:75"]) vInput("password", @["required", "string", "min_complexity", "max:100"]) var csrfTokenInput = formInput("csrf_token") #create formResult and redirect on validation errors. if formErrors.len > 0: addFormOldInput("email", formInput("email")) #discard assignErrorFR(formErrors, formOldInputs, csrfTokenInput) discard assignErrorFR(formErrors, formOldInputs) let frJson = formResult.toJson() #let cookieHeader = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" if APP_MODE == "dev": cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;" else: cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;" reply(Http303, [locationBack(), cookieHeader1]) else: #inputs pass validation rules. let's see if the creds supplied are valid. let registeredUser = getUserByEmail(email) if registeredUser.email.len > 0: if password.isValidPassword(registeredUser.password): #create sessionId var sessionId = $urandom(32) sessionId = base64.encode(sessionId) #create session var userSession: Session userSession.sessionId = sessionId userSession.userId = registeredUser.id userSession.csrfToken = newCsrfToken() createUserSession(userSession) discard assignLoginSuccessFR() let frJson = formResult.toJson() #redirect, and set session cookie. #will probably need to detect requested url for redirect (with static fallback) instead of just static location. #Set-Cookie: =; Domain=; Secure; HttpOnly #dev #let cookieHeader1 = "Set-Cookie: " & APP_NAME & "_session=" & sessionId & ";" & "HttpOnly;" & "SameSite=Lax;" #let cookieHeader2 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;" #prod #let cookieHeader1 = "Set-Cookie: " & APP_NAME & "_session=" & sessionId & ";" & "HttpOnly;" & "Secure=true;" & "SameSite=Lax;" #let cookieHeader2 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;" if APP_MODE == "dev": cookieHeader1 = "Set-Cookie: " & APP_NAME & "_session=" & sessionId & ";" & "HttpOnly;" & "SameSite=Lax;" cookieHeader2 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;" else: cookieHeader1 = "Set-Cookie: " & APP_NAME & "_session=" & sessionId & ";" & "HttpOnly;" & "Secure=true;" & "SameSite=Lax;" cookieHeader2 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;" #headers are just an openarray of strings. reply(Http303, [location("/"), cookieHeader1, cookieHeader2]) else: #password supplied did not match password in DB for supplied email address. redirect back to login with creds error. #create a formError. formError.fieldName = "password" formError.fieldMessage = "Entered password is not valid." #add it to formErrors seq. formErrors.add(formError) formResult.message = "Authentication error." formResult.messageClass = "text-red-500" formResult.errors = toJson(formErrors) formResult.oldInputs = getOldInputJson() let frJson = formResult.toJson() #let cookieHeader = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" #let cookieHeader = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" if APP_MODE == "dev": cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;" else: cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;" reply(Http303, [locationBack(), cookieHeader1]) else: formError.fieldName = "email" formError.fieldMessage = "No user found with supplied email address." #add it to formErrors seq. formErrors.add(formError) formResult.message = "Authentication error." formResult.messageClass = "text-red-500" formResult.errors = toJson(formErrors) formResult.oldInputs = getOldInputJson() let frJson = formResult.toJson() #let cookieHeader = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" if APP_MODE == "dev": cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;" else: cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;" reply(Http303, [locationBack(), cookieHeader1]) except Exception as e: echo e.msg #reply(Http500) discard assignGeneralErrorFR(e.msg) setFR() reply(Http303, [location("/500")])