mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
Only call resolve_remote_post() from activitypub, modify it to also accept Announce/Update, and remove reliance on 'audience' field (#427)
This commit is contained in:
parent
e45c8d9db3
commit
5bf0ddc32a
2 changed files with 85 additions and 85 deletions
|
@ -614,7 +614,7 @@ def process_inbox_request(request_json, store_ap_json):
|
||||||
if request_json['object'].startswith('https://' + current_app.config['SERVER_NAME']):
|
if request_json['object'].startswith('https://' + current_app.config['SERVER_NAME']):
|
||||||
log_incoming_ap(id, APLOG_DUPLICATE, APLOG_IGNORED, saved_json, 'Activity about local content which is already present')
|
log_incoming_ap(id, APLOG_DUPLICATE, APLOG_IGNORED, saved_json, 'Activity about local content which is already present')
|
||||||
return
|
return
|
||||||
post = resolve_remote_post(request_json['object'], community.id, announce_actor=community.ap_profile_id, store_ap_json=store_ap_json)
|
post = resolve_remote_post(request_json['object'], community, id, store_ap_json)
|
||||||
if post:
|
if post:
|
||||||
log_incoming_ap(id, APLOG_ANNOUNCE, APLOG_SUCCESS, request_json)
|
log_incoming_ap(id, APLOG_ANNOUNCE, APLOG_SUCCESS, request_json)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -2295,93 +2295,86 @@ def can_delete(user_ap_id, post):
|
||||||
return can_edit(user_ap_id, post)
|
return can_edit(user_ap_id, post)
|
||||||
|
|
||||||
|
|
||||||
def resolve_remote_post(uri: str, community_id: int, announce_actor=None, store_ap_json=False) -> Union[Post, PostReply, None]:
|
# called from incoming activitypub, when the object in an Announce is just a URL
|
||||||
post = Post.query.filter_by(ap_id=uri).first()
|
# despite the name, it works for both posts and replies
|
||||||
if post:
|
def resolve_remote_post(uri: str, community, announce_id, store_ap_json) -> Union[Post, PostReply, None]:
|
||||||
return post
|
|
||||||
|
|
||||||
community = Community.query.get(community_id)
|
|
||||||
site = Site.query.get(1)
|
|
||||||
|
|
||||||
parsed_url = urlparse(uri)
|
parsed_url = urlparse(uri)
|
||||||
uri_domain = parsed_url.netloc
|
uri_domain = parsed_url.netloc
|
||||||
if announce_actor:
|
announce_actor = community.ap_profile_id
|
||||||
parsed_url = urlparse(announce_actor)
|
parsed_url = urlparse(announce_actor)
|
||||||
announce_actor_domain = parsed_url.netloc
|
announce_actor_domain = parsed_url.netloc
|
||||||
if announce_actor_domain != 'a.gup.pe' and announce_actor_domain != uri_domain:
|
if announce_actor_domain != 'a.gup.pe' and announce_actor_domain != uri_domain:
|
||||||
return None
|
return None
|
||||||
actor_domain = None
|
actor_domain = None
|
||||||
actor = None
|
actor = None
|
||||||
post_request = get_request(uri, headers={'Accept': 'application/activity+json'})
|
|
||||||
if post_request.status_code == 200:
|
try:
|
||||||
post_data = post_request.json()
|
object_request = get_request(uri, headers={'Accept': 'application/activity+json'})
|
||||||
post_request.close()
|
except httpx.HTTPError:
|
||||||
# check again that it doesn't already exist (can happen with different but equivalent URLs)
|
time.sleep(3)
|
||||||
post = Post.query.filter_by(ap_id=post_data['id']).first()
|
try:
|
||||||
if post:
|
object_request = get_request(uri, headers={'Accept': 'application/activity+json'})
|
||||||
return post
|
except httpx.HTTPError:
|
||||||
|
return None
|
||||||
|
if object_request.status_code == 200:
|
||||||
|
try:
|
||||||
|
post_data = object_request.json()
|
||||||
|
except:
|
||||||
|
object_request.close()
|
||||||
|
return None
|
||||||
|
object_request.close()
|
||||||
|
elif object_request.status_code == 401:
|
||||||
|
try:
|
||||||
|
site = Site.query.get(1)
|
||||||
|
object_request = signed_get_request(uri, site.private_key, f"https://{current_app.config['SERVER_NAME']}/actor#main-key")
|
||||||
|
except httpx.HTTPError:
|
||||||
|
time.sleep(3)
|
||||||
|
try:
|
||||||
|
object_request = signed_get_request(uri, site.private_key, f"https://{current_app.config['SERVER_NAME']}/actor#main-key")
|
||||||
|
except httpx.HTTPError:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
post_data = object_request.json()
|
||||||
|
except:
|
||||||
|
object_request.close()
|
||||||
|
return None
|
||||||
|
object_request.close()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# find the author. Make sure their domain matches the site hosting it to mitigate impersonation attempts
|
||||||
if 'attributedTo' in post_data:
|
if 'attributedTo' in post_data:
|
||||||
if isinstance(post_data['attributedTo'], str):
|
attributed_to = post_data['attributedTo']
|
||||||
actor = post_data['attributedTo']
|
if isinstance(attributed_to, str):
|
||||||
parsed_url = urlparse(post_data['attributedTo'])
|
actor = attributed_to
|
||||||
|
parsed_url = urlparse(actor)
|
||||||
actor_domain = parsed_url.netloc
|
actor_domain = parsed_url.netloc
|
||||||
elif isinstance(post_data['attributedTo'], list):
|
elif isinstance(attributed_to, list):
|
||||||
for a in post_data['attributedTo']:
|
for a in attributed_to:
|
||||||
if a['type'] == 'Person':
|
if isinstance(a, dict) and a.get('type') == 'Person':
|
||||||
actor = a['id']
|
actor = a.get('id')
|
||||||
parsed_url = urlparse(a['id'])
|
if isinstance(actor, str): # Ensure `actor` is a valid string
|
||||||
|
parsed_url = urlparse(actor)
|
||||||
|
actor_domain = parsed_url.netloc
|
||||||
|
break
|
||||||
|
elif isinstance(a, str):
|
||||||
|
actor = a
|
||||||
|
parsed_url = urlparse(actor)
|
||||||
actor_domain = parsed_url.netloc
|
actor_domain = parsed_url.netloc
|
||||||
break
|
break
|
||||||
if uri_domain != actor_domain:
|
if uri_domain != actor_domain:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not announce_actor:
|
|
||||||
# make sure that the post actually belongs in the community a user says it does
|
|
||||||
remote_community = None
|
|
||||||
if post_data['type'] == 'Page': # lemmy
|
|
||||||
remote_community = post_data['audience'] if 'audience' in post_data else None
|
|
||||||
if remote_community and remote_community.lower() != community.ap_profile_id:
|
|
||||||
return None
|
|
||||||
elif post_data['type'] == 'Video': # peertube
|
|
||||||
if 'attributedTo' in post_data and isinstance(post_data['attributedTo'], list):
|
|
||||||
for a in post_data['attributedTo']:
|
|
||||||
if a['type'] == 'Group':
|
|
||||||
remote_community = a['id']
|
|
||||||
break
|
|
||||||
if remote_community and remote_community.lower() != community.ap_profile_id:
|
|
||||||
return None
|
|
||||||
else: # mastodon, etc
|
|
||||||
if 'inReplyTo' not in post_data or post_data['inReplyTo'] != None:
|
|
||||||
return None
|
|
||||||
community_found = False
|
|
||||||
if not community_found and 'to' in post_data and isinstance(post_data['to'], str):
|
|
||||||
remote_community = post_data['to']
|
|
||||||
if remote_community.lower() == community.ap_profile_id:
|
|
||||||
community_found = True
|
|
||||||
if not community_found and 'cc' in post_data and isinstance(post_data['cc'], str):
|
|
||||||
remote_community = post_data['cc']
|
|
||||||
if remote_community.lower() == community.ap_profile_id:
|
|
||||||
community_found = True
|
|
||||||
if not community_found and 'to' in post_data and isinstance(post_data['to'], list):
|
|
||||||
for t in post_data['to']:
|
|
||||||
if t.lower() == community.ap_profile_id:
|
|
||||||
community_found = True
|
|
||||||
break
|
|
||||||
if not community_found and 'cc' in post_data and isinstance(post_data['cc'], list):
|
|
||||||
for c in post_data['cc']:
|
|
||||||
if c.lower() == community.ap_profile_id:
|
|
||||||
community_found = True
|
|
||||||
break
|
|
||||||
if not community_found:
|
|
||||||
return None
|
|
||||||
|
|
||||||
user = find_actor_or_create(actor)
|
user = find_actor_or_create(actor)
|
||||||
if user and community and post_data:
|
if user and community and post_data:
|
||||||
request_json = {
|
activity = 'update' if 'updated' in post_data else 'create'
|
||||||
'id': f"https://{uri_domain}/activities/create/{gibberish(15)}",
|
request_json = {'id': f"https://{uri_domain}/activities/{activity}/{gibberish(15)}", 'object': post_data}
|
||||||
'object': post_data
|
|
||||||
}
|
|
||||||
if 'inReplyTo' in request_json['object'] and request_json['object']['inReplyTo']:
|
if 'inReplyTo' in request_json['object'] and request_json['object']['inReplyTo']:
|
||||||
|
if activity == 'update':
|
||||||
|
post_reply = PostReply.get_by_ap_id(uri)
|
||||||
|
if post_reply:
|
||||||
|
update_post_reply_from_activity(post_reply, request_json)
|
||||||
|
else:
|
||||||
post_reply = create_post_reply(store_ap_json, community, request_json['object']['inReplyTo'], request_json, user)
|
post_reply = create_post_reply(store_ap_json, community, request_json['object']['inReplyTo'], request_json, user)
|
||||||
if post_reply:
|
if post_reply:
|
||||||
if 'published' in post_data:
|
if 'published' in post_data:
|
||||||
|
@ -2389,21 +2382,28 @@ def resolve_remote_post(uri: str, community_id: int, announce_actor=None, store_
|
||||||
post_reply.post.last_active = post_data['published']
|
post_reply.post.last_active = post_data['published']
|
||||||
post_reply.community.last_active = utcnow()
|
post_reply.community.last_active = utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
if post_reply:
|
||||||
return post_reply
|
return post_reply
|
||||||
else:
|
else:
|
||||||
post = create_post(store_ap_json, community, request_json, user)
|
if activity == 'update':
|
||||||
|
post = Post.get_by_ap_id(uri)
|
||||||
|
if post:
|
||||||
|
update_post_from_activity(post_reply, request_json)
|
||||||
|
else:
|
||||||
|
post = create_post(store_ap_json, community, request_json, user, announce_id)
|
||||||
if post:
|
if post:
|
||||||
if 'published' in post_data:
|
if 'published' in post_data:
|
||||||
post.posted_at=post_data['published']
|
post.posted_at=post_data['published']
|
||||||
post.last_active=post_data['published']
|
post.last_active=post_data['published']
|
||||||
post.community.last_active = utcnow()
|
post.community.last_active = utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
if post:
|
||||||
return post
|
return post
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
# called from UI, via 'search' option in navbar
|
# called from UI, via 'search' option in navbar, or 'Retrieve a post from the original server' in community sidebar
|
||||||
def resolve_remote_post_from_search(uri: str) -> Union[Post, None]:
|
def resolve_remote_post_from_search(uri: str) -> Union[Post, None]:
|
||||||
post = Post.query.filter_by(ap_id=uri).first()
|
post = Post.query.filter_by(ap_id=uri).first()
|
||||||
if post:
|
if post:
|
||||||
|
|
Loading…
Reference in a new issue