Repository: digitalfabrik/integreat-cms

Issue:
Clone region copies API token
### Describe the Bug
When a region is cloned the  access token for the push page content API endpoint is cloned as well. This is a leak of information as users of the newly cloned region can use this token to push content to the source region.


### Steps to Reproduce

1. Edit a page and set the "API access token"
2. Clone the region
3. Open the page in the cloned region and look at the token.

### Expected Behavior
API access tokens should be cleared after cloning.


### Actual Behavior
API access tokens are cloned along all other page properties.


### Additional Information
Should we reserve a CVE? :joy_cat: 


Discussion:

Resolving patch:
diff --git a/integreat_cms/cms/forms/regions/region_form.py b/integreat_cms/cms/forms/regions/region_form.py
--- a/integreat_cms/cms/forms/regions/region_form.py
+++ b/integreat_cms/cms/forms/regions/region_form.py
@@ -164,6 +164,9 @@ def save(self, commit=True):
             # Duplicate pages
             logger.info("Duplicating page tree of %r to %r", source_region, region)
             duplicate_pages(source_region, region)
+            # Duplicate Imprint
+            logger.info("Duplicating imprint of %r to %r", source_region, region)
+            duplicate_imprint(source_region, region)
             # Duplicate media content
             duplicate_media(source_region, region)
 
@@ -506,6 +509,8 @@ def duplicate_pages(
         target_page.tree_id = target_tree_id
         # Delete the primary key to duplicate the object instance instead of updating it
         target_page.pk = None
+        # Set push API token to blank for duplicated page
+        target_page.api_token = ""
         # Check if the page is valid
         target_page.full_clean()
         # Save duplicated page
@@ -567,6 +572,41 @@ def duplicate_page_translations(source_page, target_page, logging_prefix):
         )
 
 
+def duplicate_imprint(source_region, target_region):
+    """
+    Function to duplicate the imprint from one region to another.
+
+    :param source_region: the source region from which the imprint should be duplicated
+    :type source_region: ~integreat_cms.cms.models.regions.region.Region
+
+    :param target_region: the target region
+    :type target_region: ~integreat_cms.cms.models.regions.region.Region
+
+    """
+    source_imprint = source_region.imprint
+    target_imprint = deepcopy(source_imprint)
+    target_imprint.region = target_region
+    # Delete the primary key to duplicate the object instance instead of updating it
+    target_imprint.pk = None
+    # Check if the new imprint object is valid
+    target_imprint.full_clean()
+
+    target_imprint.save()
+
+    # Duplicate imprint translations by iterating to all existing ones
+    source_page_translations = source_imprint.translations.all()
+
+    for imprint_translation in source_page_translations:
+        # Set the page of the source translation to the new imprint
+        imprint_translation.page = target_imprint
+        # Delete the primary key to duplicate the object instance instead of updating it
+        imprint_translation.pk = None
+        # Check if the imprint translation is valid
+        imprint_translation.full_clean()
+        # Save duplicated imprint translation
+        imprint_translation.save(update_timestamp=False)
+
+
 # pylint: disable=unused-argument
 def duplicate_media(source_region, target_region):
     """


Test patch:
diff --git a/tests/cms/test_duplicate_regions.py b/tests/cms/test_duplicate_regions.py
--- a/tests/cms/test_duplicate_regions.py
+++ b/tests/cms/test_duplicate_regions.py
@@ -44,10 +44,10 @@ def test_duplicate_regions(load_test_data, admin_client):
     assert len(source_pages) == len(target_pages)
     for source_page, target_page in zip(source_pages, target_pages):
         source_page_dict = model_to_dict(
-            source_page, exclude=["id", "tree_id", "region", "parent"]
+            source_page, exclude=["id", "tree_id", "region", "parent", "api_token"]
         )
         target_page_dict = model_to_dict(
-            target_page, exclude=["id", "tree_id", "region", "parent"]
+            target_page, exclude=["id", "tree_id", "region", "parent", "api_token"]
         )
         assert source_page_dict == target_page_dict