From 757cee67fb9c6e39c2b7a516749b8f544ebb3d99 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 22 Sep 2022 16:48:16 +0200 Subject: [PATCH] :tada: Add the ability to completly block access to a profile --- backend/src/app/auth/oidc.clj | 4 +++ backend/src/app/migrations.clj | 3 ++ .../migrations/sql/0079-mod-profile-table.sql | 2 ++ backend/src/app/rpc/commands/auth.clj | 28 ++++++++++++------- backend/src/app/rpc/commands/ldap.clj | 5 ++++ backend/src/app/srepl/main.clj | 27 ++++++++++++++---- frontend/src/app/main/ui/auth/login.cljs | 16 +++++++++-- frontend/src/app/main/ui/auth/register.cljs | 15 ++++++---- frontend/translations/en.po | 5 +++- frontend/translations/es.po | 5 +++- 10 files changed, 83 insertions(+), 27 deletions(-) create mode 100644 backend/src/app/migrations/sql/0079-mod-profile-table.sql diff --git a/backend/src/app/auth/oidc.clj b/backend/src/app/auth/oidc.clj index 4d8551076..464c44197 100644 --- a/backend/src/app/auth/oidc.clj +++ b/backend/src/app/auth/oidc.clj @@ -434,6 +434,10 @@ (assoc :path "/#/auth/verify-token") (assoc :query (u/map->query-string params)))] + (when (:is-blocked profile) + (ex/raise :type :restriction + :code :profile-blocked)) + (when (fn? audit) (audit :cmd :submit :type "command" diff --git a/backend/src/app/migrations.clj b/backend/src/app/migrations.clj index 0a43b15cd..009593e39 100644 --- a/backend/src/app/migrations.clj +++ b/backend/src/app/migrations.clj @@ -244,6 +244,9 @@ {:name "0078-mod-file-media-object-table-drop-cascade" :fn (mg/resource "app/migrations/sql/0078-mod-file-media-object-table-drop-cascade.sql")} + + {:name "0079-mod-profile-table" + :fn (mg/resource "app/migrations/sql/0079-mod-profile-table.sql")} ]) diff --git a/backend/src/app/migrations/sql/0079-mod-profile-table.sql b/backend/src/app/migrations/sql/0079-mod-profile-table.sql new file mode 100644 index 000000000..8bfe93b80 --- /dev/null +++ b/backend/src/app/migrations/sql/0079-mod-profile-table.sql @@ -0,0 +1,2 @@ +ALTER TABLE profile + ADD COLUMN is_blocked boolean DEFAULT false; diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index f307d653d..486755e39 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -97,15 +97,19 @@ (:valid (verify-password password (:password profile)))) (validate-profile [profile] - (when-not (:is-active profile) - (ex/raise :type :validation - :code :wrong-credentials)) (when-not profile (ex/raise :type :validation :code :wrong-credentials)) + (when-not (:is-active profile) + (ex/raise :type :validation + :code :wrong-credentials)) + (when (:is-blocked profile) + (ex/raise :type :restriction + :code :profile-blocked)) (when-not (check-password profile password) (ex/raise :type :validation :code :wrong-credentials)) + profile)] (db/with-atomic [conn pool] @@ -231,15 +235,19 @@ (validate-register-attempt! cfg params) (let [profile (when-let [profile (profile/retrieve-profile-data-by-email pool (:email params))] - (if (:is-active profile) + (cond + (:is-blocked profile) + (ex/raise :type :restriction + :code :profile-blocked) + + (and (not (:is-active profile)) + (elapsed-register-retry-threshold? profile)) + profile + + :else (ex/raise :type :validation :code :email-already-exists - :hint "profile already exists and correctly validated") - (if (elapsed-register-retry-threshold? profile) - profile - (ex/raise :type :validation - :code :email-already-exists - :hint "profile already exists")))) + :hint "profile already exists"))) params {:email (:email params) :password (:password params) diff --git a/backend/src/app/rpc/commands/ldap.clj b/backend/src/app/rpc/commands/ldap.clj index 6f14a5068..a0eab43e9 100644 --- a/backend/src/app/rpc/commands/ldap.clj +++ b/backend/src/app/rpc/commands/ldap.clj @@ -46,6 +46,11 @@ :code :wrong-credentials)) (let [profile (login-or-register cfg info)] + + (when (:is-blocked profile) + (ex/raise :type :restriction + :code :profile-blocked)) + (if-let [token (:invitation-token params)] ;; If invitation token comes in params, this is because the ;; user comes from team-invitation process; in this case, diff --git a/backend/src/app/srepl/main.clj b/backend/src/app/srepl/main.clj index 0569fa285..bcc0c0847 100644 --- a/backend/src/app/srepl/main.clj +++ b/backend/src/app/srepl/main.clj @@ -64,7 +64,7 @@ (defn update-profile "Update a limited set of profile attrs." - [system & {:keys [email id active? deleted?]}] + [system & {:keys [email id active? deleted? blocked?]}] (us/verify! :expr (some? system) @@ -74,15 +74,30 @@ :expr (or (string? email) (uuid? id)) :hint "email or id should be provided") - (let [pool (:app.db/pool system) - params (cond-> {} + (let [params (cond-> {} (true? active?) (assoc :is-active true) (false? active?) (assoc :is-active false) - (true? deleted?) (assoc :deleted-at (dt/now))) + (true? deleted?) (assoc :deleted-at (dt/now)) + (true? blocked?) (assoc :is-blocked true) + (false? blocked?) (assoc :is-blocked false)) opts (cond-> {} (some? email) (assoc :email (str/lower email)) (some? id) (assoc :id id))] - (some-> (db/update! pool :profile params opts) - (profile/decode-profile-row)))) + (db/with-atomic [conn (:app.db/pool system)] + (some-> (db/update! conn :profile params opts) + (profile/decode-profile-row))))) +(defn mark-profile-as-blocked! + "Mark the profile blocked and removes all the http sessiones + associated with the profile-id." + [system email] + (db/with-atomic [conn (:app.db/pool system)] + (when-let [profile (db/get-by-params conn :profile + {:email (str/lower email)} + {:columns [:id :email] + :check-not-found false})] + (when-not (:is-blocked profile) + (db/update! conn :profile {:is-blocked true} {:id (:id profile)}) + (db/delete! conn :http-session {:profile-id (:id profile)}) + :blocked)))) diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index 886b8cf73..72fe95705 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -83,14 +83,24 @@ form (fm/use-form :spec ::login-form :initial initial) on-error - (fn [_] - (reset! error (tr "errors.wrong-credentials"))) + (fn [cause] + (cond + (and (= :restriction (:type cause)) + (= :profile-blocked (:code cause))) + (reset! error (tr "errors.profile-blocked")) + + (and (= :validation (:type cause)) + (= :wrong-credentials (:code cause))) + (reset! error (tr "errors.wrong-credentials")) + + :else + (reset! error (tr "errors.generic")))) on-success-default (fn [data] (when-let [token (:invitation-token data)] (st/emit! (rt/nav :auth-verify-token {} {:token token})))) - + on-success (fn [data] (if (nil? on-success-callback) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index d738e1c6d..d70f00afd 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -48,20 +48,23 @@ :opt-un [::invitation-token])) (defn- handle-prepare-register-error - [form error] - (case (:code error) - :registration-disabled + [form {:keys [type code] :as cause}] + (condp = [type code] + [:restriction :registration-disabled] (st/emit! (dm/error (tr "errors.registration-disabled"))) - :email-has-permanent-bounces + [:restriction :profile-blocked] + (st/emit! (dm/error (tr "errors.profile-blocked"))) + + [:validation :email-has-permanent-bounces] (let [email (get @form [:data :email])] (st/emit! (dm/error (tr "errors.email-has-permanent-bounces" email)))) - :email-already-exists + [:validation :email-already-exists] (swap! form assoc-in [:errors :email] {:message "errors.email-already-exists"}) - :email-as-password + [:validation :email-as-password] (swap! form assoc-in [:errors :password] {:message "errors.email-as-password"}) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 3c53e4754..374a9cc61 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -4558,4 +4558,7 @@ msgid "workspace.updates.update" msgstr "Update" msgid "workspace.viewport.click-to-close-path" -msgstr "Click to close the path" \ No newline at end of file +msgstr "Click to close the path" + +msgid "errors.profile-blocked" +msgstr "The profile is blocked" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 85ee471b2..84d0d8f29 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -4765,4 +4765,7 @@ msgid "workspace.updates.update" msgstr "Actualizar" msgid "workspace.viewport.click-to-close-path" -msgstr "Pulsar para cerrar la ruta" \ No newline at end of file +msgstr "Pulsar para cerrar la ruta" + +msgid "errors.profile-blocked" +msgstr "El perfil esta blockeado"