(import-macros {:compile-html HTML} :macros) (local forms (require :forms)) (local lib (require :lib)) (local templates (require :templates)) (local auth-form [ {:title "" :fields [ (forms.text-input "name" "Пользователь" true) (forms.password-input "password" "Пароль" true)]}]) (fn content [data errors] (set data.password nil) [(HTML [:div {:class "side"} (templates.header "/auth")]) (HTML [:section {:class "content"} [:div {:class "mb-1"} [: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 [name request.form.name entered-password request.form.password correct-creds? (check-user db name entered-password) errors (if (not correct-creds?) {:password "Пользователя с таким именем и паролем не существует."} nil)] (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 200 {} (templates.base (content request.form errors))))) (values 200 {} (templates.base (content {} {})))))) {: render}