mirror of
https://github.com/penpot/penpot.git
synced 2026-09-06 20:18:39 +00:00
🐛 Invalidate all sessions on profile deletion (#11115)
When a profile is deleted, only the current session was being invalidated. Other active sessions on different devices remained functional until the background cleanup task completed. Add session/invalidate-all helper that deletes all sessions for a profile by profile_id, and call it from delete-profile before the response transform. This ensures immediate access revocation across all devices when an account is deleted. Closes #11114 AI-assisted-by: qwen3.7-plus
This commit is contained in:
parent
e2d429d283
commit
2f04fcddbf
@ -226,6 +226,14 @@
|
|||||||
(-> (db/exec-one! cfg [sql (:profile-id session) (:id session)])
|
(-> (db/exec-one! cfg [sql (:profile-id session) (:id session)])
|
||||||
(db/get-update-count))))
|
(db/get-update-count))))
|
||||||
|
|
||||||
|
(defn invalidate-all
|
||||||
|
"Delete all sessions for a given profile. Used when a profile is deleted
|
||||||
|
to ensure immediate access revocation across all devices."
|
||||||
|
[cfg profile-id]
|
||||||
|
(let [sql "delete from http_session_v2 where profile_id = ?"]
|
||||||
|
(-> (db/exec-one! cfg [sql profile-id])
|
||||||
|
(db/get-update-count))))
|
||||||
|
|
||||||
(def ^:private sql:clear-organization-sso-sessions
|
(def ^:private sql:clear-organization-sso-sessions
|
||||||
(str "UPDATE http_session_v2 "
|
(str "UPDATE http_session_v2 "
|
||||||
"SET props = props #- ARRAY['~:sso', ?]::text[] "
|
"SET props = props #- ARRAY['~:sso', ?]::text[] "
|
||||||
|
|||||||
@ -534,6 +534,10 @@
|
|||||||
:deleted-at deleted-at
|
:deleted-at deleted-at
|
||||||
:id profile-id}})
|
:id profile-id}})
|
||||||
|
|
||||||
|
;; Invalidate all sessions for this profile to ensure immediate
|
||||||
|
;; access revocation across all devices
|
||||||
|
(session/invalidate-all cfg profile-id)
|
||||||
|
|
||||||
(-> (rph/wrap nil)
|
(-> (rph/wrap nil)
|
||||||
(rph/with-transform (session/delete-fn cfg)))))
|
(rph/with-transform (session/delete-fn cfg)))))
|
||||||
|
|
||||||
|
|||||||
@ -388,6 +388,31 @@
|
|||||||
(let [result (th/run-task! :objects-gc {:min-age 0})]
|
(let [result (th/run-task! :objects-gc {:min-age 0})]
|
||||||
(t/is (= 10 (:processed result))))))
|
(t/is (= 10 (:processed result))))))
|
||||||
|
|
||||||
|
(t/deftest profile-deletion-invalidates-all-sessions
|
||||||
|
(let [prof (th/create-profile* 1)
|
||||||
|
|
||||||
|
;; Insert 3 sessions for this profile directly into the database
|
||||||
|
session-ids (doall
|
||||||
|
(for [i (range 3)]
|
||||||
|
(let [sid (uuid/random)]
|
||||||
|
(th/db-exec-one! ["INSERT INTO http_session_v2 (id, profile_id, user_agent) VALUES (?, ?, ?)"
|
||||||
|
sid (:id prof) (str "user-agent-" i)])
|
||||||
|
sid)))]
|
||||||
|
|
||||||
|
;; Verify sessions exist
|
||||||
|
(let [count-before (:count (th/db-exec-one! ["SELECT count(*) FROM http_session_v2 WHERE profile_id = ?" (:id prof)]))]
|
||||||
|
(t/is (= 3 count-before)))
|
||||||
|
|
||||||
|
;; Request profile to be deleted
|
||||||
|
(let [params {::th/type :delete-profile
|
||||||
|
::rpc/profile-id (:id prof)}
|
||||||
|
out (th/command! params)]
|
||||||
|
(t/is (nil? (:error out))))
|
||||||
|
|
||||||
|
;; Verify ALL sessions were invalidated (not just one)
|
||||||
|
(let [count-after (:count (th/db-exec-one! ["SELECT count(*) FROM http_session_v2 WHERE profile_id = ?" (:id prof)]))]
|
||||||
|
(t/is (= 0 count-after)))))
|
||||||
|
|
||||||
|
|
||||||
(t/deftest email-blacklist-1
|
(t/deftest email-blacklist-1
|
||||||
(t/is (false? (email.blacklist/enabled? th/*system*)))
|
(t/is (false? (email.blacklist/enabled? th/*system*)))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user