view-database permission

Also now using 🔒 to indicate private resources - resources that
would not be available to the anonymous user. Refs #811
This commit is contained in:
Simon Willison 2020-06-07 20:50:37 -07:00
commit 9b42e1a4f5
8 changed files with 69 additions and 16 deletions

View file

@ -11,6 +11,12 @@ def permission_allowed(datasette, actor, action, resource_type, resource_identif
allow = datasette.metadata("allow")
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-query":
# Check if this query has a "allow" block in metadata
assert resource_type == "query"
@ -20,7 +26,6 @@ def permission_allowed(datasette, actor, action, resource_type, resource_identif
if isinstance(queries_metadata[query_name], str):
return True
allow = queries_metadata[query_name].get("allow")
print("checking allow - actor = {}, allow = {}".format(actor, allow))
if allow is None:
return True
return actor_matches_allow(actor, allow)

View file

@ -60,7 +60,7 @@
<h2 id="queries">Queries</h2>
<ul>
{% for query in queries %}
<li><a href="{{ database_url(database) }}/{{ query.name|urlencode }}{% if query.fragment %}#{{ query.fragment }}{% endif %}" title="{{ query.description or query.sql }}">{{ query.title or query.name }}</a> {% if query.requires_auth %} - requires authentication{% endif %}</li>
<li><a href="{{ database_url(database) }}/{{ query.name|urlencode }}{% if query.fragment %}#{{ query.fragment }}{% endif %}" title="{{ query.description or query.sql }}">{{ query.title or query.name }}</a> {% if query.private %} 🔒{% endif %}</li>
{% endfor %}
</ul>
{% endif %}

View file

@ -10,7 +10,7 @@
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
{% for database in databases %}
<h2 style="padding-left: 10px; border-left: 10px solid #{{ database.color }}"><a href="{{ database.path }}">{{ database.name }}</a></h2>
<h2 style="padding-left: 10px; border-left: 10px solid #{{ database.color }}"><a href="{{ database.path }}">{{ database.name }}</a>{% if database.private %} 🔒{% endif %}</h2>
<p>
{% if database.show_table_row_counts %}{{ "{:,}".format(database.table_rows_sum) }} rows in {% endif %}{{ database.tables_count }} table{% if database.tables_count != 1 %}s{% endif %}{% if database.tables_count and database.hidden_tables_count %}, {% endif -%}
{% if database.hidden_tables_count -%}

View file

@ -58,8 +58,7 @@ class DatabaseView(DataView):
tables.sort(key=lambda t: (t["hidden"], t["name"]))
canned_queries = [
dict(
query,
requires_auth=not actor_matches_allow(None, query.get("allow", None)),
query, private=not actor_matches_allow(None, query.get("allow", None)),
)
for query in self.ds.get_canned_queries(database)
if actor_matches_allow(

View file

@ -2,7 +2,7 @@ import hashlib
import json
from datasette.utils import CustomJSONEncoder
from datasette.utils.asgi import Response
from datasette.utils.asgi import Response, Forbidden
from datasette.version import __version__
from .base import BaseView
@ -25,6 +25,22 @@ class IndexView(BaseView):
await self.check_permission(request, "view-instance")
databases = []
for name, db in self.ds.databases.items():
# Check permission
allowed = await self.ds.permission_allowed(
request.scope.get("actor"),
"view-database",
resource_type="database",
resource_identifier=name,
default=True,
)
if not allowed:
continue
private = not await self.ds.permission_allowed(
None,
"view-database",
resource_type="database",
resource_identifier=name,
)
table_names = await db.table_names()
hidden_table_names = set(await db.hidden_table_names())
views = await db.view_names()
@ -95,6 +111,7 @@ class IndexView(BaseView):
),
"hidden_tables_count": len(hidden_tables),
"views_count": len(views),
"private": private,
}
)