diff --git a/app.py b/app.py index 9ddb269..12a8c0a 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,4 @@ import json -from werkzeug.exceptions import InternalServerError import logging import os import traceback @@ -30,6 +29,7 @@ from little_boxes.errors import ActivityGoneError from little_boxes.errors import Error from little_boxes.httpsig import verify_request from little_boxes.webfinger import get_remote_follow_template +from werkzeug.exceptions import InternalServerError import blueprints.admin import blueprints.indieauth @@ -827,7 +827,30 @@ def inbox(): # We fetched the remote data successfully data = remote_data - activity = ap.parse_activity(data) + try: + activity = ap.parse_activity(data) + except ValueError: + logger.exception("failed to parse activity for req {g.request_id}: {data!r}") + + # Track/store the payload for analysis + ip, geoip = _get_ip() + + DB.trash.insert( + { + "activity": data, + "meta": { + "ts": datetime.now().timestamp(), + "ip_address": ip, + "geoip": geoip, + "tb": traceback.format_exc(), + "headers": dict(request.headers), + "request_id": g.request_id, + }, + } + ) + + return Response(status=201) + logger.debug(f"inbox activity={g.request_id}/{activity}/{data}") post_to_inbox(activity) diff --git a/blueprints/api.py b/blueprints/api.py index b90d40a..2fe03f6 100644 --- a/blueprints/api.py +++ b/blueprints/api.py @@ -34,9 +34,12 @@ from core import feed from core.activitypub import activity_url from core.activitypub import new_context from core.activitypub import post_to_outbox +from core.db import update_one_activity from core.meta import Box from core.meta import MetaKey from core.meta import _meta +from core.meta import by_object_id +from core.meta import by_type from core.shared import MY_PERSON from core.shared import _Response from core.shared import csrf @@ -178,6 +181,31 @@ def api_boost() -> _Response: return _user_api_response(activity=announce_id) +@blueprint.route("/ack_reply", methods=["POST"]) +@api_required +def api_ack_reply() -> _Response: + reply_iri = _user_api_arg("reply_iri") + obj = ap.fetch_remote_activity(reply_iri) + if obj.has_type(ap.ActivityType.CREATE): + obj = obj.get_object() + # TODO(tsileo): tweak the adressing? + update_one_activity( + {**by_type(ap.ActivityType.CREATE), **by_object_id(obj.id)}, + {"$set": {"meta.reply_acked": True}}, + ) + read = ap.Read( + actor=MY_PERSON.id, + object=obj.id, + to=[MY_PERSON.followers], + cc=[ap.AS_PUBLIC, obj.get_actor().id], + published=now(), + context=new_context(obj), + ) + + read_id = post_to_outbox(read) + return _user_api_response(activity=read_id) + + @blueprint.route("/mark_notifications_as_read", methods=["POST"]) @api_required def api_mark_notification_as_read() -> _Response: diff --git a/core/tasks.py b/core/tasks.py index 31bb39b..4278fb7 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -66,10 +66,6 @@ class Tasks: # TODO(tsileo): log invalid emoji pass - @staticmethod - def ack_reply(reply_iri: str) -> None: - p.push({"reply_iri": reply_iri}, "/task/ack_reply") - @staticmethod def post_to_remote_inbox(payload: str, recp: str) -> None: p.push({"payload": payload, "to": recp}, "/task/post_to_remote_inbox") diff --git a/templates/stream.html b/templates/stream.html index 452eb17..fda3d34 100644 --- a/templates/stream.html +++ b/templates/stream.html @@ -126,6 +126,17 @@ {% for item in inbox_data %} {% if 'actor' in item.meta %} {% if item | has_type('Create') %} + {% if request.path.startswith("/admin") and not item.meta.reply_acked and item.meta.object_visibility | visibility_is_public %} +