mirror of https://gitlab.com/bashrc2/epicyon
335 lines
16 KiB
Python
335 lines
16 KiB
Python
__filename__ = "daemon_post_moderator.py"
|
|
__author__ = "Bob Mottram"
|
|
__license__ = "AGPL3+"
|
|
__version__ = "1.5.0"
|
|
__maintainer__ = "Bob Mottram"
|
|
__email__ = "bob@libreserver.org"
|
|
__status__ = "Production"
|
|
__module_group__ = "Core POST"
|
|
|
|
import os
|
|
import errno
|
|
import urllib.parse
|
|
from socket import error as SocketError
|
|
from utils import data_dir
|
|
from utils import delete_post
|
|
from utils import locate_post
|
|
from utils import get_full_domain
|
|
from utils import get_domain_from_actor
|
|
from utils import get_nickname_from_actor
|
|
from utils import get_instance_url
|
|
from posts import is_moderator
|
|
from httpcodes import write2
|
|
from httpheaders import redirect_headers
|
|
from httpheaders import login_headers
|
|
from webapp_moderation import html_account_info
|
|
from webapp_moderation import html_moderation_info
|
|
from person import can_remove_post
|
|
from person import remove_account
|
|
from person import suspend_account
|
|
from person import reenable_account
|
|
from filters import add_global_filter
|
|
from filters import remove_global_filter
|
|
from cache import clear_actor_cache
|
|
from blocking import add_global_block
|
|
from blocking import update_blocked_cache
|
|
from blocking import remove_global_block
|
|
|
|
|
|
def moderator_actions(self, path: str, calling_domain: str, cookie: str,
|
|
base_dir: str, http_prefix: str,
|
|
domain: str, port: int, debug: bool,
|
|
domain_full: str,
|
|
onion_domain: str, i2p_domain: str,
|
|
translate: {},
|
|
system_language: str,
|
|
signing_priv_key_pem: str,
|
|
block_federated: [],
|
|
theme_name: str,
|
|
access_keys: {}, person_cache: {},
|
|
recent_posts_cache: {},
|
|
blocked_cache: {}) -> None:
|
|
"""Actions on the moderator screen
|
|
"""
|
|
users_path = path.replace('/moderationaction', '')
|
|
nickname = users_path.replace('/users/', '')
|
|
actor_str = \
|
|
get_instance_url(calling_domain,
|
|
http_prefix, domain_full,
|
|
onion_domain, i2p_domain) + \
|
|
users_path
|
|
if not is_moderator(base_dir, nickname):
|
|
redirect_headers(self, actor_str + '/moderation',
|
|
cookie, calling_domain, 303)
|
|
self.server.postreq_busy = False
|
|
return
|
|
|
|
length = int(self.headers['Content-length'])
|
|
|
|
try:
|
|
moderation_params = self.rfile.read(length).decode('utf-8')
|
|
except SocketError as ex:
|
|
if ex.errno == errno.ECONNRESET:
|
|
print('EX: POST moderation_params connection was reset')
|
|
else:
|
|
print('EX: POST moderation_params ' +
|
|
'rfile.read socket error')
|
|
self.send_response(400)
|
|
self.end_headers()
|
|
self.server.postreq_busy = False
|
|
return
|
|
except ValueError as ex:
|
|
print('EX: POST moderation_params rfile.read failed, ' +
|
|
str(ex))
|
|
self.send_response(400)
|
|
self.end_headers()
|
|
self.server.postreq_busy = False
|
|
return
|
|
|
|
if '&' in moderation_params:
|
|
moderation_text = None
|
|
moderation_button = None
|
|
# get the moderation text first
|
|
act_str = 'moderationAction='
|
|
for moderation_str in moderation_params.split('&'):
|
|
if moderation_str.startswith(act_str):
|
|
if act_str in moderation_str:
|
|
moderation_text = \
|
|
moderation_str.split(act_str)[1].strip()
|
|
mod_text = moderation_text.replace('+', ' ')
|
|
moderation_text = \
|
|
urllib.parse.unquote_plus(mod_text.strip())
|
|
# which button was pressed?
|
|
for moderation_str in moderation_params.split('&'):
|
|
if moderation_str.startswith('submitInfo='):
|
|
if not moderation_text and \
|
|
'submitInfo=' in moderation_str:
|
|
moderation_text = \
|
|
moderation_str.split('submitInfo=')[1].strip()
|
|
mod_text = moderation_text.replace('+', ' ')
|
|
moderation_text = \
|
|
urllib.parse.unquote_plus(mod_text.strip())
|
|
search_handle = moderation_text
|
|
if search_handle:
|
|
if '/@' in search_handle and \
|
|
'/@/' not in search_handle:
|
|
search_nickname = \
|
|
get_nickname_from_actor(search_handle)
|
|
if search_nickname:
|
|
search_domain, _ = \
|
|
get_domain_from_actor(search_handle)
|
|
if search_domain:
|
|
search_handle = \
|
|
search_nickname + '@' + search_domain
|
|
else:
|
|
search_handle = ''
|
|
else:
|
|
search_handle = ''
|
|
if '@' not in search_handle or \
|
|
'/@/' in search_handle:
|
|
if search_handle.startswith('http') or \
|
|
search_handle.startswith('ipfs') or \
|
|
search_handle.startswith('ipns'):
|
|
search_nickname = \
|
|
get_nickname_from_actor(search_handle)
|
|
if search_nickname:
|
|
search_domain, _ = \
|
|
get_domain_from_actor(search_handle)
|
|
if search_domain:
|
|
search_handle = \
|
|
search_nickname + '@' + \
|
|
search_domain
|
|
else:
|
|
search_handle = ''
|
|
else:
|
|
search_handle = ''
|
|
if '@' not in search_handle:
|
|
# is this a local nickname on this instance?
|
|
local_handle = \
|
|
search_handle + '@' + domain
|
|
dir_str = data_dir(base_dir)
|
|
if os.path.isdir(dir_str + '/' + local_handle):
|
|
search_handle = local_handle
|
|
else:
|
|
search_handle = ''
|
|
if search_handle is None:
|
|
search_handle = ''
|
|
if '@' in search_handle:
|
|
msg = \
|
|
html_account_info(translate,
|
|
base_dir, http_prefix,
|
|
nickname,
|
|
domain,
|
|
search_handle,
|
|
debug,
|
|
system_language,
|
|
signing_priv_key_pem,
|
|
None,
|
|
block_federated)
|
|
else:
|
|
msg = \
|
|
html_moderation_info(translate,
|
|
base_dir, nickname,
|
|
domain,
|
|
theme_name,
|
|
access_keys)
|
|
if msg:
|
|
msg = msg.encode('utf-8')
|
|
msglen = len(msg)
|
|
login_headers(self, 'text/html',
|
|
msglen, calling_domain)
|
|
write2(self, msg)
|
|
self.server.postreq_busy = False
|
|
return
|
|
if moderation_str.startswith('submitBlock'):
|
|
moderation_button = 'block'
|
|
elif moderation_str.startswith('submitUnblock'):
|
|
moderation_button = 'unblock'
|
|
elif moderation_str.startswith('submitFilter'):
|
|
moderation_button = 'filter'
|
|
elif moderation_str.startswith('submitUnfilter'):
|
|
moderation_button = 'unfilter'
|
|
elif moderation_str.startswith('submitClearCache'):
|
|
moderation_button = 'clearcache'
|
|
elif moderation_str.startswith('submitSuspend'):
|
|
moderation_button = 'suspend'
|
|
elif moderation_str.startswith('submitUnsuspend'):
|
|
moderation_button = 'unsuspend'
|
|
elif moderation_str.startswith('submitRemove'):
|
|
moderation_button = 'remove'
|
|
if moderation_button and moderation_text:
|
|
if debug:
|
|
print('moderation_button: ' + moderation_button)
|
|
print('moderation_text: ' + moderation_text)
|
|
nickname = moderation_text
|
|
if nickname.startswith('http') or \
|
|
nickname.startswith('ipfs') or \
|
|
nickname.startswith('ipns') or \
|
|
nickname.startswith('hyper'):
|
|
nickname = get_nickname_from_actor(nickname)
|
|
if '@' in nickname:
|
|
nickname = nickname.split('@')[0]
|
|
if moderation_button == 'suspend':
|
|
suspend_account(base_dir, nickname, domain)
|
|
if moderation_button == 'unsuspend':
|
|
reenable_account(base_dir, nickname)
|
|
if moderation_button == 'filter':
|
|
add_global_filter(base_dir, moderation_text)
|
|
if moderation_button == 'unfilter':
|
|
remove_global_filter(base_dir, moderation_text)
|
|
if moderation_button == 'clearcache':
|
|
clear_actor_cache(base_dir, person_cache,
|
|
moderation_text)
|
|
if moderation_button == 'block':
|
|
full_block_domain = None
|
|
moderation_text = moderation_text.strip()
|
|
moderation_reason = None
|
|
if ' ' in moderation_text:
|
|
moderation_domain = moderation_text.split(' ', 1)[0]
|
|
moderation_reason = moderation_text.split(' ', 1)[1]
|
|
else:
|
|
moderation_domain = moderation_text
|
|
if moderation_domain.startswith('http') or \
|
|
moderation_domain.startswith('ipfs') or \
|
|
moderation_domain.startswith('ipns') or \
|
|
moderation_domain.startswith('hyper'):
|
|
# https://domain
|
|
block_domain, block_port = \
|
|
get_domain_from_actor(moderation_domain)
|
|
if block_domain:
|
|
full_block_domain = \
|
|
get_full_domain(block_domain, block_port)
|
|
if '@' in moderation_domain:
|
|
# nick@domain or *@domain
|
|
full_block_domain = \
|
|
moderation_domain.split('@')[1]
|
|
else:
|
|
# assume the text is a domain name
|
|
if not full_block_domain and '.' in moderation_domain:
|
|
nickname = '*'
|
|
full_block_domain = \
|
|
moderation_domain.strip()
|
|
if full_block_domain or nickname.startswith('#'):
|
|
if nickname.startswith('#') and ' ' in nickname:
|
|
nickname = nickname.split(' ')[0]
|
|
add_global_block(base_dir, nickname,
|
|
full_block_domain, moderation_reason)
|
|
blocked_cache_last_updated = \
|
|
self.server.blocked_cache_last_updated
|
|
self.server.blocked_cache_last_updated = \
|
|
update_blocked_cache(base_dir, blocked_cache,
|
|
blocked_cache_last_updated, 0)
|
|
if moderation_button == 'unblock':
|
|
full_block_domain = None
|
|
if ' ' in moderation_text:
|
|
moderation_domain = moderation_text.split(' ', 1)[0]
|
|
else:
|
|
moderation_domain = moderation_text
|
|
if moderation_domain.startswith('http') or \
|
|
moderation_domain.startswith('ipfs') or \
|
|
moderation_domain.startswith('ipns') or \
|
|
moderation_domain.startswith('hyper'):
|
|
# https://domain
|
|
block_domain, block_port = \
|
|
get_domain_from_actor(moderation_domain)
|
|
if block_domain:
|
|
full_block_domain = \
|
|
get_full_domain(block_domain, block_port)
|
|
if '@' in moderation_domain:
|
|
# nick@domain or *@domain
|
|
full_block_domain = moderation_domain.split('@')[1]
|
|
else:
|
|
# assume the text is a domain name
|
|
if not full_block_domain and '.' in moderation_domain:
|
|
nickname = '*'
|
|
full_block_domain = moderation_domain.strip()
|
|
if full_block_domain or nickname.startswith('#'):
|
|
if nickname.startswith('#') and ' ' in nickname:
|
|
nickname = nickname.split(' ')[0]
|
|
remove_global_block(base_dir, nickname,
|
|
full_block_domain)
|
|
blocked_cache_last_updated = \
|
|
self.server.blocked_cache_last_updated
|
|
self.server.blocked_cache_last_updated = \
|
|
update_blocked_cache(base_dir, blocked_cache,
|
|
blocked_cache_last_updated, 0)
|
|
if moderation_button == 'remove':
|
|
if '/statuses/' not in moderation_text:
|
|
remove_account(base_dir, nickname, domain, port)
|
|
else:
|
|
# remove a post or thread
|
|
post_filename = \
|
|
locate_post(base_dir, nickname, domain,
|
|
moderation_text)
|
|
if post_filename:
|
|
if can_remove_post(base_dir, domain, port,
|
|
moderation_text):
|
|
delete_post(base_dir,
|
|
http_prefix,
|
|
nickname, domain,
|
|
post_filename,
|
|
debug,
|
|
recent_posts_cache,
|
|
True)
|
|
if nickname != 'news':
|
|
# if this is a local blog post then also remove it
|
|
# from the news actor
|
|
post_filename = \
|
|
locate_post(base_dir, 'news', domain,
|
|
moderation_text)
|
|
if post_filename:
|
|
if can_remove_post(base_dir, domain, port,
|
|
moderation_text):
|
|
delete_post(base_dir,
|
|
http_prefix,
|
|
'news', domain,
|
|
post_filename,
|
|
debug,
|
|
recent_posts_cache,
|
|
True)
|
|
|
|
redirect_headers(self, actor_str + '/moderation',
|
|
cookie, calling_domain, 303)
|
|
self.server.postreq_busy = False
|
|
return
|