22 (:require
33 [rum.core :as rum]
44 [clojure.set :as set]
5- [grumpy.core :as grumpy ]
5+ [clojure.string :as str ]
66 [clojure.java.io :as io]
7- [compojure.core :as compojure]
87 [clojure.java.shell :as shell]
8+ [io.pedestal.http.route :as route]
99 [ring.middleware.session :as session]
10- [ring.middleware.session.cookie :as session.cookie])
10+ [io.pedestal.interceptor :as interceptor]
11+ [io.pedestal.http.body-params :as body-params]
12+ [ring.middleware.session.cookie :as session.cookie]
13+ [io.pedestal.http.ring-middlewares :as middlewares]
14+ [grumpy.core :as grumpy]
15+ [grumpy.routes :as routes])
1116 (:import
1217 [java.security SecureRandom]))
1318
6772 (:value token)))))
6873
6974
70- (defn- expire-session [handler]
71- (fn [req]
72- (let [created (:created (:session req))]
73- (if (and (some? created)
74- (> (grumpy/age created) session-ttl-ms))
75- (handler (dissoc req :session ))
76- (handler req)))))
77-
78-
79- (defn force-user [handler]
80- (fn [req]
81- (if-some [u grumpy/forced-user]
82- (some-> req
83- (assoc-in [:session :user ] u)
84- (handler )
85- (assoc :cookies { " grumpy_user" { :value u }}
86- :session { :user u
87- :created (grumpy/now ) }))
88- (handler req))))
75+ (def expire-session
76+ {:name ::expire-session
77+ :enter
78+ (fn [ctx]
79+ (let [created (-> ctx :request :session :created )]
80+ (if (and (some? created)
81+ (> (grumpy/age created) session-ttl-ms))
82+ (update ctx :request dissoc :session )
83+ ctx)))})
84+
85+
86+ (def force-user
87+ {:name ::force-user
88+ :enter
89+ (fn [ctx]
90+ (if-some [u grumpy/forced-user]
91+ (assoc-in ctx [:request :session :user ] u)
92+ ctx))
93+ :leave
94+ (fn [ctx]
95+ (if-some [u grumpy/forced-user]
96+ (update ctx :response assoc :cookies {" grumpy_user" {:value u}}
97+ :session {:user u
98+ :created (grumpy/now )})
99+ ctx))})
89100
90101
91- (defn wrap- session [handler]
92- (-> handler
93- ( expire- session )
94- ( force-user )
95- ( session/wrap-session
96- { :store ( session.cookie/cookie-store { :key cookie-secret } )
97- :cookie-name " grumpy_session "
98- :cookie-attrs { :http-only true
99- :secure ( not grumpy/dev?) }})) )
102+ (def session
103+ (middlewares/session
104+ { :store ( session.cookie/cookie-store { :key cookie-secret} )
105+ :cookie-name " grumpy_session "
106+ :cookie-attrs { :http-only true
107+ :secure ( not grumpy/dev?)}}) )
108+
109+
110+ ( def populate-session [session force-user expire-session] )
100111
101112
102113(defn user [req]
103114 (get-in req [:session :user ]))
104115
105116
106- (defn check-session [req]
107- (when (nil? (user req))
108- (grumpy/redirect " /forbidden" { :redirect-url (:uri req) })))
117+ (def require-user
118+ {:name ::require-user
119+ :enter (fn [{req :request :as ctx}]
120+ (if (nil? (user req))
121+ (assoc ctx :response (grumpy/redirect " /forbidden" {:redirect-url (:uri req)}))
122+ ctx))})
109123
110124
111125(rum/defc email-sent-page [message]
116130
117131
118132(rum/defc forbidden-page [redirect-url email]
119- (grumpy/page { :title " Log in"
120- :styles [" authors.css" ] }
133+ (grumpy/page {:title " Log in"
134+ :styles [" authors.css" ]}
121135 [:form.forbidden
122- { :action " /send-email"
123- :method " post" }
124- [:.form_row
125- [:input { :type " text"
126- :name " email"
127- :placeholder " E-mail"
128- :autofocus true
129- :value email }]
130- [:input { :type " hidden" :name " redirect-url" :value redirect-url }]]
131- [:.form_row
132- [:button " Send email" ]]]))
133-
134-
135- (compojure/defroutes routes
136- (compojure/GET " /forbidden" [:as req]
137- (let [redirect-url (get (:params req) " redirect-url" )
138- user (get-in (:cookies req) [" grumpy_user" :value ])
139- email (:email (grumpy/author-by :user user))]
140- (grumpy/html-response (forbidden-page redirect-url email))))
141-
142- (compojure/GET " /authenticate" [:as req] ; ; ?email=...&token=...&redirect-url=...
143- (let [email (get (:params req) " email" )
144- user (:user (grumpy/author-by :email email))
145- token (get (:params req) " token" )
146- redirect-url (get (:params req) " redirect-url" )]
147- (if (= token (get-token email))
148- (do
149- (swap! *tokens dissoc email)
150- (assoc
151- (grumpy/redirect redirect-url)
152- :cookies { " grumpy_user" { :value user }}
153- :session { :user user
154- :created (grumpy/now ) }))
155- { :status 403
156- :body " 403 Bad token" })))
157-
158- (compojure/GET " /logout" [:as req]
159- (assoc
160- (grumpy/redirect " /" )
161- :session nil ))
162-
163- (compojure/POST " /send-email" [:as req]
164- (let [params (:params req)
165- email (get params " email" )
166- user (:user (grumpy/author-by :email email))]
167- (cond
168- (nil? (grumpy/author-by :email email))
169- (grumpy/redirect " /email-sent" { :message (str " You aren't the author, " email) })
170- (some? (get-token email))
171- (grumpy/redirect " /email-sent" { :message (str " Emailed link is still valid, " user) })
172- :else
173- (let [token (gen-token )
174- redirect-url (get params " redirect-url" )
175- link (grumpy/url (str grumpy/hostname " /authenticate" )
176- { :email email
177- :token token
178- :redirect-url redirect-url })]
179- (swap! *tokens assoc email { :value token :created (grumpy/now ) })
180- (send-email!
181- { :to email
182- :subject (str " Log into Grumpy " (grumpy/format-date (grumpy/now )))
183- :body (str " <html><div style='text-align: center;'><a href=\" " link " \" style='display: inline-block; font-size: 16px; padding: 0.5em 1.75em; background: #c3c; color: white; text-decoration: none; border-radius: 4px;'>Login now!</a></div></html>" ) })
184- (grumpy/redirect " /email-sent" { :message (str " Check your email, " user) })))))
185-
186- (compojure/GET " /email-sent" [:as req]
187- (grumpy/html-response (email-sent-page (get-in req [:params " message" ])))))
136+ {:action " /send-email"
137+ :method " post" }
138+ [:.form_row
139+ [:input {:type " text"
140+ :name " email"
141+ :placeholder " E-mail"
142+ :autofocus true
143+ :value email}]
144+ [:input {:type " hidden" :name " redirect-url" :value redirect-url}]]
145+ [:.form_row
146+ [:button " Send email" ]]]))
147+
148+
149+ (defn handle-forbidden [{:keys [query-params cookies]}]
150+ (let [user (get-in cookies [" grumpy_user" :value ])
151+ email (:email (grumpy/author-by :user user))]
152+ (grumpy/html-response (forbidden-page (:redirect-url query-params) email))))
153+
154+
155+ (defn handle-send-email [{:keys [form-params] :as req}]
156+ (let [email (:email form-params)
157+ user (:user (grumpy/author-by :email email))]
158+ (cond
159+ (nil? (grumpy/author-by :email email))
160+ (grumpy/redirect " /email-sent" {:message (str " You aren't the author, " email)})
161+
162+ (some? (get-token email))
163+ (grumpy/redirect " /email-sent" {:message (str " Emailed link is still valid, " user)})
164+
165+ :else
166+ (let [token (gen-token )
167+ redirect-url (:redirect-url form-params)
168+ link (grumpy/url (str grumpy/hostname " /authenticate" )
169+ {:email email
170+ :token token
171+ :redirect-url redirect-url})]
172+ (swap! *tokens assoc email { :value token :created (grumpy/now ) })
173+ (send-email!
174+ {:to email
175+ :subject (str " Log into Grumpy " (grumpy/format-date (grumpy/now )))
176+ :body (str " <html><div style='text-align: center;'><a href=\" " link " \" style='display: inline-block; font-size: 16px; padding: 0.5em 1.75em; background: #c3c; color: white; text-decoration: none; border-radius: 4px;'>Login now!</a></div></html>" )})
177+ (grumpy/redirect " /email-sent" {:message (str " Check your email, " user)})))))
178+
179+
180+ (defn handle-email-sent [{:keys [query-params]}]
181+ (grumpy/html-response (email-sent-page (:message query-params))))
182+
183+
184+ (defn handle-authenticate [{:keys [query-params]}] ; ; ?email=...&token=...&redirect-url=...
185+ (let [email (:email query-params)
186+ user (:user (grumpy/author-by :email email))
187+ redirect-url (if (str/blank? (:redirect-url query-params))
188+ " /"
189+ (:redirect-url query-params))]
190+ (if (= (:token query-params) (get-token email))
191+ (do
192+ (swap! *tokens dissoc email)
193+ (assoc (grumpy/redirect redirect-url)
194+ :cookies {" grumpy_user" {:value user}}
195+ :session {:user user
196+ :created (grumpy/now )}))
197+ {:status 403
198+ :body " 403 Bad token" })))
199+
200+
201+ (def routes
202+ (routes/expand
203+ [:get " /forbidden" populate-session route/query-params `handle-forbidden]
204+ [:post " /send-email" populate-session (body-params/body-params ) `handle-send-email]
205+ [:get " /email-sent" populate-session route/query-params `handle-email-sent]
206+ [:get " /authenticate" populate-session route/query-params `handle-authenticate]
207+ [:get " /logout" populate-session (fn [_] (assoc (grumpy/redirect " /" ) :session nil ))]))
0 commit comments