mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 10:38:13 -05:00
♻️ Minor refactor of auth data-flow.
This fixes many issues related to using penpot on-premise instances on different domain than localhost. This changes ensures correct data flow of authenticated and not authenticated sessions.
This commit is contained in:
parent
ece914303a
commit
2596ad27c3
10 changed files with 95 additions and 56 deletions
|
@ -58,7 +58,9 @@
|
|||
(assoc response :cookies {cookie-name {:path "/"
|
||||
:http-only true
|
||||
:value id
|
||||
:same-site (if cors? :none :strict)
|
||||
:same-site (cond (not secure?) :lax
|
||||
cors? :none
|
||||
:else :strict)
|
||||
:secure secure?}})))
|
||||
|
||||
(defn- clear-cookies
|
||||
|
|
|
@ -335,9 +335,9 @@
|
|||
;; --- MUTATION: Logout
|
||||
|
||||
(s/def ::logout
|
||||
(s/keys :req-un [::profile-id]))
|
||||
(s/keys :opt-un [::profile-id]))
|
||||
|
||||
(sv/defmethod ::logout
|
||||
(sv/defmethod ::logout {:auth false}
|
||||
[{:keys [session] :as cfg} _]
|
||||
(with-meta {}
|
||||
{:transform-response (:delete session)}))
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
(ns app.main.data.users
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
|
@ -90,6 +91,8 @@
|
|||
|
||||
;; --- EVENT: fetch-profile
|
||||
|
||||
(declare logout)
|
||||
|
||||
(def profile-fetched?
|
||||
(ptk/type? ::profile-fetched))
|
||||
|
||||
|
@ -102,18 +105,18 @@
|
|||
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :profile-id id)
|
||||
(assoc :profile profile)))
|
||||
(cond-> state
|
||||
(is-authenticated? profile)
|
||||
(-> (assoc :profile-id id)
|
||||
(assoc :profile profile))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [profile (:profile state)]
|
||||
(when (not= uuid/zero (:id profile))
|
||||
(swap! storage assoc :profile profile)
|
||||
(i18n/set-locale! (:lang profile))
|
||||
(some-> (:theme profile)
|
||||
(theme/set-current-theme!)))))))
|
||||
(when-let [profile (:profile state)]
|
||||
(swap! storage assoc :profile profile)
|
||||
(i18n/set-locale! (:lang profile))
|
||||
(some-> (:theme profile)
|
||||
(theme/set-current-theme!))))))
|
||||
|
||||
(defn fetch-profile
|
||||
[]
|
||||
|
@ -154,38 +157,65 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(let [team-id (:default-team-id profile)]
|
||||
(->> (rx/concat
|
||||
(rx/of (profile-fetched profile)
|
||||
(fetch-teams))
|
||||
(->> (rx/of (rt/nav' :dashboard-projects {:team-id team-id}))
|
||||
(rx/delay 1000)))
|
||||
(rx/observe-on :async))))))
|
||||
(when (is-authenticated? profile)
|
||||
(let [team-id (:default-team-id profile)]
|
||||
(->> (rx/of (profile-fetched profile)
|
||||
(fetch-teams)
|
||||
(rt/nav' :dashboard-projects {:team-id team-id}))
|
||||
(rx/observe-on :async)))))))
|
||||
|
||||
(s/def ::login-params
|
||||
(s/keys :req-un [::email ::password]))
|
||||
|
||||
(declare login-from-register)
|
||||
|
||||
(defn login
|
||||
[{:keys [email password] :as data}]
|
||||
(us/verify ::login-params data)
|
||||
(ptk/reify ::login
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(watch [_ _ stream]
|
||||
(let [{:keys [on-error on-success]
|
||||
:or {on-error rx/throw
|
||||
on-success identity}} (meta data)
|
||||
params {:email email
|
||||
:password password
|
||||
:scope "webapp"}]
|
||||
(->> (rx/timer 100)
|
||||
(rx/mapcat #(rp/mutation :login params))
|
||||
(rx/tap on-success)
|
||||
(rx/catch on-error)
|
||||
(rx/map (fn [profile]
|
||||
(with-meta profile
|
||||
{::ev/source "login"})))
|
||||
(rx/map logged-in)
|
||||
(rx/observe-on :async))))
|
||||
|
||||
;; NOTE: We can't take the profile value from login because
|
||||
;; there are cases when login is successfull but the cookie is
|
||||
;; not set properly (because of possible misconfiguration).
|
||||
;; So, we proceed to make an additional call to fetch the
|
||||
;; profile, and ensure that cookie is set correctly. If
|
||||
;; profile fetch is successful, we mark the user logged in, if
|
||||
;; the returned profile is an NOT authenticated profile, we
|
||||
;; proceed to logout and show an error message.
|
||||
|
||||
(rx/merge
|
||||
(->> (rp/mutation :login params)
|
||||
(rx/map fetch-profile)
|
||||
(rx/catch on-error))
|
||||
|
||||
(->> stream
|
||||
(rx/filter profile-fetched?)
|
||||
(rx/take 1)
|
||||
(rx/map deref)
|
||||
(rx/filter (complement is-authenticated?))
|
||||
(rx/tap on-error)
|
||||
(rx/map #(ex/raise :type :authentication))
|
||||
(rx/observe-on :async))
|
||||
|
||||
(->> stream
|
||||
(rx/filter profile-fetched?)
|
||||
(rx/take 1)
|
||||
(rx/map deref)
|
||||
(rx/filter is-authenticated?)
|
||||
(rx/map (fn [profile]
|
||||
(with-meta profile
|
||||
{::ev/source "login"})))
|
||||
(rx/tap on-success)
|
||||
(rx/map logged-in)
|
||||
(rx/observe-on :async)))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.main.data.users :as du]
|
||||
[app.main.sentry :as sentry]
|
||||
[app.main.store :as st]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.router :as rt]
|
||||
[app.util.timers :as ts]
|
||||
[cljs.pprint :refer [pprint]]
|
||||
|
@ -48,7 +49,9 @@
|
|||
;; here and not in app.main.errors because of circular dependency.
|
||||
(defmethod ptk/handle-error :authentication
|
||||
[_]
|
||||
(ts/schedule (st/emitf (du/logout))))
|
||||
(let [msg (tr "errors.auth.unable-to-login")]
|
||||
(st/emit! (du/logout))
|
||||
(ts/schedule 500 (st/emitf (dm/warn msg)))))
|
||||
|
||||
|
||||
;; That are special case server-errors that should be treated
|
||||
|
|
|
@ -73,29 +73,30 @@
|
|||
:dashboard-font-providers
|
||||
:dashboard-team-members
|
||||
:dashboard-team-settings)
|
||||
(when profile
|
||||
(let [props (:props profile)]
|
||||
[:*
|
||||
#_[:div.modal-wrapper
|
||||
#_[:& app.main.ui.onboarding/onboarding-templates-modal]
|
||||
[:& app.main.ui.onboarding/onboarding-modal]
|
||||
#_[:& app.main.ui.onboarding/onboarding-team-modal]
|
||||
]
|
||||
(cond
|
||||
(and cf/onboarding-form-id
|
||||
(not (:onboarding-questions-answered props false)))
|
||||
[:& app.main.ui.onboarding.questions/questions
|
||||
{:profile profile
|
||||
:form-id cf/onboarding-form-id}]
|
||||
|
||||
(not (:onboarding-viewed props))
|
||||
[:& app.main.ui.onboarding/onboarding-modal {}]
|
||||
[:*
|
||||
#_[:div.modal-wrapper
|
||||
#_[:& app.main.ui.onboarding/onboarding-templates-modal]
|
||||
#_[:& app.main.ui.onboarding/onboarding-modal]
|
||||
#_[:& app.main.ui.onboarding/onboarding-team-modal]
|
||||
]
|
||||
(when-let [props (some-> profile (get :props {}))]
|
||||
(cond
|
||||
(and cf/onboarding-form-id
|
||||
(not (:onboarding-questions-answered props false)))
|
||||
[:& app.main.ui.onboarding.questions/questions
|
||||
{:profile profile
|
||||
:form-id cf/onboarding-form-id}]
|
||||
|
||||
(and (:onboarding-viewed props)
|
||||
(not= (:release-notes-viewed props) (:main @cf/version))
|
||||
(not= "0.0" (:main @cf/version)))
|
||||
[:& app.main.ui.releases/release-notes-modal {}])
|
||||
[:& dashboard {:route route}]]))
|
||||
(not (:onboarding-viewed props))
|
||||
[:& app.main.ui.onboarding/onboarding-modal {}]
|
||||
|
||||
(and (:onboarding-viewed props)
|
||||
(not= (:release-notes-viewed props) (:main @cf/version))
|
||||
(not= "0.0" (:main @cf/version)))
|
||||
[:& app.main.ui.releases/release-notes-modal {}]))
|
||||
|
||||
[:& dashboard {:route route :profile profile}]]
|
||||
|
||||
:viewer
|
||||
(let [{:keys [query-params path-params]} route
|
||||
|
|
|
@ -74,9 +74,8 @@
|
|||
nil)])
|
||||
|
||||
(mf/defc dashboard
|
||||
[{:keys [route] :as props}]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
section (get-in route [:data :name])
|
||||
[{:keys [route profile] :as props}]
|
||||
(let [section (get-in route [:data :name])
|
||||
params (parse-params route)
|
||||
|
||||
project-id (:project-id params)
|
||||
|
|
|
@ -514,7 +514,7 @@
|
|||
[:li {:on-click (partial on-click :settings-password)}
|
||||
[:span.icon i/lock]
|
||||
[:span.text (tr "labels.password")]]
|
||||
[:li {:on-click (partial on-click (du/logout))}
|
||||
[:li {:on-click #(on-click (du/logout) %)}
|
||||
[:span.icon i/exit]
|
||||
[:span.text (tr "labels.logout")]]
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
(defn load-arengu-sdk
|
||||
[container-ref email form-id]
|
||||
(letfn [(on-init []
|
||||
(let [container (mf/ref-val container-ref)]
|
||||
(when-let [container (mf/ref-val container-ref)]
|
||||
(-> (.embed js/ArenguForms form-id container)
|
||||
(p/then (fn [form] (.setHiddenField ^js form "email" email))))))
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
:credentials credentials
|
||||
:referrerPolicy "no-referrer"
|
||||
:signal signal}]
|
||||
|
||||
(-> (js/fetch (str uri) params)
|
||||
(p/then (fn [response]
|
||||
(vreset! abortable? false)
|
||||
|
|
|
@ -3255,3 +3255,6 @@ msgstr "Owner can't leave team, you must reassign the owner role."
|
|||
|
||||
msgid "errors.team-leave.insufficient-members"
|
||||
msgstr "Insufficient members to leave team, you probably want to delete it."
|
||||
|
||||
msgid "errors.auth.unable-to-login"
|
||||
msgstr "Unable to login, looks like you are not authenticated."
|
||||
|
|
Loading…
Add table
Reference in a new issue