epicyon/manualapprove.py

297 lines
14 KiB
Python

__filename__ = "manualapprove.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.2.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "ActivityPub"
import os
from follow import followedAccountAccepts
from follow import followedAccountRejects
from follow import removeFromFollowRequests
from utils import loadJson
from utils import removeDomainPort
from utils import getPortFromDomain
from utils import getUserPaths
from utils import acctDir
from threads import threadWithTrace
def manualDenyFollowRequest(session, baseDir: str,
httpPrefix: str,
nickname: str, domain: str, port: int,
denyHandle: str,
federationList: [],
sendThreads: [], postLog: [],
cachedWebfingers: {}, personCache: {},
debug: bool,
projectVersion: str,
signingPrivateKeyPem: str) -> None:
"""Manually deny a follow request
"""
accountsDir = acctDir(baseDir, nickname, domain)
# has this handle already been rejected?
rejectedFollowsFilename = accountsDir + '/followrejects.txt'
if os.path.isfile(rejectedFollowsFilename):
if denyHandle in open(rejectedFollowsFilename).read():
removeFromFollowRequests(baseDir, nickname, domain,
denyHandle, debug)
print(denyHandle + ' has already been rejected as a follower of ' +
nickname)
return
removeFromFollowRequests(baseDir, nickname, domain, denyHandle, debug)
# Store rejected follows
with open(rejectedFollowsFilename, 'a+') as rejectsFile:
rejectsFile.write(denyHandle + '\n')
denyNickname = denyHandle.split('@')[0]
denyDomain = \
denyHandle.split('@')[1].replace('\n', '').replace('\r', '')
denyPort = port
if ':' in denyDomain:
denyPort = getPortFromDomain(denyDomain)
denyDomain = removeDomainPort(denyDomain)
followedAccountRejects(session, baseDir, httpPrefix,
nickname, domain, port,
denyNickname, denyDomain, denyPort,
federationList,
sendThreads, postLog,
cachedWebfingers, personCache,
debug, projectVersion,
signingPrivateKeyPem)
print('Follow request from ' + denyHandle + ' was denied.')
def manualDenyFollowRequestThread(session, baseDir: str,
httpPrefix: str,
nickname: str, domain: str, port: int,
denyHandle: str,
federationList: [],
sendThreads: [], postLog: [],
cachedWebfingers: {}, personCache: {},
debug: bool,
projectVersion: str,
signingPrivateKeyPem: str) -> None:
"""Manually deny a follow request, within a thread so that the
user interface doesn't lag
"""
thr = \
threadWithTrace(target=manualDenyFollowRequest,
args=(session, baseDir,
httpPrefix,
nickname, domain, port,
denyHandle,
federationList,
sendThreads, postLog,
cachedWebfingers, personCache,
debug,
projectVersion,
signingPrivateKeyPem), daemon=True)
thr.start()
sendThreads.append(thr)
def _approveFollowerHandle(accountDir: str, approveHandle: str) -> None:
""" Record manually approved handles so that if they unfollow and then
re-follow later then they don't need to be manually approved again
"""
approvedFilename = accountDir + '/approved.txt'
if os.path.isfile(approvedFilename):
if approveHandle not in open(approvedFilename).read():
with open(approvedFilename, 'a+') as approvedFile:
approvedFile.write(approveHandle + '\n')
else:
with open(approvedFilename, 'w+') as approvedFile:
approvedFile.write(approveHandle + '\n')
def manualApproveFollowRequest(session, baseDir: str,
httpPrefix: str,
nickname: str, domain: str, port: int,
approveHandle: str,
federationList: [],
sendThreads: [], postLog: [],
cachedWebfingers: {}, personCache: {},
debug: bool,
projectVersion: str,
signingPrivateKeyPem: str) -> None:
"""Manually approve a follow request
"""
handle = nickname + '@' + domain
print('Manual follow accept: ' + handle +
' approving follow request from ' + approveHandle)
accountDir = baseDir + '/accounts/' + handle
approveFollowsFilename = accountDir + '/followrequests.txt'
if not os.path.isfile(approveFollowsFilename):
print('Manual follow accept: follow requests file ' +
approveFollowsFilename + ' not found')
return
# is the handle in the requests file?
approveFollowsStr = ''
with open(approveFollowsFilename, 'r') as fpFollowers:
approveFollowsStr = fpFollowers.read()
exists = False
approveHandleFull = approveHandle
if approveHandle in approveFollowsStr:
exists = True
elif '@' in approveHandle:
groupAccount = False
if approveHandle.startswith('!'):
groupAccount = True
reqNick = approveHandle.split('@')[0].replace('!', '')
reqDomain = approveHandle.split('@')[1].strip()
reqPrefix = httpPrefix + '://' + reqDomain
paths = getUserPaths()
for userPath in paths:
if reqPrefix + userPath + reqNick in approveFollowsStr:
exists = True
approveHandleFull = reqPrefix + userPath + reqNick
if groupAccount:
approveHandleFull = '!' + approveHandleFull
break
if not exists:
print('Manual follow accept: ' + approveHandleFull +
' not in requests file "' +
approveFollowsStr.replace('\n', ' ') +
'" ' + approveFollowsFilename)
return
with open(approveFollowsFilename + '.new', 'w+') as approvefilenew:
updateApprovedFollowers = False
followActivityfilename = None
with open(approveFollowsFilename, 'r') as approvefile:
for handleOfFollowRequester in approvefile:
# is this the approved follow?
if handleOfFollowRequester.startswith(approveHandleFull):
handleOfFollowRequester = \
handleOfFollowRequester.replace('\n', '')
handleOfFollowRequester = \
handleOfFollowRequester.replace('\r', '')
port2 = port
if ':' in handleOfFollowRequester:
port2 = getPortFromDomain(handleOfFollowRequester)
requestsDir = accountDir + '/requests'
followActivityfilename = \
requestsDir + '/' + handleOfFollowRequester + '.follow'
if os.path.isfile(followActivityfilename):
followJson = loadJson(followActivityfilename)
if followJson:
approveNickname = approveHandle.split('@')[0]
approveDomain = approveHandle.split('@')[1]
approveDomain = \
approveDomain.replace('\n', '')
approveDomain = \
approveDomain.replace('\r', '')
approvePort = port2
if ':' in approveDomain:
approvePort = getPortFromDomain(approveDomain)
approveDomain = removeDomainPort(approveDomain)
print('Manual follow accept: Sending Accept for ' +
handle + ' follow request from ' +
approveNickname + '@' + approveDomain)
followedAccountAccepts(session, baseDir,
httpPrefix,
nickname, domain, port,
approveNickname,
approveDomain,
approvePort,
followJson['actor'],
federationList,
followJson,
sendThreads, postLog,
cachedWebfingers,
personCache,
debug,
projectVersion, False,
signingPrivateKeyPem)
updateApprovedFollowers = True
else:
# this isn't the approved follow so it will remain
# in the requests file
approvefilenew.write(handleOfFollowRequester)
followersFilename = accountDir + '/followers.txt'
if updateApprovedFollowers:
# update the followers
print('Manual follow accept: updating ' + followersFilename)
if os.path.isfile(followersFilename):
if approveHandleFull not in open(followersFilename).read():
try:
with open(followersFilename, 'r+') as followersFile:
content = followersFile.read()
if approveHandleFull + '\n' not in content:
followersFile.seek(0, 0)
followersFile.write(approveHandleFull + '\n' +
content)
except Exception as e:
print('WARN: Manual follow accept. ' +
'Failed to write entry to followers file ' + str(e))
else:
print('WARN: Manual follow accept: ' + approveHandleFull +
' already exists in ' + followersFilename)
else:
print('Manual follow accept: first follower accepted for ' +
handle + ' is ' + approveHandleFull)
with open(followersFilename, 'w+') as followersFile:
followersFile.write(approveHandleFull + '\n')
# only update the follow requests file if the follow is confirmed to be
# in followers.txt
if approveHandleFull in open(followersFilename).read():
# mark this handle as approved for following
_approveFollowerHandle(accountDir, approveHandle)
# update the follow requests with the handles not yet approved
os.rename(approveFollowsFilename + '.new', approveFollowsFilename)
# remove the .follow file
if followActivityfilename:
if os.path.isfile(followActivityfilename):
try:
os.remove(followActivityfilename)
except BaseException:
print('EX: manualApproveFollowRequest unable to delete ' +
followActivityfilename)
pass
else:
try:
os.remove(approveFollowsFilename + '.new')
except BaseException:
print('EX: manualApproveFollowRequest unable to delete ' +
approveFollowsFilename + '.new')
pass
def manualApproveFollowRequestThread(session, baseDir: str,
httpPrefix: str,
nickname: str, domain: str, port: int,
approveHandle: str,
federationList: [],
sendThreads: [], postLog: [],
cachedWebfingers: {}, personCache: {},
debug: bool,
projectVersion: str,
signingPrivateKeyPem: str) -> None:
"""Manually approve a follow request, in a thread so as not to cause
the UI to lag
"""
thr = \
threadWithTrace(target=manualApproveFollowRequest,
args=(session, baseDir,
httpPrefix,
nickname, domain, port,
approveHandle,
federationList,
sendThreads, postLog,
cachedWebfingers, personCache,
debug,
projectVersion,
signingPrivateKeyPem), daemon=True)
thr.start()
sendThreads.append(thr)