utilize mastodon-style regular expressions for defederation

This commit is contained in:
rimu 2024-12-31 13:55:24 +13:00
parent 2dea250e8c
commit 93ee376525
4 changed files with 20 additions and 21 deletions

View file

@ -19,7 +19,7 @@ from app.models import User, Community, CommunityJoinRequest, CommunityMember, C
PostReply, Instance, PostVote, PostReplyVote, File, AllowedInstances, BannedInstances, utcnow, Site, Notification, \ PostReply, Instance, PostVote, PostReplyVote, File, AllowedInstances, BannedInstances, utcnow, Site, Notification, \
ChatMessage, Conversation, UserFollower, UserBlock, Poll, PollChoice ChatMessage, Conversation, UserFollower, UserBlock, Poll, PollChoice
from app.activitypub.util import public_key, users_total, active_half_year, active_month, local_posts, local_comments, \ from app.activitypub.util import public_key, users_total, active_half_year, active_month, local_posts, local_comments, \
post_to_activity, find_actor_or_create, instance_blocked, find_reply_parent, find_liked_object, \ post_to_activity, find_actor_or_create, find_reply_parent, find_liked_object, \
lemmy_site_data, is_activitypub_request, delete_post_or_comment, community_members, \ lemmy_site_data, is_activitypub_request, 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, \
@ -29,7 +29,7 @@ from app.activitypub.util import public_key, users_total, active_half_year, acti
from app.utils import gibberish, get_setting, render_template, \ from app.utils import gibberish, get_setting, render_template, \
community_membership, ap_datetime, ip_address, can_downvote, \ 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, \
community_moderators, markdown_to_html, html_to_text, add_to_modlog_activitypub community_moderators, html_to_text, add_to_modlog_activitypub, instance_banned
@bp.route('/testredis') @bp.route('/testredis')
@ -1311,7 +1311,7 @@ def announce_activity_to_followers(community, creator, activity):
awaken_dormant_instance(instance) awaken_dormant_instance(instance)
# All good? Send! # All good? Send!
if instance and instance.online() and not instance_blocked(instance.inbox): if instance and instance.online() and not instance_banned(instance.inbox):
if creator.instance_id != instance.id: # don't send it to the instance that hosts the creator as presumably they already have the content if creator.instance_id != instance.id: # don't send it to the instance that hosts the creator as presumably they already have the content
send_to_remote_instance(instance.id, community.id, announce_activity) send_to_remote_instance(instance.id, community.id, announce_activity)

View file

