mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Migrate all view files to use new allowed() method with Resource objects
- Converted all permission_allowed() calls to allowed() - Use proper Resource objects (InstanceResource, DatabaseResource, TableResource) - Removed explicit InstanceResource() parameters where default applies - Updated PermissionRulesView to use build_permission_rules_sql() helper
This commit is contained in:
parent
224084facc
commit
a0659075a3
6 changed files with 81 additions and 68 deletions
|
|
@ -1,4 +1,5 @@
|
|||
from datasette import hookimpl
|
||||
from datasette.resources import DatabaseResource
|
||||
from datasette.views.base import DatasetteError
|
||||
from datasette.utils.asgi import BadRequest
|
||||
import json
|
||||
|
|
@ -13,10 +14,10 @@ def where_filters(request, database, datasette):
|
|||
where_clauses = []
|
||||
extra_wheres_for_ui = []
|
||||
if "_where" in request.args:
|
||||
if not await datasette.permission_allowed(
|
||||
request.actor,
|
||||
"execute-sql",
|
||||
resource=database,
|
||||
if not await datasette.allowed(
|
||||
action="execute-sql",
|
||||
resource=DatabaseResource(database=database),
|
||||
actor=request.actor,
|
||||
default=True,
|
||||
):
|
||||
raise DatasetteError("_where= is not allowed", status=403)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from typing import List
|
|||
|
||||
from datasette.events import AlterTableEvent, CreateTableEvent, InsertRowsEvent
|
||||
from datasette.database import QueryInterrupted
|
||||
from datasette.resources import DatabaseResource
|
||||
from datasette.utils import (
|
||||
add_cors_headers,
|
||||
await_me_maybe,
|
||||
|
|
@ -119,8 +120,8 @@ class DatabaseView(View):
|
|||
|
||||
attached_databases = [d.name for d in await db.attached_databases()]
|
||||
|
||||
allow_execute_sql = await datasette.permission_allowed(
|
||||
request.actor, "execute-sql", database
|
||||
allow_execute_sql = await datasette.allowed(
|
||||
action="execute-sql", resource=DatabaseResource(database=database), actor=request.actor
|
||||
)
|
||||
json_data = {
|
||||
"database": database,
|
||||
|
|
@ -729,8 +730,8 @@ class QueryView(View):
|
|||
path_with_format(request=request, format=key)
|
||||
)
|
||||
|
||||
allow_execute_sql = await datasette.permission_allowed(
|
||||
request.actor, "execute-sql", database
|
||||
allow_execute_sql = await datasette.allowed(
|
||||
action="execute-sql", resource=DatabaseResource(database=database), actor=request.actor
|
||||
)
|
||||
|
||||
show_hide_hidden = ""
|
||||
|
|
@ -940,8 +941,8 @@ class TableCreateView(BaseView):
|
|||
database_name = db.name
|
||||
|
||||
# Must have create-table permission
|
||||
if not await self.ds.permission_allowed(
|
||||
request.actor, "create-table", resource=database_name
|
||||
if not await self.ds.allowed(
|
||||
action="create-table", resource=DatabaseResource(database=database_name), actor=request.actor
|
||||
):
|
||||
return _error(["Permission denied"], 403)
|
||||
|
||||
|
|
@ -977,8 +978,8 @@ class TableCreateView(BaseView):
|
|||
|
||||
if replace:
|
||||
# Must have update-row permission
|
||||
if not await self.ds.permission_allowed(
|
||||
request.actor, "update-row", resource=database_name
|
||||
if not await self.ds.allowed(
|
||||
action="update-row", resource=DatabaseResource(database=database_name), actor=request.actor
|
||||
):
|
||||
return _error(["Permission denied: need update-row"], 403)
|
||||
|
||||
|
|
@ -1001,8 +1002,8 @@ class TableCreateView(BaseView):
|
|||
|
||||
if rows or row:
|
||||
# Must have insert-row permission
|
||||
if not await self.ds.permission_allowed(
|
||||
request.actor, "insert-row", resource=database_name
|
||||
if not await self.ds.allowed(
|
||||
action="insert-row", resource=DatabaseResource(database=database_name), actor=request.actor
|
||||
):
|
||||
return _error(["Permission denied: need insert-row"], 403)
|
||||
|
||||
|
|
@ -1014,8 +1015,8 @@ class TableCreateView(BaseView):
|
|||
else:
|
||||
# alter=True only if they request it AND they have permission
|
||||
if data.get("alter"):
|
||||
if not await self.ds.permission_allowed(
|
||||
request.actor, "alter-table", resource=database_name
|
||||
if not await self.ds.allowed(
|
||||
action="alter-table", resource=DatabaseResource(database=database_name), actor=request.actor
|
||||
):
|
||||
return _error(["Permission denied: need alter-table"], 403)
|
||||
alter = True
|
||||
|
|
|
|||
|
|
@ -177,8 +177,8 @@ class IndexView(BaseView):
|
|||
"databases": databases,
|
||||
"metadata": await self.ds.get_instance_metadata(),
|
||||
"datasette_version": __version__,
|
||||
"private": not await self.ds.permission_allowed(
|
||||
None, "view-instance"
|
||||
"private": not await self.ds.allowed(
|
||||
action="view-instance", actor=None
|
||||
),
|
||||
"top_homepage": make_slot_function(
|
||||
"top_homepage", self.ds, request
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from datasette.utils.asgi import NotFound, Forbidden, Response
|
||||
from datasette.database import QueryInterrupted
|
||||
from datasette.events import UpdateRowEvent, DeleteRowEvent
|
||||
from datasette.resources import TableResource
|
||||
from .base import DataView, BaseView, _error
|
||||
from datasette.utils import (
|
||||
await_me_maybe,
|
||||
|
|
@ -184,8 +185,8 @@ async def _resolve_row_and_check_permission(datasette, request, permission):
|
|||
return False, _error(["Record not found: {}".format(e.pk_values)], 404)
|
||||
|
||||
# Ensure user has permission to delete this row
|
||||
if not await datasette.permission_allowed(
|
||||
request.actor, permission, resource=(resolved.db.name, resolved.table)
|
||||
if not await datasette.allowed(
|
||||
action=permission, resource=TableResource(database=resolved.db.name, table=resolved.table), actor=request.actor
|
||||
):
|
||||
return False, _error(["Permission denied"], 403)
|
||||
|
||||
|
|
@ -257,8 +258,8 @@ class RowUpdateView(BaseView):
|
|||
update = data["update"]
|
||||
|
||||
alter = data.get("alter")
|
||||
if alter and not await self.ds.permission_allowed(
|
||||
request.actor, "alter-table", resource=(resolved.db.name, resolved.table)
|
||||
if alter and not await self.ds.allowed(
|
||||
action="alter-table", resource=TableResource(database=resolved.db.name, table=resolved.table), actor=request.actor
|
||||
):
|
||||
return _error(["Permission denied for alter-table"], 403)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
import logging
|
||||
from datasette.events import LogoutEvent, LoginEvent, CreateTokenEvent
|
||||
from datasette.resources import DatabaseResource, TableResource, InstanceResource
|
||||
from datasette.utils.asgi import Response, Forbidden
|
||||
from datasette.utils import (
|
||||
actor_matches_allow,
|
||||
|
|
@ -112,7 +113,7 @@ class PermissionsDebugView(BaseView):
|
|||
|
||||
async def get(self, request):
|
||||
await self.ds.ensure_permissions(request.actor, ["view-instance"])
|
||||
if not await self.ds.permission_allowed(request.actor, "permissions-debug"):
|
||||
if not await self.ds.allowed(action="permissions-debug", actor=request.actor):
|
||||
raise Forbidden("Permission denied")
|
||||
filter_ = request.args.get("filter") or "all"
|
||||
permission_checks = list(reversed(self.ds._permission_checks))
|
||||
|
|
@ -151,29 +152,31 @@ class PermissionsDebugView(BaseView):
|
|||
|
||||
async def post(self, request):
|
||||
await self.ds.ensure_permissions(request.actor, ["view-instance"])
|
||||
if not await self.ds.permission_allowed(request.actor, "permissions-debug"):
|
||||
if not await self.ds.allowed(action="permissions-debug", actor=request.actor):
|
||||
raise Forbidden("Permission denied")
|
||||
vars = await request.post_vars()
|
||||
actor = json.loads(vars["actor"])
|
||||
permission = vars["permission"]
|
||||
resource_1 = vars["resource_1"]
|
||||
resource_2 = vars["resource_2"]
|
||||
resource = []
|
||||
if resource_1:
|
||||
resource.append(resource_1)
|
||||
if resource_2:
|
||||
resource.append(resource_2)
|
||||
resource = tuple(resource)
|
||||
if len(resource) == 1:
|
||||
resource = resource[0]
|
||||
result = await self.ds.permission_allowed(
|
||||
actor, permission, resource, default="USE_DEFAULT"
|
||||
# Convert to Resource object
|
||||
if resource_1 and resource_2:
|
||||
resource_obj = TableResource(database=resource_1, table=resource_2)
|
||||
resource_for_response = (resource_1, resource_2)
|
||||
elif resource_1:
|
||||
resource_obj = DatabaseResource(database=resource_1)
|
||||
resource_for_response = resource_1
|
||||
else:
|
||||
resource_obj = InstanceResource()
|
||||
resource_for_response = None
|
||||
result = await self.ds.allowed(
|
||||
action=permission, resource=resource_obj, actor=actor
|
||||
)
|
||||
return Response.json(
|
||||
{
|
||||
"actor": actor,
|
||||
"permission": permission,
|
||||
"resource": resource,
|
||||
"resource": resource_for_response,
|
||||
"result": result,
|
||||
"default": self.ds.permissions[permission].default,
|
||||
}
|
||||
|
|
@ -204,8 +207,8 @@ class AllowedResourcesView(BaseView):
|
|||
await self.ds.refresh_schemas()
|
||||
|
||||
# Check if user has permissions-debug (to show sensitive fields)
|
||||
has_debug_permission = await self.ds.permission_allowed(
|
||||
request.actor, "permissions-debug"
|
||||
has_debug_permission = await self.ds.allowed(
|
||||
action="permissions-debug", actor=request.actor
|
||||
)
|
||||
|
||||
# Check if this is a request for JSON (has .json extension)
|
||||
|
|
@ -360,7 +363,7 @@ class PermissionRulesView(BaseView):
|
|||
|
||||
async def get(self, request):
|
||||
await self.ds.ensure_permissions(request.actor, ["view-instance"])
|
||||
if not await self.ds.permission_allowed(request.actor, "permissions-debug"):
|
||||
if not await self.ds.allowed(action="permissions-debug", actor=request.actor):
|
||||
raise Forbidden("Permission denied")
|
||||
|
||||
# Check if this is a request for JSON (has .json extension)
|
||||
|
|
@ -401,8 +404,10 @@ class PermissionRulesView(BaseView):
|
|||
page_size = max_page_size
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
union_sql, union_params = await self.ds._build_permission_rules_sql(
|
||||
actor, action
|
||||
from datasette.utils.actions_sql import build_permission_rules_sql
|
||||
|
||||
union_sql, union_params = await build_permission_rules_sql(
|
||||
self.ds, actor, action
|
||||
)
|
||||
await self.ds.refresh_schemas()
|
||||
db = self.ds.get_internal_database()
|
||||
|
|
@ -482,8 +487,8 @@ class PermissionCheckView(BaseView):
|
|||
|
||||
async def get(self, request):
|
||||
# Check if user has permissions-debug (to show sensitive fields)
|
||||
has_debug_permission = await self.ds.permission_allowed(
|
||||
request.actor, "permissions-debug"
|
||||
has_debug_permission = await self.ds.allowed(
|
||||
action="permissions-debug", actor=request.actor
|
||||
)
|
||||
|
||||
# Check if this is a request for JSON (has .json extension)
|
||||
|
|
@ -513,15 +518,19 @@ class PermissionCheckView(BaseView):
|
|||
{"error": "parent is required when child is provided"}, status=400
|
||||
)
|
||||
|
||||
# Convert to Resource object
|
||||
if parent and child:
|
||||
resource_obj = TableResource(database=parent, table=child)
|
||||
resource = (parent, child)
|
||||
elif parent:
|
||||
resource_obj = DatabaseResource(database=parent)
|
||||
resource = parent
|
||||
else:
|
||||
resource_obj = InstanceResource()
|
||||
resource = None
|
||||
|
||||
before_checks = len(self.ds._permission_checks)
|
||||
allowed = await self.ds.permission_allowed_2(request.actor, action, resource)
|
||||
allowed = await self.ds.allowed(action=action, resource=resource_obj, actor=request.actor)
|
||||
|
||||
info = None
|
||||
if len(self.ds._permission_checks) > before_checks:
|
||||
|
|
@ -642,8 +651,8 @@ class CreateTokenView(BaseView):
|
|||
for database in self.ds.databases.values():
|
||||
if database.name == "_memory":
|
||||
continue
|
||||
if not await self.ds.permission_allowed(
|
||||
request.actor, "view-database", database.name
|
||||
if not await self.ds.allowed(
|
||||
action="view-database", resource=DatabaseResource(database=database.name), actor=request.actor
|
||||
):
|
||||
continue
|
||||
hidden_tables = await database.hidden_table_names()
|
||||
|
|
@ -651,10 +660,10 @@ class CreateTokenView(BaseView):
|
|||
for table in await database.table_names():
|
||||
if table in hidden_tables:
|
||||
continue
|
||||
if not await self.ds.permission_allowed(
|
||||
request.actor,
|
||||
"view-table",
|
||||
resource=(database.name, table),
|
||||
if not await self.ds.allowed(
|
||||
action="view-table",
|
||||
resource=TableResource(database=database.name, table=table),
|
||||
actor=request.actor
|
||||
):
|
||||
continue
|
||||
tables.append({"name": table, "encoded": tilde_encode(table)})
|
||||
|
|
@ -795,8 +804,8 @@ class ApiExplorerView(BaseView):
|
|||
if not db.is_mutable:
|
||||
continue
|
||||
|
||||
if await self.ds.permission_allowed(
|
||||
request.actor, "insert-row", (name, table)
|
||||
if await self.ds.allowed(
|
||||
action="insert-row", resource=TableResource(database=name, table=table), actor=request.actor
|
||||
):
|
||||
pks = await db.primary_keys(table)
|
||||
table_links.extend(
|
||||
|
|
@ -831,8 +840,8 @@ class ApiExplorerView(BaseView):
|
|||
},
|
||||
]
|
||||
)
|
||||
if await self.ds.permission_allowed(
|
||||
request.actor, "drop-table", (name, table)
|
||||
if await self.ds.allowed(
|
||||
action="drop-table", resource=TableResource(database=name, table=table), actor=request.actor
|
||||
):
|
||||
table_links.append(
|
||||
{
|
||||
|
|
@ -844,7 +853,7 @@ class ApiExplorerView(BaseView):
|
|||
)
|
||||
database_links = []
|
||||
if (
|
||||
await self.ds.permission_allowed(request.actor, "create-table", name)
|
||||
await self.ds.allowed(action="create-table", resource=DatabaseResource(database=name), actor=request.actor)
|
||||
and db.is_mutable
|
||||
):
|
||||
database_links.append(
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ from datasette.events import (
|
|||
UpsertRowsEvent,
|
||||
)
|
||||
from datasette import tracer
|
||||
from datasette.resources import DatabaseResource, TableResource
|
||||
from datasette.utils import (
|
||||
add_cors_headers,
|
||||
await_me_maybe,
|
||||
|
|
@ -449,11 +450,11 @@ class TableInsertView(BaseView):
|
|||
if upsert:
|
||||
# Must have insert-row AND upsert-row permissions
|
||||
if not (
|
||||
await self.ds.permission_allowed(
|
||||
request.actor, "insert-row", resource=(database_name, table_name)
|
||||
await self.ds.allowed(
|
||||
action="insert-row", resource=TableResource(database=database_name, table=table_name), actor=request.actor
|
||||
)
|
||||
and await self.ds.permission_allowed(
|
||||
request.actor, "update-row", resource=(database_name, table_name)
|
||||
and await self.ds.allowed(
|
||||
action="update-row", resource=TableResource(database=database_name, table=table_name), actor=request.actor
|
||||
)
|
||||
):
|
||||
return _error(
|
||||
|
|
@ -461,8 +462,8 @@ class TableInsertView(BaseView):
|
|||
)
|
||||
else:
|
||||
# Must have insert-row permission
|
||||
if not await self.ds.permission_allowed(
|
||||
request.actor, "insert-row", resource=(database_name, table_name)
|
||||
if not await self.ds.allowed(
|
||||
action="insert-row", resource=TableResource(database=database_name, table=table_name), actor=request.actor
|
||||
):
|
||||
return _error(["Permission denied"], 403)
|
||||
|
||||
|
|
@ -491,16 +492,16 @@ class TableInsertView(BaseView):
|
|||
if upsert and (ignore or replace):
|
||||
return _error(["Upsert does not support ignore or replace"], 400)
|
||||
|
||||
if replace and not await self.ds.permission_allowed(
|
||||
request.actor, "update-row", resource=(database_name, table_name)
|
||||
if replace and not await self.ds.allowed(
|
||||
action="update-row", resource=TableResource(database=database_name, table=table_name), actor=request.actor
|
||||
):
|
||||
return _error(['Permission denied: need update-row to use "replace"'], 403)
|
||||
|
||||
initial_schema = None
|
||||
if alter:
|
||||
# Must have alter-table permission
|
||||
if not await self.ds.permission_allowed(
|
||||
request.actor, "alter-table", resource=(database_name, table_name)
|
||||
if not await self.ds.allowed(
|
||||
action="alter-table", resource=TableResource(database=database_name, table=table_name), actor=request.actor
|
||||
):
|
||||
return _error(["Permission denied for alter-table"], 403)
|
||||
# Track initial schema to check if it changed later
|
||||
|
|
@ -627,8 +628,8 @@ class TableDropView(BaseView):
|
|||
db = self.ds.get_database(database_name)
|
||||
if not await db.table_exists(table_name):
|
||||
return _error(["Table not found: {}".format(table_name)], 404)
|
||||
if not await self.ds.permission_allowed(
|
||||
request.actor, "drop-table", resource=(database_name, table_name)
|
||||
if not await self.ds.allowed(
|
||||
action="drop-table", resource=TableResource(database=database_name, table=table_name), actor=request.actor
|
||||
):
|
||||
return _error(["Permission denied"], 403)
|
||||
if not db.is_mutable:
|
||||
|
|
@ -914,8 +915,8 @@ async def table_view_traced(datasette, request):
|
|||
"true" if datasette.setting("allow_facet") else "false"
|
||||
),
|
||||
is_sortable=any(c["sortable"] for c in data["display_columns"]),
|
||||
allow_execute_sql=await datasette.permission_allowed(
|
||||
request.actor, "execute-sql", resolved.db.name
|
||||
allow_execute_sql=await datasette.allowed(
|
||||
action="execute-sql", resource=DatabaseResource(database=resolved.db.name), actor=request.actor
|
||||
),
|
||||
query_ms=1.2,
|
||||
select_templates=[
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue