(import-macros {:compile-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) [(<> [:div {:class "side"} (templates.header "/auth")]) (<> [:section {:class "content"} [:div {:class "mb-1"} [:a {:href "/"} "⟵ Обратно на главную"]] [:h2 {} "Войти"] (forms.render-form auth-form data errors)])]) (fn create-session [db user] (local id (_G.must (luna.crypto.random-string 64))) (local next-week (os.date "%Y-%m-%d %H:%M:%S" (+ (os.time) (* 60 60 24 7)))) (_G.must (luna.db.exec db "INSERT INTO auth_sessions (id, user, creation_time, expires_at) VALUES (?, ?, ?, ?)" [id user (lib.now) next-week])) 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? (do (local session-id (create-session db name)) (values 302 {:Location "/shop" :Set-Cookie (.. "auth= " session-id "; HttpOnly; SameSite=strict" (if luna.debug? "" "; Secure"))} "")) (values 200 {} (templates.base (content request.form errors))))) (values 200 {} (templates.base (content {} {})))))) {: render}