-
Notifications
You must be signed in to change notification settings - Fork 0
/
core.cljs
366 lines (297 loc) · 10.8 KB
/
core.cljs
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
(ns re-auth0.core
(:require [cljsjs.auth0]
[re-frame.core :as re-frame]))
(defonce web-auth-instance (atom nil))
(defonce app-state (atom {}))
(defn local-storage-key []
(str "auth0."
(-> @app-state :info :client-id)))
(defn *js->clj
"Always keywordize keys"
[js]
(js->clj js :keywordize-keys true))
(defn remove-nils-and-empty
"Take a map, and remove all nil or empty values"
[m]
(->> m
(filter (fn [[k v]]
(not (or (nil? v) (empty? v)))))
(into {})))
(defn *clj->js
"Nil-prune too"
[clj]
(clj->js (remove-nils-and-empty clj)))
(defn web-auth
"Builds the WebAuth object."
[{:keys [domain client-id redirect-uri scope
audience response-type response-mode]}]
(js/auth0.WebAuth. (*clj->js
{:domain domain
:clientID client-id
:redirectUri redirect-uri
:scope scope
:audience audience
:responseType response-type
:responseMode response-mode})))
(defn auth-results-cb
[on-auth-result on-error]
(fn [err auth-result]
(if err
(if on-error
(re-frame/dispatch (conj on-error (*js->clj err)))
(when-let [defautl-on-error (:on-error @app-state)]
(re-frame/dispatch (conj defautl-on-error (*js->clj err)))))
(do
(.setItem (.-localStorage js/window)
(local-storage-key)
(.stringify js/JSON auth-result))
(if on-auth-result
(re-frame/dispatch (conj on-auth-result
(*js->clj auth-result)))
(when-let [default-on-auth-result (:on-authenticated @app-state)]
(re-frame/dispatch (conj default-on-auth-result
(*js->clj auth-result)))))))))
(defn parse-hash
[web-auth {:keys [hash state nonce]}
on-authenticated on-error]
(.parseHash web-auth (*clj->js
{:hash hash
:state state
:nonce nonce})
(auth-results-cb on-authenticated
on-error))
(set! (.-hash js/window.location) ""))
(defn authorize
"The basic authorize"
[web-auth {:keys [audience connection scope response-type
client-id redirect-uri leeway state]}
on-authenticated on-error]
(.authorize web-auth (*clj->js
{:audience audience
:connection connection
:scope scope
:responseType response-type
:clientID client-id
:redirectUri redirect-uri
:leeway leeway
:state state})
(auth-results-cb on-authenticated
on-error)))
(defn popup-preload
"Preloads the popup window, to get around blockers"
[]
(swap! app-state
assoc :popup-handler
(.preload (.-popup @web-auth-instance))))
(defn popup-authorize
"Popup variant"
[web-auth {:keys [audience connection scope response-type
client-id redirect-uri leeway state]}
on-authenticated on-error]
(.authorize (.-popup web-auth)
(let [opts (*clj->js {:audience audience
:connection connection
:scope scope
:responseType response-type
:clientID client-id
:redirectUri redirect-uri
:leeway leeway
:state state})
popup-handler (:popup-handler @app-state)]
(when popup-handler
(aset opts "popupHandler" popup-handler))
opts)
(auth-results-cb on-authenticated
on-error)))
(defn logout
"Logout"
[web-auth {:keys [return-to client-id]}]
(.logout web-auth
(*clj->js {:returnTo return-to
:clientID client-id})))
(defn check-session
"Check session"
[web-auth {:keys [domain client-id response-type state nonce
redirect-uri scope audience timeout]}
on-authenticated on-error]
(.checkSession web-auth (*clj->js
{:domain domain
:clientID client-id
:responseType response-type
:state state
:nonce nonce
:redirectUri redirect-uri
:scope scope
:audience audience
:timeout timeout})
(auth-results-cb on-authenticated
on-error)))
(defn passwordless-start
"Start passwordless authentication"
[web-auth {:keys [connection send phone-number email]}
on-authenticated on-error]
(.passwordlessStart web-auth (*clj->js
{:connection connection
:send send
:email email
:phoneNumber phone-number})
(auth-results-cb on-authenticated
on-error)))
(defn passwordless-login
"Enter code for passwordless login"
[web-auth {:keys [connection code phone-number email]}
on-authenticated on-error]
(.passwordlessLogin web-auth (*clj->js
{:connection connection
:verificationCode code
:email email
:phoneNumber phone-number})
(auth-results-cb on-authenticated
on-error)))
(defn dispatch-error
[on-error err]
(if on-error
(re-frame/dispatch (conj on-error err))
(when-let [default-on-error (:on-error @app-state)]
(re-frame/dispatch (conj default-on-error err)))))
(defn signup
"Signs up using username password"
[web-auth {:keys [username email password connection metadata]}
on-success on-error]
(.signup web-auth (*clj->js
{:username username
:email email
:password password
:connection connection
:user_metadata metadata})
(fn [err]
(if err
(dispatch-error on-error err)
(re-frame/dispatch on-success)))))
(defn login
"Logs in user username and password"
[web-auth {:keys [username email password connection]}
on-authenticated on-error]
(.login web-auth (*clj->js
{:username username
:email email
:password password
:realm connection})
(auth-results-cb on-authenticated
on-error)))
(defn reset-password
"Requests a password reset"
[web-auth {:keys [email connection]}
on-success on-error]
(.changePassword web-auth (*clj->js
{:email email
:connection connection})
(fn [err resp]
(if err
(dispatch-error on-error err)
(re-frame/dispatch (conj on-success resp))))))
;; App boot fn
(defn maybe-auth-result
"Tries to fetch auth results from local storage"
[]
(when-let [v (.getItem (.-localStorage js/window)
(local-storage-key))]
(*js->clj (.parse js/JSON v))))
(defn init-app
"A more substantial app boot, including loading stored credentials"
[auth0-info {:keys [on-authenticated on-error]}]
(swap! app-state assoc :info auth0-info)
(when on-authenticated
(swap! app-state assoc :on-authenticated on-authenticated))
(when on-error
(swap! app-state assoc :on-error on-error))
(reset! web-auth-instance
(web-auth auth0-info))
(let [hash (-> js/window .-location .-hash)
stored (maybe-auth-result)]
(cond
;; Hash fragment in the URL
(> (count hash) 100)
(parse-hash @web-auth-instance
nil
on-authenticated
on-error)
;; Local storage
stored
(re-frame/dispatch (conj on-authenticated stored)))))
;; Registering re-frame effects
(re-frame/reg-fx
::init
(fn [options]
(reset! web-auth-instance (web-auth options))))
(re-frame/reg-fx
::authorize
(fn [{:keys [on-authenticated on-error] :as options}]
(authorize @web-auth-instance
options
on-authenticated
on-error)))
(re-frame/reg-fx
::popup-authorize
(fn [{:keys [on-authenticated on-error] :as options}]
(popup-authorize @web-auth-instance
options
on-authenticated
on-error)))
(re-frame/reg-fx
::parse-hash
(fn [{:keys [on-authenticated on-error] :as options}]
(parse-hash @web-auth-instance
options
on-authenticated
on-error)))
(re-frame/reg-fx
::logout
(fn [options]
(.removeItem (.-localStorage js/window)
(local-storage-key))
(logout @web-auth-instance
(merge {:client-id (:client-id @app-state)}
options))))
(re-frame/reg-fx
::check-session
(fn [{:keys [on-authenticated on-error] :as options}]
(check-session @web-auth-instance
options
on-authenticated
on-error)))
(re-frame/reg-fx
::passwordless-start
(fn [{:keys [on-authenticated on-error] :as options}]
(passwordless-start @web-auth-instance
options
on-authenticated
on-error)))
(re-frame/reg-fx
::passwordless-login
(fn [{:keys [on-authenticated on-error] :as options}]
(passwordless-login @web-auth-instance
options
on-authenticated
on-error)))
(re-frame/reg-fx
::signup
(fn [{:keys [on-success on-error] :as options}]
(signup @web-auth-instance
options
on-success
on-error)))
(re-frame/reg-fx
::login
(fn [{:keys [on-authenticated on-error] :as options}]
(login @web-auth-instance
options
on-authenticated
on-error)))
(re-frame/reg-fx
::reset-password
(fn [{:keys [on-success on-error] :as options}]
(reset-password @web-auth-instance
options
on-success
on-error)))