#[Copyright 2025 ITwrx. This file is part of Forget-Me-Not. Forget-Me-Not is released under the GNU Affero General Public License 3.0. See COPYING or 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, 5050): quit() if not epolldispatcher.start(postserver, 5051, threadpoolsize = 20): quit() joinThreads(getserver.thread, postserver.thread)