mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
dee81cca8f
4 changed files with 163 additions and 67 deletions
|
@ -21,7 +21,7 @@ from app.activitypub.util import public_key, users_total, active_half_year, acti
|
||||||
upvote_post, delete_post_or_comment, community_members, \
|
upvote_post, delete_post_or_comment, community_members, \
|
||||||
user_removed_from_remote_server, create_post, create_post_reply, update_post_reply_from_activity, \
|
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, \
|
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
|
process_report, ensure_domains_match, can_edit, can_delete, remove_data_from_banned_user
|
||||||
from app.utils import gibberish, get_setting, is_image_url, allowlist_html, render_template, \
|
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, \
|
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, \
|
can_upvote, can_create_post, awaken_dormant_instance, shorten_string, can_create_post_reply, sha256_digest, \
|
||||||
|
@ -439,6 +439,11 @@ def shared_inbox():
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/site_inbox', methods=['GET', 'POST'])
|
||||||
|
def site_inbox():
|
||||||
|
return shared_inbox()
|
||||||
|
|
||||||
|
|
||||||
@celery.task
|
@celery.task
|
||||||
def process_inbox_request(request_json, activitypublog_id, ip_address):
|
def process_inbox_request(request_json, activitypublog_id, ip_address):
|
||||||
with current_app.app_context():
|
with current_app.app_context():
|
||||||
|
@ -800,6 +805,15 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
||||||
if existing_membership:
|
if existing_membership:
|
||||||
existing_membership.is_moderator = False
|
existing_membership.is_moderator = False
|
||||||
activity_log.result = 'success'
|
activity_log.result = 'success'
|
||||||
|
elif request_json['object']['type'] == 'Block' and 'target' in request_json['object']:
|
||||||
|
activity_log.activity_type = 'Community Ban'
|
||||||
|
mod_ap_id = request_json['object']['actor']
|
||||||
|
user_ap_id = request_json['object']['object']
|
||||||
|
target = request_json['object']['target']
|
||||||
|
remove_data = request_json['object']['removeData']
|
||||||
|
if target == request_json['actor'] and remove_data == True:
|
||||||
|
remove_data_from_banned_user(mod_ap_id, user_ap_id, target)
|
||||||
|
activity_log.result = 'success'
|
||||||
else:
|
else:
|
||||||
activity_log.exception_message = 'Invalid type for Announce'
|
activity_log.exception_message = 'Invalid type for Announce'
|
||||||
|
|
||||||
|
@ -1076,6 +1090,15 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
||||||
activity_log.result = 'success'
|
activity_log.result = 'success'
|
||||||
else:
|
else:
|
||||||
activity_log.exception_message = 'Report ignored due to missing user or content'
|
activity_log.exception_message = 'Report ignored due to missing user or content'
|
||||||
|
elif request_json['type'] == 'Block':
|
||||||
|
activity_log.activity_type = 'Site Ban'
|
||||||
|
admin_ap_id = request_json['actor']
|
||||||
|
user_ap_id = request_json['object']
|
||||||
|
target = request_json['target']
|
||||||
|
remove_data = request_json['removeData']
|
||||||
|
if remove_data == True:
|
||||||
|
remove_data_from_banned_user(admin_ap_id, user_ap_id, target)
|
||||||
|
activity_log.result = 'success'
|
||||||
|
|
||||||
# Flush the caches of any major object that was created. To be sure.
|
# Flush the caches of any major object that was created. To be sure.
|
||||||
if 'user' in vars() and user is not None:
|
if 'user' in vars() and user is not None:
|
||||||
|
|
|
@ -1041,23 +1041,22 @@ def find_instance_id(server):
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# Spawn background task to fill in more details
|
# Spawn background task to fill in more details
|
||||||
refresh_instance_profile(new_instance.id)
|
new_instance_profile(new_instance.id)
|
||||||
|
|
||||||
return new_instance.id
|
return new_instance.id
|
||||||
|
|
||||||
|
|
||||||
def refresh_instance_profile(instance_id: int):
|
def new_instance_profile(instance_id: int):
|
||||||
if instance_id:
|
if instance_id:
|
||||||
if current_app.debug:
|
if current_app.debug:
|
||||||
refresh_instance_profile_task(instance_id)
|
new_instance_profile_task(instance_id)
|
||||||
else:
|
else:
|
||||||
refresh_instance_profile_task.apply_async(args=(instance_id,), countdown=randint(1, 10))
|
new_instance_profile_task.apply_async(args=(instance_id,), countdown=randint(1, 10))
|
||||||
|
|
||||||
|
|
||||||
@celery.task
|
@celery.task
|
||||||
def refresh_instance_profile_task(instance_id: int):
|
def new_instance_profile_task(instance_id: int):
|
||||||
instance = Instance.query.get(instance_id)
|
instance = Instance.query.get(instance_id)
|
||||||
if instance.inbox is None or instance.updated_at < utcnow() - timedelta(days=7):
|
|
||||||
try:
|
try:
|
||||||
instance_data = get_request(f"https://{instance.domain}", headers={'Accept': 'application/activity+json'})
|
instance_data = get_request(f"https://{instance.domain}", headers={'Accept': 'application/activity+json'})
|
||||||
except:
|
except:
|
||||||
|
@ -1069,23 +1068,9 @@ def refresh_instance_profile_task(instance_id: int):
|
||||||
except requests.exceptions.JSONDecodeError as ex:
|
except requests.exceptions.JSONDecodeError as ex:
|
||||||
instance_json = {}
|
instance_json = {}
|
||||||
if 'type' in instance_json and instance_json['type'] == 'Application':
|
if 'type' in instance_json and instance_json['type'] == 'Application':
|
||||||
# 'name' is unreliable as the admin can change it to anything. todo: find better way
|
|
||||||
if instance_json['name'].lower() == 'kbin':
|
|
||||||
software = 'kbin'
|
|
||||||
elif instance_json['name'].lower() == 'mbin':
|
|
||||||
software = 'mbin'
|
|
||||||
elif instance_json['name'].lower() == 'piefed':
|
|
||||||
software = 'piefed'
|
|
||||||
elif instance_json['name'].lower() == 'system account':
|
|
||||||
software = 'friendica'
|
|
||||||
else:
|
|
||||||
software = 'lemmy'
|
|
||||||
instance.inbox = instance_json['inbox']
|
instance.inbox = instance_json['inbox']
|
||||||
instance.outbox = instance_json['outbox']
|
instance.outbox = instance_json['outbox']
|
||||||
instance.software = software
|
else: # it's pretty much always /inbox so just assume that it is for whatever this instance is running
|
||||||
if instance.inbox.endswith('/site_inbox'): # Lemmy provides a /site_inbox but it always returns 400 when trying to POST to it. wtf.
|
|
||||||
instance.inbox = instance.inbox.replace('/site_inbox', '/inbox')
|
|
||||||
else: # it's pretty much always /inbox so just assume that it is for whatever this instance is running (mostly likely Mastodon)
|
|
||||||
instance.inbox = f"https://{instance.domain}/inbox"
|
instance.inbox = f"https://{instance.domain}/inbox"
|
||||||
instance.updated_at = utcnow()
|
instance.updated_at = utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -1122,12 +1107,39 @@ def refresh_instance_profile_task(instance_id: int):
|
||||||
InstanceRole.instance_id == instance.id,
|
InstanceRole.instance_id == instance.id,
|
||||||
InstanceRole.role == 'admin').delete()
|
InstanceRole.role == 'admin').delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
elif instance_data.status_code == 406: # Mastodon does this
|
elif instance_data.status_code == 406: # Mastodon and PeerTube do this
|
||||||
instance.software = 'mastodon'
|
|
||||||
instance.inbox = f"https://{instance.domain}/inbox"
|
instance.inbox = f"https://{instance.domain}/inbox"
|
||||||
instance.updated_at = utcnow()
|
instance.updated_at = utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
HEADERS = {'User-Agent': 'PieFed/1.0', 'Accept': 'application/activity+json'}
|
||||||
|
try:
|
||||||
|
nodeinfo = requests.get(f"https://{instance.domain}/.well-known/nodeinfo", headers=HEADERS,
|
||||||
|
timeout=5, allow_redirects=True)
|
||||||
|
|
||||||
|
if nodeinfo.status_code == 200:
|
||||||
|
nodeinfo_json = nodeinfo.json()
|
||||||
|
for links in nodeinfo_json['links']:
|
||||||
|
if 'rel' in links and (
|
||||||
|
links['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.0' or
|
||||||
|
links['rel'] == 'https://nodeinfo.diaspora.software/ns/schema/2.0'):
|
||||||
|
try:
|
||||||
|
time.sleep(0.1)
|
||||||
|
node = requests.get(links['href'], headers=HEADERS, timeout=5,
|
||||||
|
allow_redirects=True)
|
||||||
|
if node.status_code == 200:
|
||||||
|
node_json = node.json()
|
||||||
|
if 'software' in node_json:
|
||||||
|
instance.software = node_json['software']['name'].lower()
|
||||||
|
instance.version = node_json['software']['version']
|
||||||
|
db.session.commit()
|
||||||
|
except:
|
||||||
|
# todo: update new field in Instance to indicate bad nodeinfo response
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
# todo: update new field in Instance to indicate bad nodeinfo response
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
# alter the effect of upvotes based on their instance. Default to 1.0
|
# alter the effect of upvotes based on their instance. Default to 1.0
|
||||||
@cache.memoize(timeout=50)
|
@cache.memoize(timeout=50)
|
||||||
|
@ -1329,6 +1341,57 @@ def delete_post_or_comment_task(user_ap_id, community_ap_id, to_be_deleted_ap_id
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def remove_data_from_banned_user(deletor_ap_id, user_ap_id, target):
|
||||||
|
if current_app.debug:
|
||||||
|
remove_data_from_banned_user_task(deletor_ap_id, user_ap_id, target)
|
||||||
|
else:
|
||||||
|
remove_data_from_banned_user_task.delay(deletor_ap_id, user_ap_id, target)
|
||||||
|
|
||||||
|
|
||||||
|
@celery.task
|
||||||
|
def remove_data_from_banned_user_task(deletor_ap_id, user_ap_id, target):
|
||||||
|
deletor = find_actor_or_create(deletor_ap_id, create_if_not_found=False)
|
||||||
|
user = find_actor_or_create(user_ap_id, create_if_not_found=False)
|
||||||
|
community = Community.query.filter_by(ap_profile_id=target).first()
|
||||||
|
|
||||||
|
if not deletor and not user:
|
||||||
|
return
|
||||||
|
|
||||||
|
# site bans by admins
|
||||||
|
if deletor.instance.user_is_admin(deletor.id) and target == f"https://{deletor.instance.domain}/" and deletor.instance_id == user.instance_id:
|
||||||
|
post_replies = PostReply.query.filter_by(user_id=user.id)
|
||||||
|
posts = Post.query.filter_by(user_id=user.id)
|
||||||
|
|
||||||
|
# community bans by mods
|
||||||
|
elif community and community.is_moderator(deletor):
|
||||||
|
post_replies = PostReply.query.filter_by(user_id=user.id, community_id=community.id)
|
||||||
|
posts = Post.query.filter_by(user_id=user.id, community_id=community.id)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
for pr in post_replies:
|
||||||
|
pr.post.reply_count -= 1
|
||||||
|
if pr.has_replies():
|
||||||
|
pr.body = 'Banned'
|
||||||
|
pr.body_html = lemmy_markdown_to_html(pr.body)
|
||||||
|
else:
|
||||||
|
pr.delete_dependencies()
|
||||||
|
db.session.delete(pr)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
for p in posts:
|
||||||
|
if p.cross_posts:
|
||||||
|
old_cross_posts = Post.query.filter(Post.id.in_(p.cross_posts)).all()
|
||||||
|
for ocp in old_cross_posts:
|
||||||
|
if ocp.cross_posts is not None:
|
||||||
|
ocp.cross_posts.remove(p.id)
|
||||||
|
p.delete_dependencies()
|
||||||
|
db.session.delete(p)
|
||||||
|
p.community.post_count -= 1
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
def create_post_reply(activity_log: ActivityPubLog, community: Community, in_reply_to, request_json: dict, user: User, announce_id=None) -> Union[Post, None]:
|
def create_post_reply(activity_log: ActivityPubLog, community: Community, in_reply_to, request_json: dict, user: User, announce_id=None) -> Union[Post, None]:
|
||||||
if community.local_only:
|
if community.local_only:
|
||||||
activity_log.exception_message = 'Community is local only, reply discarded'
|
activity_log.exception_message = 'Community is local only, reply discarded'
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
from random import randint
|
||||||
from typing import List
|
from typing import List
|
||||||
import requests
|
import requests
|
||||||
from PIL import Image, ImageOps
|
from PIL import Image, ImageOps
|
||||||
|
@ -44,7 +45,7 @@ def search_for_community(address: str):
|
||||||
webfinger_data = get_request(f"https://{server}/.well-known/webfinger",
|
webfinger_data = get_request(f"https://{server}/.well-known/webfinger",
|
||||||
params={'resource': f"acct:{address[1:]}"})
|
params={'resource': f"acct:{address[1:]}"})
|
||||||
except requests.exceptions.ReadTimeout:
|
except requests.exceptions.ReadTimeout:
|
||||||
time.sleep(randint(3, 10))
|
sleep(randint(3, 10))
|
||||||
try:
|
try:
|
||||||
webfinger_data = get_request(f"https://{server}/.well-known/webfinger",
|
webfinger_data = get_request(f"https://{server}/.well-known/webfinger",
|
||||||
params={'resource': f"acct:{address[1:]}"})
|
params={'resource': f"acct:{address[1:]}"})
|
||||||
|
|
|
@ -429,6 +429,15 @@ def activitypub_application():
|
||||||
'updated': ap_datetime(g.site.updated),
|
'updated': ap_datetime(g.site.updated),
|
||||||
'inbox': f"https://{current_app.config['SERVER_NAME']}/site_inbox",
|
'inbox': f"https://{current_app.config['SERVER_NAME']}/site_inbox",
|
||||||
'outbox': f"https://{current_app.config['SERVER_NAME']}/site_outbox",
|
'outbox': f"https://{current_app.config['SERVER_NAME']}/site_outbox",
|
||||||
|
'icon': {
|
||||||
|
'type': 'Image',
|
||||||
|
'url': f"https://{current_app.config['SERVER_NAME']}/static/images/logo2.png"
|
||||||
|
},
|
||||||
|
'publicKey': {
|
||||||
|
'id': f"https://{current_app.config['SERVER_NAME']}/#main-key",
|
||||||
|
'owner': f"https://{current_app.config['SERVER_NAME']}/",
|
||||||
|
'publicKeyPem': g.site.public_key
|
||||||
|
}
|
||||||
}
|
}
|
||||||
resp = jsonify(application_data)
|
resp = jsonify(application_data)
|
||||||
resp.content_type = 'application/activity+json'
|
resp.content_type = 'application/activity+json'
|
||||||
|
|
Loading…
Add table
Reference in a new issue