epicyon/manualapprove.py

399 lines
19 KiB
Python
Raw Normal View History

2020-04-03 16:45:00 +00:00
__filename__ = "manualapprove.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2023-01-21 23:03:30 +00:00
__version__ = "1.4.0"
2020-04-03 16:45:00 +00:00
__maintainer__ = "Bob Mottram"
2021-09-10 16:14:50 +00:00
__email__ = "bob@libreserver.org"
2020-04-03 16:45:00 +00:00
__status__ = "Production"
2021-06-15 15:08:12 +00:00
__module_group__ = "ActivityPub"
2019-07-20 18:25:40 +00:00
import os
2021-12-29 21:55:09 +00:00
from follow import followed_account_accepts
from follow import followed_account_rejects
from follow import remove_from_follow_requests
2022-12-18 15:29:54 +00:00
from utils import acct_handle_dir
2021-12-26 15:13:34 +00:00
from utils import load_json
2021-12-26 18:17:37 +00:00
from utils import remove_domain_port
2021-12-26 18:14:21 +00:00
from utils import get_port_from_domain
2021-12-26 12:24:40 +00:00
from utils import get_user_paths
2021-12-26 12:02:29 +00:00
from utils import acct_dir
2022-06-10 11:43:33 +00:00
from utils import text_in_file
2022-06-21 11:58:50 +00:00
from utils import remove_eol
2021-12-28 21:36:27 +00:00
from threads import thread_with_trace
2022-07-28 09:59:18 +00:00
from threads import begin_thread
from session import create_session
2019-07-20 18:25:40 +00:00
2020-04-03 16:45:00 +00:00
def manual_deny_follow_request(session, session_onion, session_i2p,
onion_domain: str, i2p_domain: str,
base_dir: str, http_prefix: str,
2021-12-29 21:55:09 +00:00
nickname: str, domain: str, port: int,
2022-01-02 21:58:58 +00:00
deny_handle: str,
2021-12-29 21:55:09 +00:00
federation_list: [],
2022-01-02 21:58:58 +00:00
send_threads: [], post_log: [],
2021-12-29 21:55:09 +00:00
cached_webfingers: {}, person_cache: {},
debug: bool,
project_version: str,
signing_priv_key_pem: str,
2023-09-15 21:04:31 +00:00
followers_sync_cache: {},
2023-10-25 19:55:40 +00:00
sites_unavailable: [],
system_language: str) -> None:
2019-07-20 18:25:40 +00:00
"""Manually deny a follow request
"""
2022-01-02 21:58:58 +00:00
accounts_dir = acct_dir(base_dir, nickname, domain)
# has this handle already been rejected?
2022-01-02 21:58:58 +00:00
rejected_follows_filename = accounts_dir + '/followrejects.txt'
if os.path.isfile(rejected_follows_filename):
2022-06-10 13:01:39 +00:00
if text_in_file(deny_handle, rejected_follows_filename):
2021-12-29 21:55:09 +00:00
remove_from_follow_requests(base_dir, nickname, domain,
2022-01-02 21:58:58 +00:00
deny_handle, debug)
2022-01-02 22:35:39 +00:00
print(deny_handle +
' has already been rejected as a follower of ' + nickname)
return
2022-01-02 21:58:58 +00:00
remove_from_follow_requests(base_dir, nickname, domain, deny_handle, debug)
# Store rejected follows
2021-11-25 21:18:53 +00:00
try:
2022-06-09 14:46:30 +00:00
with open(rejected_follows_filename, 'a+',
encoding='utf-8') as rejects_file:
2022-01-02 21:58:58 +00:00
rejects_file.write(deny_handle + '\n')
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 21:58:58 +00:00
print('EX: unable to append ' + rejected_follows_filename)
2020-03-22 21:16:02 +00:00
2022-01-02 21:58:58 +00:00
deny_nickname = deny_handle.split('@')[0]
2022-06-21 11:58:50 +00:00
deny_domain = remove_eol(deny_handle.split('@')[1])
2022-01-02 21:58:58 +00:00
deny_port = port
if ':' in deny_domain:
deny_port = get_port_from_domain(deny_domain)
deny_domain = remove_domain_port(deny_domain)
followed_account_rejects(session, session_onion, session_i2p,
onion_domain, i2p_domain,
base_dir, http_prefix,
2021-12-29 21:55:09 +00:00
nickname, domain, port,
2022-01-02 21:58:58 +00:00
deny_nickname, deny_domain, deny_port,
2021-12-29 21:55:09 +00:00
federation_list,
2022-01-02 21:58:58 +00:00
send_threads, post_log,
2021-12-29 21:55:09 +00:00
cached_webfingers, person_cache,
debug, project_version,
signing_priv_key_pem,
2023-09-15 21:04:31 +00:00
followers_sync_cache,
2023-10-25 19:55:40 +00:00
sites_unavailable,
system_language)
2020-04-03 16:45:00 +00:00
2022-01-02 21:58:58 +00:00
print('Follow request from ' + deny_handle + ' was denied.')
2020-03-22 21:16:02 +00:00
def manual_deny_follow_request_thread(session, session_onion, session_i2p,
onion_domain: str, i2p_domain: str,
base_dir: str, http_prefix: str,
2021-12-29 21:55:09 +00:00
nickname: str, domain: str, port: int,
2022-01-02 21:58:58 +00:00
deny_handle: str,
2021-12-29 21:55:09 +00:00
federation_list: [],
2022-01-02 21:58:58 +00:00
send_threads: [], post_log: [],
2021-12-29 21:55:09 +00:00
cached_webfingers: {}, person_cache: {},
debug: bool,
project_version: str,
signing_priv_key_pem: str,
2023-09-15 21:04:31 +00:00
followers_sync_cache: {},
2023-10-25 19:55:40 +00:00
sites_unavailable: [],
system_language: str) -> None:
2021-10-23 11:58:38 +00:00
"""Manually deny a follow request, within a thread so that the
user interface doesn't lag
"""
2022-03-13 11:01:07 +00:00
print('THREAD: manual_deny_follow_request')
2021-10-23 11:58:38 +00:00
thr = \
2021-12-29 21:55:09 +00:00
thread_with_trace(target=manual_deny_follow_request,
args=(session, session_onion, session_i2p,
onion_domain, i2p_domain,
base_dir, http_prefix,
2021-12-28 21:36:27 +00:00
nickname, domain, port,
2022-01-02 21:58:58 +00:00
deny_handle,
2021-12-28 21:36:27 +00:00
federation_list,
2022-01-02 21:58:58 +00:00
send_threads, post_log,
2021-12-28 21:36:27 +00:00
cached_webfingers, person_cache,
debug,
project_version,
signing_priv_key_pem,
2023-09-15 21:04:31 +00:00
followers_sync_cache,
2023-10-25 19:55:40 +00:00
sites_unavailable,
system_language), daemon=True)
2022-07-28 09:59:18 +00:00
begin_thread(thr, 'manual_deny_follow_request_thread')
2021-12-25 21:37:41 +00:00
send_threads.append(thr)
2021-10-23 11:58:38 +00:00
2022-01-02 21:58:58 +00:00
def _approve_follower_handle(account_dir: str, approve_handle: str) -> None:
2019-12-31 09:23:41 +00:00
""" Record manually approved handles so that if they unfollow and then
re-follow later then they don't need to be manually approved again
2020-03-22 21:16:02 +00:00
"""
2022-01-02 21:58:58 +00:00
approved_filename = account_dir + '/approved.txt'
if os.path.isfile(approved_filename):
2022-06-10 11:43:33 +00:00
if not text_in_file(approve_handle, approved_filename):
2021-11-25 21:18:53 +00:00
try:
2022-06-10 14:32:48 +00:00
with open(approved_filename, 'a+',
encoding='utf-8') as approved_file:
2022-01-02 21:58:58 +00:00
approved_file.write(approve_handle + '\n')
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 21:58:58 +00:00
print('EX: unable to append ' + approved_filename)
2019-12-31 09:23:41 +00:00
else:
2021-11-25 21:18:53 +00:00
try:
2022-06-10 14:32:48 +00:00
with open(approved_filename, 'w+',
encoding='utf-8') as approved_file:
2022-01-02 21:58:58 +00:00
approved_file.write(approve_handle + '\n')
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 21:58:58 +00:00
print('EX: unable to write ' + approved_filename)
2020-03-22 21:16:02 +00:00
2020-04-03 16:45:00 +00:00
def manual_approve_follow_request(session, session_onion, session_i2p,
onion_domain: str, i2p_domain: str,
base_dir: str, http_prefix: str,
2021-12-29 21:55:09 +00:00
nickname: str, domain: str, port: int,
2022-01-02 21:58:58 +00:00
approve_handle: str,
2021-12-29 21:55:09 +00:00
federation_list: [],
2022-01-02 21:58:58 +00:00
send_threads: [], post_log: [],
2021-12-29 21:55:09 +00:00
cached_webfingers: {}, person_cache: {},
debug: bool,
project_version: str,
signing_priv_key_pem: str,
proxy_type: str,
2023-09-15 21:04:31 +00:00
followers_sync_cache: {},
2023-10-25 19:55:40 +00:00
sites_unavailable: [],
system_language: str) -> None:
2019-07-20 18:25:40 +00:00
"""Manually approve a follow request
"""
2020-04-03 16:45:00 +00:00
handle = nickname + '@' + domain
print('Manual follow accept: ' + handle +
2022-01-02 21:58:58 +00:00
' approving follow request from ' + approve_handle)
2022-12-18 15:29:54 +00:00
account_dir = acct_handle_dir(base_dir, handle)
2022-01-02 21:58:58 +00:00
approve_follows_filename = account_dir + '/followrequests.txt'
if not os.path.isfile(approve_follows_filename):
2020-04-03 16:45:00 +00:00
print('Manual follow accept: follow requests file ' +
2022-01-02 21:58:58 +00:00
approve_follows_filename + ' not found')
2019-08-07 13:05:09 +00:00
return
2019-12-29 12:59:13 +00:00
# is the handle in the requests file?
2022-01-02 21:58:58 +00:00
approve_follows_str = ''
2022-06-09 14:46:30 +00:00
with open(approve_follows_filename, 'r', encoding='utf-8') as fp_foll:
2022-01-02 21:58:58 +00:00
approve_follows_str = fp_foll.read()
2020-10-28 10:02:02 +00:00
exists = False
2022-01-02 21:58:58 +00:00
approve_handle_full = approve_handle
if approve_handle in approve_follows_str:
2020-10-28 10:02:02 +00:00
exists = True
2022-01-02 21:58:58 +00:00
elif '@' in approve_handle:
2021-12-26 00:07:44 +00:00
group_account = False
2022-01-02 21:58:58 +00:00
if approve_handle.startswith('!'):
2021-12-26 00:07:44 +00:00
group_account = True
2022-01-02 21:58:58 +00:00
req_nick = approve_handle.split('@')[0].replace('!', '')
req_domain = approve_handle.split('@')[1].strip()
req_prefix = http_prefix + '://' + req_domain
2021-12-26 12:24:40 +00:00
paths = get_user_paths()
2023-05-10 11:53:38 +00:00
for user_path in paths:
if req_prefix + user_path + req_nick in approve_follows_str:
exists = True
approve_handle_full = req_prefix + user_path + req_nick
if group_account:
approve_handle_full = '!' + approve_handle_full
break
if not exists:
2023-05-10 11:53:38 +00:00
if req_prefix + '/' + req_nick in approve_follows_str:
exists = True
approve_handle_full = req_prefix + '/' + req_nick
if group_account:
approve_handle_full = '!' + approve_handle_full
if not exists:
2022-01-02 21:58:58 +00:00
print('Manual follow accept: ' + approve_handle_full +
2020-10-28 10:02:02 +00:00
' not in requests file "' +
2022-01-02 21:58:58 +00:00
approve_follows_str.replace('\n', ' ') +
'" ' + approve_follows_filename)
2019-08-07 13:05:09 +00:00
return
2020-03-22 21:16:02 +00:00
2022-06-09 14:46:30 +00:00
with open(approve_follows_filename + '.new', 'w+',
encoding='utf-8') as approvefilenew:
2022-01-02 21:58:58 +00:00
update_approved_followers = False
follow_activity_filename = None
2022-06-09 14:46:30 +00:00
with open(approve_follows_filename, 'r',
encoding='utf-8') as approvefile:
2022-01-02 21:58:58 +00:00
for handle_of_follow_requester in approvefile:
2021-06-22 12:27:10 +00:00
# is this the approved follow?
2022-01-02 21:58:58 +00:00
if handle_of_follow_requester.startswith(approve_handle_full):
handle_of_follow_requester = \
2022-06-21 11:58:50 +00:00
remove_eol(handle_of_follow_requester)
2022-01-02 21:58:58 +00:00
handle_of_follow_requester = \
handle_of_follow_requester.replace('\r', '')
2021-06-22 12:27:10 +00:00
port2 = port
2022-01-02 21:58:58 +00:00
if ':' in handle_of_follow_requester:
port2 = \
get_port_from_domain(handle_of_follow_requester)
requests_dir = account_dir + '/requests'
follow_activity_filename = \
requests_dir + '/' + \
handle_of_follow_requester + '.follow'
if os.path.isfile(follow_activity_filename):
follow_json = load_json(follow_activity_filename)
if follow_json:
approve_nickname = approve_handle.split('@')[0]
approve_domain = approve_handle.split('@')[1]
approve_domain = \
2022-06-21 11:58:50 +00:00
remove_eol(approve_domain)
2022-01-02 21:58:58 +00:00
approve_domain = \
approve_domain.replace('\r', '')
approve_port = port2
if ':' in approve_domain:
approve_port = \
get_port_from_domain(approve_domain)
approve_domain = \
remove_domain_port(approve_domain)
curr_domain = domain
curr_port = port
curr_session = session
curr_http_prefix = http_prefix
curr_proxy_type = proxy_type
if onion_domain and \
not curr_domain.endswith('.onion') and \
approve_domain.endswith('.onion'):
curr_domain = onion_domain
curr_port = 80
approve_port = 80
curr_session = session_onion
curr_http_prefix = 'http'
curr_proxy_type = 'tor'
elif (i2p_domain and
not curr_domain.endswith('.i2p') and
approve_domain.endswith('.i2p')):
curr_domain = i2p_domain
curr_port = 80
approve_port = 80
curr_session = session_i2p
curr_http_prefix = 'http'
curr_proxy_type = 'i2p'
if not curr_session:
curr_session = create_session(curr_proxy_type)
2021-06-22 12:27:10 +00:00
print('Manual follow accept: Sending Accept for ' +
handle + ' follow request from ' +
2022-01-02 21:58:58 +00:00
approve_nickname + '@' + approve_domain)
followed_account_accepts(curr_session, base_dir,
curr_http_prefix,
nickname,
curr_domain, curr_port,
2022-01-02 21:58:58 +00:00
approve_nickname,
approve_domain,
approve_port,
follow_json['actor'],
2021-12-29 21:55:09 +00:00
federation_list,
2022-01-02 21:58:58 +00:00
follow_json,
send_threads, post_log,
2021-12-29 21:55:09 +00:00
cached_webfingers,
person_cache,
debug,
project_version, False,
signing_priv_key_pem,
domain,
onion_domain,
i2p_domain,
2023-09-15 21:04:31 +00:00
followers_sync_cache,
2023-10-25 19:55:40 +00:00
sites_unavailable,
system_language)
2022-01-02 21:58:58 +00:00
update_approved_followers = True
2021-06-22 12:27:10 +00:00
else:
# this isn't the approved follow so it will remain
# in the requests file
2022-01-02 21:58:58 +00:00
approvefilenew.write(handle_of_follow_requester)
2019-08-31 14:21:59 +00:00
2022-01-02 21:58:58 +00:00
followers_filename = account_dir + '/followers.txt'
if update_approved_followers:
2019-08-31 14:21:59 +00:00
# update the followers
2022-01-02 21:58:58 +00:00
print('Manual follow accept: updating ' + followers_filename)
if os.path.isfile(followers_filename):
2022-06-10 11:43:33 +00:00
if not text_in_file(approve_handle_full, followers_filename):
2019-11-05 13:13:55 +00:00
try:
2022-06-09 14:46:30 +00:00
with open(followers_filename, 'r+',
encoding='utf-8') as followers_file:
2022-01-02 21:58:58 +00:00
content = followers_file.read()
if approve_handle_full + '\n' not in content:
followers_file.seek(0, 0)
followers_file.write(approve_handle_full + '\n' +
content)
2023-02-09 12:41:31 +00:00
except OSError as ex:
2020-04-03 16:45:00 +00:00
print('WARN: Manual follow accept. ' +
2021-12-25 15:28:52 +00:00
'Failed to write entry to followers file ' + str(ex))
2019-12-29 12:59:13 +00:00
else:
2022-01-02 21:58:58 +00:00
print('WARN: Manual follow accept: ' + approve_handle_full +
' already exists in ' + followers_filename)
2019-08-31 14:21:59 +00:00
else:
2020-04-03 16:45:00 +00:00
print('Manual follow accept: first follower accepted for ' +
2022-01-02 21:58:58 +00:00
handle + ' is ' + approve_handle_full)
2021-11-25 21:18:53 +00:00
try:
2022-06-09 14:46:30 +00:00
with open(followers_filename, 'w+',
encoding='utf-8') as followers_file:
2022-01-02 21:58:58 +00:00
followers_file.write(approve_handle_full + '\n')
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 21:58:58 +00:00
print('EX: unable to write ' + followers_filename)
2019-12-29 12:59:13 +00:00
# only update the follow requests file if the follow is confirmed to be
# in followers.txt
2022-06-10 13:01:39 +00:00
if text_in_file(approve_handle_full, followers_filename):
2019-12-31 09:23:41 +00:00
# mark this handle as approved for following
2022-01-02 21:58:58 +00:00
_approve_follower_handle(account_dir, approve_handle)
2019-12-29 12:59:13 +00:00
# update the follow requests with the handles not yet approved
2022-01-02 21:58:58 +00:00
os.rename(approve_follows_filename + '.new', approve_follows_filename)
# remove the .follow file
2022-01-02 21:58:58 +00:00
if follow_activity_filename:
if os.path.isfile(follow_activity_filename):
try:
2022-01-02 21:58:58 +00:00
os.remove(follow_activity_filename)
2021-11-25 18:42:38 +00:00
except OSError:
2021-12-29 21:55:09 +00:00
print('EX: manual_approve_follow_request ' +
2022-01-02 21:58:58 +00:00
'unable to delete ' + follow_activity_filename)
2019-12-29 12:59:13 +00:00
else:
try:
2022-01-02 21:58:58 +00:00
os.remove(approve_follows_filename + '.new')
2021-11-25 18:42:38 +00:00
except OSError:
2021-12-29 21:55:09 +00:00
print('EX: manual_approve_follow_request unable to delete ' +
2022-01-02 21:58:58 +00:00
approve_follows_filename + '.new')
2021-10-23 11:58:38 +00:00
def manual_approve_follow_request_thread(session, session_onion, session_i2p,
onion_domain: str, i2p_domain: str,
base_dir: str, http_prefix: str,
2021-12-29 21:55:09 +00:00
nickname: str, domain: str, port: int,
2022-01-02 21:58:58 +00:00
approve_handle: str,
2021-12-29 21:55:09 +00:00
federation_list: [],
2022-01-02 21:58:58 +00:00
send_threads: [], post_log: [],
2021-12-29 21:55:09 +00:00
cached_webfingers: {},
person_cache: {},
debug: bool,
project_version: str,
signing_priv_key_pem: str,
proxy_type: str,
2023-09-15 21:04:31 +00:00
followers_sync_cache: {},
2023-10-25 19:55:40 +00:00
sites_unavailable: [],
system_language: str) -> None:
2021-10-23 11:58:38 +00:00
"""Manually approve a follow request, in a thread so as not to cause
the UI to lag
"""
2022-03-13 11:01:07 +00:00
print('THREAD: manual_approve_follow_request')
2021-10-23 11:58:38 +00:00
thr = \
2021-12-29 21:55:09 +00:00
thread_with_trace(target=manual_approve_follow_request,
args=(session, session_onion, session_i2p,
onion_domain, i2p_domain,
base_dir, http_prefix,
2021-12-28 21:36:27 +00:00
nickname, domain, port,
2022-01-02 21:58:58 +00:00
approve_handle,
2021-12-28 21:36:27 +00:00
federation_list,
2022-01-02 21:58:58 +00:00
send_threads, post_log,
2021-12-28 21:36:27 +00:00
cached_webfingers, person_cache,
debug,
project_version,
signing_priv_key_pem,
proxy_type,
2023-09-15 21:04:31 +00:00
followers_sync_cache,
2023-10-25 19:55:40 +00:00
sites_unavailable,
system_language), daemon=True)
2022-07-28 09:59:18 +00:00
begin_thread(thr, 'manual_approve_follow_request_thread')
2021-12-25 21:37:41 +00:00
send_threads.append(thr)