Skip to content

Commit

Permalink
CreateTokenEvent, refs #2240
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Jan 31, 2024
1 parent f997cd9 commit fe9dfbf
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
28 changes: 27 additions & 1 deletion datasette/events.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from abc import ABC, abstractproperty
from dataclasses import asdict, dataclass
from datasette.hookspecs import hookimpl
from typing import Optional


@dataclass
Expand Down Expand Up @@ -39,6 +40,31 @@ class LogoutEvent(Event):
name = "logout"


@dataclass
class CreateTokenEvent(Event):
"""
Event name: ``create-token``
A user created an API token.
:ivar expires_after: Number of seconds after which this token will expire.
:type expires_after: int or None
:ivar restrict_all: Restricted permissions for this token.
:type restrict_all: list
:ivar restrict_database: Restricted database permissions for this token.
:type restrict_database: dict
:ivar restrict_resource: Restricted resource permissions for this token.
:type restrict_resource: dict
"""

name = "create-token"

expires_after: Optional[int]
restrict_all: list
restrict_database: dict
restrict_resource: dict


@dataclass
class CreateTableEvent(Event):
"""
Expand All @@ -62,4 +88,4 @@ class CreateTableEvent(Event):

@hookimpl
def register_events():
return [LoginEvent, LogoutEvent, CreateTableEvent]
return [LoginEvent, LogoutEvent, CreateTableEvent, CreateTokenEvent]
11 changes: 10 additions & 1 deletion datasette/views/special.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import json
from datasette.events import LogoutEvent, LoginEvent
from datasette.events import LogoutEvent, LoginEvent, CreateTokenEvent
from datasette.utils.asgi import Response, Forbidden
from datasette.utils import (
actor_matches_allow,
Expand Down Expand Up @@ -351,6 +351,15 @@ async def post(self, request):
restrict_resource=restrict_resource,
)
token_bits = self.ds.unsign(token[len("dstok_") :], namespace="token")
await self.ds.track_event(
CreateTokenEvent(
actor=request.actor,
expires_after=expires_after,
restrict_all=restrict_all,
restrict_database=restrict_database,
restrict_resource=restrict_resource,
)
)
context = await self.shared(request)
context.update({"errors": errors, "token": token, "token_bits": token_bits})
return await self.render(["create_token.html"], request, context)
Expand Down
7 changes: 7 additions & 0 deletions tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,13 @@ def test_auth_create_token(
for error in errors:
assert '<p class="message-error">{}</p>'.format(error) in response2.text
else:
# Check create-token event
event = last_event(app_client.ds)
assert event.name == "create-token"
assert event.expires_after == expected_duration
assert isinstance(event.restrict_all, list)
assert isinstance(event.restrict_database, dict)
assert isinstance(event.restrict_resource, dict)
# Extract token from page
token = response2.text.split('value="dstok_')[1].split('"')[0]
details = app_client.ds.unsign(token, "token")
Expand Down

0 comments on commit fe9dfbf

Please sign in to comment.