From e5b9b133fccceb37097867b3c2a45a59c34472fa Mon Sep 17 00:00:00 2001 From: Reid 'arrdem' McKenzie Date: Sat, 26 Nov 2022 19:26:39 -0700 Subject: [PATCH] Create some quick and dirty admin endpoints --- projects/activitypub_relay/relay.sh | 2 +- .../src/python/relay/__main__.py | 1 + .../src/python/relay/config.py | 1 + .../src/python/relay/misc.py | 3 +- .../src/python/relay/views.py | 77 ++++++++++++++++++- .../shoggoth/src/python/ichor/__main__.py | 6 +- .../shoggoth/src/python/shoggoth/analyzer.py | 13 +++- 7 files changed, 90 insertions(+), 13 deletions(-) diff --git a/projects/activitypub_relay/relay.sh b/projects/activitypub_relay/relay.sh index f004c74..6444e60 100755 --- a/projects/activitypub_relay/relay.sh +++ b/projects/activitypub_relay/relay.sh @@ -4,4 +4,4 @@ cd "$(realpath $(dirname $0))" bazel build ... -exec ../../bazel-bin/projects/activitypub_relay/activitypub_relay -c $(realpath ./relay.yaml) run +exec ../../bazel-bin/projects/activitypub_relay/activitypub_relay -c $(realpath ./relay_prod.yaml) run diff --git a/projects/activitypub_relay/src/python/relay/__main__.py b/projects/activitypub_relay/src/python/relay/__main__.py index 87a3fe0..699daee 100644 --- a/projects/activitypub_relay/src/python/relay/__main__.py +++ b/projects/activitypub_relay/src/python/relay/__main__.py @@ -357,6 +357,7 @@ def relay_setup(obj: Application): obj.config.listen = os.getenv("LISTEN_ADDRESS", obj.config.listen) obj.config.port = int(os.getenv("LISTEN_PORT", obj.config.port)) obj.config.host = os.getenv("RELAY_HOSTNAME") + obj.config.admin_token = os.getenv("RELAY_ADMIN_TOKEN") if not obj.config.host: click.echo("Error: No relay host configured! Set $RELAY_HOSTNAME") exit(1) diff --git a/projects/activitypub_relay/src/python/relay/config.py b/projects/activitypub_relay/src/python/relay/config.py index 431a674..b40288b 100644 --- a/projects/activitypub_relay/src/python/relay/config.py +++ b/projects/activitypub_relay/src/python/relay/config.py @@ -78,6 +78,7 @@ class RelayConfig(DotDict): "json": 1024, "objects": 1024, "digests": 1024, + "admin_token": None, } ) diff --git a/projects/activitypub_relay/src/python/relay/misc.py b/projects/activitypub_relay/src/python/relay/misc.py index 20d67c6..412185f 100644 --- a/projects/activitypub_relay/src/python/relay/misc.py +++ b/projects/activitypub_relay/src/python/relay/misc.py @@ -6,6 +6,7 @@ import logging import socket from urllib.parse import urlparse import uuid +from typing import Union from Crypto.Hash import SHA, SHA256, SHA512 from Crypto.PublicKey import RSA @@ -453,7 +454,7 @@ class Message(DotDict): class Response(AiohttpResponse): @classmethod - def new(cls, body="", status=200, headers=None, ctype="text"): + def new(cls, body: Union[dict, str, bytes] = "", status=200, headers=None, ctype="text"): kwargs = { "status": status, "headers": headers, diff --git a/projects/activitypub_relay/src/python/relay/views.py b/projects/activitypub_relay/src/python/relay/views.py index 5f11990..06b26e5 100644 --- a/projects/activitypub_relay/src/python/relay/views.py +++ b/projects/activitypub_relay/src/python/relay/views.py @@ -1,6 +1,6 @@ import logging -from aiohttp.web import HTTPUnauthorized +from aiohttp.web import HTTPUnauthorized, Request from relay import __version__, misc from relay.http_debug import STATS from relay.misc import ( @@ -148,7 +148,8 @@ async def inbox(request): @register_route("GET", "/.well-known/webfinger") async def webfinger(request): - subject = request.query["resource"] + if not (subject := request.query.get("resource")): + return Response.new_error(404, "no resource specified", "json") if subject != f"acct:relay@{request.app.config.host}": return Response.new_error(404, "user not found", "json") @@ -203,5 +204,73 @@ async def nodeinfo_wellknown(request): @register_route("GET", "/stats") -async def stats(*args, **kwargs): - return Response.new(STATS, ctype="json") +async def stats(request): + stats = STATS.copy() + stats["pending_requests"] = len(request.app.database.get("follow-requests", {})) + return Response.new(stats, ctype="json") + + +@register_route("POST", "/admin/config") +async def set_config(request: Request): + if not (auth := request.headers.get("Authorization")): + return Response.new_error(403, "access denied", "json") + + if not auth == f"Bearer {request.app.config.admin_token}": + return Response.new_error(403, "access denied", "json") + + # FIXME: config doesn't have a way to go from JSON or update, using dict stuff + new_config = await request.json() + + request.app.config.update(new_config) + + # If there are pending follows which are NOW whitelisted, allow them + if request.app.config.whitelist_enabled: + for domain in request.app.config.whitelist: + if (pending_follow := request.app.database.get_request(domain, False)): + await misc.request( + actor.shared_inbox, + misc.Message.new_response( + host=request.app.config.host, + actor=pending_follow["actor"], + followid=pending_follow["followid"], + accept=True + ), + ) + + await misc.request( + actor.shared_inbox, + misc.Message.new_follow( + host=request.app.config.host, + actor=pending_follow["actor"] + ), + ) + + request.app.database.del_request(domain) + + request.app.database.save() + + request.app.config.save() + + return Response.new(status=202) + + +@register_route("GET", "/admin/config") +def set_config(request: Request): + if not (auth := request.headers.get("Authorization")): + return Response.new_error(403, "access denied", "json") + + if not auth == f"Bearer {request.app.config.admin_token}": + return Response.new_error(403, "access denied", "json") + + return Response.new(request.app.config, status=200, ctype="json") + + +@register_route("GET", "/admin/pending") +def get_pending(request): + if not (auth := request.headers.get("Authorization")): + return Response.new_error(403, "access denied", "json") + + if not auth == f"Bearer {request.app.config.admin_token}": + return Response.new_error(403, "access denied", "json") + + return Response.new(request.app.database["follow-requests"], status=200, ctype="json") diff --git a/projects/shoggoth/src/python/ichor/__main__.py b/projects/shoggoth/src/python/ichor/__main__.py index db49042..ad3e6f6 100644 --- a/projects/shoggoth/src/python/ichor/__main__.py +++ b/projects/shoggoth/src/python/ichor/__main__.py @@ -4,12 +4,8 @@ ichor entrypoint """ -from ichor.bootstrap import ( - BOOTSTRAP, - NOT1, - TRUE, -) from ichor import isa +from ichor.bootstrap import BOOTSTRAP, NOT1, TRUE from ichor.interpreter import Interpreter diff --git a/projects/shoggoth/src/python/shoggoth/analyzer.py b/projects/shoggoth/src/python/shoggoth/analyzer.py index d11a985..8def210 100644 --- a/projects/shoggoth/src/python/shoggoth/analyzer.py +++ b/projects/shoggoth/src/python/shoggoth/analyzer.py @@ -5,6 +5,7 @@ from abc import ABC from dataclasses import dataclass import typing as t +from uuid import UUID from shoggoth.types import Keyword, List, Symbol @@ -85,12 +86,20 @@ class Multiverse: """ - soup: t.Dict[] - @dataclass class Namespace: pass + @dataclass + class Entry: + ns: "Namespace" + expr: t.Any + value: t.Any + + soup: t.Dict[UUID, Entry] = {} + + + BOOTSTRAP = "lang.shoggoth.v0.bootstrap" SPECIALS = Multiverse.Namespace(Symbol(BOOTSTRAP), {