diff --git a/app/activitypub/routes.py b/app/activitypub/routes.py index 68bf24f1..694a968e 100644 --- a/app/activitypub/routes.py +++ b/app/activitypub/routes.py @@ -22,7 +22,7 @@ from app.activitypub.util import public_key, users_total, active_half_year, acti user_removed_from_remote_server, create_post, create_post_reply, update_post_reply_from_activity, \ update_post_from_activity, undo_vote, undo_downvote, post_to_page, get_redis_connection, find_reported_object, \ process_report, ensure_domains_match, can_edit, can_delete, remove_data_from_banned_user, resolve_remote_post, \ - inform_followers_of_post_update + inform_followers_of_post_update, comment_model_to_json from app.utils import gibberish, get_setting, is_image_url, allowlist_html, render_template, \ domain_from_url, markdown_to_html, community_membership, ap_datetime, ip_address, can_downvote, \ can_upvote, can_create_post, awaken_dormant_instance, shorten_string, can_create_post_reply, sha256_digest, \ @@ -859,7 +859,7 @@ def process_inbox_request(request_json, activitypublog_id, ip_address): "id": f"https://{current_app.config['SERVER_NAME']}/activities/reject/" + gibberish(32) } # Lemmy doesn't yet understand Reject/Follow, so send without worrying about response for now. - post_request(user.ap_inbox_url, reject, community.private_key, f"https://{current_app.config['SERVER_NAME']}/c/{community.name}#main-key") + post_request(user.ap_inbox_url, reject, community.private_key, f"{community.public_url()}#main-key") else: if user is not None and community is not None: # check if user is banned from this community @@ -888,7 +888,7 @@ def process_inbox_request(request_json, activitypublog_id, ip_address): "type": "Accept", "id": f"https://{current_app.config['SERVER_NAME']}/activities/accept/" + gibberish(32) } - if post_request(user.ap_inbox_url, accept, community.private_key, f"https://{current_app.config['SERVER_NAME']}/c/{community.name}#main-key"): + if post_request(user.ap_inbox_url, accept, community.private_key, f"{community.public_url()}#main-key"): activity_log.result = 'success' else: activity_log.exception_message = 'Error sending Accept' @@ -1457,37 +1457,7 @@ def user_followers(actor): def comment_ap(comment_id): if is_activitypub_request(): reply = PostReply.query.get_or_404(comment_id) - reply_data = { - "@context": default_context(), - "type": "Note", - "id": reply.ap_id, - "attributedTo": reply.author.public_url(), - "inReplyTo": reply.in_reply_to(), - "to": [ - "https://www.w3.org/ns/activitystreams#Public", - reply.to() - ], - "cc": [ - reply.community.public_url(), - reply.author.followers_url() - ], - 'content': reply.body_html, - 'mediaType': 'text/html', - 'published': ap_datetime(reply.created_at), - 'distinguished': False, - 'audience': reply.community.public_url(), - 'language': { - 'identifier': reply.language_code(), - 'name': reply.language_name() - } - } - if reply.edited_at: - reply_data['updated'] = ap_datetime(reply.edited_at) - if reply.body.strip(): - reply_data['source'] = { - 'content': reply.body, - 'mediaType': 'text/markdown' - } + reply_data = comment_model_to_json(reply) resp = jsonify(reply_data) resp.content_type = 'application/activity+json' resp.headers.set('Vary', 'Accept') diff --git a/app/activitypub/util.py b/app/activitypub/util.py index 4f1cd1da..a99e5ad3 100644 --- a/app/activitypub/util.py +++ b/app/activitypub/util.py @@ -4,12 +4,12 @@ import html import os from datetime import timedelta from random import randint -from typing import Union, Tuple +from typing import Union, Tuple, List import redis from flask import current_app, request, g, url_for, json from flask_babel import _ -from sqlalchemy import text, func +from sqlalchemy import text, func, desc from app import db, cache, constants, celery from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance, utcnow, \ PostVote, PostReplyVote, ActivityPubLog, Notification, Site, CommunityMember, InstanceRole, Report, Conversation, \ @@ -127,7 +127,7 @@ def post_to_activity(post: Post, community: Community): create_id = post.ap_create_id if post.ap_create_id else f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}" announce_id = post.ap_announce_id if post.ap_announce_id else f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}" activity_data = { - "actor": f"https://{current_app.config['SERVER_NAME']}/c/{community.name}", + "actor": community.public_url(), "to": [ "https://www.w3.org/ns/activitystreams#Public" ], @@ -142,7 +142,7 @@ def post_to_activity(post: Post, community: Community): "id": post.ap_id, "attributedTo": post.author.public_url(), "to": [ - f"https://{current_app.config['SERVER_NAME']}/c/{community.name}", + community.public_url(), "https://www.w3.org/ns/activitystreams#Public" ], "name": post.title, @@ -154,21 +154,22 @@ def post_to_activity(post: Post, community: Community): "sensitive": post.nsfw or post.nsfl, "published": ap_datetime(post.created_at), "stickied": post.sticky, - "audience": f"https://{current_app.config['SERVER_NAME']}/c/{community.name}", + "audience": community.public_url(), 'language': { 'identifier': post.language_code(), 'name': post.language_name() }, - 'tag': post.tags_for_activitypub() + 'tag': post.tags_for_activitypub(), + 'replies': post_replies_for_ap(post.id) }, "cc": [ - f"https://{current_app.config['SERVER_NAME']}/c/{community.name}" + community.public_url() ], "type": "Create", - "audience": f"https://{current_app.config['SERVER_NAME']}/c/{community.name}" + "audience": community.public_url() }, "cc": [ - f"https://{current_app.config['SERVER_NAME']}/c/{community.name}/followers" + f"{community.public_url()}/followers" ], "type": "Announce", "id": announce_id @@ -255,6 +256,52 @@ def post_to_page(post: Post): return activity_data +def post_replies_for_ap(post_id: int) -> List[dict]: + replies = PostReply.query.\ + filter_by(post_id=post_id, deleted=False).\ + order_by(desc(PostReply.posted_at)).\ + limit(2000) + return [comment_model_to_json(reply) for reply in replies] + + +def comment_model_to_json(reply: PostReply) -> dict: + reply_data = { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + ], + "type": "Note", + "id": reply.ap_id, + "attributedTo": reply.author.public_url(), + "inReplyTo": reply.in_reply_to(), + "to": [ + "https://www.w3.org/ns/activitystreams#Public", + reply.to() + ], + "cc": [ + reply.community.public_url(), + reply.author.followers_url() + ], + 'content': reply.body_html, + 'mediaType': 'text/html', + 'published': ap_datetime(reply.created_at), + 'distinguished': False, + 'audience': reply.community.public_url(), + 'language': { + 'identifier': reply.language_code(), + 'name': reply.language_name() + } + } + if reply.edited_at: + reply_data['updated'] = ap_datetime(reply.edited_at) + if reply.body.strip(): + reply_data['source'] = { + 'content': reply.body, + 'mediaType': 'text/markdown' + } + return reply + + def banned_user_agents(): return [] # todo: finish this function diff --git a/app/models.py b/app/models.py index ee580842..625beca1 100644 --- a/app/models.py +++ b/app/models.py @@ -3,7 +3,6 @@ from time import time from typing import List, Union import requests -from bs4 import BeautifulSoup from flask import current_app, escape, url_for, render_template_string from flask_login import UserMixin, current_user from sqlalchemy import or_, text, desc diff --git a/app/utils.py b/app/utils.py index fe3d2888..0cc1d940 100644 --- a/app/utils.py +++ b/app/utils.py @@ -17,6 +17,9 @@ from functools import wraps import flask from bs4 import BeautifulSoup, MarkupResemblesLocatorWarning import warnings + +from app.activitypub.signature import default_context + warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning) import requests import os