diff --git a/datasette/app.py b/datasette/app.py index 87e542c18a..c12e0af0cd 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -465,7 +465,7 @@ def _show_messages(self, request): return [] async def permission_allowed( - self, actor, action, resource_type=None, resource_identifier=None, default=False + self, actor, action, resource_identifier=None, default=False ): "Check permissions using the permissions_allowed plugin hook" result = None @@ -473,7 +473,6 @@ async def permission_allowed( datasette=self, actor=actor, action=action, - resource_type=resource_type, resource_identifier=resource_identifier, ): if callable(check): @@ -491,7 +490,6 @@ async def permission_allowed( "when": datetime.datetime.utcnow().isoformat(), "actor": actor, "action": action, - "resource_type": resource_type, "resource_identifier": resource_identifier, "used_default": used_default, "result": result, diff --git a/datasette/default_permissions.py b/datasette/default_permissions.py index dd1770a347..d27704aa35 100644 --- a/datasette/default_permissions.py +++ b/datasette/default_permissions.py @@ -3,7 +3,7 @@ @hookimpl -def permission_allowed(datasette, actor, action, resource_type, resource_identifier): +def permission_allowed(datasette, actor, action, resource_identifier): if action == "permissions-debug": if actor and actor.get("id") == "root": return True @@ -12,13 +12,11 @@ def permission_allowed(datasette, actor, action, resource_type, resource_identif if allow is not None: return actor_matches_allow(actor, allow) elif action == "view-database": - assert resource_type == "database" database_allow = datasette.metadata("allow", database=resource_identifier) if database_allow is None: return True return actor_matches_allow(actor, database_allow) elif action == "view-table": - assert resource_type == "table" database, table = resource_identifier tables = datasette.metadata("tables", database=database) or {} table_allow = (tables.get(table) or {}).get("allow") @@ -27,7 +25,6 @@ def permission_allowed(datasette, actor, action, resource_type, resource_identif return actor_matches_allow(actor, table_allow) elif action == "view-query": # Check if this query has a "allow" block in metadata - assert resource_type == "query" database, query_name = resource_identifier queries_metadata = datasette.metadata("queries", database=database) assert query_name in queries_metadata diff --git a/datasette/hookspecs.py b/datasette/hookspecs.py index 71d06661fc..3c202553fd 100644 --- a/datasette/hookspecs.py +++ b/datasette/hookspecs.py @@ -66,5 +66,5 @@ def actor_from_request(datasette, request): @hookspec -def permission_allowed(datasette, actor, action, resource_type, resource_identifier): +def permission_allowed(datasette, actor, action, resource_identifier): "Check if actor is allowed to perfom this action - return True, False or None" diff --git a/datasette/templates/permissions_debug.html b/datasette/templates/permissions_debug.html index dda57dfa6f..7d3ee71206 100644 --- a/datasette/templates/permissions_debug.html +++ b/datasette/templates/permissions_debug.html @@ -46,8 +46,8 @@
Actor: {{ check.actor|tojson }}
- {% if check.resource_type %} -Resource: {{ check.resource_type }} = {{ check.resource_identifier }}
+ {% if check.resource_identifier %} +Resource: {{ check.resource_identifier }}
{% endif %} {% endfor %} diff --git a/datasette/utils/__init__.py b/datasette/utils/__init__.py index 3d964049ad..257d1285c1 100644 --- a/datasette/utils/__init__.py +++ b/datasette/utils/__init__.py @@ -876,24 +876,14 @@ def actor_matches_allow(actor, allow): return False -async def check_visibility( - datasette, actor, action, resource_type, resource_identifier, default=True -): +async def check_visibility(datasette, actor, action, resource_identifier, default=True): "Returns (visible, private) - visible = can you see it, private = can others see it too" visible = await datasette.permission_allowed( - actor, - action, - resource_type=resource_type, - resource_identifier=resource_identifier, - default=default, + actor, action, resource_identifier=resource_identifier, default=default, ) if not visible: return (False, False) private = not await datasette.permission_allowed( - None, - action, - resource_type=resource_type, - resource_identifier=resource_identifier, - default=default, + None, action, resource_identifier=resource_identifier, default=default, ) return visible, private diff --git a/datasette/views/base.py b/datasette/views/base.py index 000d354b2e..2ca5e86ac5 100644 --- a/datasette/views/base.py +++ b/datasette/views/base.py @@ -64,13 +64,10 @@ async def head(self, *args, **kwargs): response.body = b"" return response - async def check_permission( - self, request, action, resource_type=None, resource_identifier=None - ): + async def check_permission(self, request, action, resource_identifier=None): ok = await self.ds.permission_allowed( request.actor, action, - resource_type=resource_type, resource_identifier=resource_identifier, default=True, ) diff --git a/datasette/views/database.py b/datasette/views/database.py index 824cb6321d..d562ecb1ab 100644 --- a/datasette/views/database.py +++ b/datasette/views/database.py @@ -21,7 +21,7 @@ class DatabaseView(DataView): async def data(self, request, database, hash, default_labels=False, _size=None): await self.check_permission(request, "view-instance") - await self.check_permission(request, "view-database", "database", database) + await self.check_permission(request, "view-database", database) metadata = (self.ds.metadata("databases") or {}).get(database, {}) self.ds.update_with_inherited_metadata(metadata) @@ -43,7 +43,7 @@ async def data(self, request, database, hash, default_labels=False, _size=None): views = [] for view_name in await db.view_names(): visible, private = await check_visibility( - self.ds, request.actor, "view-table", "table", (database, view_name), + self.ds, request.actor, "view-table", (database, view_name), ) if visible: views.append( @@ -53,7 +53,7 @@ async def data(self, request, database, hash, default_labels=False, _size=None): tables = [] for table in table_counts: visible, private = await check_visibility( - self.ds, request.actor, "view-table", "table", (database, table), + self.ds, request.actor, "view-table", (database, table), ) if not visible: continue @@ -75,11 +75,7 @@ async def data(self, request, database, hash, default_labels=False, _size=None): canned_queries = [] for query in self.ds.get_canned_queries(database): visible, private = await check_visibility( - self.ds, - request.actor, - "view-query", - "query", - (database, query["name"]), + self.ds, request.actor, "view-query", (database, query["name"]), ) if visible: canned_queries.append(dict(query, private=private)) @@ -112,10 +108,8 @@ class DatabaseDownload(DataView): 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", database) - await self.check_permission( - request, "view-database-download", "database", database - ) + await self.check_permission(request, "view-database", database) + await self.check_permission(request, "view-database-download", database) if database not in self.ds.databases: raise DatasetteError("Invalid database", status=404) db = self.ds.databases[database] @@ -155,17 +149,15 @@ async def data( # Respect canned query permissions await self.check_permission(request, "view-instance") - await self.check_permission(request, "view-database", "database", database) + await self.check_permission(request, "view-database", database) private = False if canned_query: - await self.check_permission( - request, "view-query", "query", (database, canned_query) - ) + await self.check_permission(request, "view-query", (database, canned_query)) private = not await self.ds.permission_allowed( - None, "view-query", "query", (database, canned_query), default=True + None, "view-query", (database, canned_query), default=True ) else: - await self.check_permission(request, "execute-sql", "database", database) + await self.check_permission(request, "execute-sql", database) # Extract any :named parameters named_parameters = named_parameters or self.re_named_parameter.findall(sql) named_parameter_values = { diff --git a/datasette/views/index.py b/datasette/views/index.py index a3e8388cf0..b2706251a3 100644 --- a/datasette/views/index.py +++ b/datasette/views/index.py @@ -26,7 +26,7 @@ async def get(self, request, as_format): databases = [] for name, db in self.ds.databases.items(): visible, database_private = await check_visibility( - self.ds, request.actor, "view-database", "database", name, + self.ds, request.actor, "view-database", name, ) if not visible: continue @@ -36,7 +36,7 @@ async def get(self, request, as_format): views = [] for view_name in await db.view_names(): visible, private = await check_visibility( - self.ds, request.actor, "view-table", "table", (name, view_name), + self.ds, request.actor, "view-table", (name, view_name), ) if visible: views.append({"name": view_name, "private": private}) @@ -52,7 +52,7 @@ async def get(self, request, as_format): tables = {} for table in table_names: visible, private = await check_visibility( - self.ds, request.actor, "view-table", "table", (name, table), + self.ds, request.actor, "view-table", (name, table), ) if not visible: continue diff --git a/datasette/views/table.py b/datasette/views/table.py index cd95256861..4cec0cda8c 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -268,11 +268,11 @@ async def data( raise NotFound("Table not found: {}".format(table)) await self.check_permission(request, "view-instance") - await self.check_permission(request, "view-database", "database", database) - await self.check_permission(request, "view-table", "table", (database, table)) + await self.check_permission(request, "view-database", database) + await self.check_permission(request, "view-table", (database, table)) private = not await self.ds.permission_allowed( - None, "view-table", "table", (database, table), default=True + None, "view-table", (database, table), default=True ) pks = await db.primary_keys(table) @@ -854,8 +854,8 @@ class RowView(RowTableShared): async def data(self, request, database, hash, table, pk_path, default_labels=False): pk_values = urlsafe_components(pk_path) await self.check_permission(request, "view-instance") - await self.check_permission(request, "view-database", "database", database) - await self.check_permission(request, "view-table", "table", (database, table)) + await self.check_permission(request, "view-database", database) + await self.check_permission(request, "view-table", (database, table)) db = self.ds.databases[database] pks = await db.primary_keys(table) use_rowid = not pks diff --git a/docs/authentication.rst b/docs/authentication.rst index bda6a0b7ee..67112969c2 100644 --- a/docs/authentication.rst +++ b/docs/authentication.rst @@ -52,7 +52,7 @@ The URL on the first line includes a one-use token which can be used to sign in Permissions =========== -Datasette plugins can check if an actor has permission to perform an action using the :ref:`datasette.permission_allowed(...)