| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | __filename__ = "follow.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							| 
									
										
										
										
											2021-01-26 10:07:42 +00:00
										 |  |  | __version__ = "1.2.0" | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							|  |  |  | __email__ = "bob@freedombone.net" | 
					
						
							|  |  |  | __status__ = "Production" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-29 18:23:13 +00:00
										 |  |  | from pprint import pprint | 
					
						
							|  |  |  | import os | 
					
						
							| 
									
										
										
										
											2020-12-23 10:57:44 +00:00
										 |  |  | from utils import hasUsersPath | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  | from utils import getFullDomain | 
					
						
							| 
									
										
										
										
											2020-10-23 19:05:17 +00:00
										 |  |  | from utils import isSystemAccount | 
					
						
							| 
									
										
										
										
											2020-09-25 14:14:59 +00:00
										 |  |  | from utils import getFollowersList | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  | from utils import validNickname | 
					
						
							| 
									
										
										
										
											2019-07-02 10:39:55 +00:00
										 |  |  | from utils import domainPermitted | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  | from utils import getDomainFromActor | 
					
						
							|  |  |  | from utils import getNicknameFromActor | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  | from utils import getStatusNumber | 
					
						
							|  |  |  | from utils import followPerson | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  | from posts import sendSignedJson | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  | from posts import getPersonBox | 
					
						
							| 
									
										
										
										
											2019-10-22 11:55:06 +00:00
										 |  |  | from utils import loadJson | 
					
						
							|  |  |  | from utils import saveJson | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  | from acceptreject import createAccept | 
					
						
							| 
									
										
										
										
											2019-09-09 12:19:00 +00:00
										 |  |  | from acceptreject import createReject | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  | from webfinger import webfingerHandle | 
					
						
							|  |  |  | from auth import createBasicAuthHeader | 
					
						
							|  |  |  | from session import postJson | 
					
						
							| 
									
										
										
										
											2019-06-29 18:23:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-13 22:01:10 +00:00
										 |  |  | def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None: | 
					
						
							|  |  |  |     """Creates initial lastseen files for all follows
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     for subdir, dirs, files in os.walk(baseDir + '/accounts'): | 
					
						
							|  |  |  |         for acct in dirs: | 
					
						
							|  |  |  |             if '@' not in acct: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if 'inbox@' in acct or 'news@' in acct: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             accountDir = os.path.join(baseDir + '/accounts', acct) | 
					
						
							|  |  |  |             followingFilename = accountDir + '/following.txt' | 
					
						
							|  |  |  |             if not os.path.isfile(followingFilename): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             lastSeenDir = accountDir + '/lastseen' | 
					
						
							|  |  |  |             if not os.path.isdir(lastSeenDir): | 
					
						
							|  |  |  |                 os.mkdir(lastSeenDir) | 
					
						
							|  |  |  |             with open(followingFilename, 'r') as fp: | 
					
						
							|  |  |  |                 followingHandles = fp.readlines() | 
					
						
							|  |  |  |                 for handle in followingHandles: | 
					
						
							|  |  |  |                     if '#' in handle: | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     if '@' not in handle: | 
					
						
							|  |  |  |                         continue | 
					
						
							| 
									
										
										
										
											2020-12-13 22:24:02 +00:00
										 |  |  |                     handle = handle.replace('\n', '') | 
					
						
							| 
									
										
										
										
											2020-12-13 22:01:10 +00:00
										 |  |  |                     nickname = handle.split('@')[0] | 
					
						
							| 
									
										
										
										
											2020-12-13 22:23:39 +00:00
										 |  |  |                     domain = handle.split('@')[1] | 
					
						
							| 
									
										
										
										
											2020-12-13 22:01:10 +00:00
										 |  |  |                     actor = \ | 
					
						
							| 
									
										
										
										
											2020-12-13 22:32:13 +00:00
										 |  |  |                         httpPrefix + '://' + domain + '/users/' + nickname | 
					
						
							| 
									
										
										
										
											2020-12-13 22:01:10 +00:00
										 |  |  |                     lastSeenFilename = \ | 
					
						
							|  |  |  |                         lastSeenDir + '/' + actor.replace('/', '#') + '.txt' | 
					
						
							| 
									
										
										
										
											2020-12-13 22:24:41 +00:00
										 |  |  |                     print('lastSeenFilename: ' + lastSeenFilename) | 
					
						
							| 
									
										
										
										
											2020-12-13 22:01:10 +00:00
										 |  |  |                     if not os.path.isfile(lastSeenFilename): | 
					
						
							|  |  |  |                         with open(lastSeenFilename, 'w+') as fp: | 
					
						
							| 
									
										
										
										
											2020-12-13 22:28:39 +00:00
										 |  |  |                             fp.write(str(100)) | 
					
						
							| 
									
										
										
										
											2020-12-13 22:01:10 +00:00
										 |  |  |         break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  | def _preApprovedFollower(baseDir: str, | 
					
						
							|  |  |  |                          nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-12-26 10:22:56 +00:00
										 |  |  |                          approveHandle: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-12-31 09:23:41 +00:00
										 |  |  |     """Is the given handle an already manually approved follower?
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							|  |  |  |     accountDir = baseDir + '/accounts/' + handle | 
					
						
							|  |  |  |     approvedFilename = accountDir + '/approved.txt' | 
					
						
							| 
									
										
										
										
											2019-12-31 09:23:41 +00:00
										 |  |  |     if os.path.isfile(approvedFilename): | 
					
						
							|  |  |  |         if approveHandle in open(approvedFilename).read(): | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  | def _removeFromFollowBase(baseDir: str, | 
					
						
							|  |  |  |                           nickname: str, domain: str, | 
					
						
							|  |  |  |                           acceptOrDenyHandle: str, followFile: str, | 
					
						
							|  |  |  |                           debug: bool) -> None: | 
					
						
							| 
									
										
										
										
											2021-03-12 10:44:37 +00:00
										 |  |  |     """Removes a handle/actor from follow requests or rejects file
 | 
					
						
							| 
									
										
										
										
											2019-09-18 17:04:19 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							|  |  |  |     accountsDir = baseDir + '/accounts/' + handle | 
					
						
							|  |  |  |     approveFollowsFilename = accountsDir + '/' + followFile + '.txt' | 
					
						
							| 
									
										
										
										
											2019-09-18 17:04:19 +00:00
										 |  |  |     if not os.path.isfile(approveFollowsFilename): | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('WARN: Approve follow requests file ' + | 
					
						
							|  |  |  |                   approveFollowsFilename + ' not found') | 
					
						
							| 
									
										
										
										
											2019-09-18 17:04:19 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-03-12 10:44:37 +00:00
										 |  |  |     acceptDenyActor = None | 
					
						
							| 
									
										
										
										
											2019-10-06 09:48:37 +00:00
										 |  |  |     if acceptOrDenyHandle not in open(approveFollowsFilename).read(): | 
					
						
							| 
									
										
										
										
											2021-03-12 10:44:37 +00:00
										 |  |  |         # is this stored in the file as an actor rather than a handle? | 
					
						
							|  |  |  |         acceptDenyNickname = acceptOrDenyHandle.split('@')[0] | 
					
						
							|  |  |  |         acceptDenyDomain = acceptOrDenyHandle.split('@')[1] | 
					
						
							|  |  |  |         # for each possible users path construct an actor and | 
					
						
							|  |  |  |         # check if it exists in teh file | 
					
						
							|  |  |  |         usersPaths = ('users', 'profile', 'channel', 'accounts', 'u') | 
					
						
							|  |  |  |         actorFound = False | 
					
						
							|  |  |  |         for usersName in usersPaths: | 
					
						
							|  |  |  |             acceptDenyActor = \ | 
					
						
							|  |  |  |                 '://' + acceptDenyDomain + '/' + \ | 
					
						
							|  |  |  |                 usersName + '/' + acceptDenyNickname | 
					
						
							|  |  |  |             if acceptDenyActor in open(approveFollowsFilename).read(): | 
					
						
							|  |  |  |                 actorFound = True | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |         if not actorFound: | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     approvefilenew = open(approveFollowsFilename + '.new', 'w+') | 
					
						
							| 
									
										
										
										
											2019-09-18 17:04:19 +00:00
										 |  |  |     with open(approveFollowsFilename, 'r') as approvefile: | 
					
						
							| 
									
										
										
										
											2021-03-12 10:52:50 +00:00
										 |  |  |         if not acceptDenyActor: | 
					
						
							|  |  |  |             for approveHandle in approvefile: | 
					
						
							|  |  |  |                 if not approveHandle.startswith(acceptOrDenyHandle): | 
					
						
							|  |  |  |                     approvefilenew.write(approveHandle) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             for approveHandle in approvefile: | 
					
						
							|  |  |  |                 if acceptDenyActor not in approveHandle: | 
					
						
							|  |  |  |                     approvefilenew.write(approveHandle) | 
					
						
							| 
									
										
										
										
											2019-09-18 17:04:19 +00:00
										 |  |  |     approvefilenew.close() | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     os.rename(approveFollowsFilename + '.new', approveFollowsFilename) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-18 17:04:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | def removeFromFollowRequests(baseDir: str, | 
					
						
							|  |  |  |                              nickname: str, domain: str, | 
					
						
							|  |  |  |                              denyHandle: str, debug: bool) -> None: | 
					
						
							| 
									
										
										
										
											2019-10-06 09:48:37 +00:00
										 |  |  |     """Removes a handle from follow requests
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |     _removeFromFollowBase(baseDir, nickname, domain, | 
					
						
							|  |  |  |                           denyHandle, 'followrequests', debug) | 
					
						
							| 
									
										
										
										
											2019-10-06 09:48:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  | def _removeFromFollowRejects(baseDir: str, | 
					
						
							|  |  |  |                              nickname: str, domain: str, | 
					
						
							|  |  |  |                              acceptHandle: str, debug: bool) -> None: | 
					
						
							| 
									
										
										
										
											2019-10-06 09:48:37 +00:00
										 |  |  |     """Removes a handle from follow rejects
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |     _removeFromFollowBase(baseDir, nickname, domain, | 
					
						
							|  |  |  |                           acceptHandle, 'followrejects', debug) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-06 09:48:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | def isFollowingActor(baseDir: str, | 
					
						
							|  |  |  |                      nickname: str, domain: str, actor: str) -> bool: | 
					
						
							| 
									
										
										
										
											2020-07-14 09:09:33 +00:00
										 |  |  |     """Is the given nickname following the given actor?
 | 
					
						
							| 
									
										
										
										
											2021-02-24 09:54:37 +00:00
										 |  |  |     The actor can also be a handle: nickname@domain | 
					
						
							| 
									
										
										
										
											2019-07-29 19:46:30 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     if ':' in domain: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         domain = domain.split(':')[0] | 
					
						
							|  |  |  |     handle = nickname + '@' + domain | 
					
						
							|  |  |  |     if not os.path.isdir(baseDir + '/accounts/' + handle): | 
					
						
							| 
									
										
										
										
											2019-07-29 19:46:30 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     followingFile = baseDir + '/accounts/' + handle + '/following.txt' | 
					
						
							| 
									
										
										
										
											2019-08-31 12:25:42 +00:00
										 |  |  |     if not os.path.isfile(followingFile): | 
					
						
							| 
									
										
										
										
											2019-07-29 19:46:30 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-07-14 20:55:47 +00:00
										 |  |  |     if actor.lower() in open(followingFile).read().lower(): | 
					
						
							| 
									
										
										
										
											2019-07-29 19:46:30 +00:00
										 |  |  |         return True | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     followingNickname = getNicknameFromActor(actor) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |     if not followingNickname: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('WARN: unable to find nickname in ' + actor) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     followingDomain, followingPort = getDomainFromActor(actor) | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     followingHandle = \ | 
					
						
							|  |  |  |         getFullDomain(followingNickname + '@' + followingDomain, followingPort) | 
					
						
							| 
									
										
										
										
											2020-07-14 20:55:47 +00:00
										 |  |  |     if followingHandle.lower() in open(followingFile).read().lower(): | 
					
						
							| 
									
										
										
										
											2019-07-29 19:46:30 +00:00
										 |  |  |         return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def getMutualsOfPerson(baseDir: str, | 
					
						
							| 
									
										
										
										
											2020-09-25 10:20:58 +00:00
										 |  |  |                        nickname: str, domain: str) -> []: | 
					
						
							| 
									
										
										
										
											2020-01-13 16:06:31 +00:00
										 |  |  |     """Returns the mutuals of a person
 | 
					
						
							|  |  |  |     i.e. accounts which they follow and which also follow back | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     followers = \ | 
					
						
							| 
									
										
										
										
											2020-09-25 14:14:59 +00:00
										 |  |  |         getFollowersList(baseDir, nickname, domain, 'followers.txt') | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     following = \ | 
					
						
							| 
									
										
										
										
											2020-09-25 14:14:59 +00:00
										 |  |  |         getFollowersList(baseDir, nickname, domain, 'following.txt') | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     mutuals = [] | 
					
						
							| 
									
										
										
										
											2020-01-13 16:06:31 +00:00
										 |  |  |     for handle in following: | 
					
						
							|  |  |  |         if handle in followers: | 
					
						
							|  |  |  |             mutuals.append(handle) | 
					
						
							|  |  |  |     return mutuals | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def followerOfPerson(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                      followerNickname: str, followerDomain: str, | 
					
						
							|  |  |  |                      federationList: [], debug: bool) -> bool: | 
					
						
							| 
									
										
										
										
											2019-06-29 21:13:44 +00:00
										 |  |  |     """Adds a follower of the given person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     return followPerson(baseDir, nickname, domain, | 
					
						
							|  |  |  |                         followerNickname, followerDomain, | 
					
						
							|  |  |  |                         federationList, debug, 'followers.txt') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-29 18:23:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-02 11:37:24 +00:00
										 |  |  | def isFollowerOfPerson(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                        followerNickname: str, followerDomain: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-31 15:17:07 +00:00
										 |  |  |     """is the given nickname a follower of followerNickname?
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if ':' in domain: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         domain = domain.split(':')[0] | 
					
						
							|  |  |  |     followersFile = baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |         nickname + '@' + domain + '/followers.txt' | 
					
						
							| 
									
										
										
										
											2019-08-31 15:17:07 +00:00
										 |  |  |     if not os.path.isfile(followersFile): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     handle = followerNickname + '@' + followerDomain | 
					
						
							| 
									
										
										
										
											2020-10-24 09:58:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     alreadyFollowing = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     followersStr = '' | 
					
						
							|  |  |  |     with open(followersFile, 'r') as fpFollowers: | 
					
						
							|  |  |  |         followersStr = fpFollowers.read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if handle in followersStr: | 
					
						
							|  |  |  |         alreadyFollowing = True | 
					
						
							|  |  |  |     elif '://' + followerDomain + \ | 
					
						
							|  |  |  |          '/profile/' + followerNickname in followersStr: | 
					
						
							|  |  |  |         alreadyFollowing = True | 
					
						
							|  |  |  |     elif '://' + followerDomain + \ | 
					
						
							|  |  |  |          '/channel/' + followerNickname in followersStr: | 
					
						
							|  |  |  |         alreadyFollowing = True | 
					
						
							|  |  |  |     elif '://' + followerDomain + \ | 
					
						
							|  |  |  |          '/accounts/' + followerNickname in followersStr: | 
					
						
							|  |  |  |         alreadyFollowing = True | 
					
						
							| 
									
										
										
										
											2021-02-09 17:00:35 +00:00
										 |  |  |     elif '://' + followerDomain + \ | 
					
						
							|  |  |  |          '/u/' + followerNickname in followersStr: | 
					
						
							|  |  |  |         alreadyFollowing = True | 
					
						
							| 
									
										
										
										
											2020-10-24 09:58:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 11:11:14 +00:00
										 |  |  |     return alreadyFollowing | 
					
						
							| 
									
										
										
										
											2019-08-31 15:17:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 13:57:24 +00:00
										 |  |  | def unfollowAccount(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                     followNickname: str, followDomain: str, | 
					
						
							|  |  |  |                     followFile='following.txt', | 
					
						
							|  |  |  |                     debug=False) -> bool: | 
					
						
							| 
									
										
										
										
											2019-06-29 18:23:13 +00:00
										 |  |  |     """Removes a person to the follow list
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-07-17 11:54:13 +00:00
										 |  |  |     if ':' in domain: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         domain = domain.split(':')[0] | 
					
						
							|  |  |  |     handle = nickname + '@' + domain | 
					
						
							|  |  |  |     handleToUnfollow = followNickname + '@' + followDomain | 
					
						
							|  |  |  |     if not os.path.isdir(baseDir + '/accounts'): | 
					
						
							|  |  |  |         os.mkdir(baseDir + '/accounts') | 
					
						
							|  |  |  |     if not os.path.isdir(baseDir + '/accounts/' + handle): | 
					
						
							|  |  |  |         os.mkdir(baseDir + '/accounts/' + handle) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     filename = baseDir + '/accounts/' + handle + '/' + followFile | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |     if not os.path.isfile(filename): | 
					
						
							| 
									
										
										
										
											2019-07-17 11:54:13 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: follow file ' + filename + ' was not found') | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-08-20 12:11:07 +00:00
										 |  |  |     handleToUnfollowLower = handleToUnfollow.lower() | 
					
						
							|  |  |  |     if handleToUnfollowLower not in open(filename).read().lower(): | 
					
						
							| 
									
										
										
										
											2019-07-17 11:54:13 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: handle to unfollow ' + handleToUnfollow + | 
					
						
							|  |  |  |                   ' is not in ' + filename) | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |         return | 
					
						
							|  |  |  |     with open(filename, "r") as f: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         lines = f.readlines() | 
					
						
							| 
									
										
										
										
											2020-11-06 18:56:53 +00:00
										 |  |  |         with open(filename, 'w+') as f: | 
					
						
							|  |  |  |             for line in lines: | 
					
						
							|  |  |  |                 if line.strip("\n").strip("\r").lower() != \ | 
					
						
							|  |  |  |                    handleToUnfollowLower: | 
					
						
							|  |  |  |                     f.write(line) | 
					
						
							| 
									
										
										
										
											2020-02-22 10:50:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # write to an unfollowed file so that if a follow accept | 
					
						
							|  |  |  |     # later arrives then it can be ignored | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     unfollowedFilename = baseDir + '/accounts/' + handle + '/unfollowed.txt' | 
					
						
							| 
									
										
										
										
											2020-02-22 10:50:07 +00:00
										 |  |  |     if os.path.isfile(unfollowedFilename): | 
					
						
							| 
									
										
										
										
											2020-07-14 21:48:39 +00:00
										 |  |  |         if handleToUnfollowLower not in \ | 
					
						
							|  |  |  |            open(unfollowedFilename).read().lower(): | 
					
						
							| 
									
										
										
										
											2020-11-06 18:56:53 +00:00
										 |  |  |             with open(unfollowedFilename, "a+") as f: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                 f.write(handleToUnfollow + '\n') | 
					
						
							| 
									
										
										
										
											2020-02-22 10:50:07 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-02-22 11:04:08 +00:00
										 |  |  |         with open(unfollowedFilename, "w+") as f: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             f.write(handleToUnfollow + '\n') | 
					
						
							| 
									
										
										
										
											2020-02-22 10:50:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 21:44:16 +00:00
										 |  |  |     return True | 
					
						
							| 
									
										
										
										
											2019-06-29 18:23:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 13:57:24 +00:00
										 |  |  | def unfollowerOfAccount(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                         followerNickname: str, followerDomain: str, | 
					
						
							|  |  |  |                         debug=False) -> bool: | 
					
						
							| 
									
										
										
										
											2019-06-29 21:13:44 +00:00
										 |  |  |     """Remove a follower of a person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-12-22 13:57:24 +00:00
										 |  |  |     return unfollowAccount(baseDir, nickname, domain, | 
					
						
							|  |  |  |                            followerNickname, followerDomain, | 
					
						
							|  |  |  |                            'followers.txt', debug) | 
					
						
							| 
									
										
										
										
											2019-06-29 18:23:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def clearFollows(baseDir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |                  followFile='following.txt') -> None: | 
					
						
							| 
									
										
										
										
											2019-06-29 18:23:13 +00:00
										 |  |  |     """Removes all follows
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-09-15 09:16:03 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     if not os.path.isdir(baseDir + '/accounts'): | 
					
						
							|  |  |  |         os.mkdir(baseDir + '/accounts') | 
					
						
							|  |  |  |     if not os.path.isdir(baseDir + '/accounts/' + handle): | 
					
						
							|  |  |  |         os.mkdir(baseDir + '/accounts/' + handle) | 
					
						
							|  |  |  |     filename = baseDir + '/accounts/' + handle + '/' + followFile | 
					
						
							| 
									
										
										
										
											2019-06-29 18:23:13 +00:00
										 |  |  |     if os.path.isfile(filename): | 
					
						
							|  |  |  |         os.remove(filename) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def clearFollowers(baseDir: str, nickname: str, domain: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-06-29 21:13:44 +00:00
										 |  |  |     """Removes all followers
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     clearFollows(baseDir, nickname, domain, 'followers.txt') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  | def _getNoOfFollows(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                     authenticated: bool, | 
					
						
							|  |  |  |                     followFile='following.txt') -> int: | 
					
						
							| 
									
										
										
										
											2019-06-29 21:13:44 +00:00
										 |  |  |     """Returns the number of follows or followers
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-07-19 08:40:51 +00:00
										 |  |  |     # only show number of followers to authenticated | 
					
						
							|  |  |  |     # account holders | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     # if not authenticated: | 
					
						
							|  |  |  |     #     return 9999 | 
					
						
							| 
									
										
										
										
											2020-09-15 09:16:03 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     filename = baseDir + '/accounts/' + handle + '/' + followFile | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     if not os.path.isfile(filename): | 
					
						
							|  |  |  |         return 0 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     ctr = 0 | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     with open(filename, "r") as f: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         lines = f.readlines() | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         for line in lines: | 
					
						
							| 
									
										
										
										
											2020-10-23 19:48:59 +00:00
										 |  |  |             if '#' in line: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if '@' in line and \ | 
					
						
							|  |  |  |                '.' in line and \ | 
					
						
							|  |  |  |                not line.startswith('http'): | 
					
						
							|  |  |  |                 ctr += 1 | 
					
						
							| 
									
										
										
										
											2020-10-24 11:07:22 +00:00
										 |  |  |             elif ((line.startswith('http') or | 
					
						
							|  |  |  |                    line.startswith('dat')) and | 
					
						
							| 
									
										
										
										
											2020-12-23 10:57:44 +00:00
										 |  |  |                   hasUsersPath(line)): | 
					
						
							| 
									
										
										
										
											2020-10-23 19:48:59 +00:00
										 |  |  |                 ctr += 1 | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     return ctr | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  | def _getNoOfFollowers(baseDir: str, | 
					
						
							|  |  |  |                       nickname: str, domain: str, authenticated: bool) -> int: | 
					
						
							| 
									
										
										
										
											2019-06-29 21:13:44 +00:00
										 |  |  |     """Returns the number of followers of the given person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |     return _getNoOfFollows(baseDir, nickname, domain, | 
					
						
							|  |  |  |                            authenticated, 'followers.txt') | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | def getFollowingFeed(baseDir: str, domain: str, port: int, path: str, | 
					
						
							| 
									
										
										
										
											2019-07-19 08:40:51 +00:00
										 |  |  |                      httpPrefix: str, authenticated: bool, | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                      followsPerPage=12, | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |                      followFile='following') -> {}: | 
					
						
							| 
									
										
										
										
											2020-10-24 09:28:21 +00:00
										 |  |  |     """Returns the following and followers feeds from GET requests.
 | 
					
						
							|  |  |  |     This accesses the following.txt or followers.txt and builds a collection. | 
					
						
							| 
									
										
										
										
											2019-06-29 21:13:44 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-07-19 08:40:51 +00:00
										 |  |  |     # Show a small number of follows to non-authenticated viewers | 
					
						
							|  |  |  |     if not authenticated: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         followsPerPage = 6 | 
					
						
							| 
									
										
										
										
											2019-07-19 08:40:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     if '/' + followFile not in path: | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  |     # handle page numbers | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     headerOnly = True | 
					
						
							|  |  |  |     pageNumber = None | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     if '?page=' in path: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         pageNumber = path.split('?page=')[1] | 
					
						
							|  |  |  |         if pageNumber == 'true' or not authenticated: | 
					
						
							|  |  |  |             pageNumber = 1 | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                 pageNumber = int(pageNumber) | 
					
						
							|  |  |  |             except BaseException: | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         path = path.split('?page=')[0] | 
					
						
							|  |  |  |         headerOnly = False | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     if not path.endswith('/' + followFile): | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     nickname = None | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     if path.startswith('/users/'): | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         nickname = path.replace('/users/', '', 1).replace('/' + followFile, '') | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     if path.startswith('/@'): | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         nickname = path.replace('/@', '', 1).replace('/' + followFile, '') | 
					
						
							| 
									
										
										
										
											2019-07-03 09:40:27 +00:00
										 |  |  |     if not nickname: | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     if not validNickname(domain, nickname): | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     domain = getFullDomain(domain, port) | 
					
						
							| 
									
										
										
										
											2019-06-30 19:01:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     if headerOnly: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         firstStr = \ | 
					
						
							|  |  |  |             httpPrefix + '://' + domain + '/users/' + \ | 
					
						
							|  |  |  |             nickname + '/' + followFile + '?page=1' | 
					
						
							|  |  |  |         idStr = \ | 
					
						
							|  |  |  |             httpPrefix + '://' + domain + '/users/' + \ | 
					
						
							|  |  |  |             nickname + '/' + followFile | 
					
						
							|  |  |  |         totalStr = \ | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |             _getNoOfFollows(baseDir, nickname, domain, authenticated) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         following = { | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |             '@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             'first': firstStr, | 
					
						
							|  |  |  |             'id': idStr, | 
					
						
							|  |  |  |             'totalItems': totalStr, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |             'type': 'OrderedCollection' | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         return following | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not pageNumber: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         pageNumber = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     nextPageNumber = int(pageNumber + 1) | 
					
						
							|  |  |  |     idStr = \ | 
					
						
							|  |  |  |         httpPrefix + '://' + domain + '/users/' + \ | 
					
						
							|  |  |  |         nickname + '/' + followFile + '?page=' + str(pageNumber) | 
					
						
							|  |  |  |     partOfStr = \ | 
					
						
							|  |  |  |         httpPrefix + '://' + domain + '/users/' + nickname + '/' + followFile | 
					
						
							|  |  |  |     following = { | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         '@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         'id': idStr, | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         'orderedItems': [], | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         'partOf': partOfStr, | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         'totalItems': 0, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'type': 'OrderedCollectionPage' | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     handleDomain = domain | 
					
						
							| 
									
										
										
										
											2019-07-22 11:44:31 +00:00
										 |  |  |     if ':' in handleDomain: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         handleDomain = domain.split(':')[0] | 
					
						
							| 
									
										
										
										
											2020-09-15 09:16:03 +00:00
										 |  |  |     handle = nickname + '@' + handleDomain | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     filename = baseDir + '/accounts/' + handle + '/' + followFile + '.txt' | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     if not os.path.isfile(filename): | 
					
						
							|  |  |  |         return following | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     currPage = 1 | 
					
						
							|  |  |  |     pageCtr = 0 | 
					
						
							|  |  |  |     totalCtr = 0 | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     with open(filename, "r") as f: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         lines = f.readlines() | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |         for line in lines: | 
					
						
							|  |  |  |             if '#' not in line: | 
					
						
							| 
									
										
										
										
											2019-07-22 11:44:31 +00:00
										 |  |  |                 if '@' in line and not line.startswith('http'): | 
					
						
							| 
									
										
										
										
											2020-10-24 09:28:21 +00:00
										 |  |  |                     # nickname@domain | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |                     pageCtr += 1 | 
					
						
							|  |  |  |                     totalCtr += 1 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                     if currPage == pageNumber: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                         line2 = \ | 
					
						
							|  |  |  |                             line.lower().replace('\n', '').replace('\r', '') | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                         url = httpPrefix + '://' + \ | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                             line2.split('@')[1] + \ | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                             '/users/' + \ | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                             line2.split('@')[0] | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |                         following['orderedItems'].append(url) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                 elif ((line.startswith('http') or | 
					
						
							| 
									
										
										
										
											2020-10-24 09:28:21 +00:00
										 |  |  |                        line.startswith('dat')) and | 
					
						
							| 
									
										
										
										
											2020-12-23 10:57:44 +00:00
										 |  |  |                       hasUsersPath(line)): | 
					
						
							| 
									
										
										
										
											2020-10-24 09:28:21 +00:00
										 |  |  |                     # https://domain/users/nickname | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |                     pageCtr += 1 | 
					
						
							|  |  |  |                     totalCtr += 1 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                     if currPage == pageNumber: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                         appendStr = \ | 
					
						
							|  |  |  |                             line.lower().replace('\n', '').replace('\r', '') | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                         following['orderedItems'].append(appendStr) | 
					
						
							|  |  |  |             if pageCtr >= followsPerPage: | 
					
						
							|  |  |  |                 pageCtr = 0 | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |                 currPage += 1 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     following['totalItems'] = totalCtr | 
					
						
							|  |  |  |     lastPage = int(totalCtr / followsPerPage) | 
					
						
							|  |  |  |     if lastPage < 1: | 
					
						
							|  |  |  |         lastPage = 1 | 
					
						
							|  |  |  |     if nextPageNumber > lastPage: | 
					
						
							|  |  |  |         following['next'] = \ | 
					
						
							|  |  |  |             httpPrefix + '://' + domain + '/users/' + \ | 
					
						
							|  |  |  |             nickname + '/' + followFile + '?page=' + str(lastPage) | 
					
						
							| 
									
										
										
										
											2019-06-29 20:21:37 +00:00
										 |  |  |     return following | 
					
						
							| 
									
										
										
										
											2019-07-02 18:17:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  | def _followApprovalRequired(baseDir: str, nicknameToFollow: str, | 
					
						
							|  |  |  |                             domainToFollow: str, debug: bool, | 
					
						
							| 
									
										
										
										
											2020-12-26 10:22:56 +00:00
										 |  |  |                             followRequestHandle: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-07-19 20:03:50 +00:00
										 |  |  |     """ Returns the policy for follower approvals
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-01-02 22:42:06 +00:00
										 |  |  |     # has this handle already been manually approved? | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |     if _preApprovedFollower(baseDir, nicknameToFollow, domainToFollow, | 
					
						
							| 
									
										
										
										
											2020-12-26 10:22:56 +00:00
										 |  |  |                             followRequestHandle): | 
					
						
							| 
									
										
										
										
											2019-12-31 09:23:41 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     manuallyApproveFollows = False | 
					
						
							| 
									
										
										
										
											2019-08-31 14:42:35 +00:00
										 |  |  |     if ':' in domainToFollow: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         domainToFollow = domainToFollow.split(':')[0] | 
					
						
							|  |  |  |     actorFilename = baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |         nicknameToFollow + '@' + domainToFollow + '.json' | 
					
						
							| 
									
										
										
										
											2019-07-19 20:03:50 +00:00
										 |  |  |     if os.path.isfile(actorFilename): | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         actor = loadJson(actorFilename) | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  |         if actor: | 
					
						
							| 
									
										
										
										
											2019-07-19 20:03:50 +00:00
										 |  |  |             if actor.get('manuallyApprovesFollowers'): | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                 manuallyApproveFollows = actor['manuallyApprovesFollowers'] | 
					
						
							| 
									
										
										
										
											2019-07-19 20:03:50 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                     print(nicknameToFollow + '@' + domainToFollow + | 
					
						
							|  |  |  |                           ' automatically approves followers') | 
					
						
							| 
									
										
										
										
											2019-07-19 20:03:50 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: Actor file not found: ' + actorFilename) | 
					
						
							| 
									
										
										
										
											2019-07-19 20:03:50 +00:00
										 |  |  |     return manuallyApproveFollows | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  | def _noOfFollowRequests(baseDir: str, | 
					
						
							|  |  |  |                         nicknameToFollow: str, domainToFollow: str, | 
					
						
							|  |  |  |                         nickname: str, domain: str, fromPort: int, | 
					
						
							|  |  |  |                         followType: str) -> int: | 
					
						
							| 
									
										
										
										
											2020-01-03 16:52:31 +00:00
										 |  |  |     """Returns the current number of follow requests
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     accountsDir = baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |         nicknameToFollow + '@' + domainToFollow | 
					
						
							|  |  |  |     approveFollowsFilename = accountsDir + '/followrequests.txt' | 
					
						
							| 
									
										
										
										
											2020-01-03 16:52:31 +00:00
										 |  |  |     if not os.path.isfile(approveFollowsFilename): | 
					
						
							|  |  |  |         return 0 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     ctr = 0 | 
					
						
							| 
									
										
										
										
											2020-01-03 16:52:31 +00:00
										 |  |  |     with open(approveFollowsFilename, "r") as f: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         lines = f.readlines() | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |         if followType == "onion": | 
					
						
							|  |  |  |             for fileLine in lines: | 
					
						
							|  |  |  |                 if '.onion' in fileLine: | 
					
						
							|  |  |  |                     ctr += 1 | 
					
						
							|  |  |  |         elif followType == "i2p": | 
					
						
							|  |  |  |             for fileLine in lines: | 
					
						
							|  |  |  |                 if '.i2p' in fileLine: | 
					
						
							|  |  |  |                     ctr += 1 | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-01-03 16:52:31 +00:00
										 |  |  |             return len(lines) | 
					
						
							|  |  |  |     return ctr | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  | def _storeFollowRequest(baseDir: str, | 
					
						
							|  |  |  |                         nicknameToFollow: str, domainToFollow: str, port: int, | 
					
						
							|  |  |  |                         nickname: str, domain: str, fromPort: int, | 
					
						
							|  |  |  |                         followJson: {}, | 
					
						
							|  |  |  |                         debug: bool, personUrl: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  |     """Stores the follow request for later use
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     accountsDir = baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |         nicknameToFollow + '@' + domainToFollow | 
					
						
							| 
									
										
										
										
											2019-08-07 11:49:38 +00:00
										 |  |  |     if not os.path.isdir(accountsDir): | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     approveHandle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     domainFull = getFullDomain(domain, fromPort) | 
					
						
							| 
									
										
										
										
											2020-12-16 11:29:35 +00:00
										 |  |  |     approveHandle = getFullDomain(nickname + '@' + domain, fromPort) | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     followersFilename = accountsDir + '/followers.txt' | 
					
						
							| 
									
										
										
										
											2019-08-26 22:38:09 +00:00
										 |  |  |     if os.path.isfile(followersFilename): | 
					
						
							| 
									
										
										
										
											2020-10-24 09:52:12 +00:00
										 |  |  |         alreadyFollowing = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         followersStr = '' | 
					
						
							|  |  |  |         with open(followersFilename, 'r') as fpFollowers: | 
					
						
							|  |  |  |             followersStr = fpFollowers.read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if approveHandle in followersStr: | 
					
						
							|  |  |  |             alreadyFollowing = True | 
					
						
							|  |  |  |         elif '://' + domainFull + '/profile/' + nickname in followersStr: | 
					
						
							|  |  |  |             alreadyFollowing = True | 
					
						
							|  |  |  |         elif '://' + domainFull + '/channel/' + nickname in followersStr: | 
					
						
							|  |  |  |             alreadyFollowing = True | 
					
						
							|  |  |  |         elif '://' + domainFull + '/accounts/' + nickname in followersStr: | 
					
						
							|  |  |  |             alreadyFollowing = True | 
					
						
							| 
									
										
										
										
											2021-02-09 17:00:35 +00:00
										 |  |  |         elif '://' + domainFull + '/u/' + nickname in followersStr: | 
					
						
							|  |  |  |             alreadyFollowing = True | 
					
						
							| 
									
										
										
										
											2020-10-24 09:52:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if alreadyFollowing: | 
					
						
							| 
									
										
										
										
											2019-08-26 22:38:09 +00:00
										 |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                 print('DEBUG: ' + | 
					
						
							|  |  |  |                       nicknameToFollow + '@' + domainToFollow + | 
					
						
							|  |  |  |                       ' already following ' + approveHandle) | 
					
						
							| 
									
										
										
										
											2019-08-26 22:38:09 +00:00
										 |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-18 19:01:07 +00:00
										 |  |  |     # should this follow be denied? | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     denyFollowsFilename = accountsDir + '/followrejects.txt' | 
					
						
							| 
									
										
										
										
											2019-09-18 19:01:07 +00:00
										 |  |  |     if os.path.isfile(denyFollowsFilename): | 
					
						
							| 
									
										
										
										
											2019-09-18 19:05:08 +00:00
										 |  |  |         if approveHandle in open(denyFollowsFilename).read(): | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             removeFromFollowRequests(baseDir, nicknameToFollow, | 
					
						
							|  |  |  |                                      domainToFollow, approveHandle, debug) | 
					
						
							|  |  |  |             print(approveHandle + ' was already denied as a follower of ' + | 
					
						
							|  |  |  |                   nicknameToFollow) | 
					
						
							| 
									
										
										
										
											2019-09-18 19:01:07 +00:00
										 |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  |     # add to a file which contains a list of requests | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     approveFollowsFilename = accountsDir + '/followrequests.txt' | 
					
						
							| 
									
										
										
										
											2020-10-24 11:07:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # store either nick@domain or the full person/actor url | 
					
						
							|  |  |  |     approveHandleStored = approveHandle | 
					
						
							|  |  |  |     if '/users/' not in personUrl: | 
					
						
							|  |  |  |         approveHandleStored = personUrl | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  |     if os.path.isfile(approveFollowsFilename): | 
					
						
							|  |  |  |         if approveHandle not in open(approveFollowsFilename).read(): | 
					
						
							| 
									
										
										
										
											2020-08-20 11:34:39 +00:00
										 |  |  |             with open(approveFollowsFilename, 'a+') as fp: | 
					
						
							| 
									
										
										
										
											2020-10-24 11:07:22 +00:00
										 |  |  |                 fp.write(approveHandleStored + '\n') | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2020-10-24 11:07:22 +00:00
										 |  |  |                 print('DEBUG: ' + approveHandleStored + | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                       ' is already awaiting approval') | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2019-12-29 12:59:13 +00:00
										 |  |  |         with open(approveFollowsFilename, "w+") as fp: | 
					
						
							| 
									
										
										
										
											2020-10-24 11:07:22 +00:00
										 |  |  |             fp.write(approveHandleStored + '\n') | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # store the follow request in its own directory | 
					
						
							|  |  |  |     # We don't rely upon the inbox because items in there could expire | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     requestsDir = accountsDir + '/requests' | 
					
						
							| 
									
										
										
										
											2019-07-20 13:31:20 +00:00
										 |  |  |     if not os.path.isdir(requestsDir): | 
					
						
							|  |  |  |         os.mkdir(requestsDir) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     followActivityfilename = requestsDir + '/' + approveHandle + '.follow' | 
					
						
							|  |  |  |     return saveJson(followJson, followActivityfilename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def receiveFollowRequest(session, baseDir: str, httpPrefix: str, | 
					
						
							|  |  |  |                          port: int, sendThreads: [], postLog: [], | 
					
						
							|  |  |  |                          cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                          messageJson: {}, federationList: [], | 
					
						
							| 
									
										
										
										
											2020-10-23 19:18:13 +00:00
										 |  |  |                          debug: bool, projectVersion: str, | 
					
						
							| 
									
										
										
										
											2020-10-23 19:48:59 +00:00
										 |  |  |                          maxFollowers: int) -> bool: | 
					
						
							| 
									
										
										
										
											2019-07-02 18:38:51 +00:00
										 |  |  |     """Receives a follow request within the POST section of HTTPServer
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:17:04 +00:00
										 |  |  |     if not messageJson['type'].startswith('Follow'): | 
					
						
							| 
									
										
										
										
											2021-02-08 14:48:37 +00:00
										 |  |  |         if not messageJson['type'].startswith('Join'): | 
					
						
							|  |  |  |             return False | 
					
						
							| 
									
										
										
										
											2019-08-15 16:05:28 +00:00
										 |  |  |     print('Receiving follow request') | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |     if not messageJson.get('actor'): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: follow request has no actor') | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-12-23 10:57:44 +00:00
										 |  |  |     if not hasUsersPath(messageJson['actor']): | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-10-24 09:43:00 +00:00
										 |  |  |             print('DEBUG: users/profile/accounts/channel missing from actor') | 
					
						
							| 
									
										
										
										
											2019-07-02 18:17:04 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     domain, tempPort = getDomainFromActor(messageJson['actor']) | 
					
						
							|  |  |  |     fromPort = port | 
					
						
							| 
									
										
										
										
											2020-12-16 11:29:35 +00:00
										 |  |  |     domainFull = getFullDomain(domain, tempPort) | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |     if tempPort: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         fromPort = tempPort | 
					
						
							|  |  |  |     if not domainPermitted(domain, federationList): | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: follower from domain not permitted - ' + domain) | 
					
						
							| 
									
										
										
										
											2019-07-02 18:17:04 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     nickname = getNicknameFromActor(messageJson['actor']) | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |     if not nickname: | 
					
						
							| 
									
										
										
										
											2019-10-21 12:27:47 +00:00
										 |  |  |         # single user instance | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         nickname = 'dev' | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: follow request does not contain a ' + | 
					
						
							| 
									
										
										
										
											2020-03-02 21:28:22 +00:00
										 |  |  |                   'nickname. Assuming single user instance.') | 
					
						
							| 
									
										
										
										
											2019-08-15 17:05:22 +00:00
										 |  |  |     if not messageJson.get('to'): | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         messageJson['to'] = messageJson['object'] | 
					
						
							| 
									
										
										
										
											2020-12-23 10:57:44 +00:00
										 |  |  |     if not hasUsersPath(messageJson['object']): | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-10-24 09:43:00 +00:00
										 |  |  |             print('DEBUG: users/profile/channel/accounts ' + | 
					
						
							|  |  |  |                   'not found within object') | 
					
						
							| 
									
										
										
										
											2019-07-02 18:17:04 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     domainToFollow, tempPort = getDomainFromActor(messageJson['object']) | 
					
						
							|  |  |  |     if not domainPermitted(domainToFollow, federationList): | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: follow domain not permitted ' + domainToFollow) | 
					
						
							| 
									
										
										
										
											2019-08-26 18:41:35 +00:00
										 |  |  |         return True | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     domainToFollowFull = getFullDomain(domainToFollow, tempPort) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     nicknameToFollow = getNicknameFromActor(messageJson['object']) | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |     if not nicknameToFollow: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: follow request does not contain a ' + | 
					
						
							|  |  |  |                   'nickname for the account followed') | 
					
						
							| 
									
										
										
										
											2019-08-26 18:41:35 +00:00
										 |  |  |         return True | 
					
						
							| 
									
										
										
										
											2020-10-23 19:05:17 +00:00
										 |  |  |     if isSystemAccount(nicknameToFollow): | 
					
						
							| 
									
										
										
										
											2020-12-26 10:22:56 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: Cannot follow system account - ' + | 
					
						
							|  |  |  |                   nicknameToFollow) | 
					
						
							|  |  |  |         return True | 
					
						
							| 
									
										
										
										
											2020-10-23 19:48:59 +00:00
										 |  |  |     if maxFollowers > 0: | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |         if _getNoOfFollowers(baseDir, | 
					
						
							|  |  |  |                              nicknameToFollow, domainToFollow, | 
					
						
							|  |  |  |                              True) > maxFollowers: | 
					
						
							| 
									
										
										
										
											2020-10-23 19:48:59 +00:00
										 |  |  |             print('WARN: ' + nicknameToFollow + | 
					
						
							|  |  |  |                   ' has reached their maximum number of followers') | 
					
						
							|  |  |  |             return True | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     handleToFollow = nicknameToFollow + '@' + domainToFollow | 
					
						
							|  |  |  |     if domainToFollow == domain: | 
					
						
							|  |  |  |         if not os.path.isdir(baseDir + '/accounts/' + handleToFollow): | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                 print('DEBUG: followed account not found - ' + | 
					
						
							|  |  |  |                       baseDir + '/accounts/' + handleToFollow) | 
					
						
							| 
									
										
										
										
											2019-08-26 18:41:35 +00:00
										 |  |  |             return True | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-02 11:37:24 +00:00
										 |  |  |     if isFollowerOfPerson(baseDir, | 
					
						
							|  |  |  |                           nicknameToFollow, domainToFollowFull, | 
					
						
							|  |  |  |                           nickname, domainFull): | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: ' + nickname + '@' + domain + | 
					
						
							|  |  |  |                   ' is already a follower of ' + | 
					
						
							|  |  |  |                   nicknameToFollow + '@' + domainToFollow) | 
					
						
							| 
									
										
										
										
											2019-08-26 18:41:35 +00:00
										 |  |  |         return True | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-19 20:03:50 +00:00
										 |  |  |     # what is the followers policy? | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     approveHandle = nickname + '@' + domainFull | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |     if _followApprovalRequired(baseDir, nicknameToFollow, | 
					
						
							| 
									
										
										
										
											2020-12-26 10:22:56 +00:00
										 |  |  |                                domainToFollow, debug, approveHandle): | 
					
						
							| 
									
										
										
										
											2020-02-19 12:51:14 +00:00
										 |  |  |         print('Follow approval is required') | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |         if domain.endswith('.onion'): | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |             if _noOfFollowRequests(baseDir, | 
					
						
							|  |  |  |                                    nicknameToFollow, domainToFollow, | 
					
						
							|  |  |  |                                    nickname, domain, fromPort, | 
					
						
							|  |  |  |                                    'onion') > 5: | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |                 print('Too many follow requests from onion addresses') | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |         elif domain.endswith('.i2p'): | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |             if _noOfFollowRequests(baseDir, | 
					
						
							|  |  |  |                                    nicknameToFollow, domainToFollow, | 
					
						
							|  |  |  |                                    nickname, domain, fromPort, | 
					
						
							|  |  |  |                                    'i2p') > 5: | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |                 print('Too many follow requests from i2p addresses') | 
					
						
							| 
									
										
										
										
											2020-01-03 16:52:31 +00:00
										 |  |  |                 return False | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |             if _noOfFollowRequests(baseDir, | 
					
						
							|  |  |  |                                    nicknameToFollow, domainToFollow, | 
					
						
							|  |  |  |                                    nickname, domain, fromPort, | 
					
						
							|  |  |  |                                    '') > 10: | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |                 print('Too many follow requests') | 
					
						
							| 
									
										
										
										
											2020-01-03 16:52:31 +00:00
										 |  |  |                 return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-15 16:05:28 +00:00
										 |  |  |         print('Storing follow request for approval') | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |         return _storeFollowRequest(baseDir, | 
					
						
							|  |  |  |                                    nicknameToFollow, domainToFollow, port, | 
					
						
							|  |  |  |                                    nickname, domain, fromPort, | 
					
						
							|  |  |  |                                    messageJson, debug, messageJson['actor']) | 
					
						
							| 
									
										
										
										
											2019-08-31 14:42:35 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2019-09-01 20:03:20 +00:00
										 |  |  |         print('Follow request does not require approval') | 
					
						
							| 
									
										
										
										
											2019-09-01 20:28:43 +00:00
										 |  |  |         # update the followers | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         if os.path.isdir(baseDir + '/accounts/' + | 
					
						
							|  |  |  |                          nicknameToFollow + '@' + domainToFollow): | 
					
						
							|  |  |  |             followersFilename = \ | 
					
						
							|  |  |  |                 baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |                 nicknameToFollow + '@' + domainToFollow + '/followers.txt' | 
					
						
							| 
									
										
										
										
											2020-10-24 09:43:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # for actors which don't follow the mastodon | 
					
						
							|  |  |  |             # /users/ path convention store the full actor | 
					
						
							|  |  |  |             if '/users/' not in messageJson['actor']: | 
					
						
							|  |  |  |                 approveHandle = messageJson['actor'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('Updating followers file: ' + | 
					
						
							|  |  |  |                   followersFilename + ' adding ' + approveHandle) | 
					
						
							| 
									
										
										
										
											2019-09-01 20:28:43 +00:00
										 |  |  |             if os.path.isfile(followersFilename): | 
					
						
							|  |  |  |                 if approveHandle not in open(followersFilename).read(): | 
					
						
							| 
									
										
										
										
											2019-10-26 15:15:38 +00:00
										 |  |  |                     try: | 
					
						
							|  |  |  |                         with open(followersFilename, 'r+') as followersFile: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                             content = followersFile.read() | 
					
						
							| 
									
										
										
										
											2020-12-29 20:22:28 +00:00
										 |  |  |                             if approveHandle + '\n' not in content: | 
					
						
							|  |  |  |                                 followersFile.seek(0, 0) | 
					
						
							|  |  |  |                                 followersFile.write(approveHandle + '\n' + | 
					
						
							|  |  |  |                                                     content) | 
					
						
							| 
									
										
										
										
											2019-10-26 15:15:38 +00:00
										 |  |  |                     except Exception as e: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                         print('WARN: ' + | 
					
						
							|  |  |  |                               'Failed to write entry to followers file ' + | 
					
						
							|  |  |  |                               str(e)) | 
					
						
							| 
									
										
										
										
											2019-09-01 20:28:43 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                 followersFile = open(followersFilename, "w+") | 
					
						
							|  |  |  |                 followersFile.write(approveHandle + '\n') | 
					
						
							| 
									
										
										
										
											2019-09-01 20:28:43 +00:00
										 |  |  |                 followersFile.close() | 
					
						
							| 
									
										
										
										
											2019-08-15 16:05:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     print('Beginning follow accept') | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     return followedAccountAccepts(session, baseDir, httpPrefix, | 
					
						
							|  |  |  |                                   nicknameToFollow, domainToFollow, port, | 
					
						
							|  |  |  |                                   nickname, domain, fromPort, | 
					
						
							|  |  |  |                                   messageJson['actor'], federationList, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                                   messageJson, sendThreads, postLog, | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                                   cachedWebfingers, personCache, | 
					
						
							|  |  |  |                                   debug, projectVersion, True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def followedAccountAccepts(session, baseDir: str, httpPrefix: str, | 
					
						
							|  |  |  |                            nicknameToFollow: str, domainToFollow: str, | 
					
						
							|  |  |  |                            port: int, | 
					
						
							|  |  |  |                            nickname: str, domain: str, fromPort: int, | 
					
						
							|  |  |  |                            personUrl: str, federationList: [], | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                            followJson: {}, sendThreads: [], postLog: [], | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                            cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                            debug: bool, projectVersion: str, | 
					
						
							| 
									
										
										
										
											2019-12-29 13:19:51 +00:00
										 |  |  |                            removeFollowActivity: bool): | 
					
						
							| 
									
										
										
										
											2019-07-20 08:33:18 +00:00
										 |  |  |     """The person receiving a follow request accepts the new follower
 | 
					
						
							|  |  |  |     and sends back an Accept activity | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     acceptHandle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2019-10-06 09:57:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  |     # send accept back | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('DEBUG: sending Accept activity for ' + | 
					
						
							|  |  |  |               'follow request which arrived at ' + | 
					
						
							|  |  |  |               nicknameToFollow + '@' + domainToFollow + | 
					
						
							|  |  |  |               ' back to ' + acceptHandle) | 
					
						
							|  |  |  |     acceptJson = createAccept(baseDir, federationList, | 
					
						
							|  |  |  |                               nicknameToFollow, domainToFollow, port, | 
					
						
							|  |  |  |                               personUrl, '', httpPrefix, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                               followJson) | 
					
						
							| 
									
										
										
										
											2019-07-06 15:17:21 +00:00
										 |  |  |     if debug: | 
					
						
							|  |  |  |         pprint(acceptJson) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('DEBUG: sending follow Accept from ' + | 
					
						
							|  |  |  |               nicknameToFollow + '@' + domainToFollow + | 
					
						
							|  |  |  |               ' port ' + str(port) + ' to ' + | 
					
						
							|  |  |  |               acceptHandle + ' port ' + str(fromPort)) | 
					
						
							|  |  |  |     clientToServer = False | 
					
						
							| 
									
										
										
										
											2019-12-16 10:19:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-29 13:19:51 +00:00
										 |  |  |     if removeFollowActivity: | 
					
						
							|  |  |  |         # remove the follow request json | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         followActivityfilename = \ | 
					
						
							|  |  |  |             baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |             nicknameToFollow + '@' + domainToFollow + '/requests/' + \ | 
					
						
							|  |  |  |             nickname + '@' + domain + '.follow' | 
					
						
							| 
									
										
										
										
											2019-12-29 13:19:51 +00:00
										 |  |  |         if os.path.isfile(followActivityfilename): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 os.remove(followActivityfilename) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             except BaseException: | 
					
						
							| 
									
										
										
										
											2019-12-29 13:19:51 +00:00
										 |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2019-12-16 10:19:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     return sendSignedJson(acceptJson, session, baseDir, | 
					
						
							|  |  |  |                           nicknameToFollow, domainToFollow, port, | 
					
						
							|  |  |  |                           nickname, domain, fromPort, '', | 
					
						
							|  |  |  |                           httpPrefix, True, clientToServer, | 
					
						
							|  |  |  |                           federationList, | 
					
						
							|  |  |  |                           sendThreads, postLog, cachedWebfingers, | 
					
						
							|  |  |  |                           personCache, debug, projectVersion) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def followedAccountRejects(session, baseDir: str, httpPrefix: str, | 
					
						
							|  |  |  |                            nicknameToFollow: str, domainToFollow: str, | 
					
						
							|  |  |  |                            port: int, | 
					
						
							|  |  |  |                            nickname: str, domain: str, fromPort: int, | 
					
						
							|  |  |  |                            federationList: [], | 
					
						
							|  |  |  |                            sendThreads: [], postLog: [], | 
					
						
							|  |  |  |                            cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                            debug: bool, projectVersion: str): | 
					
						
							| 
									
										
										
										
											2019-09-09 12:19:00 +00:00
										 |  |  |     """The person receiving a follow request rejects the new follower
 | 
					
						
							|  |  |  |     and sends back a Reject activity | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     # send reject back | 
					
						
							|  |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('DEBUG: sending Reject activity for ' + | 
					
						
							|  |  |  |               'follow request which arrived at ' + | 
					
						
							|  |  |  |               nicknameToFollow + '@' + domainToFollow + | 
					
						
							|  |  |  |               ' back to ' + nickname + '@' + domain) | 
					
						
							| 
									
										
										
										
											2019-12-16 10:01:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-16 10:12:44 +00:00
										 |  |  |     # get the json for the original follow request | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     followActivityfilename = \ | 
					
						
							|  |  |  |         baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |         nicknameToFollow + '@' + domainToFollow + '/requests/' + \ | 
					
						
							|  |  |  |         nickname + '@' + domain + '.follow' | 
					
						
							|  |  |  |     followJson = loadJson(followActivityfilename) | 
					
						
							| 
									
										
										
										
											2019-12-16 10:01:57 +00:00
										 |  |  |     if not followJson: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('No follow request json was found for ' + | 
					
						
							| 
									
										
										
										
											2019-12-16 10:19:21 +00:00
										 |  |  |               followActivityfilename) | 
					
						
							| 
									
										
										
										
											2019-12-16 10:01:57 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2019-12-16 10:12:44 +00:00
										 |  |  |     # actor who made the follow request | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     personUrl = followJson['actor'] | 
					
						
							| 
									
										
										
										
											2019-12-16 10:01:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-16 10:12:44 +00:00
										 |  |  |     # create the reject activity | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     rejectJson = \ | 
					
						
							|  |  |  |         createReject(baseDir, federationList, | 
					
						
							|  |  |  |                      nicknameToFollow, domainToFollow, port, | 
					
						
							|  |  |  |                      personUrl, '', httpPrefix, followJson) | 
					
						
							| 
									
										
										
										
											2019-09-09 12:19:00 +00:00
										 |  |  |     if debug: | 
					
						
							|  |  |  |         pprint(rejectJson) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('DEBUG: sending follow Reject from ' + | 
					
						
							|  |  |  |               nicknameToFollow + '@' + domainToFollow + | 
					
						
							|  |  |  |               ' port ' + str(port) + ' to ' + | 
					
						
							|  |  |  |               nickname + '@' + domain + ' port ' + str(fromPort)) | 
					
						
							|  |  |  |     clientToServer = False | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     denyHandle = getFullDomain(nickname + '@' + domain, fromPort) | 
					
						
							| 
									
										
										
										
											2019-12-16 10:12:44 +00:00
										 |  |  |     # remove from the follow requests file | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     removeFromFollowRequests(baseDir, nicknameToFollow, domainToFollow, | 
					
						
							|  |  |  |                              denyHandle, debug) | 
					
						
							| 
									
										
										
										
											2019-12-16 10:12:44 +00:00
										 |  |  |     # remove the follow request json | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											2019-12-16 10:19:21 +00:00
										 |  |  |         os.remove(followActivityfilename) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     except BaseException: | 
					
						
							| 
									
										
										
										
											2019-12-16 10:12:44 +00:00
										 |  |  |         pass | 
					
						
							|  |  |  |     # send the reject activity | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     return sendSignedJson(rejectJson, session, baseDir, | 
					
						
							|  |  |  |                           nicknameToFollow, domainToFollow, port, | 
					
						
							|  |  |  |                           nickname, domain, fromPort, '', | 
					
						
							|  |  |  |                           httpPrefix, True, clientToServer, | 
					
						
							|  |  |  |                           federationList, | 
					
						
							|  |  |  |                           sendThreads, postLog, cachedWebfingers, | 
					
						
							|  |  |  |                           personCache, debug, projectVersion) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def sendFollowRequest(session, baseDir: str, | 
					
						
							|  |  |  |                       nickname: str, domain: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |                       followNickname: str, followDomain: str, | 
					
						
							| 
									
										
										
										
											2021-02-09 19:02:10 +00:00
										 |  |  |                       followedActor: str, | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                       followPort: int, followHttpPrefix: str, | 
					
						
							|  |  |  |                       clientToServer: bool, federationList: [], | 
					
						
							|  |  |  |                       sendThreads: [], postLog: [], cachedWebfingers: {}, | 
					
						
							|  |  |  |                       personCache: {}, debug: bool, | 
					
						
							| 
									
										
										
										
											2020-12-26 10:22:56 +00:00
										 |  |  |                       projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-02 20:54:22 +00:00
										 |  |  |     """Gets the json object for sending a follow request
 | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     if not domainPermitted(followDomain, federationList): | 
					
						
							| 
									
										
										
										
											2021-02-09 19:02:10 +00:00
										 |  |  |         print('You are not permitted to follow the domain ' + followDomain) | 
					
						
							| 
									
										
										
										
											2019-07-02 18:38:51 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     fullDomain = getFullDomain(domain, port) | 
					
						
							| 
									
										
										
										
											2020-12-16 11:29:35 +00:00
										 |  |  |     followActor = httpPrefix + '://' + fullDomain + '/users/' + nickname | 
					
						
							| 
									
										
										
										
											2019-07-02 18:38:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     requestDomain = getFullDomain(followDomain, followPort) | 
					
						
							| 
									
										
										
										
											2019-07-06 10:33:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     statusNumber, published = getStatusNumber() | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-21 14:12:22 +00:00
										 |  |  |     if followNickname: | 
					
						
							| 
									
										
										
										
											2021-02-09 19:02:10 +00:00
										 |  |  |         followedId = followedActor | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         followHandle = followNickname + '@' + requestDomain | 
					
						
							| 
									
										
										
										
											2019-10-21 14:12:22 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: sendFollowRequest - assuming single user instance') | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         followedId = followHttpPrefix + '://' + requestDomain | 
					
						
							|  |  |  |         singleUserNickname = 'dev' | 
					
						
							|  |  |  |         followHandle = singleUserNickname + '@' + requestDomain | 
					
						
							| 
									
										
										
										
											2019-07-06 19:24:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     newFollowJson = { | 
					
						
							| 
									
										
										
										
											2019-08-16 21:52:11 +00:00
										 |  |  |         '@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         'id': followActor + '/statuses/' + str(statusNumber), | 
					
						
							| 
									
										
										
										
											2019-07-02 18:38:51 +00:00
										 |  |  |         'type': 'Follow', | 
					
						
							| 
									
										
										
										
											2019-07-06 10:33:57 +00:00
										 |  |  |         'actor': followActor, | 
					
						
							| 
									
										
										
										
											2019-08-16 21:52:11 +00:00
										 |  |  |         'object': followedId | 
					
						
							| 
									
										
										
										
											2019-07-02 18:38:51 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-02 19:05:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |     if _followApprovalRequired(baseDir, nickname, domain, debug, | 
					
						
							| 
									
										
										
										
											2020-12-26 10:22:56 +00:00
										 |  |  |                                followHandle): | 
					
						
							| 
									
										
										
										
											2020-02-19 12:51:14 +00:00
										 |  |  |         # Remove any follow requests rejected for the account being followed. | 
					
						
							|  |  |  |         # It's assumed that if you are following someone then you are | 
					
						
							|  |  |  |         # ok with them following back. If this isn't the case then a rejected | 
					
						
							|  |  |  |         # follow request will block them again. | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |         _removeFromFollowRejects(baseDir, | 
					
						
							|  |  |  |                                  nickname, domain, | 
					
						
							|  |  |  |                                  followHandle, debug) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sendSignedJson(newFollowJson, session, baseDir, nickname, domain, port, | 
					
						
							|  |  |  |                    followNickname, followDomain, followPort, | 
					
						
							|  |  |  |                    'https://www.w3.org/ns/activitystreams#Public', | 
					
						
							|  |  |  |                    httpPrefix, True, clientToServer, | 
					
						
							|  |  |  |                    federationList, | 
					
						
							|  |  |  |                    sendThreads, postLog, cachedWebfingers, personCache, | 
					
						
							|  |  |  |                    debug, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-07-05 20:32:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return newFollowJson | 
					
						
							| 
									
										
										
										
											2019-07-08 16:49:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def sendFollowRequestViaServer(baseDir: str, session, | 
					
						
							|  |  |  |                                fromNickname: str, password: str, | 
					
						
							|  |  |  |                                fromDomain: str, fromPort: int, | 
					
						
							|  |  |  |                                followNickname: str, followDomain: str, | 
					
						
							|  |  |  |                                followPort: int, | 
					
						
							|  |  |  |                                httpPrefix: str, | 
					
						
							|  |  |  |                                cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                                debug: bool, projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  |     """Creates a follow request via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendFollowRequestViaServer') | 
					
						
							|  |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     fromDomainFull = getFullDomain(fromDomain, fromPort) | 
					
						
							| 
									
										
										
										
											2019-07-18 11:35:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     followDomainFull = getFullDomain(followDomain, followPort) | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     followActor = httpPrefix + '://' + \ | 
					
						
							|  |  |  |         fromDomainFull + '/users/' + fromNickname | 
					
						
							|  |  |  |     followedId = httpPrefix + '://' + \ | 
					
						
							|  |  |  |         followDomainFull + '/users/' + followNickname | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     statusNumber, published = getStatusNumber() | 
					
						
							|  |  |  |     newFollowJson = { | 
					
						
							| 
									
										
										
										
											2019-08-16 21:52:11 +00:00
										 |  |  |         '@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         'id': followActor + '/statuses/' + str(statusNumber), | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  |         'type': 'Follow', | 
					
						
							|  |  |  |         'actor': followActor, | 
					
						
							| 
									
										
										
										
											2019-08-16 21:52:11 +00:00
										 |  |  |         'object': followedId | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     wfRequest = \ | 
					
						
							|  |  |  |         webfingerHandle(session, handle, httpPrefix, cachedWebfingers, | 
					
						
							| 
									
										
										
										
											2021-03-14 19:22:58 +00:00
										 |  |  |                         fromDomain, projectVersion, debug) | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: announce webfinger failed for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:12 +00:00
										 |  |  |     if not isinstance(wfRequest, dict): | 
					
						
							|  |  |  |         print('WARN: Webfinger for ' + handle + ' did not return a dict. ' + | 
					
						
							|  |  |  |               str(wfRequest)) | 
					
						
							|  |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     postToBox = 'outbox' | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     (inboxUrl, pubKeyId, pubKey, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |      fromPersonId, sharedInbox, avatarUrl, | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |      displayName) = getPersonBox(baseDir, session, wfRequest, personCache, | 
					
						
							|  |  |  |                                  projectVersion, httpPrefix, fromNickname, | 
					
						
							| 
									
										
										
										
											2020-12-18 17:49:17 +00:00
										 |  |  |                                  fromDomain, postToBox, 52025) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: No ' + postToBox + ' was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  |         return 3 | 
					
						
							|  |  |  |     if not fromPersonId: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: No actor was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  |         return 4 | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     authHeader = createBasicAuthHeader(fromNickname, password) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     headers = { | 
					
						
							|  |  |  |         'host': fromDomain, | 
					
						
							|  |  |  |         'Content-type': 'application/json', | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'Authorization': authHeader | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     postResult = \ | 
					
						
							| 
									
										
										
										
											2021-03-10 19:24:52 +00:00
										 |  |  |         postJson(session, newFollowJson, [], inboxUrl, headers, 30, True) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     if not postResult: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: POST announce failed for c2s to ' + inboxUrl) | 
					
						
							|  |  |  |         return 5 | 
					
						
							| 
									
										
										
										
											2019-07-16 21:38:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST follow success') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return newFollowJson | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def sendUnfollowRequestViaServer(baseDir: str, session, | 
					
						
							|  |  |  |                                  fromNickname: str, password: str, | 
					
						
							|  |  |  |                                  fromDomain: str, fromPort: int, | 
					
						
							|  |  |  |                                  followNickname: str, followDomain: str, | 
					
						
							|  |  |  |                                  followPort: int, | 
					
						
							|  |  |  |                                  httpPrefix: str, | 
					
						
							|  |  |  |                                  cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                                  debug: bool, projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |     """Creates a unfollow request via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendUnfollowRequestViaServer') | 
					
						
							|  |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     fromDomainFull = getFullDomain(fromDomain, fromPort) | 
					
						
							|  |  |  |     followDomainFull = getFullDomain(followDomain, followPort) | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     followActor = httpPrefix + '://' + \ | 
					
						
							|  |  |  |         fromDomainFull + '/users/' + fromNickname | 
					
						
							|  |  |  |     followedId = httpPrefix + '://' + \ | 
					
						
							|  |  |  |         followDomainFull + '/users/' + followNickname | 
					
						
							|  |  |  |     statusNumber, published = getStatusNumber() | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     unfollowJson = { | 
					
						
							| 
									
										
										
										
											2019-08-16 21:52:11 +00:00
										 |  |  |         '@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         'id': followActor + '/statuses/' + str(statusNumber) + '/undo', | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |         'type': 'Undo', | 
					
						
							|  |  |  |         'actor': followActor, | 
					
						
							|  |  |  |         'object': { | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             'id': followActor + '/statuses/' + str(statusNumber), | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |             'type': 'Follow', | 
					
						
							|  |  |  |             'actor': followActor, | 
					
						
							| 
									
										
										
										
											2019-08-16 21:52:11 +00:00
										 |  |  |             'object': followedId | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     wfRequest = \ | 
					
						
							|  |  |  |         webfingerHandle(session, handle, httpPrefix, cachedWebfingers, | 
					
						
							| 
									
										
										
										
											2021-03-14 19:22:58 +00:00
										 |  |  |                         fromDomain, projectVersion, debug) | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: announce webfinger failed for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:12 +00:00
										 |  |  |     if not isinstance(wfRequest, dict): | 
					
						
							|  |  |  |         print('WARN: Webfinger for ' + handle + ' did not return a dict. ' + | 
					
						
							|  |  |  |               str(wfRequest)) | 
					
						
							|  |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     postToBox = 'outbox' | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     (inboxUrl, pubKeyId, pubKey, | 
					
						
							|  |  |  |      fromPersonId, sharedInbox, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |      avatarUrl, displayName) = getPersonBox(baseDir, session, | 
					
						
							|  |  |  |                                             wfRequest, personCache, | 
					
						
							|  |  |  |                                             projectVersion, httpPrefix, | 
					
						
							|  |  |  |                                             fromNickname, | 
					
						
							| 
									
										
										
										
											2020-12-18 17:49:17 +00:00
										 |  |  |                                             fromDomain, postToBox, | 
					
						
							|  |  |  |                                             76536) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: No ' + postToBox + ' was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |         return 3 | 
					
						
							|  |  |  |     if not fromPersonId: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: No actor was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |         return 4 | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     authHeader = createBasicAuthHeader(fromNickname, password) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     headers = { | 
					
						
							|  |  |  |         'host': fromDomain, | 
					
						
							|  |  |  |         'Content-type': 'application/json', | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'Authorization': authHeader | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     postResult = \ | 
					
						
							| 
									
										
										
										
											2021-03-10 19:24:52 +00:00
										 |  |  |         postJson(session, unfollowJson, [], inboxUrl, headers, 30, True) | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     if not postResult: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: POST announce failed for c2s to ' + inboxUrl) | 
					
						
							|  |  |  |         return 5 | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST unfollow success') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return unfollowJson | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def getFollowersOfActor(baseDir: str, actor: str, debug: bool) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-08 16:49:12 +00:00
										 |  |  |     """In a shared inbox if we receive a post we know who it's from
 | 
					
						
							| 
									
										
										
										
											2019-07-08 17:15:55 +00:00
										 |  |  |     and if it's addressed to followers then we need to get a list of those. | 
					
						
							|  |  |  |     This returns a list of account handles which follow the given actor | 
					
						
							| 
									
										
										
										
											2019-07-08 16:49:12 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('DEBUG: getting followers of ' + actor) | 
					
						
							|  |  |  |     recipientsDict = {} | 
					
						
							| 
									
										
										
										
											2019-07-08 17:15:55 +00:00
										 |  |  |     if ':' not in actor: | 
					
						
							| 
									
										
										
										
											2019-07-08 22:12:24 +00:00
										 |  |  |         return recipientsDict | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     nickname = getNicknameFromActor(actor) | 
					
						
							| 
									
										
										
										
											2019-07-08 16:49:12 +00:00
										 |  |  |     if not nickname: | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: no nickname found in ' + actor) | 
					
						
							| 
									
										
										
										
											2019-07-08 22:12:24 +00:00
										 |  |  |         return recipientsDict | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     domain, port = getDomainFromActor(actor) | 
					
						
							| 
									
										
										
										
											2019-07-08 16:49:12 +00:00
										 |  |  |     if not domain: | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: no domain found in ' + actor) | 
					
						
							| 
									
										
										
										
											2019-07-08 22:12:24 +00:00
										 |  |  |         return recipientsDict | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     actorHandle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('DEBUG: searching for handle ' + actorHandle) | 
					
						
							| 
									
										
										
										
											2019-07-08 16:49:12 +00:00
										 |  |  |     # for each of the accounts | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     for subdir, dirs, files in os.walk(baseDir + '/accounts'): | 
					
						
							| 
									
										
										
										
											2019-07-08 16:49:12 +00:00
										 |  |  |         for account in dirs: | 
					
						
							|  |  |  |             if '@' in account and not account.startswith('inbox@'): | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                 followingFilename = \ | 
					
						
							|  |  |  |                     os.path.join(subdir, account) + '/following.txt' | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |                 if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                     print('DEBUG: examining follows of ' + account) | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |                     print(followingFilename) | 
					
						
							| 
									
										
										
										
											2019-07-08 16:49:12 +00:00
										 |  |  |                 if os.path.isfile(followingFilename): | 
					
						
							|  |  |  |                     # does this account follow the given actor? | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |                     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                         print('DEBUG: checking if ' + actorHandle + | 
					
						
							|  |  |  |                               ' in ' + followingFilename) | 
					
						
							| 
									
										
										
										
											2019-07-08 17:15:55 +00:00
										 |  |  |                     if actorHandle in open(followingFilename).read(): | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |                         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |                             print('DEBUG: ' + account + | 
					
						
							|  |  |  |                                   ' follows ' + actorHandle) | 
					
						
							| 
									
										
										
										
											2020-09-27 18:35:35 +00:00
										 |  |  |                         recipientsDict[account] = None | 
					
						
							| 
									
										
										
										
											2020-12-13 22:13:45 +00:00
										 |  |  |         break | 
					
						
							| 
									
										
										
										
											2019-07-08 22:12:24 +00:00
										 |  |  |     return recipientsDict | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def outboxUndoFollow(baseDir: str, messageJson: {}, debug: bool) -> None: | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |     """When an unfollow request is received by the outbox from c2s
 | 
					
						
							|  |  |  |     This removes the followed handle from the following.txt file | 
					
						
							|  |  |  |     of the relevant account | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not messageJson.get('type'): | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     if not messageJson['type'] == 'Undo': | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |         return | 
					
						
							|  |  |  |     if not messageJson.get('object'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not isinstance(messageJson['object'], dict): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not messageJson['object'].get('type'): | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     if not messageJson['object']['type'] == 'Follow': | 
					
						
							| 
									
										
										
										
											2021-02-08 14:48:37 +00:00
										 |  |  |         if not messageJson['object']['type'] == 'Join': | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |     if not messageJson['object'].get('object'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not messageJson['object'].get('actor'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not isinstance(messageJson['object']['object'], str): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: undo follow arrived in outbox') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     nicknameFollower = getNicknameFromActor(messageJson['object']['actor']) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |     if not nicknameFollower: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('WARN: unable to find nickname in ' + | 
					
						
							|  |  |  |               messageJson['object']['actor']) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     domainFollower, portFollower = \ | 
					
						
							|  |  |  |         getDomainFromActor(messageJson['object']['actor']) | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     domainFollowerFull = getFullDomain(domainFollower, portFollower) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     nicknameFollowing = getNicknameFromActor(messageJson['object']['object']) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |     if not nicknameFollowing: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |         print('WARN: unable to find nickname in ' + | 
					
						
							|  |  |  |               messageJson['object']['object']) | 
					
						
							| 
									
										
										
										
											2019-09-02 09:43:43 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |     domainFollowing, portFollowing = \ | 
					
						
							|  |  |  |         getDomainFromActor(messageJson['object']['object']) | 
					
						
							| 
									
										
										
										
											2020-12-16 10:30:54 +00:00
										 |  |  |     domainFollowingFull = getFullDomain(domainFollowing, portFollowing) | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 13:57:24 +00:00
										 |  |  |     if unfollowAccount(baseDir, nicknameFollower, domainFollowerFull, | 
					
						
							|  |  |  |                        nicknameFollowing, domainFollowingFull): | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('DEBUG: ' + nicknameFollower + ' unfollowed ' + | 
					
						
							|  |  |  |                   nicknameFollowing + '@' + domainFollowingFull) | 
					
						
							| 
									
										
										
										
											2019-07-17 10:34:00 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 11:38:44 +00:00
										 |  |  |             print('WARN: ' + nicknameFollower + ' could not unfollow ' + | 
					
						
							|  |  |  |                   nicknameFollowing + '@' + domainFollowingFull) | 
					
						
							| 
									
										
										
										
											2020-11-09 15:40:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def followerApprovalActive(baseDir: str, nickname: str, domain: str) -> bool: | 
					
						
							|  |  |  |     """Returns true if the given account requires follower approval
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     manuallyApprovesFollowers = False | 
					
						
							|  |  |  |     actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json' | 
					
						
							|  |  |  |     if os.path.isfile(actorFilename): | 
					
						
							|  |  |  |         actorJson = loadJson(actorFilename) | 
					
						
							|  |  |  |         if actorJson: | 
					
						
							|  |  |  |             if actorJson.get('manuallyApprovesFollowers'): | 
					
						
							|  |  |  |                 manuallyApprovesFollowers = \ | 
					
						
							|  |  |  |                     actorJson['manuallyApprovesFollowers'] | 
					
						
							|  |  |  |     return manuallyApprovesFollowers |