0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-31 00:51:19 -05:00

Improve auth module.

This commit is contained in:
Andrey Antukh 2021-02-11 13:36:46 +01:00
parent d5ff5ea91e
commit 5858f3f180
12 changed files with 269 additions and 254 deletions

View file

@ -12,7 +12,6 @@
[app.common.data :as d]
[app.common.spec :as us]
[app.config :as cfg]
[app.http.auth :as auth]
[app.http.errors :as errors]
[app.http.middleware :as middleware]
[app.metrics :as mtx]
@ -147,9 +146,6 @@
["/github" {:post (:auth-handler github-auth)}]
["/github/callback" {:get (:callback-handler github-auth)}]]
["/login" {:post #(auth/login-handler cfg %)}]
["/logout" {:post #(auth/logout-handler cfg %)}]
["/login-ldap" {:post ldap-auth}]
["/rpc" {:middleware [(:middleware session)]}

View file

@ -1,31 +0,0 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
(ns app.http.auth
(:require
[app.http.session :as session]))
(defn login-handler
[{:keys [session rpc] :as cfg} request]
(let [data (:params request)
uagent (get-in request [:headers "user-agent"])
method (get-in rpc [:methods :mutation :login])
profile (method data)
id (session/create! session {:profile-id (:id profile)
:user-agent uagent})]
{:status 200
:cookies (session/cookies session {:value id})
:body profile}))
(defn logout-handler
[{:keys [session] :as cfg} request]
(session/delete! cfg request)
{:status 204
:cookies (session/cookies session {:value "" :max-age -1})
:body ""})

View file

@ -12,7 +12,6 @@
[app.common.exceptions :as ex]
[app.common.spec :as us]
[app.config :as cfg]
[app.http.session :as session]
[app.util.http :as http]
[app.util.time :as dt]
[clojure.data.json :as json]
@ -38,7 +37,6 @@
(def scope "user:email")
(defn- build-redirect-url
[cfg]
(let [public (u/uri (:public-uri cfg))]
@ -46,57 +44,47 @@
(defn- get-access-token
[cfg state code]
(let [params {:client_id (:client-id cfg)
:client_secret (:client-secret cfg)
:code code
:state state
:redirect_uri (build-redirect-url cfg)}
req {:method :post
:headers {"content-type" "application/x-www-form-urlencoded"
"accept" "application/json"}
:uri (str token-url)
:body (u/map->query-string params)}
res (http/send! req)]
(try
(let [params {:client_id (:client-id cfg)
:client_secret (:client-secret cfg)
:code code
:state state
:redirect_uri (build-redirect-url cfg)}
req {:method :post
:headers {"content-type" "application/x-www-form-urlencoded"
"accept" "application/json"}
:uri (str token-url)
:timeout 6000
:body (u/map->query-string params)}
res (http/send! req)]
(when (not= 200 (:status res))
(ex/raise :type :internal
:code :invalid-response-from-github
:context {:status (:status res)
:body (:body res)}))
(try
(let [data (json/read-str (:body res))]
(get data "access_token"))
(catch Throwable e
(log/error "unexpected error on parsing response body from github access token request" e)
nil))))
(when (= 200 (:status res))
(-> (json/read-str (:body res))
(get "access_token"))))
(catch Exception e
(log/error e "unexpected error on get-access-token")
nil)))
(defn- get-user-info
[token]
(let [req {:uri (str user-info-url)
:headers {"authorization" (str "token " token)}
:method :get}
res (http/send! req)]
(when (not= 200 (:status res))
(ex/raise :type :internal
:code :invalid-response-from-github
:context {:status (:status res)
:body (:body res)}))
(try
(let [data (json/read-str (:body res))]
{:email (get data "email")
:fullname (get data "name")})
(catch Throwable e
(log/error "unexpected error on parsing response body from github access token request" e)
nil))))
(try
(let [req {:uri (str user-info-url)
:headers {"authorization" (str "token " token)}
:timeout 6000
:method :get}
res (http/send! req)]
(when (= 200 (:status res))
(let [data (json/read-str (:body res))]
{:email (get data "email")
:fullname (get data "name")})))
(catch Exception e
(log/error e "unexpected exception on get-user-info")
nil)))
(defn auth
[{:keys [tokens] :as cfg} _request]
(let [state (tokens :generate
{:iss :github-oauth
:exp (dt/in-future "15m")})
(let [state (tokens :generate {:iss :github-oauth :exp (dt/in-future "15m")})
params {:client_id (:client-id cfg/config)
:redirect_uri (build-redirect-url cfg)
:state state
@ -109,37 +97,37 @@
(defn callback
[{:keys [tokens rpc session] :as cfg} request]
(let [state (get-in request [:params :state])
_ (tokens :verify {:token state :iss :github-oauth})
info (some->> (get-in request [:params :code])
(get-access-token cfg state)
(get-user-info))]
(try
(let [state (get-in request [:params :state])
_ (tokens :verify {:token state :iss :github-oauth})
info (some->> (get-in request [:params :code])
(get-access-token cfg state)
(get-user-info))
(when-not info
(ex/raise :type :authentication
:code :unable-to-authenticate-with-github))
_ (when-not info
(ex/raise :type :internal
:code :unable-to-auth))
(let [method-fn (get-in rpc [:methods :mutation :login-or-register])
method-fn (get-in rpc [:methods :mutation :login-or-register])
profile (method-fn {:email (:email info)
:fullname (:fullname info)})
uagent (get-in request [:headers "user-agent"])
token (tokens :generate
{:iss :auth
:exp (dt/in-future "15m")
:profile-id (:id profile)})
uri (-> (u/uri (:public-uri cfg/config))
(assoc :path "/#/auth/verify-token")
(assoc :query (u/map->query-string {:token token})))
sid (session/create! session {:profile-id (:id profile)
:user-agent uagent})]
{:status 302
:headers {"location" (str uri)}
:cookies (session/cookies session/cookies {:value sid})
:body ""})))
sxf ((:create session) (:id profile))
rsp {:status 302 :headers {"location" (str uri)} :body ""}]
(sxf request rsp))
(catch Exception _e
(let [uri (-> (u/uri (:public-uri cfg))
(assoc :path "/#/auth/login")
(assoc :query (u/map->query-string {:error "unable-to-auth"})))]
{:status 302
:headers {"location" (str uri)}
:body ""}))))
;; --- ENTRY POINT

View file

@ -12,88 +12,75 @@
[app.common.data :as d]
[app.common.exceptions :as ex]
[app.common.spec :as us]
[app.http.session :as session]
[app.util.http :as http]
[app.util.time :as dt]
[clojure.data.json :as json]
[clojure.spec.alpha :as s]
[clojure.tools.logging :as log]
[integrant.core :as ig]
[lambdaisland.uri :as uri]))
[lambdaisland.uri :as u]))
(def scope "read_user")
(defn- build-redirect-url
[cfg]
(let [public (uri/uri (:public-uri cfg))]
(let [public (u/uri (:public-uri cfg))]
(str (assoc public :path "/api/oauth/gitlab/callback"))))
(defn- build-oauth-uri
[cfg]
(let [base-uri (uri/uri (:base-uri cfg))]
(let [base-uri (u/uri (:base-uri cfg))]
(assoc base-uri :path "/oauth/authorize")))
(defn- build-token-url
[cfg]
(let [base-uri (uri/uri (:base-uri cfg))]
(let [base-uri (u/uri (:base-uri cfg))]
(str (assoc base-uri :path "/oauth/token"))))
(defn- build-user-info-url
[cfg]
(let [base-uri (uri/uri (:base-uri cfg))]
(let [base-uri (u/uri (:base-uri cfg))]
(str (assoc base-uri :path "/api/v4/user"))))
(defn- get-access-token
[cfg code]
(let [params {:client_id (:client-id cfg)
:client_secret (:client-secret cfg)
:code code
:grant_type "authorization_code"
:redirect_uri (build-redirect-url cfg)}
req {:method :post
:headers {"content-type" "application/x-www-form-urlencoded"}
:uri (build-token-url cfg)
:body (uri/map->query-string params)}
(try
(let [params {:client_id (:client-id cfg)
:client_secret (:client-secret cfg)
:code code
:grant_type "authorization_code"
:redirect_uri (build-redirect-url cfg)}
req {:method :post
:headers {"content-type" "application/x-www-form-urlencoded"}
:uri (build-token-url cfg)
:body (u/map->query-string params)}
res (http/send! req)]
(when (not= 200 (:status res))
(ex/raise :type :internal
:code :invalid-response-from-gitlab
:context {:status (:status res)
:body (:body res)}))
(try
(let [data (json/read-str (:body res))]
(get data "access_token"))
(catch Throwable e
(log/error "unexpected error on parsing response body from gitlab access token request" e)
nil))))
(when (= 200 (:status res))
(-> (json/read-str (:body res))
(get "access_token"))))
(catch Exception e
(log/error e "unexpected error on get-access-token")
nil)))
(defn- get-user-info
[cfg token]
(let [req {:uri (build-user-info-url cfg)
:headers {"Authorization" (str "Bearer " token)}
:method :get}
res (http/send! req)]
(try
(let [req {:uri (build-user-info-url cfg)
:headers {"Authorization" (str "Bearer " token)}
:timeout 6000
:method :get}
res (http/send! req)]
(when (not= 200 (:status res))
(ex/raise :type :internal
:code :invalid-response-from-gitlab
:context {:status (:status res)
:body (:body res)}))
(when (= 200 (:status res))
(let [data (json/read-str (:body res))]
{:email (get data "email")
:fullname (get data "name")})))
(try
(let [data (json/read-str (:body res))]
;; (clojure.pprint/pprint data)
{:email (get data "email")
:fullname (get data "name")})
(catch Throwable e
(log/error "unexpected error on parsing response body from gitlab access token request" e)
nil))))
(catch Exception e
(log/error e "unexpected exception on get-user-info")
nil)))
(defn auth
[{:keys [tokens] :as cfg} _request]
@ -105,7 +92,7 @@
:response_type "code"
:state token
:scope scope}
query (uri/map->query-string params)
query (u/map->query-string params)
uri (-> (build-oauth-uri cfg)
(assoc :query query))]
{:status 200
@ -113,36 +100,37 @@
(defn callback
[{:keys [tokens rpc session] :as cfg} request]
(let [token (get-in request [:params :state])
_ (tokens :verify {:token token :iss :gitlab-oauth})
info (some->> (get-in request [:params :code])
(get-access-token cfg)
(get-user-info cfg))]
(try
(let [token (get-in request [:params :state])
_ (tokens :verify {:token token :iss :gitlab-oauth})
info (some->> (get-in request [:params :code])
(get-access-token cfg)
(get-user-info cfg))
_ (when-not info
(ex/raise :type :internal
:code :unable-to-auth))
(when-not info
(ex/raise :type :authentication
:code :unable-to-authenticate-with-gitlab))
(let [method-fn (get-in rpc [:methods :mutation :login-or-register])
method-fn (get-in rpc [:methods :mutation :login-or-register])
profile (method-fn {:email (:email info)
:fullname (:fullname info)})
uagent (get-in request [:headers "user-agent"])
token (tokens :generate {:iss :auth
:exp (dt/in-future "15m")
:profile-id (:id profile)})
uri (-> (uri/uri (:public-uri cfg))
uri (-> (u/uri (:public-uri cfg))
(assoc :path "/#/auth/verify-token")
(assoc :query (uri/map->query-string {:token token})))
sid (session/create! session {:profile-id (:id profile)
:user-agent uagent})]
{:status 302
:headers {"location" (str uri)}
:cookies (session/cookies session {:value sid})
:body ""})))
(assoc :query (u/map->query-string {:token token})))
sxf ((:create session) (:id profile))
rsp {:status 302 :headers {"location" (str uri)} :body ""}]
(sxf request rsp))
(catch Exception _e
(let [uri (-> (u/uri (:public-uri cfg))
(assoc :path "/#/auth/login")
(assoc :query (u/map->query-string {:error "unable-to-auth"})))]
{:status 302
:headers {"location" (str uri)}
:body ""}))))
(s/def ::client-id ::us/not-empty-string)
(s/def ::client-secret ::us/not-empty-string)

View file

@ -11,14 +11,13 @@
(:require
[app.common.exceptions :as ex]
[app.common.spec :as us]
[app.http.session :as session]
[app.util.http :as http]
[app.util.time :as dt]
[clojure.data.json :as json]
[clojure.spec.alpha :as s]
[clojure.tools.logging :as log]
[integrant.core :as ig]
[lambdaisland.uri :as uri]))
[lambdaisland.uri :as u]))
(def base-goauth-uri "https://accounts.google.com/o/oauth2/v2/auth")
@ -30,7 +29,7 @@
(defn- build-redirect-url
[cfg]
(let [public (uri/uri (:public-uri cfg))]
(let [public (u/uri (:public-uri cfg))]
(str (assoc public :path "/api/oauth/google/callback"))))
(defn- get-access-token
@ -44,7 +43,7 @@
req {:method :post
:headers {"content-type" "application/x-www-form-urlencoded"}
:uri "https://oauth2.googleapis.com/token"
:body (uri/map->query-string params)}
:body (u/map->query-string params)}
res (http/send! req)]
(when (= 200 (:status res))
@ -80,8 +79,8 @@
:response_type "code"
:redirect_uri (build-redirect-url cfg)
:client_id (:client-id cfg)}
query (uri/map->query-string params)
uri (-> (uri/uri base-goauth-uri)
query (u/map->query-string params)
uri (-> (u/uri base-goauth-uri)
(assoc :query query))]
{:status 200
:body {:redirect-uri (str uri)}}))
@ -100,24 +99,20 @@
method-fn (get-in rpc [:methods :mutation :login-or-register])
profile (method-fn {:email (:email info)
:fullname (:fullname info)})
uagent (get-in request [:headers "user-agent"])
token (tokens :generate {:iss :auth
:exp (dt/in-future "15m")
:profile-id (:id profile)})
uri (-> (uri/uri (:public-uri cfg))
uri (-> (u/uri (:public-uri cfg))
(assoc :path "/#/auth/verify-token")
(assoc :query (uri/map->query-string {:token token})))
(assoc :query (u/map->query-string {:token token})))
sid (session/create! session {:profile-id (:id profile)
:user-agent uagent})]
{:status 302
:headers {"location" (str uri)}
:cookies (session/cookies session {:value sid})
:body ""})
sxf ((:create session) (:id profile))
rsp {:status 302 :headers {"location" (str uri)} :body ""}]
(sxf request rsp))
(catch Exception _e
(let [uri (-> (uri/uri (:public-uri cfg))
(let [uri (-> (u/uri (:public-uri cfg))
(assoc :path "/#/auth/login")
(assoc :query (uri/map->query-string {:error "unable-to-auth"})))]
(assoc :query (u/map->query-string {:error "unable-to-auth"})))]
{:status 302
:headers {"location" (str uri)}
:body ""}))))

