summaryrefslogtreecommitdiff
path: root/pages/auth.fnl
blob: 29187df7b5bc37e8c44a0faac948a761724c099c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
(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}