Start support for acking/federating replies via Read activities

This commit is contained in:
Thomas Sileo 2019-09-15 22:09:32 +02:00
parent 801d0effa9
commit af6f7c1a5a
4 changed files with 64 additions and 6 deletions

25
app.py
View file

@ -1,5 +1,4 @@
import json import json
from werkzeug.exceptions import InternalServerError
import logging import logging
import os import os
import traceback import traceback
@ -30,6 +29,7 @@ from little_boxes.errors import ActivityGoneError
from little_boxes.errors import Error from little_boxes.errors import Error
from little_boxes.httpsig import verify_request from little_boxes.httpsig import verify_request
from little_boxes.webfinger import get_remote_follow_template from little_boxes.webfinger import get_remote_follow_template
from werkzeug.exceptions import InternalServerError
import blueprints.admin import blueprints.admin
import blueprints.indieauth import blueprints.indieauth
@ -827,7 +827,30 @@ def inbox():
# We fetched the remote data successfully # We fetched the remote data successfully
data = remote_data data = remote_data
try:
activity = ap.parse_activity(data) 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}") logger.debug(f"inbox activity={g.request_id}/{activity}/{data}")
post_to_inbox(activity) post_to_inbox(activity)

View file

@ -34,9 +34,12 @@ from core import feed
from core.activitypub import activity_url from core.activitypub import activity_url
from core.activitypub import new_context from core.activitypub import new_context
from core.activitypub import post_to_outbox from core.activitypub import post_to_outbox
from core.db import update_one_activity
from core.meta import Box from core.meta import Box
from core.meta import MetaKey from core.meta import MetaKey
from core.meta import _meta 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 MY_PERSON
from core.shared import _Response from core.shared import _Response
from core.shared import csrf from core.shared import csrf
@ -178,6 +181,31 @@ def api_boost() -> _Response:
return _user_api_response(activity=announce_id) 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"]) @blueprint.route("/mark_notifications_as_read", methods=["POST"])
@api_required @api_required
def api_mark_notification_as_read() -> _Response: def api_mark_notification_as_read() -> _Response:

View file

@ -66,10 +66,6 @@ class Tasks:
# TODO(tsileo): log invalid emoji # TODO(tsileo): log invalid emoji
pass pass
@staticmethod
def ack_reply(reply_iri: str) -> None:
p.push({"reply_iri": reply_iri}, "/task/ack_reply")
@staticmethod @staticmethod
def post_to_remote_inbox(payload: str, recp: str) -> None: def post_to_remote_inbox(payload: str, recp: str) -> None:
p.push({"payload": payload, "to": recp}, "/task/post_to_remote_inbox") p.push({"payload": payload, "to": recp}, "/task/post_to_remote_inbox")

View file

@ -126,6 +126,17 @@
{% for item in inbox_data %} {% for item in inbox_data %}
{% if 'actor' in item.meta %} {% if 'actor' in item.meta %}
{% if item | has_type('Create') %} {% if item | has_type('Create') %}
{% if request.path.startswith("/admin") and not item.meta.reply_acked and item.meta.object_visibility | visibility_is_public %}
<div style="margin-left:70px;padding-bottom:5px;margin-bottom:15px;display:inline-block;">
<form action="/api/ack_reply" class="action-form" method="POST">
<input type="hidden" name="redirect" value="{{ request.path }}"/>
<input type="hidden" name="reply_iri" value="{{ item.meta.object_id }}"/>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<button type="submit" class="bar-item">ack reply</button>
</form>
</div>
{% endif %}
{{ utils.display_note(item.activity.object, ui=True, meta=item.meta) }} {{ utils.display_note(item.activity.object, ui=True, meta=item.meta) }}
{% else %} {% else %}
{% if item | has_type('Announce') %} {% if item | has_type('Announce') %}