View file

@ -11,7 +11,6 @@
(:require
[app.common.exceptions :as ex]
[app.config :as cfg]
[app.http.session :as session]
[clj-ldap.client :as client]
[clojure.set :as set]
[clojure.spec.alpha :as s]
@ -66,12 +65,10 @@
(let [method-fn (get-in rpc [:methods :mutation :login-or-register])
profile (method-fn {:email (:email info)
:fullname (:fullname info)})
uagent (get-in request [:headers "user-agent"])
sid (session/create! session {:profile-id (:id profile)
:user-agent uagent})]
{:status 200
:cookies (session/cookies session {:value sid})
:body profile}))))
sxf ((:create session) (:id profile))
rsp {:status 200 :body profile}]
(sxf request rsp)))))
{::conn conn})))
(defmethod ig/halt-key! ::client

View file

@ -16,14 +16,16 @@
[clojure.spec.alpha :as s]
[integrant.core :as ig]))
(defn next-session-id
;; --- IMPL
(defn- next-session-id
([] (next-session-id 96))
([n]
(-> (bn/random-nonce n)
(bc/bytes->b64u)
(bc/bytes->str))))
(defn create!
(defn- create
[{:keys [conn] :as cfg} {:keys [profile-id user-agent]}]
(let [id (next-session-id)]
(db/insert! conn :http-session {:id id
@ -31,28 +33,28 @@
:user-agent user-agent})
id))
(defn delete!
[{:keys [conn cookie-name] :as cfg} request]
(when-let [token (get-in request [:cookies cookie-name :value])]
(defn- delete
[{:keys [conn cookie-name] :as cfg} {:keys [cookies] :as request}]
(when-let [token (get-in cookies [cookie-name :value])]
(db/delete! conn :http-session {:id token}))
nil)
(defn retrieve
(defn- retrieve
[{:keys [conn] :as cfg} token]
(when token
(-> (db/exec-one! conn ["select profile_id from http_session where id = ?" token])
(:profile-id))))
(defn retrieve-from-request
[{:keys [cookie-name] :as cfg} request]
(->> (get-in request [:cookies cookie-name :value])
(defn- retrieve-from-request
[{:keys [cookie-name] :as cfg} {:keys [cookies] :as request}]
(->> (get-in cookies [cookie-name :value])
(retrieve cfg)))
(defn cookies
(defn- cookies
[{:keys [cookie-name] :as cfg} vals]
{cookie-name (merge vals {:path "/" :http-only true})})
(defn middleware
(defn- middleware
[cfg handler]
(fn [request]
(if-let [profile-id (retrieve-from-request cfg request)]
@ -61,6 +63,8 @@
(handler (assoc request :profile-id profile-id)))
(handler request))))
;; --- STATE INIT
(defmethod ig/pre-init-spec ::session [_]
(s/keys :req-un [::db/pool]))
@ -71,4 +75,17 @@
(defmethod ig/init-key ::session
[_ {:keys [pool] :as cfg}]
(let [cfg (assoc cfg :conn pool)]
(merge cfg {:middleware #(middleware cfg %)})))
(-> cfg
(assoc :middleware #(middleware cfg %))
(assoc :create (fn [profile-id]
(fn [request response]
(let [uagent (get-in request [:headers "user-agent"])
value (create cfg {:profile-id profile-id :user-agent uagent})]
(assoc response :cookies (cookies cfg {:value value}))))))
(assoc :delete (fn [request response]
(delete cfg request)
(assoc response
:status 204
:body ""
:cookies (cookies cfg {:value "" :max-age -1})))))))

View file

@ -16,7 +16,6 @@
[app.db :as db]
[app.db.profile-initial-data :refer [create-profile-initial-data]]
[app.emails :as emails]
[app.http.session :as session]
[app.media :as media]
[app.rpc.mutations.projects :as projects]
[app.rpc.mutations.teams :as teams]
@ -95,13 +94,7 @@
(with-meta (assoc profile
:is-active true
:claims claims)
{:transform-response
(fn [request response]
(let [uagent (get-in request [:headers "user-agent"])
id (session/create! session {:profile-id (:id profile)
:user-agent uagent})]
(assoc response
:cookies (session/cookies session {:value id}))))}))
{:transform-response ((:create session) (:id profile))}))
;; If no token is provided, send a verification email
(let [token (tokens :generate
@ -217,7 +210,7 @@
:opt-un [::scope]))
(sv/defmethod ::login {:auth false :rlimit :password}
[{:keys [pool] :as cfg} {:keys [email password scope] :as params}]
[{:keys [pool session] :as cfg} {:keys [email password scope] :as params}]
(letfn [(check-password [profile password]
(when (= (:password profile) "!")
(ex/raise :type :validation
@ -240,8 +233,21 @@
(let [prof (-> (profile/retrieve-profile-data-by-email conn email)
(validate-profile)
(profile/strip-private-attrs))
addt (profile/retrieve-additional-data conn (:id prof))]
(merge prof addt)))))
addt (profile/retrieve-additional-data conn (:id prof))
prof (merge prof addt)]
(with-meta prof
{:transform-response ((:create session) (:id prof))})))))
;; --- Mutation: Logout
(s/def ::logout
(s/keys :req-un [::profile-id]))
(sv/defmethod ::logout
[{:keys [pool session] :as cfg} {:keys [profile-id] :as params}]
(with-meta {}
{:transform-response (:delete session)}))
;; --- Mutation: Register if not exists
@ -480,11 +486,7 @@
{:id profile-id})
(with-meta {}
{:transform-response
(fn [request response]
(session/delete! session request)
(assoc response
:cookies (session/cookies session {:value "" :max-age -1})))})))
{:transform-response (:delete session)})))
(def sql:owned-teams
"with owner_teams as (

View file

@ -5,14 +5,13 @@
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
;; Copyright (c) 2020-2021 UXBOX Labs SL
(ns app.rpc.mutations.verify-token
(:require
[app.common.exceptions :as ex]
[app.common.spec :as us]
[app.db :as db]
[app.http.session :as session]
[app.rpc.mutations.teams :as teams]
[app.rpc.queries.profile :as profile]
[app.util.services :as sv]
@ -57,14 +56,7 @@
{:id (:id profile)}))
(with-meta claims
{:transform-response
(fn [request response]
(let [uagent (get-in request [:headers "user-agent"])
id (session/create! session {:profile-id profile-id
:user-agent uagent})]
(assoc response
:cookies (session/cookies session {:value id}))))})))
{:transform-response ((:create session) profile-id)})))
(defmethod process-token :auth
[{:keys [conn] :as cfg} _params {:keys [profile-id] :as claims}]
@ -116,13 +108,7 @@
;; the user clicking the link he already has access to the
;; email account.
(with-meta claims
{:transform-response
(fn [request response]
(let [uagent (get-in request [:headers "user-agent"])
id (session/create! session {:profile-id member-id
:user-agent uagent})]
(assoc response
:cookies (session/cookies session {:value id}))))})))
{:transform-response ((:create session) member-id)})))
;; In this case, we wait until frontend app redirect user to
;; registeration page, the user is correctly registered and the

