/
inbox.py
112 lines (93 loc) · 4.16 KB
/
inbox.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import asyncio
from sanic import response, Blueprint
from sanic.log import logger
from sanic_openapi import doc
from pubgate.db import Inbox, Outbox
from pubgate.db.cached import timeline_cached
from pubgate.utils import check_origin
from pubgate.utils.networking import deliver, verify_request
from pubgate.utils.checks import user_check, token_check
from pubgate.utils.cached import ensure_inbox
from pubgate.activity import Activity
from pubgate.utils.cached import cached_mode, clear_cache
inbox_v1 = Blueprint('inbox_v1')
# @inbox_v1.middleware('response')
# async def update_headers(request, response):
# response.headers["Access-Control-Allow-Origin"] = "*"
@inbox_v1.route('/@<user>/inbox', methods=['POST'])
@doc.summary("Post to user inbox")
@doc.consumes(Inbox, location="body")
@user_check
async def inbox_post(request, user):
# TODO implement shared inbox
# TODO https://www.w3.org/TR/activitypub/#inbox-forwarding
activity = request.json.copy()
# TODO The receiver must verify the notification by fetching its source from the origin server.
verified = await verify_request(request)
if not verified:
if getattr(request.app.config, 'DEBUG_INBOX', False):
logger.info("signature incorrect")
else:
return response.json({"error": "signature incorrect"}, status=401)
# TODO skip blocked
# if Outbox.find_one(
# {
# "activity.type": "Block",
# "user_id": user_id,
# "meta.undo": False,
# }):
# return response.json({"zrada": "actor is blocked"}, status=403)
if activity["type"] == "Follow":
saved = await Inbox.save(user, activity)
if saved:
deliverance = {
"type": "Accept",
"object": activity
}
deliverance = Activity(user, deliverance)
await deliverance.save()
asyncio.ensure_future(deliver(user.key, deliverance.render, [activity["actor"]]))
elif activity["type"] in ["Announce", "Like", "Create"]:
# TODO validate if local object of reaction exists in outbox
saved = await Inbox.save(user, activity)
local_user = check_origin(activity["object"], user.uri)
if saved:
if local_user:
await user.forward_to_followers(activity)
# elif activity["type"] in ["Announce", "Like"]:
# if not check_origin(activity["object"], request.app.base_url):
# await ensure_inbox(activity['object'])
if request.app.config.get('APPLY_CASHING'):
await clear_cache(activity, Inbox)
elif activity["type"] == "Undo":
deleted = await Inbox.delete(activity["object"]["id"])
undo_obj = activity["object"].get("object", "")
if undo_obj.startswith(user.uri) and deleted:
if activity["object"]["type"] == "Follow":
await Outbox.delete(activity["object"]["id"])
elif activity["object"]["type"] in ["Announce", "Like"]:
await user.forward_to_followers(activity)
elif activity["type"] == "Delete":
await Inbox.delete(activity["object"]["id"])
# TODO handle(forward) delete of reply to local user post
else:
await Inbox.save(user, activity)
return response.json({'Created': 'success'}, status=202)
@inbox_v1.route('/@<user>/inbox', methods=['GET'])
@doc.summary("Returns user inbox, auth required")
@token_check
async def inbox_list(request, user):
if cached_mode(request):
resp = await timeline_cached(Inbox, request, user.inbox, user=user.name)
else:
resp = await user.inbox_paged(request)
return response.json(resp, headers={'Content-Type': 'application/activity+json; charset=utf-8'})
@inbox_v1.route('/timeline/federated', methods=['GET'])
@doc.summary("Returns federated timeline")
async def inbox_all(request):
url =f"{request.app.base_url}/timeline/federated"
if cached_mode(request):
resp = await timeline_cached(Inbox, request, url)
else:
resp = await Inbox.timeline_paged(request, url)
return response.json(resp, headers={'Content-Type': 'application/activity+json; charset=utf-8'})