mirror of
https://github.com/penpot/penpot.git
synced 2026-08-07 05:18:36 +00:00
🐛 Validate library belongs to same team in link/unlink/sync handlers
Add check-library-team-ownership! helper that verifies both the file and library share the same team before creating or modifying library relations. This prevents cross-team library injection where a user with edit permissions on files in different teams could link them across team boundaries. Applied to link-file-to-library, unlink-file-from-library, and update-file-library-sync-status handlers. AI-assisted-by: mimo-v2.5
This commit is contained in:
parent
8806f92cd7
commit
a91502f5e7
@ -1069,6 +1069,25 @@
|
||||
[cfg {:keys [::rpc/profile-id] :as params}]
|
||||
(db/tx-run! cfg delete-file (assoc params :profile-id profile-id)))
|
||||
|
||||
;; --- Library relation helpers
|
||||
|
||||
(defn- check-library-team-ownership!
|
||||
"Verify that file and library belong to the same team.
|
||||
Prevents cross-team library relation injection."
|
||||
[conn file-id library-id]
|
||||
(let [sql "SELECT EXISTS (
|
||||
SELECT 1 FROM file AS f
|
||||
JOIN project AS fp ON (fp.id = f.project_id)
|
||||
JOIN file AS l ON (l.id = ?)
|
||||
JOIN project AS lp ON (lp.id = l.project_id)
|
||||
WHERE f.id = ? AND fp.team_id = lp.team_id
|
||||
) AS ok"
|
||||
row (db/exec-one! conn [sql library-id file-id])]
|
||||
(when-not (:ok row)
|
||||
(ex/raise :type :not-found
|
||||
:code :object-not-found
|
||||
:hint "file and library must belong to the same team"))))
|
||||
|
||||
;; --- MUTATION COMMAND: link-file-to-library
|
||||
|
||||
(def sql:link-file-to-library
|
||||
@ -1104,6 +1123,7 @@
|
||||
|
||||
(check-edition-permissions! conn profile-id file-id)
|
||||
(check-edition-permissions! conn profile-id library-id)
|
||||
(check-library-team-ownership! conn file-id library-id)
|
||||
|
||||
(let [transitive-deps (bfc/get-libraries cfg [library-id])]
|
||||
(when (contains? transitive-deps file-id)
|
||||
@ -1135,6 +1155,7 @@
|
||||
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id file-id library-id] :as params}]
|
||||
(check-edition-permissions! conn profile-id file-id)
|
||||
(check-edition-permissions! conn profile-id library-id)
|
||||
(check-library-team-ownership! conn file-id library-id)
|
||||
(unlink-file-from-library conn params)
|
||||
nil)
|
||||
|
||||
@ -1159,6 +1180,7 @@
|
||||
[{:keys [::db/conn]} {:keys [::rpc/profile-id file-id library-id] :as params}]
|
||||
(check-edition-permissions! conn profile-id file-id)
|
||||
(check-edition-permissions! conn profile-id library-id)
|
||||
(check-library-team-ownership! conn file-id library-id)
|
||||
(update-sync conn params))
|
||||
|
||||
;; --- MUTATION COMMAND: ignore-sync
|
||||
|
||||
@ -983,6 +983,38 @@
|
||||
(t/is (some? sync))
|
||||
(t/is (some? (:synced-at sync)))))
|
||||
|
||||
(t/deftest link-file-to-library-rejects-cross-team
|
||||
;; N1-08: A file in team2 must not be linked to a library in team1,
|
||||
;; even when the user has edit permissions on both (BOLA / CWE-639).
|
||||
(let [prof1 (th/create-profile* 1)
|
||||
prof2 (th/create-profile* 2)
|
||||
team1 (th/create-team* 1 {:profile-id (:id prof1)})
|
||||
team2 (th/create-team* 2 {:profile-id (:id prof2)})
|
||||
proj1 (th/create-project* 1 {:profile-id (:id prof1)
|
||||
:team-id (:id team1)})
|
||||
proj2 (th/create-project* 2 {:profile-id (:id prof2)
|
||||
:team-id (:id team2)})
|
||||
lib (th/create-file* 1 {:project-id (:id proj1)
|
||||
:profile-id (:id prof1)
|
||||
:is-shared true})
|
||||
file2 (th/create-file* 2 {:project-id (:id proj2)
|
||||
:profile-id (:id prof2)})]
|
||||
|
||||
;; Add prof2 as editor to team1 so they have edit access to the library
|
||||
(th/db-insert! :team-profile-rel {:team-id (:id team1)
|
||||
:profile-id (:id prof2)
|
||||
:is-owner false
|
||||
:is-admin false
|
||||
:can-edit true})
|
||||
|
||||
;; prof2 tries to link file2 (team2) to lib (team1) — must fail
|
||||
(let [data {::th/type :link-file-to-library
|
||||
::rpc/profile-id (:id prof2)
|
||||
:file-id (:id file2)
|
||||
:library-id (:id lib)}
|
||||
out (th/command! data)]
|
||||
(t/is (some? (:error out))))))
|
||||
|
||||
(t/deftest update-file-library-sync-status-updates-sync-row
|
||||
(let [profile (th/create-profile* 1)
|
||||
file1 (th/create-file* 1 {:project-id (:default-project-id profile)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user