View file

@ -191,3 +191,94 @@
;; TODO: profile deletion with owner teams
;; TODO: profile registration
;; TODO: profile password recovery
(t/deftest test-register-when-registration-disabled
(with-mocks [mock {:target 'app.config/get
:return (th/mock-config-get-with
{:registration-enabled false})}]
(let [data {::th/type :register-profile
:email "user@example.com"
:password "foobar"
:fullname "foobar"}
out (th/mutation! data)
error (:error out)
edata (ex-data error)]
(t/is (th/ex-info? error))
(t/is (= (:type edata) :restriction))
(t/is (= (:code edata) :registration-disabled)))))
(t/deftest test-register-existing-profile
(let [profile (th/create-profile* 1)
data {::th/type :register-profile
:email (:email profile)
:password "foobar"
:fullname "foobar"}
out (th/mutation! data)
error (:error out)
edata (ex-data error)]
(t/is (th/ex-info? error))
(t/is (= (:type edata) :validation))
(t/is (= (:code edata) :email-already-exists))))
(t/deftest test-register-profile
(with-mocks [mock {:target 'app.emails/send!
:return nil}]
(let [pool (:app.db/pool th/*system*)
data {::th/type :register-profile
:email "user@example.com"
:password "foobar"
:fullname "foobar"}
out (th/mutation! data)]
;; (th/print-result! out)
(let [mock (deref mock)
[_ _ params] (:call-args mock)]
;; (clojure.pprint/pprint params)
(t/is (:called? mock))
(t/is (= (:email data) (:to params)))
(t/is (contains? params :extra-data))
(t/is (contains? params :token)))
(let [result (:result out)]
(t/is (false? (:is-demo result)))
(t/is (= (:email data) (:email result)))
(t/is (= "penpot" (:auth-backend result)))
(t/is (= "foobar" (:fullname result)))
(t/is (not (contains? result :password)))))))
(t/deftest test-register-profile-with-bounced-email
(with-mocks [mock {:target 'app.emails/send!
:return nil}]
(let [pool (:app.db/pool th/*system*)
data {::th/type :register-profile
:email "user@example.com"
:password "foobar"
:fullname "foobar"}
_ (th/create-global-complaint-for pool {:type :bounce :email "user@example.com"})
out (th/mutation! data)]
;; (th/print-result! out)
(let [mock (deref mock)]
(t/is (false? (:called? mock))))
(let [error (:error out)
edata (ex-data error)]
(t/is (th/ex-info? error))
(t/is (= (:type edata) :validation))
(t/is (= (:code edata) :email-has-permanent-bounces))))))
(t/deftest test-register-profile-with-complained-email
(with-mocks [mock {:target 'app.emails/send!
:return nil}]
(let [pool (:app.db/pool th/*system*)
data {::th/type :register-profile
:email "user@example.com"
:password "foobar"
:fullname "foobar"}
_ (th/create-global-complaint-for pool {:type :complaint :email "user@example.com"})
out (th/mutation! data)]
(let [mock (deref mock)]
(t/is (true? (:called? mock))))
(let [result (:result out)]
(t/is (= (:email data) (:email result)))))))

View file

@ -122,18 +122,6 @@
(seq params))
(send-mutation! id form)))
(defmethod mutation :login
[id params]
(let [uri (str cfg/public-uri "/api/login")]
(->> (http/send! {:method :post :uri uri :body params})
(rx/mapcat handle-response))))
(defmethod mutation :logout
[id params]
(let [uri (str cfg/public-uri "/api/logout")]
(->> (http/send! {:method :post :uri uri :body params})
(rx/mapcat handle-response))))
(defmethod mutation :login-with-ldap
[id params]
(let [uri (str cfg/public-uri "/api/login-ldap")]

View file

@ -63,7 +63,6 @@
on-error
(fn [form event]
(js/console.log error?)
(reset! error? true))
on-submit
@ -107,8 +106,7 @@
:help-icon i/eye
:label (tr "auth.password")}]]
[:& fm/submit-button
{:label (tr "auth.login-submit")
:on-click on-submit}]
{:label (tr "auth.login-submit")}]
(when cfg/login-with-ldap
[:& fm/submit-button