Skip to content

Commit 1aa9003

Browse files
Fix bug where encrypted XLSForm with choice filter has invalid XML (#2881)
* fix bug where encrypted XLSForm with choice filter has invalid XML The bug arises from survey.to_json_dict() generating incorrect JSON schema when publishing the XLSForm. A SurveyElementBuilder object created from an existing XForm's JSON schema generates invalid XML * fix failing tests * refactor code * remove redundant check * refactor code * refactor code
1 parent e43cb61 commit 1aa9003

File tree

4 files changed

+342
-28
lines changed

4 files changed

+342
-28
lines changed

onadata/apps/logger/models/xform.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from django.utils.translation import gettext_lazy
2828

2929
from guardian.models import GroupObjectPermissionBase, UserObjectPermissionBase
30-
from pyxform import SurveyElementBuilder, constants, create_survey_element_from_dict
30+
from pyxform import SurveyElementBuilder, constants
3131
from pyxform.errors import PyXFormError
3232
from pyxform.question import Question
3333
from pyxform.section import RepeatingSection
@@ -1113,14 +1113,12 @@ def _set_encrypted_field(self):
11131113
self.encrypted = "public_key" in json_dict
11141114

11151115
def _set_public_key_field(self):
1116-
if self.json and self.json != "":
1117-
if self.num_of_submissions == 0 and self.public_key:
1118-
json_dict = self.json_dict()
1119-
json_dict["public_key"] = self.public_key
1120-
survey = create_survey_element_from_dict(json_dict)
1121-
self.json = survey.to_json_dict()
1122-
self.xml = survey.to_xml()
1123-
self._set_encrypted_field()
1116+
if self.public_key and self.num_of_submissions == 0:
1117+
survey = self.get_survey_from_xlsform()
1118+
survey.public_key = self.public_key
1119+
self.json = survey.to_json_dict()
1120+
self.xml = survey.to_xml()
1121+
self._set_encrypted_field()
11241122

11251123
def json_dict(self):
11261124
"""Returns the `self.json` field data as a dict."""

onadata/apps/main/tests/test_base.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from django.test import RequestFactory, TransactionTestCase
2222
from django.test.client import Client
2323
from django.utils import timezone
24+
from django.utils.encoding import smart_str
2425

2526
from django_digest.test import Client as DigestClient
2627
from django_digest.test import DigestAuth
@@ -152,9 +153,9 @@ def _publish_xlsx_file_with_external_choices(self, form_version="v1"):
152153
# make sure publishing the survey worked
153154
self.assertEqual(XForm.objects.count(), pre_count + 1)
154155

155-
def _publish_xls_file_and_set_xform(self, path):
156+
def _publish_xls_file_and_set_xform(self, path, user=None):
156157
count = XForm.objects.count()
157-
self._publish_xls_file(path)
158+
self._publish_xls_file(path, user)
158159
self.assertEqual(XForm.objects.count(), count + 1)
159160
# pylint: disable=attribute-defined-outside-init
160161
self.xform = XForm.objects.order_by("pk").reverse()[0]
@@ -652,18 +653,20 @@ def _publish_entity_update_form(self, user, project=None):
652653
def _encrypt_xform(self, xform, kms_key, encrypted_by=None):
653654
version = timezone.now().strftime("%Y%m%d%H%M")
654655

655-
json_dict = xform.json_dict()
656-
json_dict["public_key"] = kms_key.public_key
657-
json_dict["version"] = version
658-
659-
survey = create_survey_element_from_dict(json_dict)
656+
survey = xform.get_survey_from_xlsform()
657+
survey.public_key = kms_key.public_key
658+
survey.version = version
660659

661660
xform.json = survey.to_json_dict()
662661
xform.xml = survey.to_xml()
663662
xform.version = version
664663
xform.public_key = kms_key.public_key
665664
xform.encrypted = True
665+
xform.is_managed = True
666666
xform.save()
667667
xform.kms_keys.create(
668668
version=version, kms_key=kms_key, encrypted_by=encrypted_by
669669
)
670+
671+
def _clean_xml(self, xml):
672+
return re.sub(r">\s+<", "><", smart_str(xml.strip()))

onadata/libs/kms/tools.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
XForm,
4343
XFormKey,
4444
)
45-
from onadata.apps.logger.models.xform import create_survey_element_from_dict
4645
from onadata.libs.exceptions import DecryptionError, EncryptionError
4746
from onadata.libs.permissions import is_organization
4847
from onadata.libs.utils.cache_tools import (
@@ -310,11 +309,9 @@ def _invalidate_xform_list_cache(xform: XForm):
310309
def _encrypt_xform(xform, kms_key, encrypted_by=None):
311310
version = timezone.now().strftime("%Y%m%d%H%M")
312311

313-
json_dict = xform.json_dict()
314-
json_dict["public_key"] = kms_key.public_key
315-
json_dict["version"] = version
316-
317-
survey = create_survey_element_from_dict(json_dict)
312+
survey = xform.get_survey_from_xlsform()
313+
survey.public_key = kms_key.public_key
314+
survey.version = version
318315

319316
xform.json = survey.to_json_dict()
320317
xform.xml = survey.to_xml()
@@ -615,11 +612,9 @@ def disable_xform_encryption(xform, disabled_by=None) -> None:
615612

616613
new_version = timezone.now().strftime("%Y%m%d%H%M")
617614

618-
json_dict = xform.json_dict()
619-
json_dict["version"] = new_version
620-
del json_dict["public_key"]
621-
622-
survey = create_survey_element_from_dict(json_dict)
615+
survey = xform.get_survey_from_xlsform()
616+
survey.public_key = None
617+
survey.version = new_version
623618

624619
xform.json = survey.to_json_dict()
625620
xform.xml = survey.to_xml()

0 commit comments

Comments
 (0)