0
Fork 0
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:
Andrey Antukh 2021-11-26 09:08:23 +01:00 committed by Alonso Torres
parent ece914303a
commit 2596ad27c3
10 changed files with 95 additions and 56 deletions

View file

@ -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

View file

@ -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)}))

View file

@ -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 [_ _ _]

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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")]]

View file

@ -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))))))

View file

@ -88,6 +88,7 @@
:credentials credentials
:referrerPolicy "no-referrer"
:signal signal}]
(-> (js/fetch (str uri) params)
(p/then (fn [response]
(vreset! abortable? false)

View file

@ -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."