diff --git a/fmn_gs.nim b/fmn_gs.nim index 3570432..d442f74 100644 --- a/fmn_gs.nim +++ b/fmn_gs.nim @@ -1,6 +1,6 @@ #[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. +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 @@ -54,7 +54,6 @@ proc handlePost() = if uri == "/send-reminders": sendRemindersPostHandler() let fr = getFormResult() - #let csrfTokenInput = formInput("csrf_token") if uri == "/login": if isValidVisitorCsrfToken(formInput("csrf_token")): loginPostHandler() diff --git a/helpers/auth.nim b/helpers/auth.nim index 1610b19..09575b5 100644 --- a/helpers/auth.nim +++ b/helpers/auth.nim @@ -1,16 +1,14 @@ #[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. +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.]# +#TODO: remove code not being used in this application. Some of this is only needed in Simple Site Manager. + 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 @@ -54,9 +52,6 @@ proc setVisitorCsrfToken*(): string = #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 @@ -77,12 +72,6 @@ proc newCsrfToken*(): string = 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. diff --git a/helpers/datetime.nim b/helpers/datetime.nim index 398d5b9..554016e 100644 --- a/helpers/datetime.nim +++ b/helpers/datetime.nim @@ -1,3 +1,8 @@ +#[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 std/[times, strutils] proc weekdayFromString(dayStr: string): Weekday = @@ -41,7 +46,6 @@ proc nextWeekday*(targetWeekdayString: string): DateTime = proc nthWeekdayInMonth*(year: int, month: Month, weekdayString: string, nth: range[1..3]): DateTime = # Start from the first day of the month - #var currentDate = dateTime(year, month, 1, 0, 0, 0, 0) var currentDate = dateTime(year, month, 1) let weekday = weekdayFromString(weekdayString) # Find the first occurrence of the specified weekday @@ -53,7 +57,6 @@ proc nthWeekdayInMonth*(year: int, month: Month, weekdayString: string, nth: ran proc lastWeekdayInMonth(year: int, month: Month, weekdayString: string): DateTime = # Create a DateTime for the last day of the given month - #var lastDay = dateTime(year, month, getDaysInMonth(month, year), 0, 0, 0, 0) var lastDay = dateTime(year, month, getDaysInMonth(month, year)) let weekday = weekdayFromString(weekdayString) # Work backwards until we find the last occurrence of the specified weekday @@ -100,53 +103,19 @@ proc nextYearlyOnWeekdayOfWeekOfMonth*(weekdayString, ocurrence, monthString: st nextSendDate = lastWeekdayInMonth(year(startingDate), month(startingDate), weekdayString) return nextSendDate -#[proc nextYearDate*(monthString: string, day: int): DateTime = - ## Aalways returns a date in the next year, - ## regardless of whether the target date has passed in the current year - #var nextSendDate = dateTime(year(now()) + 1, monthFromString(monthString), day, 0, 0, 0, 0) - #var nextSendDate = dateTime(year(now()) + 1, monthFromString(monthString), day) - #let nextSendDateString = - #echo nextSendDate - #return parse($nextSendDate, "yyyy-MM-dd") - var - let nextYear = year(now()) + 1 - let dt = dateTime(nextYear, monthFromString(monthString), day, 00, 00, 00, 00) - #echo dt - let nextSendDateString = format(dt, "yyyy-MM-dd") - #echo nextSendDateString - #let nextSendDateString = $nextYear & "-" & formattedMonthString & "-" & $day - let nextSendDate = parse(nextSendDateString, "yyyy-MM-dd") - #echo nextSendDateString - return nextSendDate]# - -proc nextYearlyDate*(monthString: string, targetDay: int): DateTime = - ## Calculates a date for the next occurrence of a specific month and day - ## - ## Parameters: - ## - baseDate: The starting date to calculate from - ## - targetMonth: The month (Month enum) for the target date - ## - targetDay: The day of month for the target date - ## - ## Returns the next occurrence of the specified month and day, which could be: - ## - Later this year if the target date hasn't occurred yet - ## - Next year if the target date has already passed this year - +#[ Returns the next occurrence of the specified month and day, which could be: + - Later this year if the target date hasn't occurred yet + - Next year if the target date has already passed this year]# +proc nextYearlyDate*(monthString: string, targetDay: int): DateTime = let baseDate = now() - let targetMonth = monthFromString(monthString) - + let targetMonth = monthFromString(monthString) # Get the current year - let currentYear = baseDate.year - + let currentYear = baseDate.year # Create a DateTime for the target date in the current year - var nextSendDate = dateTime(currentYear, targetMonth, targetDay, 00, 00, 00, 00) - + var nextSendDate = dateTime(currentYear, targetMonth, targetDay, 00, 00, 00, 00) # If the target date has already passed this year, move to next year if nextSendDate <= baseDate: - nextSendDate = dateTime(currentYear + 1, targetMonth, targetDay, 00, 00, 00, 00) - + nextSendDate = dateTime(currentYear + 1, targetMonth, targetDay, 00, 00, 00, 00) let nextSendDateString = format(nextSendDate, "yyyy-MM-dd") - #echo nextSendDateString - #let nextSendDateString = $nextYear & "-" & formattedMonthString & "-" & $day - nextSendDate = parse(nextSendDateString, "yyyy-MM-dd") - + nextSendDate = parse(nextSendDateString, "yyyy-MM-dd") return nextSendDate diff --git a/helpers/db.nim b/helpers/db.nim index f524a9a..f306c2d 100644 --- a/helpers/db.nim +++ b/helpers/db.nim @@ -1,6 +1,6 @@ #[Copyright 2024 ITwrx. -This file is part of Simple Site Manager. -Simple Site Manager is released under the GNU Affero General Public License 3.0. +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 sqliteral diff --git a/helpers/form.nim b/helpers/form.nim index 3d8c99a..7376ee2 100644 --- a/helpers/form.nim +++ b/helpers/form.nim @@ -1,8 +1,10 @@ #[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. +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.]# +#TODO: remove anything not being used by Forget-Me-Not. + import std/[cgi, strtabs, strutils, cookies, uri, tables] import jsony, guildenstern/httpserver, sqliteral import "auth", "global" diff --git a/helpers/global.nim b/helpers/global.nim index 505b9db..1a8113d 100644 --- a/helpers/global.nim +++ b/helpers/global.nim @@ -1,10 +1,15 @@ -#import std/[times, logging] +#[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 std/[times, strutils, re, uri, paths, random, strtabs] #universal const APP_PATH* = "/var/www/forget-me-not-gs" const ASSETS_PATH* = "/var/www/forget-me-not-gs/app/assets" const APP_NAME* = "Forget-Me-Not" +#set to 'dev' or 'prod' const APP_MODE* = "dev" #dev const APP_URL* = "http://fmn-gs" @@ -17,6 +22,8 @@ const ASSETS_URL* = "http://assets.fmn-gs" var frStrTab* = newStringTable() +#TODO: implement logging or remove logging code. + #Guildensterns logger is conflicting with my, evidently incorrect, usage of the std lib logger so i'll just write some lines to a file for now. #var logger* = newFileLogger("errors.log") @@ -29,7 +36,6 @@ proc writeLogLine*(errorMsg: string) = defer: logFile.close() logFile.writeLine(errorMsg) -#template location*(slug: string, csrfToken: string, fr: FormResult): untyped = template location*(slug: string): untyped = "location: " & APP_URL & slug diff --git a/helpers/reminder.nim b/helpers/reminder.nim index e71a22f..fccd928 100644 --- a/helpers/reminder.nim +++ b/helpers/reminder.nim @@ -1,3 +1,8 @@ +#[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 std/[times, osproc], smtp import ../models/reminder, ../models/user, datetime diff --git a/helpers/validation.nim b/helpers/validation.nim index dc03452..63d7964 100644 --- a/helpers/validation.nim +++ b/helpers/validation.nim @@ -1,6 +1,6 @@ -#[Copyright 2024 ITwrx. -This file is part of ITwrxorg-SiteUpdata. -ITwrxorg-SiteUpdata is released under the GNU Affero General Public License 3.0. +#[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 std/[strutils, re, typetraits, times, tables] diff --git a/models/human_checker.nim b/models/human_checker.nim index fab210c..11a6aed 100644 --- a/models/human_checker.nim +++ b/models/human_checker.nim @@ -1,10 +1,11 @@ -#[Copyright 2024 ITwrx. -This file is part of Simple Site Manager. -Simple Site Manager is released under the GNU Affero General Public License 3.0. +#[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.]# +#TODO: Use a human checker in login form or remove from project. + import std/random -#import sqliteral, "../helpers/db" type HumanChecker* = object @@ -35,32 +36,3 @@ proc getHCById*(id: int): HumanChecker = for hc in humanCheckers: if hc.id == id: return hc - -#for some reason we are creating the humanCheckers here and then checking them from the DB, instead of one data location or the other, like we probably should have. -#the below was probably supposed to be a test, but then it just stayed like that. -#[proc getHumanChecker*(): HumanChecker = - {.gcsafe.}: - randomize() - var humanCheckers{.threadvar.}: seq[HumanChecker] - humanCheckers.add(HumanChecker(id: 1, question: "26 + four, minus 10", answer: 20)) - humanCheckers.add(HumanChecker(id: 2, question: "10 minus 2, + 14", answer: 22)) - humanCheckers.add(HumanChecker(id: 3, question: "15 + five, minus 3", answer: 17)) - humanCheckers.add(HumanChecker(id: 4, question: "9 + nine, minus 6", answer: 12)) - humanCheckers.add(HumanChecker(id: 5, question: "13 - three, plus 5", answer: 15)) - humanCheckers.add(HumanChecker(id: 6, question: "7 + six, plus one", answer: 14)) - humanCheckers.add(HumanChecker(id: 7, question: "22 + 8, - 2", answer: 28)) - humanCheckers.add(HumanChecker(id: 8, question: "4 - four, + ten", answer: 10)) - humanCheckers.add(HumanChecker(id: 9, question: "16 + four, minus three", answer: 17)) - humanCheckers.add(HumanChecker(id: 10, question: "twelve minus four, plus 8", answer: 16)) - return sample(humancheckers) - -proc getHCById*(id: int): HumanChecker = - {.gcsafe.}: - var hc {.threadvar.}: HumanChecker - #prepareDb2SQL() - for row in db2.rows(SelectHumanCheckerById, id): - hc.id = row.getInt(0) - hc.question = row.getString(1) - hc.answer = row.getInt(2) - return hc]# - diff --git a/models/reminder.nim b/models/reminder.nim index d786514..dbdfd11 100644 --- a/models/reminder.nim +++ b/models/reminder.nim @@ -1,9 +1,8 @@ -#[Copyright 2024 ITwrx. -This file is part of Simple Site Manager. -Simple Site Manager is released under the GNU Affero General Public License 3.0. +#[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 sqliteral, "../helpers/db", "../helpers/global.nim", sequtils, algorithm, times import sqliteral, "../helpers/db", algorithm, times type @@ -13,9 +12,6 @@ type var allReminders: seq[Reminder] -#proc myCmp(x, y: Reminder): int = -# cmp(x.sendDate, y.sendDate) - proc getReminderSendDatetime*(reminder: Reminder): DateTime = let sendDateDTString = $reminder.sendDate & " " & $reminder.sendTimeHr & ":" & $reminder.sendTimeMin & ":" & $reminder.sendTimeAmPm #single digits for minutes, as db send_time_min is integer and won't use "00", which results in runtime parse error. diff --git a/models/session.nim b/models/session.nim index 4f8c06f..08054fc 100644 --- a/models/session.nim +++ b/models/session.nim @@ -1,6 +1,6 @@ -#[Copyright 2024 ITwrx. -This file is part of Simple Site Manager. -Simple Site Manager is released under the GNU Affero General Public License 3.0. +#[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 sqliteral, "../helpers/db" diff --git a/models/user.nim b/models/user.nim index 5edd177..e41ef27 100644 --- a/models/user.nim +++ b/models/user.nim @@ -1,6 +1,6 @@ #[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. +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 sqliteral, "../helpers/db" diff --git a/post_handlers/login_post_handler.nim b/post_handlers/login_post_handler.nim index 8500174..6bfb53f 100644 --- a/post_handlers/login_post_handler.nim +++ b/post_handlers/login_post_handler.nim @@ -1,6 +1,6 @@ #[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. +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/httpserver @@ -23,7 +23,6 @@ proc loginPostHandler*() = #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: @@ -46,14 +45,6 @@ proc loginPostHandler*() = 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;" @@ -74,8 +65,6 @@ proc loginPostHandler*() = 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: @@ -91,7 +80,6 @@ proc loginPostHandler*() = 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: @@ -100,7 +88,6 @@ proc loginPostHandler*() = except Exception as e: echo e.msg - #reply(Http500) discard assignGeneralErrorFR(e.msg) setFR() reply(Http303, [location("/500")]) diff --git a/post_handlers/reminder_post_handler.nim b/post_handlers/reminder_post_handler.nim index 96b6b37..4e3db4e 100644 --- a/post_handlers/reminder_post_handler.nim +++ b/post_handlers/reminder_post_handler.nim @@ -1,6 +1,6 @@ -#[Copyright 2024 ITwrx. -This file is part of Simple Site Manager. -Simple Site Manager is released under the GNU Affero General Public License 3.0. +#[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/httpserver @@ -12,7 +12,6 @@ proc reminderCreatePostHandler*() = try: #attempt validation first. vInput("title", @["required", "string", "max:150"]) - #vInput("subject", @["string", "max:175"]) vInput("message", @["required", "string", "max:255"]) vInput("notify_via", @["required", "string", "max:5"]) vInput("repeats", @["integer", "max:1"]) @@ -33,7 +32,6 @@ proc reminderCreatePostHandler*() = #create formResult and redirect on validation errors. if formErrors.len > 0: addFormOldInput("title", formInput("title")) - #addFormOldInput("subject", formInput("subject")) addFormOldInput("message", formInput("message")) addFormOldInput("notify_via", formInput("notify_via")) addFormOldInput("repeats", formInput("repeats")) @@ -58,7 +56,6 @@ proc reminderCreatePostHandler*() = else: var reminder: Reminder reminder.title = formInput("title") - #reminder.subject = formInput("subject") reminder.message = formInput("message") reminder.notifyVia = formInput("notify_via") reminder.repeats = formInputInt("repeats") @@ -83,7 +80,6 @@ proc reminderCreatePostHandler*() = reply(Http303, [location("/")]) except CatchableError as e: echo e.msg - #reply(Http500) discard assignGeneralErrorFR(e.msg) setFR() reply(Http303, [location("/500")]) @@ -93,7 +89,6 @@ proc reminderUpdatePostHandler*() = #var origin = http.headers.getOrDefault("origin") #attempt validation first. vInput("title", @["required", "string", "max:150"]) - #vInput("subject", @["string", "max:175"]) vInput("message", @["required", "string", "max:255"]) vInput("notify_via", @["required", "string", "max:5"]) vInput("repeats", @["integer", "max:1"]) @@ -115,7 +110,6 @@ proc reminderUpdatePostHandler*() = if formErrors.len > 0: #since validation failed we better keep add the old inputs. addFormOldInput("title", formInput("title")) - #addFormOldInput("subject", formInput("subject")) addFormOldInput("message", formInput("message")) addFormOldInput("notify_via", formInput("notify_via")) addFormOldInput("repeats", formInput("repeats")) @@ -141,7 +135,6 @@ proc reminderUpdatePostHandler*() = var reminder: Reminder reminder.id = formInputInt("reminder_id") reminder.title = formInput("title") - #reminder.subject = formInput("subject") reminder.message = formInput("message") reminder.notifyVia = formInput("notify_via") reminder.repeats = formInputInt("repeats") @@ -166,7 +159,6 @@ proc reminderUpdatePostHandler*() = reply(Http303, [location("/")]) except CatchableError as e: echo e.msg - #reply(Http500) discard assignGeneralErrorFR(e.msg) setFR() reply(Http303, [location("/500")]) @@ -190,7 +182,6 @@ proc reminderDeletePostHandler*() = reply(Http303, [location("/")]) except CatchableError as e: echo e.msg - #reply(Http500) discard assignGeneralErrorFR(e.msg) setFR() reply(Http303, [location("/500")]) diff --git a/post_handlers/send_reminders_post_handler.nim b/post_handlers/send_reminders_post_handler.nim index 0ddf441..1970e62 100644 --- a/post_handlers/send_reminders_post_handler.nim +++ b/post_handlers/send_reminders_post_handler.nim @@ -1,6 +1,6 @@ #[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. +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/httpserver, "../helpers/reminder", "../helpers/form" diff --git a/post_handlers/user_session_post_handler.nim b/post_handlers/user_session_post_handler.nim index 2448e90..718aa78 100644 --- a/post_handlers/user_session_post_handler.nim +++ b/post_handlers/user_session_post_handler.nim @@ -1,6 +1,6 @@ #[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. +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/httpserver, "../models/user_session", "../helpers/form"