diff --git a/README.rst b/README.rst index 01980a45b1..6eb4e192cb 100644 --- a/README.rst +++ b/README.rst @@ -56,6 +56,13 @@ Edit top level requirements in the file `requirements/base.in `_ into `.git/hooks/pre-commit`, it ensures staged python flake8 are in acceptable code style and conventions. + +.. code-block:: sh + + cp pre-commit.sh .git/hooks/pre-commit + chmod +x .git/hooks/pre-commit + **Security Acknowledgments** We would like to thank the following security researchers for responsibly disclosing security issues: diff --git a/onadata/apps/api/tests/viewsets/test_xform_viewset.py b/onadata/apps/api/tests/viewsets/test_xform_viewset.py index b9919cc9f5..5a2d97af39 100644 --- a/onadata/apps/api/tests/viewsets/test_xform_viewset.py +++ b/onadata/apps/api/tests/viewsets/test_xform_viewset.py @@ -751,6 +751,30 @@ def test_enketo_url(self): data = {"enketo_url": url, "enketo_preview_url": preview_url} self.assertEqual(response.data, data) + alice_data = {'username': 'alice', 'email': 'alice@localhost.com'} + alice_profile = self._create_user_profile(alice_data) + credentials = { + 'HTTP_AUTHORIZATION': ( + 'Token %s' % alice_profile.user.auth_token) + } + request = self.factory.get('/', **credentials) + response = view(request, pk=formid) + # Alice has no permissions to the form hence no access to web form + self.assertEqual(response.status_code, 404) + + # Give Alice read-only permissions to the form + ReadOnlyRole.add(alice_profile.user, self.xform) + response = view(request, pk=formid) + # Alice with read-only access should not have access to web form + self.assertEqual(response.status_code, 404) + + # Give Alice data-entry permissions + DataEntryRole.add(alice_profile.user, self.xform) + response = view(request, pk=formid) + # Alice with data-entry access should have access to web form + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data, data) + def test_get_single_submit_url(self): with HTTMock(enketo_preview_url_mock, enketo_url_mock, enketo_single_submission_mock): diff --git a/onadata/apps/api/viewsets/xform_viewset.py b/onadata/apps/api/viewsets/xform_viewset.py index f80cf0998e..da946adb0c 100644 --- a/onadata/apps/api/viewsets/xform_viewset.py +++ b/onadata/apps/api/viewsets/xform_viewset.py @@ -274,7 +274,7 @@ class XFormViewSet(AnonymousUserPublicFormsMixin, permission_classes = [XFormPermissions, ] updatable_fields = set(('description', 'downloadable', 'require_auth', 'shared', 'shared_data', 'title')) - filter_backends = (filters.AnonDjangoObjectPermissionFilter, + filter_backends = (filters.EnketoAnonDjangoObjectPermissionFilter, filters.TagFilter, filters.XFormOwnerFilter, DjangoFilterBackend) diff --git a/onadata/libs/filters.py b/onadata/libs/filters.py index 8fea1ea6a5..2f17080776 100644 --- a/onadata/libs/filters.py +++ b/onadata/libs/filters.py @@ -41,6 +41,22 @@ def filter_queryset(self, request, queryset, view): .filter_queryset(request, queryset, view) +# pylint: disable=too-few-public-methods +class EnketoAnonDjangoObjectPermissionFilter(AnonDjangoObjectPermissionFilter): + """EnketoAnonDjangoObjectPermissionFilter + + Same as AnonDjangoObjectPermissionFilter but checks 'report_xform' + permission when the view 'enketo' is accessed. + """ + + def filter_queryset(self, request, queryset, view): + """Check report_xform permission when requesting for Enketo URL.""" + if view.action == 'enketo': + self.perm_format = '%(app_label)s.report_%(model_name)s' # noqa pylint: disable=W0201 + return super(EnketoAnonDjangoObjectPermissionFilter, self)\ + .filter_queryset(request, queryset, view) + + class XFormListObjectPermissionFilter(AnonDjangoObjectPermissionFilter): perm_format = '%(app_label)s.report_%(model_name)s' diff --git a/pre-commit.sh b/pre-commit.sh new file mode 100755 index 0000000000..6d403bcc35 --- /dev/null +++ b/pre-commit.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# +# flake8 check +exec git diff --staged --name-only | grep -E '\.py$' | xargs flake8 --exclude=migrations -