diff --git a/datasette/views/database.py b/datasette/views/database.py index 025e853d60..00fbc0b010 100644 --- a/datasette/views/database.py +++ b/datasette/views/database.py @@ -131,9 +131,14 @@ class DatabaseDownload(DataView): name = "database_download" async def view_get(self, request, database, hash, correct_hash_present, **kwargs): - await self.check_permission(request, "view-instance") - await self.check_permission(request, "view-database", database) - await self.check_permission(request, "view-database-download", database) + await self.check_permissions( + request, + [ + ("view-database-download", database), + ("view-database", database), + "view-instance", + ], + ) if database not in self.ds.databases: raise DatasetteError("Invalid database", status=404) db = self.ds.databases[database] diff --git a/tests/plugins/my_plugin.py b/tests/plugins/my_plugin.py index 0870eb19d7..0dd0ad2692 100644 --- a/tests/plugins/my_plugin.py +++ b/tests/plugins/my_plugin.py @@ -193,6 +193,8 @@ def permission_allowed(actor, action): return True elif action == "this_is_denied": return False + elif action == "view-database-download": + return (actor and actor.get("can_download")) or None @hookimpl diff --git a/tests/test_permissions.py b/tests/test_permissions.py index 3c11985cdb..a935a49512 100644 --- a/tests/test_permissions.py +++ b/tests/test_permissions.py @@ -394,7 +394,7 @@ def test_view_instance(path, view_instance_client): @pytest.fixture(scope="session") def cascade_app_client(): - with make_app_client() as client: + with make_app_client(is_immutable=True) as client: yield client @@ -439,6 +439,11 @@ def cascade_app_client(): ("/fixtures", [], 403), ("/fixtures", ["instance"], 403), ("/fixtures", ["database"], 200), + # Downloading the fixtures.db file + ("/fixtures.db", [], 403), + ("/fixtures.db", ["instance"], 403), + ("/fixtures.db", ["database"], 200), + ("/fixtures.db", ["download"], 200), ], ) def test_permissions_cascade(cascade_app_client, path, permissions, expected_status): @@ -447,6 +452,9 @@ def test_permissions_cascade(cascade_app_client, path, permissions, expected_sta deny = {} previous_metadata = cascade_app_client.ds._metadata updated_metadata = copy.deepcopy(previous_metadata) + actor = {"id": "test"} + if "download" in permissions: + actor["can_download"] = 1 try: # Set up the different allow blocks updated_metadata["allow"] = allow if "instance" in permissions else deny @@ -462,7 +470,7 @@ def test_permissions_cascade(cascade_app_client, path, permissions, expected_sta cascade_app_client.ds._metadata = updated_metadata response = cascade_app_client.get( path, - cookies={"ds_actor": cascade_app_client.actor_cookie({"id": "test"})}, + cookies={"ds_actor": cascade_app_client.actor_cookie(actor)}, ) assert expected_status == response.status finally: