/-/allow-debug tool, closes #908

pull/910/head
Simon Willison 2020-07-24 15:54:41 -07:00
rodzic 6be5654ffa
commit 12c0bc09cc
5 zmienionych plików z 125 dodań i 0 usunięć

Wyświetl plik

@ -35,6 +35,7 @@ from .views.special import (
PatternPortfolioView,
AuthTokenView,
LogoutView,
AllowDebugView,
PermissionsDebugView,
MessagesDebugView,
)
@ -869,6 +870,9 @@ class Datasette:
add_route(
MessagesDebugView.as_view(self), r"/-/messages$",
)
add_route(
AllowDebugView.as_view(self), r"/-/allow-debug$",
)
add_route(
PatternPortfolioView.as_view(self), r"/-/patterns$",
)

Wyświetl plik

@ -0,0 +1,58 @@
{% extends "base.html" %}
{% block title %}Debug allow rules{% endblock %}
{% block extra_head %}
<style>
textarea {
height: 8em;
width: 95%;
box-sizing: border-box;
padding: 0.5em;
border: 2px dotted black;
}
.two-col {
display: inline-block;
width: 48%;
}
.two-col label {
width: 48%;
}
p.message-warning {
white-space: pre-wrap;
}
@media only screen and (max-width: 576px) {
.two-col {
width: 100%;
}
}
</style>
{% endblock %}
{% block content %}
<h1>Debug allow rules</h1>
<p>Use this tool to try out different actor and allow combinations. See <a href="https://datasette.readthedocs.io/en/stable/authentication.html#defining-permissions-with-allow-blocks">Defining permissions with "allow" blocks</a> for documentation.</p>
<form action="/-/allow-debug" method="get">
<div class="two-col">
<p><label>Actor</label></p>
<textarea name="actor">{{ actor_input }}</textarea>
</div>
<div class="two-col">
<p><label>Allow block</label></p>
<textarea name="allow">{{ allow_input }}</textarea>
</div>
<div style="margin-top: 1em;">
<input type="submit" value="Apply allow block to actor">
</div>
</form>
{% if error %}<p class="message-warning">{{ error }}</p>{% endif %}
{% if result == "True" %}<p class="message-info">Result: allow</p>{% endif %}
{% if result == "False" %}<p class="message-error">Result: deny</p>{% endif %}
{% endblock %}

Wyświetl plik

@ -1,5 +1,6 @@
import json
from datasette.utils.asgi import Response, Forbidden
from datasette.utils import actor_matches_allow
from .base import BaseView
import secrets
@ -107,6 +108,43 @@ class PermissionsDebugView(BaseView):
)
class AllowDebugView(BaseView):
name = "allow_debug"
def __init__(self, datasette):
self.ds = datasette
async def get(self, request):
errors = []
actor_input = request.args.get("actor") or '{"id": "root"}'
try:
actor = json.loads(actor_input)
actor_input = json.dumps(actor, indent=4)
except json.decoder.JSONDecodeError as ex:
errors.append("Actor JSON error: {}".format(ex))
allow_input = request.args.get("allow") or '{"id": "*"}'
try:
allow = json.loads(allow_input)
allow_input = json.dumps(allow, indent=4)
except json.decoder.JSONDecodeError as ex:
errors.append("Allow JSON error: {}".format(ex))
result = None
if not errors:
result = str(actor_matches_allow(actor, allow))
return await self.render(
["allow_debug.html"],
request,
{
"result": result,
"error": "\n\n".join(errors) if errors else "",
"actor_input": actor_input,
"allow_input": allow_input,
},
)
class MessagesDebugView(BaseView):
name = "messages_debug"

Wyświetl plik

@ -157,6 +157,13 @@ You can specify that unauthenticated actors (from anynomous HTTP requests) shoul
Allow keys act as an "or" mechanism. An actor will be able to execute the query if any of their JSON properties match any of the values in the corresponding lists in the ``allow`` block.
.. _AllowDebugView:
The /-/allow-debug tool
-----------------------
The ``/-/allow-debug`` tool lets you try out different ``"action"`` blocks against different ``"actor"`` JSON objects. You can try that out here: https://latest.datasette.io/-/allow-debug
.. _authentication_permissions_metadata:
Configuring permissions in metadata.json

Wyświetl plik

@ -2,6 +2,7 @@ from .fixtures import app_client, assert_permissions_checked, make_app_client
from bs4 import BeautifulSoup as Soup
import copy
import pytest
import urllib
@pytest.mark.parametrize(
@ -312,6 +313,23 @@ def test_permissions_debug(app_client):
] == checks
@pytest.mark.parametrize(
"actor,allow,expected_fragment",
[
('{"id":"root"}', "{}", "Result: deny"),
('{"id":"root"}', '{"id": "*"}', "Result: allow"),
('{"', '{"id": "*"}', "Actor JSON error"),
('{"id":"root"}', '"*"}', "Allow JSON error"),
],
)
def test_allow_debug(app_client, actor, allow, expected_fragment):
response = app_client.get(
"/-/allow-debug?" + urllib.parse.urlencode({"actor": actor, "allow": allow})
)
assert 200 == response.status
assert expected_fragment in response.text
@pytest.mark.parametrize(
"allow,expected",
[({"id": "root"}, 403), ({"id": "root", "unauthenticated": True}, 200),],