/
auth.cljs
162 lines (126 loc) · 4.88 KB
/
auth.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
;;; Author: David Goldfarb (deg@degel.com)
;;; Copyright (c) 2017, David Goldfarb
(ns com.degel.re-frame-firebase.auth
(:require-macros [reagent.ratom :refer [reaction]])
(:require
[clojure.spec.alpha :as s]
[re-frame.core :as re-frame]
[iron.re-utils :refer [>evt]]
[firebase.app :as firebase-app]
[firebase.auth :as firebase-auth]
[com.degel.re-frame-firebase.core :as core]))
(defn- user
"Extract interesting details from the Firebase JS user object."
[firebase-user]
(when firebase-user
{:uid (.-uid firebase-user)
:provider-data (.-providerData firebase-user)
:display-name (.-displayName firebase-user)
:photo-url (.-photoURL firebase-user)
:email (let [provider-data (.-providerData firebase-user)]
(when-not (empty? provider-data)
(-> provider-data first .-email)))}))
(defn- set-user
[firebase-user]
(-> firebase-user
(user)
(core/set-current-user)))
(defn- init-auth []
(.onAuthStateChanged
(js/firebase.auth)
set-user
(core/default-error-handler))
(-> (js/firebase.auth)
(.getRedirectResult)
(.then (fn on-user-credential [user-credential]
(-> user-credential
(.-user)
set-user)))
(.catch (core/default-error-handler))))
(def ^:private sign-in-fns
{:popup (memfn signInWithPopup auth-provider)
:redirect (memfn signInWithRedirect auth-provider)})
(defn- maybe-link-with-credential
[pending-credential user-credential]
(when (and pending-credential user-credential)
(when-let [firebase-user (.-user user-credential)]
(-> firebase-user
(.linkWithCredential pending-credential)
(.catch (core/default-error-handler))))))
(defn- oauth-sign-in
[auth-provider opts]
(let [{:keys [sign-in-method scopes custom-parameters link-with-credential]
:or {sign-in-method :redirect}} opts]
(doseq [scope scopes]
(.addScope auth-provider scope))
(when custom-parameters
(.setCustomParameters auth-provider (clj->js custom-parameters)))
(if-let [sign-in (sign-in-fns sign-in-method)]
(-> (js/firebase.auth)
(sign-in auth-provider)
(.then (partial maybe-link-with-credential link-with-credential))
(.catch (core/default-error-handler)))
(>evt [(core/default-error-handler)
(js/Error. (str "Unsupported sign-in-method: " sign-in-method ". Either :redirect or :popup are supported."))]))))
(defn google-sign-in
[opts]
;; TODO: use Credential for mobile.
(oauth-sign-in (js/firebase.auth.GoogleAuthProvider.) opts))
(defn facebook-sign-in
[opts]
(oauth-sign-in (js/firebase.auth.FacebookAuthProvider.) opts))
(defn twitter-sign-in
[opts]
(oauth-sign-in (js/firebase.auth.TwitterAuthProvider.) opts))
(defn github-sign-in
[opts]
(oauth-sign-in (js/firebase.auth.GithubAuthProvider.) opts))
(defn email-sign-in [{:keys [email password]}]
(-> (js/firebase.auth)
(.signInWithEmailAndPassword email password)
(.then set-user)
(.catch (core/default-error-handler))))
(defn email-create-user [{:keys [email password]}]
(-> (js/firebase.auth)
(.createUserWithEmailAndPassword email password)
(.then set-user)
(.catch (core/default-error-handler))))
(defn anonymous-sign-in [opts]
(-> (js/firebase.auth)
(.signInAnonymously)
(.then set-user)
(.catch (core/default-error-handler))))
(defn custom-token-sign-in [{:keys [token]}]
(-> (js/firebase.auth)
(.signInWithCustomToken token)
(.then set-user)
(.catch (core/default-error-handler))))
(defn init-recaptcha [{:keys [on-solve container-id]}]
(let [recaptcha (js/firebase.auth.RecaptchaVerifier.
container-id
(clj->js {:size "invisible"
:callback #(re-frame/dispatch on-solve)}))]
(swap! core/firebase-state assoc
:recaptcha-verifier recaptcha)))
(defn phone-number-sign-in [{:keys [phone-number on-send]}]
(if-let [verifier (:recaptcha-verifier @core/firebase-state)]
(-> (js/firebase.auth)
(.signInWithPhoneNumber phone-number verifier)
(.then (fn [confirmation]
(when on-send
(re-frame/dispatch on-send))
(swap! core/firebase-state assoc
:recaptcha-confirmation-result confirmation)))
(.catch (core/default-error-handler)))
(.warn js/console "Initialise reCaptcha first")))
(defn phone-number-confirm-code [{:keys [code]}]
(if-let [confirmation (:recaptcha-confirmation-result @core/firebase-state)]
(-> confirmation
(.confirm code)
(.then set-user)
(.catch (core/default-error-handler)))
(.warn js/console "reCaptcha confirmation missing")))
(defn sign-out []
(-> (js/firebase.auth)
(.signOut)
(.catch (core/default-error-handler))))