@ -2,6 +2,7 @@ from __future__ import annotations
import html import html
import os import os
import re
from datetime import timedelta, datetime, timezone from datetime import timedelta, datetime, timezone
from random import randint from random import randint
from typing import Union, Tuple, List from typing import Union, Tuple, List
@ -32,7 +33,7 @@ from app.utils import get_request, allowlist_html, get_setting, ap_datetime, mar
microblog_content_to_title, is_video_url, \ microblog_content_to_title, is_video_url, \
notification_subscribers, communities_banned_from, actor_contains_blocked_words, \ notification_subscribers, communities_banned_from, actor_contains_blocked_words, \
html_to_text, add_to_modlog_activitypub, joined_communities, \ html_to_text, add_to_modlog_activitypub, joined_communities, \
moderating_communities, get_task_session, is_video_hosting_site, opengraph_parse moderating_communities, get_task_session, is_video_hosting_site, opengraph_parse, instance_banned
from sqlalchemy import or_ from sqlalchemy import or_
@ -236,17 +237,6 @@ def banned_user_agents():
return [] # todo: finish this function return [] # todo: finish this function
@cache.memoize(150)
def instance_blocked(host: str) -> bool: # see also utils.instance_banned()
if host is None or host == '':
return True
host = host.lower()
if 'https://' in host or 'http://' in host:
host = urlparse(host).hostname
instance = BannedInstances.query.filter_by(domain=host.strip()).first()
return instance is not None
@cache.memoize(150) @cache.memoize(150)
def instance_allowed(host: str) -> bool: def instance_allowed(host: str) -> bool:
if host is None or host == '': if host is None or host == '':
@ -282,7 +272,7 @@ def find_actor_or_create(actor: str, create_if_not_found=True, community_only=Fa
if not instance_allowed(server): if not instance_allowed(server):
return None return None
else: else:
if instance_blocked(server): if instance_banned(server):
return None return None
if actor_contains_blocked_words(actor): if actor_contains_blocked_words(actor):
return None return None

View file

@ -16,7 +16,7 @@ from urllib.parse import urlparse
from app import db, celery, cache from app import db, celery, cache
from app.activitypub.routes import process_inbox_request, process_delete_request, replay_inbox_request from app.activitypub.routes import process_inbox_request, process_delete_request, replay_inbox_request
from app.activitypub.signature import post_request, default_context from app.activitypub.signature import post_request, default_context
from app.activitypub.util import instance_allowed, instance_blocked, extract_domain_and_actor from app.activitypub.util import instance_allowed, extract_domain_and_actor
from app.admin.forms import FederationForm, SiteMiscForm, SiteProfileForm, EditCommunityForm, EditUserForm, \ from app.admin.forms import FederationForm, SiteMiscForm, SiteProfileForm, EditCommunityForm, EditUserForm, \
EditTopicForm, SendNewsletterForm, AddUserForm, PreLoadCommunitiesForm, ImportExportBannedListsForm, \ EditTopicForm, SendNewsletterForm, AddUserForm, PreLoadCommunitiesForm, ImportExportBannedListsForm, \
EditInstanceForm, RemoteInstanceScanForm EditInstanceForm, RemoteInstanceScanForm
@ -32,7 +32,7 @@ from app.models import AllowedInstances, BannedInstances, ActivityPubLog, utcnow
from app.utils import render_template, permission_required, set_setting, get_setting, gibberish, markdown_to_html, \ from app.utils import render_template, permission_required, set_setting, get_setting, gibberish, markdown_to_html, \
moderating_communities, joined_communities, finalize_user_setup, theme_list, blocked_phrases, blocked_referrers, \ moderating_communities, joined_communities, finalize_user_setup, theme_list, blocked_phrases, blocked_referrers, \
topic_tree, languages_for_form, menu_topics, ensure_directory_exists, add_to_modlog, get_request, file_get_contents, \ topic_tree, languages_for_form, menu_topics, ensure_directory_exists, add_to_modlog, get_request, file_get_contents, \
download_defeds download_defeds, instance_banned
from app.admin import bp from app.admin import bp
@ -666,7 +666,7 @@ def admin_federation():
for banned in form.blocklist.data.split('\n'): for banned in form.blocklist.data.split('\n'):
if banned.strip(): if banned.strip():
db.session.add(BannedInstances(domain=banned.strip())) db.session.add(BannedInstances(domain=banned.strip()))
cache.delete_memoized(instance_blocked, banned.strip()) cache.delete_memoized(instance_banned, banned.strip())
# update and sync defederation subscriptions # update and sync defederation subscriptions
db.session.execute(text('DELETE FROM banned_instances WHERE subscription_id is not null')) db.session.execute(text('DELETE FROM banned_instances WHERE subscription_id is not null'))

View file

@ -656,12 +656,21 @@ def user_ip_banned() -> bool:
return current_ip_address in banned_ip_addresses() return current_ip_address in banned_ip_addresses()
@cache.memoize(timeout=60) @cache.memoize(timeout=150)
def instance_banned(domain: str) -> bool: # see also activitypub.util.instance_blocked() def instance_banned(domain: str) -> bool: # see also activitypub.util.instance_blocked()
if domain is None or domain == '': if domain is None or domain == '':
return False return False
domain = domain.lower().strip()
if 'https://' in domain or 'http://' in domain:
domain = urlparse(domain).hostname
banned = BannedInstances.query.filter_by(domain=domain).first() banned = BannedInstances.query.filter_by(domain=domain).first()
return banned is not None if banned is not None:
return True
# Mastodon sometimes bans with a * in the domain name, meaning "any letter", e.g. "cum.**mp"
regex_patterns = [re.compile(f"^{cond.domain.replace('*', '[a-zA-Z0-9]')}$") for cond in
BannedInstances.query.filter(BannedInstances.domain.like('%*%')).all()]
return any(pattern.match(domain) for pattern in regex_patterns)
def user_cookie_banned() -> bool: def user_cookie_banned() -> bool: