2020-04-03 17:01:25 +00:00
|
|
|
__filename__ = "migrate.py"
|
|
|
|
__author__ = "Bob Mottram"
|
|
|
|
__license__ = "AGPL3+"
|
2024-01-21 19:01:20 +00:00
|
|
|
__version__ = "1.5.0"
|
2020-04-03 17:01:25 +00:00
|
|
|
__maintainer__ = "Bob Mottram"
|
2021-09-10 16:14:50 +00:00
|
|
|
__email__ = "bob@libreserver.org"
|
2020-04-03 17:01:25 +00:00
|
|
|
__status__ = "Production"
|
2021-06-15 15:08:12 +00:00
|
|
|
__module_group__ = "Core"
|
2019-10-31 10:36:35 +00:00
|
|
|
|
|
|
|
import os
|
2024-09-13 13:58:14 +00:00
|
|
|
from flags import has_group_type
|
2024-05-12 12:35:26 +00:00
|
|
|
from utils import data_dir
|
2021-12-26 18:46:43 +00:00
|
|
|
from utils import is_account_dir
|
2021-12-27 22:19:18 +00:00
|
|
|
from utils import get_nickname_from_actor
|
2021-12-27 19:05:25 +00:00
|
|
|
from utils import get_domain_from_actor
|
2021-12-26 12:02:29 +00:00
|
|
|
from utils import acct_dir
|
2021-12-29 21:55:09 +00:00
|
|
|
from webfinger import webfinger_handle
|
|
|
|
from blocking import is_blocked
|
|
|
|
from posts import get_user_url
|
2021-12-28 20:32:11 +00:00
|
|
|
from follow import unfollow_account
|
2021-12-29 21:55:09 +00:00
|
|
|
from person import get_actor_json
|
2019-10-31 10:36:35 +00:00
|
|
|
|
2020-04-03 17:01:25 +00:00
|
|
|
|
2021-12-29 21:55:09 +00:00
|
|
|
def _move_following_handles_for_account(base_dir: str,
|
|
|
|
nickname: str, domain: str,
|
|
|
|
session,
|
|
|
|
http_prefix: str,
|
|
|
|
cached_webfingers: {},
|
|
|
|
debug: bool,
|
2024-02-09 22:09:18 +00:00
|
|
|
signing_priv_key_pem: str,
|
|
|
|
block_federated: []) -> int:
|
2021-01-09 15:08:26 +00:00
|
|
|
"""Goes through all follows for an account and updates any that have moved
|
2019-10-31 10:36:35 +00:00
|
|
|
"""
|
2021-01-09 15:08:26 +00:00
|
|
|
ctr = 0
|
2022-01-03 10:43:14 +00:00
|
|
|
following_filename = \
|
|
|
|
acct_dir(base_dir, nickname, domain) + '/following.txt'
|
|
|
|
if not os.path.isfile(following_filename):
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
2024-07-13 14:38:11 +00:00
|
|
|
try:
|
|
|
|
with open(following_filename, 'r', encoding='utf-8') as fp_foll:
|
|
|
|
following_handles = fp_foll.readlines()
|
|
|
|
for follow_handle in following_handles:
|
|
|
|
follow_handle = follow_handle.strip("\n").strip("\r")
|
|
|
|
ctr += \
|
|
|
|
_update_moved_handle(base_dir, nickname, domain,
|
|
|
|
follow_handle, session,
|
|
|
|
http_prefix, cached_webfingers,
|
|
|
|
debug, signing_priv_key_pem,
|
|
|
|
block_federated)
|
|
|
|
except OSError:
|
|
|
|
print('EX: _move_following_handles_for_account unable to read ' +
|
|
|
|
following_filename)
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
|
|
|
|
|
|
|
|
2021-12-29 21:55:09 +00:00
|
|
|
def _update_moved_handle(base_dir: str, nickname: str, domain: str,
|
|
|
|
handle: str, session,
|
|
|
|
http_prefix: str, cached_webfingers: {},
|
2024-02-09 22:09:18 +00:00
|
|
|
debug: bool, signing_priv_key_pem: str,
|
|
|
|
block_federated: []) -> int:
|
2021-01-09 15:08:26 +00:00
|
|
|
"""Check if an account has moved, and if so then alter following.txt
|
|
|
|
for each account.
|
|
|
|
Returns 1 if moved, 0 otherwise
|
2019-10-31 10:36:35 +00:00
|
|
|
"""
|
2021-01-09 15:08:26 +00:00
|
|
|
ctr = 0
|
|
|
|
if '@' not in handle:
|
|
|
|
return ctr
|
|
|
|
if len(handle) < 5:
|
|
|
|
return ctr
|
|
|
|
if handle.startswith('@'):
|
|
|
|
handle = handle[1:]
|
2022-01-02 14:51:02 +00:00
|
|
|
wf_request = webfinger_handle(session, handle,
|
|
|
|
http_prefix, cached_webfingers,
|
|
|
|
domain, __version__, debug, False,
|
|
|
|
signing_priv_key_pem)
|
|
|
|
if not wf_request:
|
2021-01-09 15:08:26 +00:00
|
|
|
print('updateMovedHandle unable to webfinger ' + handle)
|
|
|
|
return ctr
|
|
|
|
|
2022-01-02 14:51:02 +00:00
|
|
|
if not isinstance(wf_request, dict):
|
2021-01-09 15:08:26 +00:00
|
|
|
print('updateMovedHandle webfinger for ' + handle +
|
2022-01-02 14:51:02 +00:00
|
|
|
' did not return a dict. ' + str(wf_request))
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
|
|
|
|
2022-01-03 10:43:14 +00:00
|
|
|
person_url = None
|
2022-01-02 14:51:02 +00:00
|
|
|
if wf_request.get('errors'):
|
|
|
|
print('wf_request error: ' + str(wf_request['errors']))
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
2019-10-31 10:36:35 +00:00
|
|
|
|
2022-01-03 10:43:14 +00:00
|
|
|
if not person_url:
|
|
|
|
person_url = get_user_url(wf_request, 0, debug)
|
|
|
|
if not person_url:
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
|
|
|
|
2021-07-03 21:42:26 +00:00
|
|
|
gnunet = False
|
2021-12-25 17:09:22 +00:00
|
|
|
if http_prefix == 'gnunet':
|
2021-07-03 21:42:26 +00:00
|
|
|
gnunet = True
|
2022-04-29 13:54:13 +00:00
|
|
|
ipfs = False
|
|
|
|
if http_prefix == 'ipfs':
|
|
|
|
ipfs = True
|
|
|
|
ipns = False
|
|
|
|
if http_prefix == 'ipns':
|
|
|
|
ipns = True
|
2022-01-03 10:43:14 +00:00
|
|
|
person_json = \
|
2022-04-29 13:54:13 +00:00
|
|
|
get_actor_json(domain, person_url, http_prefix, gnunet, ipfs, ipns,
|
|
|
|
debug, False,
|
2021-12-29 21:55:09 +00:00
|
|
|
signing_priv_key_pem, None)
|
2022-01-03 10:43:14 +00:00
|
|
|
if not person_json:
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
2022-01-03 10:43:14 +00:00
|
|
|
if not person_json.get('movedTo'):
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
2022-01-03 10:43:14 +00:00
|
|
|
moved_to_url = person_json['movedTo']
|
|
|
|
if '://' not in moved_to_url:
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
2022-01-03 10:43:14 +00:00
|
|
|
if '.' not in moved_to_url:
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
2022-01-03 10:43:14 +00:00
|
|
|
moved_to_nickname = get_nickname_from_actor(moved_to_url)
|
|
|
|
if not moved_to_nickname:
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
2022-01-03 10:43:14 +00:00
|
|
|
moved_to_domain, moved_to_port = get_domain_from_actor(moved_to_url)
|
|
|
|
if not moved_to_domain:
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
2022-01-03 10:43:14 +00:00
|
|
|
moved_to_domain_full = moved_to_domain
|
|
|
|
if moved_to_port:
|
|
|
|
if moved_to_port not in (80, 443):
|
|
|
|
moved_to_domain_full = moved_to_domain + ':' + str(moved_to_port)
|
|
|
|
group_account = has_group_type(base_dir, moved_to_url, None)
|
2021-12-29 21:55:09 +00:00
|
|
|
if is_blocked(base_dir, nickname, domain,
|
2024-02-09 22:09:18 +00:00
|
|
|
moved_to_nickname, moved_to_domain,
|
|
|
|
None, block_federated):
|
2021-01-09 15:08:26 +00:00
|
|
|
# someone that you follow has moved to a blocked domain
|
|
|
|
# so just unfollow them
|
2021-12-28 20:32:11 +00:00
|
|
|
unfollow_account(base_dir, nickname, domain,
|
2022-01-03 10:43:14 +00:00
|
|
|
moved_to_nickname, moved_to_domain_full,
|
2021-12-28 20:32:11 +00:00
|
|
|
debug, group_account, 'following.txt')
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
2021-01-09 20:27:17 +00:00
|
|
|
|
2022-01-03 10:43:14 +00:00
|
|
|
following_filename = \
|
|
|
|
acct_dir(base_dir, nickname, domain) + '/following.txt'
|
|
|
|
if os.path.isfile(following_filename):
|
2022-11-27 18:28:42 +00:00
|
|
|
following_handles = []
|
2024-07-13 14:38:11 +00:00
|
|
|
try:
|
2024-07-16 12:20:58 +00:00
|
|
|
with open(following_filename, 'r', encoding='utf-8') as fp_foll1:
|
|
|
|
following_handles = fp_foll1.readlines()
|
2024-07-13 14:38:11 +00:00
|
|
|
except OSError:
|
|
|
|
print('EX: _update_moved_handle unable to read ' +
|
|
|
|
following_filename)
|
2021-01-09 20:27:17 +00:00
|
|
|
|
2022-11-27 18:28:42 +00:00
|
|
|
moved_to_handle = moved_to_nickname + '@' + moved_to_domain_full
|
|
|
|
handle_lower = handle.lower()
|
|
|
|
|
|
|
|
refollow_filename = \
|
|
|
|
acct_dir(base_dir, nickname, domain) + '/refollow.txt'
|
|
|
|
|
|
|
|
# unfollow the old handle
|
2024-07-16 12:20:58 +00:00
|
|
|
with open(following_filename, 'w+', encoding='utf-8') as fp_foll2:
|
2022-11-27 18:28:42 +00:00
|
|
|
for follow_handle in following_handles:
|
|
|
|
if follow_handle.strip("\n").strip("\r").lower() != \
|
|
|
|
handle_lower:
|
2024-07-16 12:20:58 +00:00
|
|
|
fp_foll2.write(follow_handle)
|
2024-07-15 19:32:09 +00:00
|
|
|
continue
|
|
|
|
handle_nickname = handle.split('@')[0]
|
|
|
|
handle_domain = handle.split('@')[1]
|
|
|
|
unfollow_account(base_dir, nickname, domain,
|
|
|
|
handle_nickname,
|
|
|
|
handle_domain,
|
|
|
|
debug, group_account, 'following.txt')
|
|
|
|
ctr += 1
|
|
|
|
print('Unfollowed ' + handle + ' who has moved to ' +
|
|
|
|
moved_to_handle)
|
2022-11-27 18:28:42 +00:00
|
|
|
|
2024-07-15 19:32:09 +00:00
|
|
|
# save the new handles to the refollow list
|
|
|
|
if os.path.isfile(refollow_filename):
|
|
|
|
try:
|
|
|
|
with open(refollow_filename, 'a+',
|
2024-07-16 12:20:58 +00:00
|
|
|
encoding='utf-8') as fp_refoll:
|
|
|
|
fp_refoll.write(moved_to_handle + '\n')
|
2024-07-15 19:32:09 +00:00
|
|
|
except OSError:
|
|
|
|
print('EX: ' +
|
|
|
|
'_update_moved_handle unable to append ' +
|
|
|
|
refollow_filename)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
with open(refollow_filename, 'w+',
|
2024-07-16 12:20:58 +00:00
|
|
|
encoding='utf-8') as fp_refoll:
|
|
|
|
fp_refoll.write(moved_to_handle + '\n')
|
2024-07-15 19:32:09 +00:00
|
|
|
except OSError:
|
|
|
|
print('EX: _update_moved_handle unable to write ' +
|
|
|
|
refollow_filename)
|
2021-01-09 20:27:17 +00:00
|
|
|
|
2022-01-03 10:43:14 +00:00
|
|
|
followers_filename = \
|
2021-12-26 12:02:29 +00:00
|
|
|
acct_dir(base_dir, nickname, domain) + '/followers.txt'
|
2022-01-03 10:43:14 +00:00
|
|
|
if os.path.isfile(followers_filename):
|
2022-11-27 18:35:11 +00:00
|
|
|
follower_handles = []
|
2024-02-01 13:30:59 +00:00
|
|
|
try:
|
2024-07-16 12:20:58 +00:00
|
|
|
with open(followers_filename, 'r', encoding='utf-8') as fp_foll3:
|
|
|
|
follower_handles = fp_foll3.readlines()
|
2024-02-01 13:30:59 +00:00
|
|
|
except OSError:
|
|
|
|
print('EX: _update_moved_handle unable to read ' +
|
|
|
|
followers_filename)
|
2021-01-09 20:27:17 +00:00
|
|
|
|
2022-11-27 18:35:11 +00:00
|
|
|
handle_lower = handle.lower()
|
2021-01-09 20:27:17 +00:00
|
|
|
|
2022-11-27 18:35:11 +00:00
|
|
|
# remove followers who have moved
|
2024-02-01 13:30:59 +00:00
|
|
|
try:
|
2024-07-16 12:20:58 +00:00
|
|
|
with open(followers_filename, 'w+', encoding='utf-8') as fp_foll4:
|
2024-02-01 13:30:59 +00:00
|
|
|
for follower_handle in follower_handles:
|
|
|
|
if follower_handle.strip("\n").strip("\r").lower() != \
|
|
|
|
handle_lower:
|
2024-07-16 12:20:58 +00:00
|
|
|
fp_foll4.write(follower_handle)
|
2024-02-01 13:30:59 +00:00
|
|
|
else:
|
|
|
|
ctr += 1
|
|
|
|
print('Removed follower who has moved ' + handle)
|
|
|
|
except OSError:
|
|
|
|
print('EX: _update_moved_handle unable to remove moved follower ' +
|
|
|
|
handle)
|
2021-01-09 20:27:17 +00:00
|
|
|
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|
|
|
|
|
|
|
|
|
2021-12-29 21:55:09 +00:00
|
|
|
def migrate_accounts(base_dir: str, session,
|
|
|
|
http_prefix: str, cached_webfingers: {},
|
2024-02-09 22:09:18 +00:00
|
|
|
debug: bool, signing_priv_key_pem: str,
|
|
|
|
block_federated: []) -> int:
|
2021-01-09 15:08:26 +00:00
|
|
|
"""If followed accounts change then this modifies the
|
|
|
|
following lists for each account accordingly.
|
|
|
|
Returns the number of accounts migrated
|
|
|
|
"""
|
2019-10-31 10:36:35 +00:00
|
|
|
# update followers and following lists for each account
|
2021-01-09 15:08:26 +00:00
|
|
|
ctr = 0
|
2024-05-12 12:35:26 +00:00
|
|
|
dir_str = data_dir(base_dir)
|
|
|
|
for _, dirs, _ in os.walk(dir_str):
|
2019-10-31 10:36:35 +00:00
|
|
|
for handle in dirs:
|
2021-12-26 18:46:43 +00:00
|
|
|
if not is_account_dir(handle):
|
2021-01-09 15:08:26 +00:00
|
|
|
continue
|
|
|
|
nickname = handle.split('@')[0]
|
|
|
|
domain = handle.split('@')[1]
|
|
|
|
ctr += \
|
2021-12-29 21:55:09 +00:00
|
|
|
_move_following_handles_for_account(base_dir, nickname, domain,
|
|
|
|
session, http_prefix,
|
|
|
|
cached_webfingers, debug,
|
2024-02-09 22:09:18 +00:00
|
|
|
signing_priv_key_pem,
|
|
|
|
block_federated)
|
2020-12-13 22:13:45 +00:00
|
|
|
break
|
2021-01-09 15:08:26 +00:00
|
|
|
return ctr
|