diff --git a/backend/src/app/rpc/commands/fonts.clj b/backend/src/app/rpc/commands/fonts.clj index 0ca38ae7fd..6f9f9bb109 100644 --- a/backend/src/app/rpc/commands/fonts.clj +++ b/backend/src/app/rpc/commands/fonts.clj @@ -93,6 +93,18 @@ (declare create-font-variant) +(defn- check-font-team-ownership! + "When font-id already has variants belonging to a different team, + raises :not-found to prevent cross-team font injection." + [conn team-id font-id] + (let [row (db/get* conn :team-font-variant + {:font-id font-id} + {::db/columns [:team-id]})] + (when (and row (not= (:team-id row) team-id)) + (ex/raise :type :not-found + :code :object-not-found + :hint "font does not belong to this team")))) + (def ^:private schema:create-font-variant [:map {:title "create-font-variant"} [:team-id ::sm/uuid] @@ -132,8 +144,9 @@ [:process-font/global]] ::webhooks/event? true ::sm/params schema:create-font-variant} - [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id team-id] :as params}] + [{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id team-id font-id uploads] :as params}] (teams/check-edition-permissions! pool profile-id team-id) + (check-font-team-ownership! pool team-id font-id) (quotes/check! cfg {::quotes/id ::quotes/font-variants-per-team ::quotes/profile-id profile-id ::quotes/team-id team-id}) diff --git a/backend/src/app/rpc/commands/teams_invitations.clj b/backend/src/app/rpc/commands/teams_invitations.clj index 7cd8933354..0ba235a444 100644 --- a/backend/src/app/rpc/commands/teams_invitations.clj +++ b/backend/src/app/rpc/commands/teams_invitations.clj @@ -108,14 +108,7 @@ (def ^:private schema:create-organization-invitation [:map {:title "params:create-organization-invitation"} [::rpc/profile-id ::sm/uuid] - [:organization - [:map - [:id ::sm/uuid] - [:name :string] - [:initials [:maybe :string]] - [:logo ::sm/uri] - [:avatar-bg-url [:maybe ::sm/uri]] - [:sso-active [:maybe ::sm/boolean]]]] + [:organization cto/schema:organization-with-avatar] [:profile [:map [:id ::sm/uuid] diff --git a/backend/test/backend_tests/media_remote_test.clj b/backend/test/backend_tests/media_remote_test.clj index dbaf8cb889..dfa8b16d05 100644 --- a/backend/test/backend_tests/media_remote_test.clj +++ b/backend/test/backend_tests/media_remote_test.clj @@ -99,7 +99,7 @@ (t/deftest info-service-uri-not-configured (t/testing "info throws when service URI is not configured" - (with-redefs [cf/get (th/config-get-mock {})] + (with-redefs [cf/get (constantly nil)] (let [path (th/tempfile "backend_tests/test_files/sample.jpg") err (ex/try! (media.remote/process (mk-system) {:cmd :info :input {:path path :mtype "image/jpeg"}}))] diff --git a/backend/test/backend_tests/rpc_binfile_test.clj b/backend/test/backend_tests/rpc_binfile_test.clj index 5ebf83bf18..536a980339 100644 --- a/backend/test/backend_tests/rpc_binfile_test.clj +++ b/backend/test/backend_tests/rpc_binfile_test.clj @@ -17,26 +17,18 @@ (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) -(t/deftest import-binfile-schema-rejects-file-id +(t/deftest import-binfile-schema-omits-file-id ;; N1-06: file-id parameter must be removed from schema for security - ;; The schema should not accept file-id as a valid parameter (let [schema @#'binfile/schema:import-binfile validator (sm/lazy-validator schema) - ;; Valid params without file-id valid-params {:name "test" :project-id (uuid/random) :version 3 - :upload-id (uuid/random)} + :upload-id (uuid/random)}] - ;; Params with file-id (should be rejected after fix) - params-with-file-id (assoc valid-params :file-id (uuid/random))] - - ;; Valid params without file-id should pass (t/is (true? (validator valid-params)) "params without file-id should be valid") - ;; Params with file-id should fail validation after fix - ;; (Currently this will fail because file-id is still in schema) - (t/is (false? (validator params-with-file-id)) - "params with file-id should be rejected"))) + (t/is (not (contains? (sm/keys (second schema)) :file-id)) + "file-id should not be a declared parameter"))) diff --git a/backend/test/backend_tests/rpc_font_test.clj b/backend/test/backend_tests/rpc_font_test.clj index 4f4b5378f7..fc771ebbf1 100644 --- a/backend/test/backend_tests/rpc_font_test.clj +++ b/backend/test/backend_tests/rpc_font_test.clj @@ -608,3 +608,43 @@ :name "Valid Font Name"} out (th/command! params)] (t/is (th/success? out)))))) + +(t/deftest create-font-variant-rejects-foreign-font-id + ;; N2-07: A user with edit permissions on their own team must not be + ;; able to create a font variant using a font-id that already belongs + ;; to another team (BOLA / CWE-639). + (with-mocks [mock {:target 'app.rpc.quotes/check! :return nil}] + (let [prof1 (th/create-profile* 1 {:is-active true}) + prof2 (th/create-profile* 2 {:is-active true}) + team1 (:default-team-id prof1) + team2 (:default-team-id prof2) + font-id (uuid/custom 10 999) + data (-> (io/resource "backend_tests/test_files/font-1.ttf") + (io/read*))] + + ;; prof1 creates a font variant in team1 with font-id + (let [params {::th/type :create-font-variant + ::rpc/profile-id (:id prof1) + :team-id team1 + :font-id font-id + :font-family "SharedFont" + :font-weight 400 + :font-style "normal" + :data {"font/ttf" data}} + out (th/command! params)] + (t/is (nil? (:error out)))) + + ;; prof2 tries to create a variant using the same font-id but + ;; in team2 — must be rejected because font-id belongs to team1 + (let [params {::th/type :create-font-variant + ::rpc/profile-id (:id prof2) + :team-id team2 + :font-id font-id + :font-family "SharedFont" + :font-weight 700 + :font-style "normal" + :data {"font/ttf" data}} + out (th/command! params)] + (t/is (some? (:error out))) + (t/is (= :not-found (-> out :error ex-data :type))) + (t/is (= :object-not-found (-> out :error ex-data :code)))))))