|
25 | 25 |
|
26 | 26 | from django.urls import reverse |
27 | 27 | from django.contrib.auth import get_user_model |
28 | | -from django.test import RequestFactory |
| 28 | +from django.test import RequestFactory, TestCase, override_settings |
29 | 29 | from rest_framework import status |
30 | 30 | from django.utils.translation import gettext as _ |
31 | 31 |
|
32 | 32 | from rest_framework.test import APITestCase |
| 33 | + |
| 34 | +from geonode.metadata.handlers.multilang import MultiLangHandler |
33 | 35 | from geonode.metadata.settings import MODEL_SCHEMA |
34 | 36 | from geonode.metadata.manager import metadata_manager, CACHE_KEY_SCHEMA |
| 37 | +from geonode.metadata.handlers.meta import CleanupHandler |
35 | 38 | from geonode.metadata.api.views import ( |
36 | 39 | ProfileAutocomplete, |
37 | 40 | MetadataLinkedResourcesAutocomplete, |
@@ -919,7 +922,7 @@ def test_update_schema_instance_no_errors(self, mock_get_schema): |
919 | 922 | mock_request.data = {"field1": "new_value1", "new_field2": "new_value2"} |
920 | 923 | mock_request.user = self.test_user_1 |
921 | 924 |
|
922 | | - expected_context = {"user": self.test_user_1} |
| 925 | + expected_context = {"user": self.test_user_1, "errors": {}} |
923 | 926 |
|
924 | 927 | mock_get_schema.return_value = self.fake_schema |
925 | 928 |
|
@@ -1151,3 +1154,58 @@ def test_delete_schema_conflict_returns_409(self, mock_get_schema): |
1151 | 1154 | url = self._url(self.resource.pk, "title") |
1152 | 1155 | response = self.client.delete(url) |
1153 | 1156 | self.assertEqual(response.status_code, status.HTTP_409_CONFLICT) |
| 1157 | + |
| 1158 | + |
| 1159 | +class CleanupHandlerTests(TestCase): |
| 1160 | + def setUp(self): |
| 1161 | + self.handler = CleanupHandler() |
| 1162 | + self.owner = get_user_model().objects.create_user( |
| 1163 | + "cleanup_owner", "cleanup_owner@fakemail.com", "cleanup_owner_password", is_active=True |
| 1164 | + ) |
| 1165 | + self.resource = ResourceBase.objects.create(title="Cleanup Test Resource", uuid=str(uuid4()), owner=self.owner) |
| 1166 | + |
| 1167 | + @override_settings(LANGUAGE_CODE="en") |
| 1168 | + def test_pre_deserialization_sanitizes_nested_values_and_logs_warnings(self): |
| 1169 | + instance = { |
| 1170 | + "title": "<i>xss</i><img src=/ onerror=\"alert('XSS');\" />", |
| 1171 | + "details": { |
| 1172 | + "summary": "plain text", |
| 1173 | + "body": "<script>alert(1)</script>safe", |
| 1174 | + }, |
| 1175 | + "items": ["ok", "<b>bad</b>"], |
| 1176 | + "count": 3, |
| 1177 | + } |
| 1178 | + |
| 1179 | + with self.assertLogs("geonode.metadata.handlers.meta", level="WARNING") as cm: |
| 1180 | + context = {"errors": {}} |
| 1181 | + self.handler.pre_deserialization(self.resource, {}, instance, partial=set(), context=context) |
| 1182 | + |
| 1183 | + self.assertEqual(instance["title"], "xss") |
| 1184 | + self.assertEqual(instance["details"]["body"], "safe") |
| 1185 | + self.assertEqual(instance["items"][1], "bad") |
| 1186 | + self.assertEqual(instance["count"], 3) |
| 1187 | + |
| 1188 | + logs = "\n".join(cm.output) |
| 1189 | + self.assertIn("Sanitized potentially unsafe metadata field 'title'", logs) |
| 1190 | + self.assertIn("Sanitized potentially unsafe metadata field 'details.body'", logs) |
| 1191 | + self.assertIn("Sanitized potentially unsafe metadata field 'items.[1]'", logs) |
| 1192 | + |
| 1193 | + self.assertIn("title", context["errors"]) |
| 1194 | + self.assertIn("__errors", context["errors"]["title"]) |
| 1195 | + self.assertIn("metadata_error_sanitized", context["errors"]["title"]["__errors"]) |
| 1196 | + |
| 1197 | + @override_settings(LANGUAGE_CODE="en", MULTILANG_FIELDS=["title"]) |
| 1198 | + def test_pre_deserialization_copies_sanitized_default_lang_value(self): |
| 1199 | + instance = { |
| 1200 | + "title_multilang_en": '<span>Hello</span><img src=x onerror="alert(1)" />', |
| 1201 | + } |
| 1202 | + context = {"errors": {}} |
| 1203 | + |
| 1204 | + ml_handler = MultiLangHandler() |
| 1205 | + with self.assertLogs("geonode.metadata.handlers.meta", level="WARNING") as cm: |
| 1206 | + self.handler.pre_deserialization(self.resource, {}, instance, partial=set(), context=context) |
| 1207 | + ml_handler.pre_deserialization(self.resource, {}, instance, partial=set(), context=context) |
| 1208 | + |
| 1209 | + self.assertEqual(instance["title_multilang_en"], "Hello") |
| 1210 | + self.assertEqual(instance["title"], "Hello") |
| 1211 | + self.assertIn("Sanitized potentially unsafe metadata field 'title_multilang_en'", "\n".join(cm.output)) |
0 commit comments