Forget-Me-Not/fmn_gs.nim

91 lines
4.0 KiB
Nim
Raw Normal View History

2025-05-15 08:01:35 -05:00
#[Copyright 2025 ITwrx.
2025-05-17 09:02:52 -05:00
This file is part of Forget-Me-Not.
Forget-Me-Not is released under the GNU Affero General Public License 3.0.
2025-05-15 08:01:35 -05:00
See COPYING or <https://www.gnu.org/licenses/> for details.]#
import guildenstern/[epolldispatcher, httpserver], sqliteral
import "templates/error404.nimf", "templates/error500.nimf", "templates/reminders.nimf", "templates/reminder_create.nimf", "templates/reminder_update.nimf", "templates/login.nimf"
import helpers/db, helpers/global, helpers/form, helpers/auth
import models/reminder
import post_handlers/reminder_post_handler, post_handlers/login_post_handler, post_handlers/send_reminders_post_handler
db1.openDatabase(APP_NAME & ".db", [RemindersSchema, UsersSchema, SessionsSchema]);
var allReminders{.threadvar.}: seq[Reminder]
#uncomment, add creds to dev/create_user and compile+run once to add new admin user.
#import dev/create_user
#createNewUser()
proc handleGet() =
{.gcsafe.}:
try:
let uri = getUri()
#overwrite cookie in browser when reply is performed, so form won't keep showing old input to this visitor if they don't POST again and also refresh for some reason.
var cookieHeader: string
if APP_MODE == "dev":
cookieHeader = "Set-Cookie: form_result=" & "" & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;"
else:
cookieHeader = "Set-Cookie: form_result=" & "" & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;"
if uri == "/login":
reply(loginTemplate(setVisitorCsrfToken(), getCookieFormResult()), [cookieHeader])
if isAuthdAdmin():
allReminders = getAllReminders()
for reminder in allReminders:
if "/reminder/" & $reminder.id & "/update" == uri:
reply(reminderUpdateTemplate(reminder.id, getUserPageCsrfToken(), getFormResult()), [cookieHeader])
case uri:
of "/":
reply(remindersTemplate(allReminders, getUserPageCsrfToken(), getFormResult()), [cookieHeader])
of "/create-reminder":
reply(reminderCreateTemplate(getUserPageCsrfToken(), getFormResult()), [cookieHeader])
of "/500":
reply(error500Template(getUserPageCsrfToken(), getFormResult()), [cookieHeader])
else:
reply(error404Template(getUserPageCsrfToken()), [cookieHeader])
else:
reply(Http302, [location("/login"), cookieHeader])
except Exception as e:
echo e.msg
proc handlePost() =
{.gcsafe.}:
try:
let uri = getUri()
if uri == "/send-reminders":
sendRemindersPostHandler()
let fr = getFormResult()
if uri == "/login":
if isValidVisitorCsrfToken(formInput("csrf_token")):
loginPostHandler()
else:
discard assignGeneralErrorFR("CSRF Token Validation Failure. Please try again (or report successive failures).")
setFR()
reply(Http302, [location("/login")])
else:
if isAuthdAdminPost():
if isValidUserCsrfToken(formInput("csrf_token")):
case uri
of "/reminder/create":
reminderCreatePostHandler()
of "/reminder/update":
reminderUpdatePostHandler()
of "/reminder/delete":
reminderDeletePostHandler()
else:
reply(error404Template(getUserPageCsrfToken()), ["Content-Type: text/html"])
else:
discard assignGeneralErrorFR("CSRF Token Validation Failure. Please try again (or report successive failures).")
setFR()
reply(Http302, [locationBack()])
else:
reply(Http302, [location("/login")])
except Exception as e:
echo e.msg
let getserver = newHttpServer(handleGet, headerfields = ["cookie", "cookie"])
let postserver = newHttpServer(handlePost, loglevel = INFO, headerfields = ["origin", "cookie", "referer"])
if not epolldispatcher.start(getserver, 8096): quit()
if not epolldispatcher.start(postserver, 8097, threadpoolsize = 20): quit()
joinThreads(getserver.thread, postserver.thread)