From b5124fa366641876dd44fa526f02caa45771ca5b Mon Sep 17 00:00:00 2001 From: Mathias Leimgruber Date: Mon, 1 May 2023 13:57:31 -0400 Subject: [PATCH] Do not expose private metadata via relationfield serializer. --- news/1634.bugfix | 2 ++ src/plone/restapi/serializer/relationfield.py | 11 ++++++-- src/plone/restapi/tests/test_content_get.py | 26 ++++++++++++++++++- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 news/1634.bugfix diff --git a/news/1634.bugfix b/news/1634.bugfix new file mode 100644 index 0000000000..b0d7788b80 --- /dev/null +++ b/news/1634.bugfix @@ -0,0 +1,2 @@ +Do not expose private metadata via relationfield serializer. +[maethu] diff --git a/src/plone/restapi/serializer/relationfield.py b/src/plone/restapi/serializer/relationfield.py index 28483ce424..c54145f1eb 100644 --- a/src/plone/restapi/serializer/relationfield.py +++ b/src/plone/restapi/serializer/relationfield.py @@ -1,3 +1,4 @@ +from plone import api from plone.dexterity.interfaces import IDexterityContent from plone.restapi.interfaces import IFieldSerializer from plone.restapi.interfaces import IJsonCompatible @@ -17,7 +18,8 @@ @adapter(IRelationValue) @implementer(IJsonCompatible) def relationvalue_converter(value): - if value.to_object: + mtool = api.portal.get_tool("portal_membership") + if value.to_object and mtool.checkPermission("View", value.to_object): request = getRequest() request.form["metadata_fields"] = ["UID"] summary = getMultiAdapter((value.to_object, request), ISerializeToJsonSummary)() @@ -33,4 +35,9 @@ class RelationChoiceFieldSerializer(DefaultFieldSerializer): @adapter(IRelationList, IDexterityContent, Interface) @implementer(IFieldSerializer) class RelationListFieldSerializer(DefaultFieldSerializer): - pass + def __call__(self): + value = self.get_value() + if value: + return [item for item in json_compatible(value) if item] + else: + return super().__call__() diff --git a/src/plone/restapi/tests/test_content_get.py b/src/plone/restapi/tests/test_content_get.py index 34cd70d137..fa0e3171fe 100644 --- a/src/plone/restapi/tests/test_content_get.py +++ b/src/plone/restapi/tests/test_content_get.py @@ -18,7 +18,6 @@ class TestContentGet(unittest.TestCase): - layer = PLONE_RESTAPI_DX_FUNCTIONAL_TESTING def setUp(self): @@ -137,6 +136,31 @@ def test_get_content_includes_related_items(self): response.json()["relatedItems"], ) + def test_get_content_includes_related_items_filtered_by_view_permission(self): + intids = getUtility(IIntIds) + self.portal.folder1.doc1.relatedItems = [ + RelationValue(intids.getId(self.portal.folder1.folder2.doc2)), + ] + + # Remove view permission + self.portal.folder1.folder2.doc2.manage_permission( + "View", roles=[], acquire=False + ) + self.portal.folder1.folder2.doc2.reindexObjectSecurity() + transaction.commit() + + response = requests.get( + self.portal.folder1.doc1.absolute_url(), + headers={"Accept": "application/json"}, + auth=(SITE_OWNER_NAME, SITE_OWNER_PASSWORD), + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(0, len(response.json()["relatedItems"])) + self.assertEqual( + [], + response.json()["relatedItems"], + ) + def test_get_content_related_items_without_workflow(self): intids = getUtility(IIntIds)