social/barkshark_social/routes/activitypub.py
2024-04-18 22:36:06 -04:00

202 lines
5.5 KiB
Python

import asyncio
from aputils import Attachment, Message, ObjectType
from basgi import HttpError, Request, Response, router
from ..processors import process_message
def ensure_signed(request: Request) -> None:
if request.state.signature is None:
raise HttpError(400, "Missing 'signature' header")
@router.get("BarksharkSocial", "/actor")
async def handle_instance_actor_get(request: Request) -> Response:
config = request.app.state.config
with request.app.state.database.session(False) as s:
if (user := s.get_user(config.host, config.host)) is None:
raise HttpError(404, "User not found")
instance = user.get_instance(s)
actor_data = {
"id": user.actor,
"inbox": user.inbox,
"outbox": f"{user.actor}/outbox",
"preferred_username": user.username,
"url": user.page_url,
"manually_approves_followers": user.locked,
"published": user.created,
"endpoints": {
"sharedInbox": instance.shared_inbox
},
"public_key": {
"id": f"{user.actor}#main-key",
"owner": user.actor,
"publicKeyPem": user.public_key
}
}
data = Message.new(ObjectType.APPLICATION, actor_data, [
"https://w3id.org/security/v1",
{
"toot": "http://joinmastodon.org/ns#",
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value",
"publicKeyBase64": "toot:publicKeyBase64",
"messageType": "toot:messageType",
"suspended": "toot:suspended"
}
])
return Response.new_activity(200, data)
@router.post("BarksharkSocial", "/inbox")
async def handle_instance_actor_post(request: Request) -> Response:
ensure_signed(request)
with request.app.state.database.session(False) as s:
if (user := s.get_user(request.app.state.config.host)) is None:
raise HttpError(404, "User not found")
message = Message.parse(await request.body())
asyncio.create_task(process_message(request, message, user))
return Response(200, "uvu")
@router.get("BarksharkSocial", "/relay")
async def handle_relay_get(request: Request) -> Response:
with request.app.state.database.session(False) as s:
if (user := s.get_user("relay")) is None:
raise HttpError(404, "User not found")
data = Message.new_actor(
ObjectType.APPLICATION,
user.username,
user.actor,
user.public_key,
user.inbox,
published = user.created.isoformat()
)
del data["outbox"]
return Response.new_activity(200, data)
@router.post("BarksharkSocial", "/relay")
async def handle_relay_post(request: Request) -> Response:
ensure_signed(request)
with request.app.state.database.session(False) as s:
if (user := s.get_user("relay")) is None:
raise HttpError(404, "User not found")
message = Message.parse(await request.body())
asyncio.create_task(process_message(request, message, user))
return Response(200, "uvu")
@router.get("BarksharkSocial", "/user/{username}")
async def handle_actor(request: Request) -> Response:
ensure_signed(request)
config = request.app.state.config
username = request.params["username"]
if username in {config.host, "relay"}:
raise HttpError(400, "Invalid user")
with request.app.state.database.session(False) as s:
if (user := s.get_user(username, None)) is None:
raise HttpError(404, "User not found")
instance = user.get_instance(s)
data = {
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"toot": "http://joinmastodon.org/ns#",
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value",
"publicKeyBase64": "toot:publicKeyBase64",
"messageType": "toot:messageType",
"suspended": "toot:suspended"
}
],
"type": ObjectType.PERSON if not user.is_bot else ObjectType.SERVICE,
"id": user.actor,
"name": user.display_name,
"summary": user.bio,
"url": user.page_url,
"inbox": user.inbox,
"outbox": f"{user.actor}/outbox",
"preferredUsername": user.username,
"manuallyApprovesFollowers": user.locked,
"discoverable": False,
"indexable": False,
"published": user.created.to_string(),
"attachment": [],
"endpoints": {
"sharedInbox": instance.shared_inbox
},
"publicKey": {
"id": f"{user.actor}#main-key",
"owner": user.actor,
"publicKeyPem": user.public_key
}
}
for key, value in user.info.items():
data["attachment"].append(Attachment.new_field(key, value))
return Response.new_activity(200, data)
@router.post("BarksharkSocial", "/user/{username}/inbox")
async def handle_user_actor(request: Request) -> Response:
ensure_signed(request)
config = request.app.state.config
username = request.params["username"]
if username in {config.host, "relay"}:
raise HttpError(400, "Invalid user")
with request.app.state.database.session(False) as s:
if (user := s.get_user(username, config.host)) is None:
raise HttpError(404, "User not found")
message = Message.parse(await request.body())
asyncio.create_task(process_message(request, message, user))
return Response(200, "uvu")
@router.get("BarksharkSocial", "/activity/follow/{id}")
async def handle_activity_follow(request: Request) -> Response:
ensure_signed(request)
with request.app.state.database.session(False) as s:
if (follow := s.get_follow(request.params["id"])) is None:
raise HttpError(404, "Follow activity not found")
if (source := s.get_user_by_id(follow.sourceid)) is None:
raise HttpError(404, "Follow activity not found")
if (target := s.get_user_by_id(follow.targetid)) is None:
raise HttpError(404, "Follow activity not found")
data = Message.new(ObjectType.FOLLOW, {
"id": follow.followid,
"actor": source.actor,
"object": target.actor
})
return Response.new_activity(200, data)