mirror of https://gitlab.com/bashrc2/epicyon
Validate sending actor when follow request is received
parent
0e0160a698
commit
23af727bec
228
follow.py
228
follow.py
|
@ -11,11 +11,9 @@ from pprint import pprint
|
||||||
import os
|
import os
|
||||||
from utils import hasObjectStringObject
|
from utils import hasObjectStringObject
|
||||||
from utils import hasObjectStringType
|
from utils import hasObjectStringType
|
||||||
from utils import hasActor
|
|
||||||
from utils import removeDomainPort
|
from utils import removeDomainPort
|
||||||
from utils import hasUsersPath
|
from utils import hasUsersPath
|
||||||
from utils import getFullDomain
|
from utils import getFullDomain
|
||||||
from utils import isSystemAccount
|
|
||||||
from utils import getFollowersList
|
from utils import getFollowersList
|
||||||
from utils import validNickname
|
from utils import validNickname
|
||||||
from utils import domainPermitted
|
from utils import domainPermitted
|
||||||
|
@ -31,7 +29,6 @@ from utils import isAccountDir
|
||||||
from utils import getUserPaths
|
from utils import getUserPaths
|
||||||
from utils import acctDir
|
from utils import acctDir
|
||||||
from utils import hasGroupType
|
from utils import hasGroupType
|
||||||
from utils import isGroupAccount
|
|
||||||
from utils import localActorUrl
|
from utils import localActorUrl
|
||||||
from acceptreject import createAccept
|
from acceptreject import createAccept
|
||||||
from acceptreject import createReject
|
from acceptreject import createReject
|
||||||
|
@ -39,7 +36,6 @@ from webfinger import webfingerHandle
|
||||||
from auth import createBasicAuthHeader
|
from auth import createBasicAuthHeader
|
||||||
from session import getJson
|
from session import getJson
|
||||||
from session import postJson
|
from session import postJson
|
||||||
from cache import getPersonPubKey
|
|
||||||
|
|
||||||
|
|
||||||
def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
|
def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
|
||||||
|
@ -418,7 +414,7 @@ def _getNoOfFollows(baseDir: str, nickname: str, domain: str,
|
||||||
return ctr
|
return ctr
|
||||||
|
|
||||||
|
|
||||||
def _getNoOfFollowers(baseDir: str,
|
def getNoOfFollowers(baseDir: str,
|
||||||
nickname: str, domain: str, authenticated: bool) -> int:
|
nickname: str, domain: str, authenticated: bool) -> int:
|
||||||
"""Returns the number of followers of the given person
|
"""Returns the number of followers of the given person
|
||||||
"""
|
"""
|
||||||
|
@ -562,7 +558,7 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str,
|
||||||
return following
|
return following
|
||||||
|
|
||||||
|
|
||||||
def _followApprovalRequired(baseDir: str, nicknameToFollow: str,
|
def followApprovalRequired(baseDir: str, nicknameToFollow: str,
|
||||||
domainToFollow: str, debug: bool,
|
domainToFollow: str, debug: bool,
|
||||||
followRequestHandle: str) -> bool:
|
followRequestHandle: str) -> bool:
|
||||||
""" Returns the policy for follower approvals
|
""" Returns the policy for follower approvals
|
||||||
|
@ -591,7 +587,7 @@ def _followApprovalRequired(baseDir: str, nicknameToFollow: str,
|
||||||
return manuallyApproveFollows
|
return manuallyApproveFollows
|
||||||
|
|
||||||
|
|
||||||
def _noOfFollowRequests(baseDir: str,
|
def noOfFollowRequests(baseDir: str,
|
||||||
nicknameToFollow: str, domainToFollow: str,
|
nicknameToFollow: str, domainToFollow: str,
|
||||||
nickname: str, domain: str, fromPort: int,
|
nickname: str, domain: str, fromPort: int,
|
||||||
followType: str) -> int:
|
followType: str) -> int:
|
||||||
|
@ -608,7 +604,7 @@ def _noOfFollowRequests(baseDir: str,
|
||||||
with open(approveFollowsFilename, 'r') as f:
|
with open(approveFollowsFilename, 'r') as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
except OSError:
|
except OSError:
|
||||||
print('EX: _noOfFollowRequests ' + approveFollowsFilename)
|
print('EX: noOfFollowRequests ' + approveFollowsFilename)
|
||||||
if lines:
|
if lines:
|
||||||
if followType == "onion":
|
if followType == "onion":
|
||||||
for fileLine in lines:
|
for fileLine in lines:
|
||||||
|
@ -623,7 +619,7 @@ def _noOfFollowRequests(baseDir: str,
|
||||||
return ctr
|
return ctr
|
||||||
|
|
||||||
|
|
||||||
def _storeFollowRequest(baseDir: str,
|
def storeFollowRequest(baseDir: str,
|
||||||
nicknameToFollow: str, domainToFollow: str, port: int,
|
nicknameToFollow: str, domainToFollow: str, port: int,
|
||||||
nickname: str, domain: str, fromPort: int,
|
nickname: str, domain: str, fromPort: int,
|
||||||
followJson: {},
|
followJson: {},
|
||||||
|
@ -651,7 +647,7 @@ def _storeFollowRequest(baseDir: str,
|
||||||
with open(followersFilename, 'r') as fpFollowers:
|
with open(followersFilename, 'r') as fpFollowers:
|
||||||
followersStr = fpFollowers.read()
|
followersStr = fpFollowers.read()
|
||||||
except OSError:
|
except OSError:
|
||||||
print('EX: _storeFollowRequest ' + followersFilename)
|
print('EX: storeFollowRequest ' + followersFilename)
|
||||||
|
|
||||||
if approveHandle in followersStr:
|
if approveHandle in followersStr:
|
||||||
alreadyFollowing = True
|
alreadyFollowing = True
|
||||||
|
@ -696,7 +692,7 @@ def _storeFollowRequest(baseDir: str,
|
||||||
with open(approveFollowsFilename, 'a+') as fp:
|
with open(approveFollowsFilename, 'a+') as fp:
|
||||||
fp.write(approveHandleStored + '\n')
|
fp.write(approveHandleStored + '\n')
|
||||||
except OSError:
|
except OSError:
|
||||||
print('EX: _storeFollowRequest 2 ' + approveFollowsFilename)
|
print('EX: storeFollowRequest 2 ' + approveFollowsFilename)
|
||||||
else:
|
else:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: ' + approveHandleStored +
|
print('DEBUG: ' + approveHandleStored +
|
||||||
|
@ -706,7 +702,7 @@ def _storeFollowRequest(baseDir: str,
|
||||||
with open(approveFollowsFilename, 'w+') as fp:
|
with open(approveFollowsFilename, 'w+') as fp:
|
||||||
fp.write(approveHandleStored + '\n')
|
fp.write(approveHandleStored + '\n')
|
||||||
except OSError:
|
except OSError:
|
||||||
print('EX: _storeFollowRequest 3 ' + approveFollowsFilename)
|
print('EX: storeFollowRequest 3 ' + approveFollowsFilename)
|
||||||
|
|
||||||
# store the follow request in its own directory
|
# store the follow request in its own directory
|
||||||
# We don't rely upon the inbox because items in there could expire
|
# We don't rely upon the inbox because items in there could expire
|
||||||
|
@ -717,212 +713,6 @@ def _storeFollowRequest(baseDir: str,
|
||||||
return saveJson(followJson, followActivityfilename)
|
return saveJson(followJson, followActivityfilename)
|
||||||
|
|
||||||
|
|
||||||
def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
|
|
||||||
port: int, sendThreads: [], postLog: [],
|
|
||||||
cachedWebfingers: {}, personCache: {},
|
|
||||||
messageJson: {}, federationList: [],
|
|
||||||
debug: bool, projectVersion: str,
|
|
||||||
maxFollowers: int, onionDomain: str,
|
|
||||||
signingPrivateKeyPem: str) -> bool:
|
|
||||||
"""Receives a follow request within the POST section of HTTPServer
|
|
||||||
"""
|
|
||||||
if not messageJson['type'].startswith('Follow'):
|
|
||||||
if not messageJson['type'].startswith('Join'):
|
|
||||||
return False
|
|
||||||
print('Receiving follow request')
|
|
||||||
if not hasActor(messageJson, debug):
|
|
||||||
return False
|
|
||||||
if not hasUsersPath(messageJson['actor']):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: users/profile/accounts/channel missing from actor')
|
|
||||||
return False
|
|
||||||
domain, tempPort = getDomainFromActor(messageJson['actor'])
|
|
||||||
fromPort = port
|
|
||||||
domainFull = getFullDomain(domain, tempPort)
|
|
||||||
if tempPort:
|
|
||||||
fromPort = tempPort
|
|
||||||
if not domainPermitted(domain, federationList):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: follower from domain not permitted - ' + domain)
|
|
||||||
return False
|
|
||||||
nickname = getNicknameFromActor(messageJson['actor'])
|
|
||||||
if not nickname:
|
|
||||||
# single user instance
|
|
||||||
nickname = 'dev'
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: follow request does not contain a ' +
|
|
||||||
'nickname. Assuming single user instance.')
|
|
||||||
if not messageJson.get('to'):
|
|
||||||
messageJson['to'] = messageJson['object']
|
|
||||||
if not hasUsersPath(messageJson['object']):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: users/profile/channel/accounts ' +
|
|
||||||
'not found within object')
|
|
||||||
return False
|
|
||||||
domainToFollow, tempPort = getDomainFromActor(messageJson['object'])
|
|
||||||
if not domainPermitted(domainToFollow, federationList):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: follow domain not permitted ' + domainToFollow)
|
|
||||||
return True
|
|
||||||
domainToFollowFull = getFullDomain(domainToFollow, tempPort)
|
|
||||||
nicknameToFollow = getNicknameFromActor(messageJson['object'])
|
|
||||||
if not nicknameToFollow:
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: follow request does not contain a ' +
|
|
||||||
'nickname for the account followed')
|
|
||||||
return True
|
|
||||||
if isSystemAccount(nicknameToFollow):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: Cannot follow system account - ' +
|
|
||||||
nicknameToFollow)
|
|
||||||
return True
|
|
||||||
if maxFollowers > 0:
|
|
||||||
if _getNoOfFollowers(baseDir,
|
|
||||||
nicknameToFollow, domainToFollow,
|
|
||||||
True) > maxFollowers:
|
|
||||||
print('WARN: ' + nicknameToFollow +
|
|
||||||
' has reached their maximum number of followers')
|
|
||||||
return True
|
|
||||||
handleToFollow = nicknameToFollow + '@' + domainToFollow
|
|
||||||
if domainToFollow == domain:
|
|
||||||
if not os.path.isdir(baseDir + '/accounts/' + handleToFollow):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: followed account not found - ' +
|
|
||||||
baseDir + '/accounts/' + handleToFollow)
|
|
||||||
return True
|
|
||||||
|
|
||||||
if isFollowerOfPerson(baseDir,
|
|
||||||
nicknameToFollow, domainToFollowFull,
|
|
||||||
nickname, domainFull):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: ' + nickname + '@' + domain +
|
|
||||||
' is already a follower of ' +
|
|
||||||
nicknameToFollow + '@' + domainToFollow)
|
|
||||||
return True
|
|
||||||
|
|
||||||
# what is the followers policy?
|
|
||||||
approveHandle = nickname + '@' + domainFull
|
|
||||||
if _followApprovalRequired(baseDir, nicknameToFollow,
|
|
||||||
domainToFollow, debug, approveHandle):
|
|
||||||
print('Follow approval is required')
|
|
||||||
if domain.endswith('.onion'):
|
|
||||||
if _noOfFollowRequests(baseDir,
|
|
||||||
nicknameToFollow, domainToFollow,
|
|
||||||
nickname, domain, fromPort,
|
|
||||||
'onion') > 5:
|
|
||||||
print('Too many follow requests from onion addresses')
|
|
||||||
return False
|
|
||||||
elif domain.endswith('.i2p'):
|
|
||||||
if _noOfFollowRequests(baseDir,
|
|
||||||
nicknameToFollow, domainToFollow,
|
|
||||||
nickname, domain, fromPort,
|
|
||||||
'i2p') > 5:
|
|
||||||
print('Too many follow requests from i2p addresses')
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
if _noOfFollowRequests(baseDir,
|
|
||||||
nicknameToFollow, domainToFollow,
|
|
||||||
nickname, domain, fromPort,
|
|
||||||
'') > 10:
|
|
||||||
print('Too many follow requests')
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Get the actor for the follower and add it to the cache.
|
|
||||||
# Getting their public key has the same result
|
|
||||||
if debug:
|
|
||||||
print('Obtaining the following actor: ' + messageJson['actor'])
|
|
||||||
if not getPersonPubKey(baseDir, session, messageJson['actor'],
|
|
||||||
personCache, debug, projectVersion,
|
|
||||||
httpPrefix, domainToFollow, onionDomain,
|
|
||||||
signingPrivateKeyPem):
|
|
||||||
if debug:
|
|
||||||
print('Unable to obtain following actor: ' +
|
|
||||||
messageJson['actor'])
|
|
||||||
|
|
||||||
groupAccount = \
|
|
||||||
hasGroupType(baseDir, messageJson['actor'], personCache)
|
|
||||||
if groupAccount and isGroupAccount(baseDir, nickname, domain):
|
|
||||||
print('Group cannot follow a group')
|
|
||||||
return False
|
|
||||||
|
|
||||||
print('Storing follow request for approval')
|
|
||||||
return _storeFollowRequest(baseDir,
|
|
||||||
nicknameToFollow, domainToFollow, port,
|
|
||||||
nickname, domain, fromPort,
|
|
||||||
messageJson, debug, messageJson['actor'],
|
|
||||||
groupAccount)
|
|
||||||
else:
|
|
||||||
print('Follow request does not require approval ' + approveHandle)
|
|
||||||
# update the followers
|
|
||||||
accountToBeFollowed = \
|
|
||||||
acctDir(baseDir, nicknameToFollow, domainToFollow)
|
|
||||||
if os.path.isdir(accountToBeFollowed):
|
|
||||||
followersFilename = accountToBeFollowed + '/followers.txt'
|
|
||||||
|
|
||||||
# for actors which don't follow the mastodon
|
|
||||||
# /users/ path convention store the full actor
|
|
||||||
if '/users/' not in messageJson['actor']:
|
|
||||||
approveHandle = messageJson['actor']
|
|
||||||
|
|
||||||
# Get the actor for the follower and add it to the cache.
|
|
||||||
# Getting their public key has the same result
|
|
||||||
if debug:
|
|
||||||
print('Obtaining the following actor: ' + messageJson['actor'])
|
|
||||||
if not getPersonPubKey(baseDir, session, messageJson['actor'],
|
|
||||||
personCache, debug, projectVersion,
|
|
||||||
httpPrefix, domainToFollow, onionDomain,
|
|
||||||
signingPrivateKeyPem):
|
|
||||||
if debug:
|
|
||||||
print('Unable to obtain following actor: ' +
|
|
||||||
messageJson['actor'])
|
|
||||||
|
|
||||||
print('Updating followers file: ' +
|
|
||||||
followersFilename + ' adding ' + approveHandle)
|
|
||||||
if os.path.isfile(followersFilename):
|
|
||||||
if approveHandle not in open(followersFilename).read():
|
|
||||||
groupAccount = \
|
|
||||||
hasGroupType(baseDir,
|
|
||||||
messageJson['actor'], personCache)
|
|
||||||
if debug:
|
|
||||||
print(approveHandle + ' / ' + messageJson['actor'] +
|
|
||||||
' is Group: ' + str(groupAccount))
|
|
||||||
if groupAccount and \
|
|
||||||
isGroupAccount(baseDir, nickname, domain):
|
|
||||||
print('Group cannot follow a group')
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
with open(followersFilename, 'r+') as followersFile:
|
|
||||||
content = followersFile.read()
|
|
||||||
if approveHandle + '\n' not in content:
|
|
||||||
followersFile.seek(0, 0)
|
|
||||||
if not groupAccount:
|
|
||||||
followersFile.write(approveHandle +
|
|
||||||
'\n' + content)
|
|
||||||
else:
|
|
||||||
followersFile.write('!' + approveHandle +
|
|
||||||
'\n' + content)
|
|
||||||
except Exception as e:
|
|
||||||
print('WARN: ' +
|
|
||||||
'Failed to write entry to followers file ' +
|
|
||||||
str(e))
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
with open(followersFilename, 'w+') as followersFile:
|
|
||||||
followersFile.write(approveHandle + '\n')
|
|
||||||
except OSError:
|
|
||||||
print('EX: unable to write ' + followersFilename)
|
|
||||||
|
|
||||||
print('Beginning follow accept')
|
|
||||||
return followedAccountAccepts(session, baseDir, httpPrefix,
|
|
||||||
nicknameToFollow, domainToFollow, port,
|
|
||||||
nickname, domain, fromPort,
|
|
||||||
messageJson['actor'], federationList,
|
|
||||||
messageJson, sendThreads, postLog,
|
|
||||||
cachedWebfingers, personCache,
|
|
||||||
debug, projectVersion, True,
|
|
||||||
signingPrivateKeyPem)
|
|
||||||
|
|
||||||
|
|
||||||
def followedAccountAccepts(session, baseDir: str, httpPrefix: str,
|
def followedAccountAccepts(session, baseDir: str, httpPrefix: str,
|
||||||
nicknameToFollow: str, domainToFollow: str,
|
nicknameToFollow: str, domainToFollow: str,
|
||||||
port: int,
|
port: int,
|
||||||
|
@ -1124,7 +914,7 @@ def sendFollowRequest(session, baseDir: str,
|
||||||
newFollowJson['to'] = followedId
|
newFollowJson['to'] = followedId
|
||||||
print('Follow request: ' + str(newFollowJson))
|
print('Follow request: ' + str(newFollowJson))
|
||||||
|
|
||||||
if _followApprovalRequired(baseDir, nickname, domain, debug,
|
if followApprovalRequired(baseDir, nickname, domain, debug,
|
||||||
followHandle):
|
followHandle):
|
||||||
# Remove any follow requests rejected for the account being followed.
|
# Remove any follow requests rejected for the account being followed.
|
||||||
# It's assumed that if you are following someone then you are
|
# It's assumed that if you are following someone then you are
|
||||||
|
|
229
inbox.py
229
inbox.py
|
@ -17,6 +17,9 @@ from languages import understoodPostLanguage
|
||||||
from like import updateLikesCollection
|
from like import updateLikesCollection
|
||||||
from reaction import updateReactionCollection
|
from reaction import updateReactionCollection
|
||||||
from reaction import validEmojiContent
|
from reaction import validEmojiContent
|
||||||
|
from utils import domainPermitted
|
||||||
|
from utils import isGroupAccount
|
||||||
|
from utils import isSystemAccount
|
||||||
from utils import invalidCiphertext
|
from utils import invalidCiphertext
|
||||||
from utils import removeHtml
|
from utils import removeHtml
|
||||||
from utils import fileLastModified
|
from utils import fileLastModified
|
||||||
|
@ -65,9 +68,14 @@ from httpsig import verifyPostHeaders
|
||||||
from session import createSession
|
from session import createSession
|
||||||
from follow import followerApprovalActive
|
from follow import followerApprovalActive
|
||||||
from follow import isFollowingActor
|
from follow import isFollowingActor
|
||||||
from follow import receiveFollowRequest
|
|
||||||
from follow import getFollowersOfActor
|
from follow import getFollowersOfActor
|
||||||
from follow import unfollowerOfAccount
|
from follow import unfollowerOfAccount
|
||||||
|
from follow import isFollowerOfPerson
|
||||||
|
from follow import followedAccountAccepts
|
||||||
|
from follow import storeFollowRequest
|
||||||
|
from follow import noOfFollowRequests
|
||||||
|
from follow import getNoOfFollowers
|
||||||
|
from follow import followApprovalRequired
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from cache import storePersonInCache
|
from cache import storePersonInCache
|
||||||
from cache import getPersonPubKey
|
from cache import getPersonPubKey
|
||||||
|
@ -3834,6 +3842,221 @@ def _checkJsonSignature(baseDir: str, queueJson: {}) -> (bool, bool):
|
||||||
return hasJsonSignature, jwebsigType
|
return hasJsonSignature, jwebsigType
|
||||||
|
|
||||||
|
|
||||||
|
def _receiveFollowRequest(session, baseDir: str, httpPrefix: str,
|
||||||
|
port: int, sendThreads: [], postLog: [],
|
||||||
|
cachedWebfingers: {}, personCache: {},
|
||||||
|
messageJson: {}, federationList: [],
|
||||||
|
debug: bool, projectVersion: str,
|
||||||
|
maxFollowers: int, onionDomain: str,
|
||||||
|
signingPrivateKeyPem: str, unitTest: bool) -> bool:
|
||||||
|
"""Receives a follow request within the POST section of HTTPServer
|
||||||
|
"""
|
||||||
|
if not messageJson['type'].startswith('Follow'):
|
||||||
|
if not messageJson['type'].startswith('Join'):
|
||||||
|
return False
|
||||||
|
print('Receiving follow request')
|
||||||
|
if not hasActor(messageJson, debug):
|
||||||
|
return False
|
||||||
|
if not hasUsersPath(messageJson['actor']):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: users/profile/accounts/channel missing from actor')
|
||||||
|
return False
|
||||||
|
domain, tempPort = getDomainFromActor(messageJson['actor'])
|
||||||
|
fromPort = port
|
||||||
|
domainFull = getFullDomain(domain, tempPort)
|
||||||
|
if tempPort:
|
||||||
|
fromPort = tempPort
|
||||||
|
if not domainPermitted(domain, federationList):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: follower from domain not permitted - ' + domain)
|
||||||
|
return False
|
||||||
|
nickname = getNicknameFromActor(messageJson['actor'])
|
||||||
|
if not nickname:
|
||||||
|
# single user instance
|
||||||
|
nickname = 'dev'
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: follow request does not contain a ' +
|
||||||
|
'nickname. Assuming single user instance.')
|
||||||
|
if not messageJson.get('to'):
|
||||||
|
messageJson['to'] = messageJson['object']
|
||||||
|
if not hasUsersPath(messageJson['object']):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: users/profile/channel/accounts ' +
|
||||||
|
'not found within object')
|
||||||
|
return False
|
||||||
|
domainToFollow, tempPort = getDomainFromActor(messageJson['object'])
|
||||||
|
if not domainPermitted(domainToFollow, federationList):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: follow domain not permitted ' + domainToFollow)
|
||||||
|
return True
|
||||||
|
domainToFollowFull = getFullDomain(domainToFollow, tempPort)
|
||||||
|
nicknameToFollow = getNicknameFromActor(messageJson['object'])
|
||||||
|
if not nicknameToFollow:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: follow request does not contain a ' +
|
||||||
|
'nickname for the account followed')
|
||||||
|
return True
|
||||||
|
if isSystemAccount(nicknameToFollow):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: Cannot follow system account - ' +
|
||||||
|
nicknameToFollow)
|
||||||
|
return True
|
||||||
|
if maxFollowers > 0:
|
||||||
|
if getNoOfFollowers(baseDir,
|
||||||
|
nicknameToFollow, domainToFollow,
|
||||||
|
True) > maxFollowers:
|
||||||
|
print('WARN: ' + nicknameToFollow +
|
||||||
|
' has reached their maximum number of followers')
|
||||||
|
return True
|
||||||
|
handleToFollow = nicknameToFollow + '@' + domainToFollow
|
||||||
|
if domainToFollow == domain:
|
||||||
|
if not os.path.isdir(baseDir + '/accounts/' + handleToFollow):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: followed account not found - ' +
|
||||||
|
baseDir + '/accounts/' + handleToFollow)
|
||||||
|
return True
|
||||||
|
|
||||||
|
if isFollowerOfPerson(baseDir,
|
||||||
|
nicknameToFollow, domainToFollowFull,
|
||||||
|
nickname, domainFull):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: ' + nickname + '@' + domain +
|
||||||
|
' is already a follower of ' +
|
||||||
|
nicknameToFollow + '@' + domainToFollow)
|
||||||
|
return True
|
||||||
|
|
||||||
|
approveHandle = nickname + '@' + domainFull
|
||||||
|
|
||||||
|
# is the actor sending the request valid?
|
||||||
|
if not validSendingActor(session, baseDir,
|
||||||
|
nicknameToFollow, domainToFollow,
|
||||||
|
personCache, messageJson,
|
||||||
|
signingPrivateKeyPem, debug, unitTest):
|
||||||
|
print('REJECT spam follow request ' + approveHandle)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# what is the followers policy?
|
||||||
|
if followApprovalRequired(baseDir, nicknameToFollow,
|
||||||
|
domainToFollow, debug, approveHandle):
|
||||||
|
print('Follow approval is required')
|
||||||
|
if domain.endswith('.onion'):
|
||||||
|
if noOfFollowRequests(baseDir,
|
||||||
|
nicknameToFollow, domainToFollow,
|
||||||
|
nickname, domain, fromPort,
|
||||||
|
'onion') > 5:
|
||||||
|
print('Too many follow requests from onion addresses')
|
||||||
|
return False
|
||||||
|
elif domain.endswith('.i2p'):
|
||||||
|
if noOfFollowRequests(baseDir,
|
||||||
|
nicknameToFollow, domainToFollow,
|
||||||
|
nickname, domain, fromPort,
|
||||||
|
'i2p') > 5:
|
||||||
|
print('Too many follow requests from i2p addresses')
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if noOfFollowRequests(baseDir,
|
||||||
|
nicknameToFollow, domainToFollow,
|
||||||
|
nickname, domain, fromPort,
|
||||||
|
'') > 10:
|
||||||
|
print('Too many follow requests')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Get the actor for the follower and add it to the cache.
|
||||||
|
# Getting their public key has the same result
|
||||||
|
if debug:
|
||||||
|
print('Obtaining the following actor: ' + messageJson['actor'])
|
||||||
|
if not getPersonPubKey(baseDir, session, messageJson['actor'],
|
||||||
|
personCache, debug, projectVersion,
|
||||||
|
httpPrefix, domainToFollow, onionDomain,
|
||||||
|
signingPrivateKeyPem):
|
||||||
|
if debug:
|
||||||
|
print('Unable to obtain following actor: ' +
|
||||||
|
messageJson['actor'])
|
||||||
|
|
||||||
|
groupAccount = \
|
||||||
|
hasGroupType(baseDir, messageJson['actor'], personCache)
|
||||||
|
if groupAccount and isGroupAccount(baseDir, nickname, domain):
|
||||||
|
print('Group cannot follow a group')
|
||||||
|
return False
|
||||||
|
|
||||||
|
print('Storing follow request for approval')
|
||||||
|
return storeFollowRequest(baseDir,
|
||||||
|
nicknameToFollow, domainToFollow, port,
|
||||||
|
nickname, domain, fromPort,
|
||||||
|
messageJson, debug, messageJson['actor'],
|
||||||
|
groupAccount)
|
||||||
|
else:
|
||||||
|
print('Follow request does not require approval ' + approveHandle)
|
||||||
|
# update the followers
|
||||||
|
accountToBeFollowed = \
|
||||||
|
acctDir(baseDir, nicknameToFollow, domainToFollow)
|
||||||
|
if os.path.isdir(accountToBeFollowed):
|
||||||
|
followersFilename = accountToBeFollowed + '/followers.txt'
|
||||||
|
|
||||||
|
# for actors which don't follow the mastodon
|
||||||
|
# /users/ path convention store the full actor
|
||||||
|
if '/users/' not in messageJson['actor']:
|
||||||
|
approveHandle = messageJson['actor']
|
||||||
|
|
||||||
|
# Get the actor for the follower and add it to the cache.
|
||||||
|
# Getting their public key has the same result
|
||||||
|
if debug:
|
||||||
|
print('Obtaining the following actor: ' + messageJson['actor'])
|
||||||
|
if not getPersonPubKey(baseDir, session, messageJson['actor'],
|
||||||
|
personCache, debug, projectVersion,
|
||||||
|
httpPrefix, domainToFollow, onionDomain,
|
||||||
|
signingPrivateKeyPem):
|
||||||
|
if debug:
|
||||||
|
print('Unable to obtain following actor: ' +
|
||||||
|
messageJson['actor'])
|
||||||
|
|
||||||
|
print('Updating followers file: ' +
|
||||||
|
followersFilename + ' adding ' + approveHandle)
|
||||||
|
if os.path.isfile(followersFilename):
|
||||||
|
if approveHandle not in open(followersFilename).read():
|
||||||
|
groupAccount = \
|
||||||
|
hasGroupType(baseDir,
|
||||||
|
messageJson['actor'], personCache)
|
||||||
|
if debug:
|
||||||
|
print(approveHandle + ' / ' + messageJson['actor'] +
|
||||||
|
' is Group: ' + str(groupAccount))
|
||||||
|
if groupAccount and \
|
||||||
|
isGroupAccount(baseDir, nickname, domain):
|
||||||
|
print('Group cannot follow a group')
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
with open(followersFilename, 'r+') as followersFile:
|
||||||
|
content = followersFile.read()
|
||||||
|
if approveHandle + '\n' not in content:
|
||||||
|
followersFile.seek(0, 0)
|
||||||
|
if not groupAccount:
|
||||||
|
followersFile.write(approveHandle +
|
||||||
|
'\n' + content)
|
||||||
|
else:
|
||||||
|
followersFile.write('!' + approveHandle +
|
||||||
|
'\n' + content)
|
||||||
|
except Exception as e:
|
||||||
|
print('WARN: ' +
|
||||||
|
'Failed to write entry to followers file ' +
|
||||||
|
str(e))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
with open(followersFilename, 'w+') as followersFile:
|
||||||
|
followersFile.write(approveHandle + '\n')
|
||||||
|
except OSError:
|
||||||
|
print('EX: unable to write ' + followersFilename)
|
||||||
|
|
||||||
|
print('Beginning follow accept')
|
||||||
|
return followedAccountAccepts(session, baseDir, httpPrefix,
|
||||||
|
nicknameToFollow, domainToFollow, port,
|
||||||
|
nickname, domain, fromPort,
|
||||||
|
messageJson['actor'], federationList,
|
||||||
|
messageJson, sendThreads, postLog,
|
||||||
|
cachedWebfingers, personCache,
|
||||||
|
debug, projectVersion, True,
|
||||||
|
signingPrivateKeyPem)
|
||||||
|
|
||||||
|
|
||||||
def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
|
def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
projectVersion: str,
|
projectVersion: str,
|
||||||
baseDir: str, httpPrefix: str, sendThreads: [], postLog: [],
|
baseDir: str, httpPrefix: str, sendThreads: [], postLog: [],
|
||||||
|
@ -4134,7 +4357,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: checking for follow requests')
|
print('DEBUG: checking for follow requests')
|
||||||
if receiveFollowRequest(session,
|
if _receiveFollowRequest(session,
|
||||||
baseDir, httpPrefix, port,
|
baseDir, httpPrefix, port,
|
||||||
sendThreads, postLog,
|
sendThreads, postLog,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
|
@ -4143,7 +4366,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
federationList,
|
federationList,
|
||||||
debug, projectVersion,
|
debug, projectVersion,
|
||||||
maxFollowers, onionDomain,
|
maxFollowers, onionDomain,
|
||||||
signingPrivateKeyPem):
|
signingPrivateKeyPem, unitTest):
|
||||||
if os.path.isfile(queueFilename):
|
if os.path.isfile(queueFilename):
|
||||||
try:
|
try:
|
||||||
os.remove(queueFilename)
|
os.remove(queueFilename)
|
||||||
|
|
Loading…
Reference in New Issue