(import-macros {:compile-html HTML} :macros)
(local forms (require :forms))
(local lib (require :lib))
(local templates (require :templates))
(local %page-title "Вход")
(local %auth-form
[{:title ""
:fields [
(forms.text-input "name" "Пользователь" true)
(forms.password-input "password" "Пароль" true)]}])
(fn content [data errors]
(set data.password nil)
[(HTML
[:aside {}
(templates.header "/auth")])
(HTML
[:section {:class "content"}
[:div {:class "back"} [:a {:href "/"} "⟵ Обратно на главную"]]
[:h2 {} "Войти"]
(forms.render-form %auth-form data errors)])])
(fn create-session [db user expires-at]
(local id (_G.must (luna.crypto.random-string 64)))
(_G.must
(luna.db.exec
db "INSERT INTO auth_sessions (id, user, creation_time, expires_at)
VALUES (?, ?, ?, ?)"
[id user (lib.now) expires-at]))
id)
(fn check-user [db name entered-pass]
(local users
(_G.must
(luna.db.query db
"SELECT users.password
FROM USERS
WHERE LOWER(users.name) = ?
LIMIT 1" [name])))
(if (< 0 (# users))
(let [password (. users 1 1)]
(_G.must (luna.crypto.check-password entered-pass password)))
false))
(fn render [request db authenticated?]
(if authenticated?
(values 302 {:Location "/"} "")
(if request.form
(let [errors (forms.validate %auth-form request.form)
has-errors? (not (lib.empty-table? errors))
{: name : password } request.form
correct-creds? (check-user db name password)]
(if has-errors?
(values 400 {} (templates.base (content request.form errors) %page-title))
(if correct-creds?
(let [next-week (+ (os.time) (* 60 60 24 7))
session-id (create-session
db name (os.date "%Y-%m-%d %H:%M:%S" next-week))
cookie-expires (os.date "%a, %d %b %Y %H:%M:%S GMT" next-week)]
(values 302 {:Location "/shop"
:Set-Cookie (.. "auth=" session-id "; HttpOnly; SameSite=strict;"
"Expires=" cookie-expires
(if luna.debug? "" "; Secure"))} ""))
(values 400 {}
(templates.base
(content request.form
{:password "Пользователя с таким именем и паролем не существует."})
%page-title)))))
(values 200 {} (templates.base (content {} {}) %page-title)))))
{: render}