| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | __filename__ = "posts.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							|  |  |  | __version__ = "1.1.0" | 
					
						
							|  |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							|  |  |  | __email__ = "bob@freedombone.net" | 
					
						
							|  |  |  | __status__ = "Production" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | import json | 
					
						
							|  |  |  | import html | 
					
						
							| 
									
										
										
										
											2019-06-29 10:08:59 +00:00
										 |  |  | import datetime | 
					
						
							| 
									
										
										
										
											2019-06-30 15:03:26 +00:00
										 |  |  | import os | 
					
						
							|  |  |  | import shutil | 
					
						
							|  |  |  | import sys | 
					
						
							| 
									
										
										
										
											2019-07-01 11:48:54 +00:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  | import uuid | 
					
						
							| 
									
										
										
										
											2020-09-25 12:33:28 +00:00
										 |  |  | import random | 
					
						
							| 
									
										
										
										
											2020-06-23 21:39:19 +00:00
										 |  |  | from socket import error as SocketError | 
					
						
							| 
									
										
										
										
											2019-10-10 13:48:05 +00:00
										 |  |  | from time import gmtime, strftime | 
					
						
							| 
									
										
										
										
											2019-07-14 09:17:50 +00:00
										 |  |  | from collections import OrderedDict | 
					
						
							| 
									
										
										
										
											2019-06-30 16:36:58 +00:00
										 |  |  | from threads import threadWithTrace | 
					
						
							| 
									
										
										
										
											2019-06-30 15:03:26 +00:00
										 |  |  | from cache import storePersonInCache | 
					
						
							|  |  |  | from cache import getPersonFromCache | 
					
						
							| 
									
										
										
										
											2019-08-20 11:51:29 +00:00
										 |  |  | from cache import expirePersonCache | 
					
						
							| 
									
										
										
										
											2019-06-29 10:08:59 +00:00
										 |  |  | from pprint import pprint | 
					
						
							| 
									
										
										
										
											2019-07-03 10:33:55 +00:00
										 |  |  | from session import createSession | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | from session import getJson | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | from session import postJson | 
					
						
							| 
									
										
										
										
											2019-08-17 10:15:01 +00:00
										 |  |  | from session import postJsonString | 
					
						
							| 
									
										
										
										
											2019-07-16 14:23:06 +00:00
										 |  |  | from session import postImage | 
					
						
							| 
									
										
										
										
											2019-06-30 22:56:37 +00:00
										 |  |  | from webfinger import webfingerHandle | 
					
						
							| 
									
										
										
										
											2019-07-01 09:31:02 +00:00
										 |  |  | from httpsig import createSignedHeader | 
					
						
							| 
									
										
										
										
											2020-09-25 14:14:59 +00:00
										 |  |  | from utils import getFollowersList | 
					
						
							| 
									
										
										
										
											2020-09-25 10:12:36 +00:00
										 |  |  | from utils import isEvil | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  | from utils import removeIdEnding | 
					
						
							| 
									
										
										
										
											2020-06-23 09:46:38 +00:00
										 |  |  | from utils import siteIsActive | 
					
						
							| 
									
										
										
										
											2019-12-01 13:51:44 +00:00
										 |  |  | from utils import getCachedPostFilename | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  | from utils import getStatusNumber | 
					
						
							| 
									
										
										
										
											2019-07-04 16:24:23 +00:00
										 |  |  | from utils import createPersonDir | 
					
						
							| 
									
										
										
										
											2019-07-02 10:39:55 +00:00
										 |  |  | from utils import urlPermitted | 
					
						
							| 
									
										
										
										
											2019-07-09 14:20:23 +00:00
										 |  |  | from utils import getNicknameFromActor | 
					
						
							|  |  |  | from utils import getDomainFromActor | 
					
						
							| 
									
										
										
										
											2019-07-14 16:37:01 +00:00
										 |  |  | from utils import deletePost | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  | from utils import validNickname | 
					
						
							| 
									
										
										
										
											2019-10-02 14:40:39 +00:00
										 |  |  | from utils import locatePost | 
					
						
							| 
									
										
										
										
											2019-10-22 11:55:06 +00:00
										 |  |  | from utils import loadJson | 
					
						
							|  |  |  | from utils import saveJson | 
					
						
							| 
									
										
										
										
											2020-10-06 08:58:44 +00:00
										 |  |  | from utils import getConfigParam | 
					
						
							| 
									
										
										
										
											2020-10-08 19:47:23 +00:00
										 |  |  | from utils import locateNewsVotes | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  | from utils import locateNewsArrival | 
					
						
							| 
									
										
										
										
											2020-10-08 19:47:23 +00:00
										 |  |  | from utils import votesOnNewswireItem | 
					
						
							| 
									
										
										
										
											2020-10-25 12:47:16 +00:00
										 |  |  | from utils import removeHtml | 
					
						
							| 
									
										
										
										
											2019-08-30 18:45:14 +00:00
										 |  |  | from media import attachMedia | 
					
						
							| 
									
										
										
										
											2020-01-15 22:31:04 +00:00
										 |  |  | from media import replaceYouTube | 
					
						
							| 
									
										
										
										
											2020-05-17 09:27:51 +00:00
										 |  |  | from content import removeLongWords | 
					
						
							| 
									
										
										
										
											2019-08-09 09:09:21 +00:00
										 |  |  | from content import addHtmlTags | 
					
						
							| 
									
										
										
										
											2019-09-29 17:42:51 +00:00
										 |  |  | from content import replaceEmojiFromTags | 
					
						
							| 
									
										
										
										
											2020-06-14 13:25:38 +00:00
										 |  |  | from content import removeTextFormatting | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  | from auth import createBasicAuthHeader | 
					
						
							| 
									
										
										
										
											2019-09-28 16:31:03 +00:00
										 |  |  | from blocking import isBlocked | 
					
						
							| 
									
										
										
										
											2020-02-05 14:57:10 +00:00
										 |  |  | from filters import isFiltered | 
					
						
							| 
									
										
										
										
											2020-05-03 12:52:13 +00:00
										 |  |  | from git import convertPostToPatch | 
					
						
							| 
									
										
										
										
											2020-06-15 13:08:19 +00:00
										 |  |  | from jsonldsig import jsonldSign | 
					
						
							| 
									
										
										
										
											2020-06-29 19:15:51 +00:00
										 |  |  | from petnames import resolvePetnames | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def isModerator(baseDir: str, nickname: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |     """Returns true if the given nickname is a moderator
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     moderatorsFile = baseDir + '/accounts/moderators.txt' | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not os.path.isfile(moderatorsFile): | 
					
						
							| 
									
										
										
										
											2020-10-10 16:10:32 +00:00
										 |  |  |         adminName = getConfigParam(baseDir, 'admin') | 
					
						
							|  |  |  |         if not adminName: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         if adminName == nickname: | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |             return True | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with open(moderatorsFile, "r") as f: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         lines = f.readlines() | 
					
						
							|  |  |  |         if len(lines) == 0: | 
					
						
							| 
									
										
										
										
											2020-10-10 16:10:32 +00:00
										 |  |  |             adminName = getConfigParam(baseDir, 'admin') | 
					
						
							|  |  |  |             if not adminName: | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |             if adminName == nickname: | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |                 return True | 
					
						
							|  |  |  |         for moderator in lines: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |             moderator = moderator.strip('\n').strip('\r') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             if moderator == nickname: | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |                 return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 19:14:36 +00:00
										 |  |  | def isEditor(baseDir: str, nickname: str) -> bool: | 
					
						
							|  |  |  |     """Returns true if the given nickname is an editor
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     editorsFile = baseDir + '/accounts/editors.txt' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not os.path.isfile(editorsFile): | 
					
						
							|  |  |  |         adminName = getConfigParam(baseDir, 'admin') | 
					
						
							|  |  |  |         if not adminName: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         if adminName == nickname: | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with open(editorsFile, "r") as f: | 
					
						
							|  |  |  |         lines = f.readlines() | 
					
						
							|  |  |  |         if len(lines) == 0: | 
					
						
							|  |  |  |             adminName = getConfigParam(baseDir, 'admin') | 
					
						
							|  |  |  |             if not adminName: | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |             if adminName == nickname: | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |         for editor in lines: | 
					
						
							|  |  |  |             editor = editor.strip('\n').strip('\r') | 
					
						
							|  |  |  |             if editor == nickname: | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def noOfFollowersOnDomain(baseDir: str, handle: str, | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |                           domain: str, followFile='followers.txt') -> int: | 
					
						
							| 
									
										
										
										
											2019-07-05 14:39:24 +00:00
										 |  |  |     """Returns the number of followers of the given handle from the given domain
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     filename = baseDir + '/accounts/' + handle + '/' + followFile | 
					
						
							| 
									
										
										
										
											2019-07-05 14:39:24 +00:00
										 |  |  |     if not os.path.isfile(filename): | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     ctr = 0 | 
					
						
							| 
									
										
										
										
											2019-07-05 14:39:24 +00:00
										 |  |  |     with open(filename, "r") as followersFilename: | 
					
						
							|  |  |  |         for followerHandle in followersFilename: | 
					
						
							|  |  |  |             if '@' in followerHandle: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                 followerDomain = followerHandle.split('@')[1] | 
					
						
							|  |  |  |                 followerDomain = followerDomain.replace('\n', '') | 
					
						
							|  |  |  |                 followerDomain = followerDomain.replace('\r', '') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 if domain == followerDomain: | 
					
						
							|  |  |  |                     ctr += 1 | 
					
						
							| 
									
										
										
										
											2019-07-05 14:39:24 +00:00
										 |  |  |     return ctr | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public', | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |                  debug=False): | 
					
						
							| 
									
										
										
										
											2019-06-30 15:03:26 +00:00
										 |  |  |     """Returns the public or private key of a person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							|  |  |  |     keyFilename = baseDir + '/keys/' + keyType + '/' + handle.lower() + '.key' | 
					
						
							| 
									
										
										
										
											2019-06-30 15:03:26 +00:00
										 |  |  |     if not os.path.isfile(keyFilename): | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: private key file not found: ' + keyFilename) | 
					
						
							| 
									
										
										
										
											2019-06-30 15:03:26 +00:00
										 |  |  |         return '' | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     keyPem = '' | 
					
						
							| 
									
										
										
										
											2019-06-30 15:03:26 +00:00
										 |  |  |     with open(keyFilename, "r") as pemFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         keyPem = pemFile.read() | 
					
						
							|  |  |  |     if len(keyPem) < 20: | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: private key was too short: ' + keyPem) | 
					
						
							| 
									
										
										
										
											2019-06-30 15:03:26 +00:00
										 |  |  |         return '' | 
					
						
							|  |  |  |     return keyPem | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | def cleanHtml(rawHtml: str) -> str: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     # text=BeautifulSoup(rawHtml, 'html.parser').get_text() | 
					
						
							|  |  |  |     text = rawHtml | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     return html.unescape(text) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-21 15:55:30 +00:00
										 |  |  | def getUserUrl(wfRequest: {}) -> str: | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     if wfRequest.get('links'): | 
					
						
							|  |  |  |         for link in wfRequest['links']: | 
					
						
							|  |  |  |             if link.get('type') and link.get('href'): | 
					
						
							| 
									
										
										
										
											2019-11-09 21:39:04 +00:00
										 |  |  |                 if link['type'] == 'application/activity+json': | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     if not ('/users/' in link['href'] or | 
					
						
							| 
									
										
										
										
											2020-08-13 16:19:35 +00:00
										 |  |  |                             '/accounts/' in link['href'] or | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             '/profile/' in link['href'] or | 
					
						
							| 
									
										
										
										
											2019-10-21 16:15:12 +00:00
										 |  |  |                             '/channel/' in link['href']): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         print('Webfinger activity+json contains ' + | 
					
						
							|  |  |  |                               'single user instance actor') | 
					
						
							| 
									
										
										
										
											2019-10-21 16:15:12 +00:00
										 |  |  |                     return link['href'] | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def parseUserFeed(session, feedUrl: str, asHeader: {}, | 
					
						
							|  |  |  |                   projectVersion: str, httpPrefix: str, | 
					
						
							| 
									
										
										
										
											2020-07-08 13:25:00 +00:00
										 |  |  |                   domain: str, depth=0) -> {}: | 
					
						
							| 
									
										
										
										
											2020-07-08 12:28:41 +00:00
										 |  |  |     if depth > 10: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     feedJson = getJson(session, feedUrl, asHeader, None, | 
					
						
							|  |  |  |                        projectVersion, httpPrefix, domain) | 
					
						
							| 
									
										
										
										
											2019-07-04 17:31:41 +00:00
										 |  |  |     if not feedJson: | 
					
						
							| 
									
										
										
										
											2020-07-08 12:28:41 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-29 10:08:59 +00:00
										 |  |  |     if 'orderedItems' in feedJson: | 
					
						
							| 
									
										
										
										
											2019-06-29 10:59:16 +00:00
										 |  |  |         for item in feedJson['orderedItems']: | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             yield item | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     nextUrl = None | 
					
						
							| 
									
										
										
										
											2019-06-29 10:08:59 +00:00
										 |  |  |     if 'first' in feedJson: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         nextUrl = feedJson['first'] | 
					
						
							| 
									
										
										
										
											2019-06-29 10:08:59 +00:00
										 |  |  |     elif 'next' in feedJson: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         nextUrl = feedJson['next'] | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if nextUrl: | 
					
						
							| 
									
										
										
										
											2019-09-01 13:13:52 +00:00
										 |  |  |         if isinstance(nextUrl, str): | 
					
						
							| 
									
										
										
										
											2020-06-28 10:02:59 +00:00
										 |  |  |             if '?max_id=0' not in nextUrl: | 
					
						
							|  |  |  |                 userFeed = \ | 
					
						
							|  |  |  |                     parseUserFeed(session, nextUrl, asHeader, | 
					
						
							|  |  |  |                                   projectVersion, httpPrefix, | 
					
						
							| 
									
										
										
										
											2020-07-08 12:28:41 +00:00
										 |  |  |                                   domain, depth+1) | 
					
						
							|  |  |  |                 if userFeed: | 
					
						
							|  |  |  |                     for item in userFeed: | 
					
						
							|  |  |  |                         yield item | 
					
						
							| 
									
										
										
										
											2019-09-01 13:13:52 +00:00
										 |  |  |         elif isinstance(nextUrl, dict): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             userFeed = nextUrl | 
					
						
							| 
									
										
										
										
											2019-09-01 13:13:52 +00:00
										 |  |  |             if userFeed.get('orderedItems'): | 
					
						
							|  |  |  |                 for item in userFeed['orderedItems']: | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |                     yield item | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def getPersonBox(baseDir: str, session, wfRequest: {}, | 
					
						
							|  |  |  |                  personCache: {}, | 
					
						
							|  |  |  |                  projectVersion: str, httpPrefix: str, | 
					
						
							|  |  |  |                  nickname: str, domain: str, | 
					
						
							|  |  |  |                  boxName='inbox') -> (str, str, str, str, str, str, str, str): | 
					
						
							|  |  |  |     profileStr = 'https://www.w3.org/ns/activitystreams' | 
					
						
							|  |  |  |     asHeader = { | 
					
						
							|  |  |  |         'Accept': 'application/activity+json; profile="' + profileStr + '"' | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-10-17 15:55:05 +00:00
										 |  |  |     if not wfRequest.get('errors'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         personUrl = getUserUrl(wfRequest) | 
					
						
							| 
									
										
										
										
											2019-10-17 15:55:05 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if nickname == 'dev': | 
					
						
							| 
									
										
										
										
											2019-10-21 16:03:44 +00:00
										 |  |  |             # try single user instance | 
					
						
							|  |  |  |             print('getPersonBox: Trying single user instance with ld+json') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             personUrl = httpPrefix + '://' + domain | 
					
						
							|  |  |  |             asHeader = { | 
					
						
							|  |  |  |                 'Accept': 'application/ld+json; profile="' + profileStr + '"' | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-10-21 16:03:44 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             personUrl = httpPrefix + '://' + domain + '/users/' + nickname | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |     if not personUrl: | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |         return None, None, None, None, None, None, None | 
					
						
							| 
									
										
										
										
											2020-08-29 10:21:29 +00:00
										 |  |  |     personJson = \ | 
					
						
							|  |  |  |         getPersonFromCache(baseDir, personUrl, personCache, True) | 
					
						
							| 
									
										
										
										
											2019-06-30 11:34:19 +00:00
										 |  |  |     if not personJson: | 
					
						
							| 
									
										
										
										
											2020-08-13 16:19:35 +00:00
										 |  |  |         if '/channel/' in personUrl or '/accounts/' in personUrl: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             asHeader = { | 
					
						
							|  |  |  |                 'Accept': 'application/ld+json; profile="' + profileStr + '"' | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         personJson = getJson(session, personUrl, asHeader, None, | 
					
						
							|  |  |  |                              projectVersion, httpPrefix, domain) | 
					
						
							| 
									
										
										
										
											2019-07-04 17:31:41 +00:00
										 |  |  |         if not personJson: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             asHeader = { | 
					
						
							|  |  |  |                 'Accept': 'application/ld+json; profile="' + profileStr + '"' | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             personJson = getJson(session, personUrl, asHeader, None, | 
					
						
							|  |  |  |                                  projectVersion, httpPrefix, domain) | 
					
						
							| 
									
										
										
										
											2019-10-21 16:20:33 +00:00
										 |  |  |             if not personJson: | 
					
						
							| 
									
										
										
										
											2019-10-21 16:21:16 +00:00
										 |  |  |                 print('Unable to get actor') | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                 return None, None, None, None, None, None, None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     boxJson = None | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |     if not personJson.get(boxName): | 
					
						
							| 
									
										
										
										
											2019-07-05 13:38:29 +00:00
										 |  |  |         if personJson.get('endpoints'): | 
					
						
							|  |  |  |             if personJson['endpoints'].get(boxName): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 boxJson = personJson['endpoints'][boxName] | 
					
						
							| 
									
										
										
										
											2019-07-05 13:38:29 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         boxJson = personJson[boxName] | 
					
						
							| 
									
										
										
										
											2019-07-05 13:38:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not boxJson: | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |         return None, None, None, None, None, None, None | 
					
						
							| 
									
										
										
										
											2019-07-05 13:38:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     personId = None | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |     if personJson.get('id'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         personId = personJson['id'] | 
					
						
							|  |  |  |     pubKeyId = None | 
					
						
							|  |  |  |     pubKey = None | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |     if personJson.get('publicKey'): | 
					
						
							| 
									
										
										
										
											2019-07-01 10:25:03 +00:00
										 |  |  |         if personJson['publicKey'].get('id'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             pubKeyId = personJson['publicKey']['id'] | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |         if personJson['publicKey'].get('publicKeyPem'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             pubKey = personJson['publicKey']['publicKeyPem'] | 
					
						
							|  |  |  |     sharedInbox = None | 
					
						
							| 
									
										
										
										
											2019-07-05 13:50:27 +00:00
										 |  |  |     if personJson.get('sharedInbox'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         sharedInbox = personJson['sharedInbox'] | 
					
						
							| 
									
										
										
										
											2019-07-05 13:50:27 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if personJson.get('endpoints'): | 
					
						
							|  |  |  |             if personJson['endpoints'].get('sharedInbox'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 sharedInbox = personJson['endpoints']['sharedInbox'] | 
					
						
							|  |  |  |     avatarUrl = None | 
					
						
							| 
									
										
										
										
											2019-07-22 14:09:21 +00:00
										 |  |  |     if personJson.get('icon'): | 
					
						
							|  |  |  |         if personJson['icon'].get('url'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             avatarUrl = personJson['icon']['url'] | 
					
						
							|  |  |  |     displayName = None | 
					
						
							| 
									
										
										
										
											2019-08-22 18:36:07 +00:00
										 |  |  |     if personJson.get('name'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         displayName = personJson['name'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 10:21:29 +00:00
										 |  |  |     storePersonInCache(baseDir, personUrl, personJson, personCache, True) | 
					
						
							| 
									
										
										
										
											2019-06-30 10:21:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     return boxJson, pubKeyId, pubKey, personId, sharedInbox, \ | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |         avatarUrl, displayName | 
					
						
							| 
									
										
										
										
											2019-06-30 10:21:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def getPosts(session, outboxUrl: str, maxPosts: int, | 
					
						
							|  |  |  |              maxMentions: int, | 
					
						
							|  |  |  |              maxEmoji: int, maxAttachments: int, | 
					
						
							|  |  |  |              federationList: [], | 
					
						
							|  |  |  |              personCache: {}, raw: bool, | 
					
						
							|  |  |  |              simple: bool, debug: bool, | 
					
						
							|  |  |  |              projectVersion: str, httpPrefix: str, | 
					
						
							|  |  |  |              domain: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-28 11:08:14 +00:00
										 |  |  |     """Gets public posts from an outbox
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     personPosts = {} | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  |     if not outboxUrl: | 
					
						
							|  |  |  |         return personPosts | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     profileStr = 'https://www.w3.org/ns/activitystreams' | 
					
						
							|  |  |  |     asHeader = { | 
					
						
							|  |  |  |         'Accept': 'application/activity+json; profile="' + profileStr + '"' | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-10-17 22:26:47 +00:00
										 |  |  |     if '/outbox/' in outboxUrl: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         asHeader = { | 
					
						
							|  |  |  |             'Accept': 'application/ld+json; profile="' + profileStr + '"' | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-07-03 11:24:38 +00:00
										 |  |  |     if raw: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         result = [] | 
					
						
							|  |  |  |         i = 0 | 
					
						
							|  |  |  |         userFeed = parseUserFeed(session, outboxUrl, asHeader, | 
					
						
							|  |  |  |                                  projectVersion, httpPrefix, domain) | 
					
						
							| 
									
										
										
										
											2019-09-01 13:13:52 +00:00
										 |  |  |         for item in userFeed: | 
					
						
							| 
									
										
										
										
											2019-07-03 11:24:38 +00:00
										 |  |  |             result.append(item) | 
					
						
							|  |  |  |             i += 1 | 
					
						
							|  |  |  |             if i == maxPosts: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |         pprint(result) | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     i = 0 | 
					
						
							|  |  |  |     userFeed = parseUserFeed(session, outboxUrl, asHeader, | 
					
						
							|  |  |  |                              projectVersion, httpPrefix, domain) | 
					
						
							| 
									
										
										
										
											2019-09-01 13:13:52 +00:00
										 |  |  |     for item in userFeed: | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |         if not item.get('id'): | 
					
						
							|  |  |  |             if debug: | 
					
						
							|  |  |  |                 print('No id') | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |         if not item.get('type'): | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |             if debug: | 
					
						
							|  |  |  |                 print('No type') | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             continue | 
					
						
							|  |  |  |         if item['type'] != 'Create': | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |             if debug: | 
					
						
							|  |  |  |                 print('Not Create type') | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             continue | 
					
						
							|  |  |  |         if not item.get('object'): | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |             if debug: | 
					
						
							|  |  |  |                 print('No object') | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             continue | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |         if not isinstance(item['object'], dict): | 
					
						
							|  |  |  |             if debug: | 
					
						
							|  |  |  |                 print('item object is not a dict') | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not item['object'].get('published'): | 
					
						
							|  |  |  |             if debug: | 
					
						
							|  |  |  |                 print('No published attribute') | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not personPosts.get(item['id']): | 
					
						
							| 
									
										
										
										
											2019-07-28 11:08:14 +00:00
										 |  |  |             # check that this is a public post | 
					
						
							|  |  |  |             # #Public should appear in the "to" list | 
					
						
							|  |  |  |             if item['object'].get('to'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 isPublic = False | 
					
						
							| 
									
										
										
										
											2019-07-28 11:08:14 +00:00
										 |  |  |                 for recipient in item['object']['to']: | 
					
						
							|  |  |  |                     if recipient.endswith('#Public'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         isPublic = True | 
					
						
							| 
									
										
										
										
											2019-07-28 11:08:14 +00:00
										 |  |  |                         break | 
					
						
							|  |  |  |                 if not isPublic: | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             content = \ | 
					
						
							|  |  |  |                 item['object']['content'].replace(''', "'") | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             mentions = [] | 
					
						
							|  |  |  |             emoji = {} | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             if item['object'].get('tag'): | 
					
						
							|  |  |  |                 for tagItem in item['object']['tag']: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     tagType = tagItem['type'].lower() | 
					
						
							|  |  |  |                     if tagType == 'emoji': | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |                         if tagItem.get('name') and tagItem.get('icon'): | 
					
						
							|  |  |  |                             if tagItem['icon'].get('url'): | 
					
						
							|  |  |  |                                 # No emoji from non-permitted domains | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                 if urlPermitted(tagItem['icon']['url'], | 
					
						
							|  |  |  |                                                 federationList, | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |                                                 "objects:read"): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                     emojiName = tagItem['name'] | 
					
						
							|  |  |  |                                     emojiIcon = tagItem['icon']['url'] | 
					
						
							|  |  |  |                                     emoji[emojiName] = emojiIcon | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |                                 else: | 
					
						
							|  |  |  |                                     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                         print('url not permitted ' + | 
					
						
							|  |  |  |                                               tagItem['icon']['url']) | 
					
						
							|  |  |  |                     if tagType == 'mention': | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |                         if tagItem.get('name'): | 
					
						
							|  |  |  |                             if tagItem['name'] not in mentions: | 
					
						
							|  |  |  |                                 mentions.append(tagItem['name']) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             if len(mentions) > maxMentions: | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |                 if debug: | 
					
						
							|  |  |  |                     print('max mentions reached') | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             if len(emoji) > maxEmoji: | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |                 if debug: | 
					
						
							|  |  |  |                     print('max emojis reached') | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             summary = '' | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             if item['object'].get('summary'): | 
					
						
							|  |  |  |                 if item['object']['summary']: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     summary = item['object']['summary'] | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             inReplyTo = '' | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             if item['object'].get('inReplyTo'): | 
					
						
							|  |  |  |                 if item['object']['inReplyTo']: | 
					
						
							| 
									
										
										
										
											2020-08-28 14:45:07 +00:00
										 |  |  |                     if isinstance(item['object']['inReplyTo'], str): | 
					
						
							|  |  |  |                         # No replies to non-permitted domains | 
					
						
							|  |  |  |                         if not urlPermitted(item['object']['inReplyTo'], | 
					
						
							|  |  |  |                                             federationList, | 
					
						
							|  |  |  |                                             "objects:read"): | 
					
						
							|  |  |  |                             if debug: | 
					
						
							|  |  |  |                                 print('url not permitted ' + | 
					
						
							|  |  |  |                                       item['object']['inReplyTo']) | 
					
						
							|  |  |  |                             continue | 
					
						
							|  |  |  |                         inReplyTo = item['object']['inReplyTo'] | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             conversation = '' | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             if item['object'].get('conversation'): | 
					
						
							|  |  |  |                 if item['object']['conversation']: | 
					
						
							|  |  |  |                     # no conversations originated in non-permitted domains | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     if urlPermitted(item['object']['conversation'], | 
					
						
							|  |  |  |                                     federationList, "objects:read"): | 
					
						
							|  |  |  |                         conversation = item['object']['conversation'] | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             attachment = [] | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             if item['object'].get('attachment'): | 
					
						
							|  |  |  |                 if item['object']['attachment']: | 
					
						
							|  |  |  |                     for attach in item['object']['attachment']: | 
					
						
							|  |  |  |                         if attach.get('name') and attach.get('url'): | 
					
						
							|  |  |  |                             # no attachments from non-permitted domains | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             if urlPermitted(attach['url'], | 
					
						
							|  |  |  |                                             federationList, | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |                                             "objects:read"): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                 attachment.append([attach['name'], | 
					
						
							|  |  |  |                                                    attach['url']]) | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |                             else: | 
					
						
							|  |  |  |                                 if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                     print('url not permitted ' + | 
					
						
							|  |  |  |                                           attach['url']) | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             sensitive = False | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |             if item['object'].get('sensitive'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 sensitive = item['object']['sensitive'] | 
					
						
							| 
									
										
										
										
											2019-07-03 11:24:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if simple: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print(cleanHtml(content) + '\n') | 
					
						
							| 
									
										
										
										
											2019-07-03 11:24:38 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2019-07-19 16:56:55 +00:00
										 |  |  |                 pprint(item) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 personPosts[item['id']] = { | 
					
						
							| 
									
										
										
										
											2019-07-03 11:24:38 +00:00
										 |  |  |                     "sensitive": sensitive, | 
					
						
							|  |  |  |                     "inreplyto": inReplyTo, | 
					
						
							|  |  |  |                     "summary": summary, | 
					
						
							|  |  |  |                     "html": content, | 
					
						
							|  |  |  |                     "plaintext": cleanHtml(content), | 
					
						
							|  |  |  |                     "attachment": attachment, | 
					
						
							|  |  |  |                     "mentions": mentions, | 
					
						
							|  |  |  |                     "emoji": emoji, | 
					
						
							|  |  |  |                     "conversation": conversation | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |         i += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if i == maxPosts: | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2019-07-02 09:25:29 +00:00
										 |  |  |     return personPosts | 
					
						
							| 
									
										
										
										
											2019-06-29 10:08:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  | def getPostDomains(session, outboxUrl: str, maxPosts: int, | 
					
						
							|  |  |  |                    maxMentions: int, | 
					
						
							|  |  |  |                    maxEmoji: int, maxAttachments: int, | 
					
						
							|  |  |  |                    federationList: [], | 
					
						
							| 
									
										
										
										
											2020-07-08 12:28:41 +00:00
										 |  |  |                    personCache: {}, | 
					
						
							|  |  |  |                    debug: bool, | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |                    projectVersion: str, httpPrefix: str, | 
					
						
							| 
									
										
										
										
											2020-07-08 10:30:29 +00:00
										 |  |  |                    domain: str, domainList=[]) -> []: | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |     """Returns a list of domains referenced within public posts
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not outboxUrl: | 
					
						
							|  |  |  |         return [] | 
					
						
							|  |  |  |     profileStr = 'https://www.w3.org/ns/activitystreams' | 
					
						
							|  |  |  |     asHeader = { | 
					
						
							|  |  |  |         'Accept': 'application/activity+json; profile="' + profileStr + '"' | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if '/outbox/' in outboxUrl: | 
					
						
							|  |  |  |         asHeader = { | 
					
						
							|  |  |  |             'Accept': 'application/ld+json; profile="' + profileStr + '"' | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 10:30:29 +00:00
										 |  |  |     postDomains = domainList | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     i = 0 | 
					
						
							|  |  |  |     userFeed = parseUserFeed(session, outboxUrl, asHeader, | 
					
						
							|  |  |  |                              projectVersion, httpPrefix, domain) | 
					
						
							|  |  |  |     for item in userFeed: | 
					
						
							| 
									
										
										
										
											2020-07-08 12:28:41 +00:00
										 |  |  |         i += 1 | 
					
						
							|  |  |  |         if i > maxPosts: | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |         if not item.get('object'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not isinstance(item['object'], dict): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if item['object'].get('inReplyTo'): | 
					
						
							| 
									
										
										
										
											2020-08-28 14:45:07 +00:00
										 |  |  |             if isinstance(item['object']['inReplyTo'], str): | 
					
						
							|  |  |  |                 postDomain, postPort = \ | 
					
						
							|  |  |  |                     getDomainFromActor(item['object']['inReplyTo']) | 
					
						
							|  |  |  |                 if postDomain not in postDomains: | 
					
						
							|  |  |  |                     postDomains.append(postDomain) | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if item['object'].get('tag'): | 
					
						
							|  |  |  |             for tagItem in item['object']['tag']: | 
					
						
							|  |  |  |                 tagType = tagItem['type'].lower() | 
					
						
							|  |  |  |                 if tagType == 'mention': | 
					
						
							|  |  |  |                     if tagItem.get('href'): | 
					
						
							|  |  |  |                         postDomain, postPort = \ | 
					
						
							|  |  |  |                             getDomainFromActor(tagItem['href']) | 
					
						
							|  |  |  |                         if postDomain not in postDomains: | 
					
						
							|  |  |  |                             postDomains.append(postDomain) | 
					
						
							|  |  |  |     return postDomains | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def deleteAllPosts(baseDir: str, | 
					
						
							|  |  |  |                    nickname: str, domain: str, boxname: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-07-04 16:24:23 +00:00
										 |  |  |     """Deletes all posts for a person from inbox or outbox
 | 
					
						
							| 
									
										
										
										
											2019-06-29 11:47:33 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |     if boxname != 'inbox' and boxname != 'outbox' and \ | 
					
						
							| 
									
										
										
										
											2020-10-07 09:10:42 +00:00
										 |  |  |        boxname != 'tlblogs' and boxname != 'tlnews' and \ | 
					
						
							|  |  |  |        boxname != 'tlevents': | 
					
						
							| 
									
										
										
										
											2019-07-04 16:24:23 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     boxDir = createPersonDir(nickname, domain, baseDir, boxname) | 
					
						
							| 
									
										
										
										
											2019-09-27 12:09:04 +00:00
										 |  |  |     for deleteFilename in os.scandir(boxDir): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         deleteFilename = deleteFilename.name | 
					
						
							|  |  |  |         filePath = os.path.join(boxDir, deleteFilename) | 
					
						
							| 
									
										
										
										
											2019-06-29 11:47:33 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             if os.path.isfile(filePath): | 
					
						
							|  |  |  |                 os.unlink(filePath) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             elif os.path.isdir(filePath): | 
					
						
							|  |  |  |                 shutil.rmtree(filePath) | 
					
						
							| 
									
										
										
										
											2019-06-29 11:47:33 +00:00
										 |  |  |         except Exception as e: | 
					
						
							|  |  |  |             print(e) | 
					
						
							| 
									
										
										
										
											2019-07-03 22:16:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def savePostToBox(baseDir: str, httpPrefix: str, postId: str, | 
					
						
							|  |  |  |                   nickname: str, domain: str, postJsonObject: {}, | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |                   boxname: str) -> str: | 
					
						
							| 
									
										
										
										
											2019-07-04 16:24:23 +00:00
										 |  |  |     """Saves the give json to the give box
 | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |     Returns the filename | 
					
						
							| 
									
										
										
										
											2019-07-03 22:16:03 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if boxname != 'inbox' and boxname != 'outbox' and \ | 
					
						
							| 
									
										
										
										
											2020-10-07 09:10:42 +00:00
										 |  |  |        boxname != 'tlblogs' and boxname != 'tlnews' and \ | 
					
						
							|  |  |  |        boxname != 'tlevents' and \ | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |        boxname != 'scheduled': | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     originalDomain = domain | 
					
						
							| 
									
										
										
										
											2019-07-03 22:16:03 +00:00
										 |  |  |     if ':' in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         domain = domain.split(':')[0] | 
					
						
							| 
									
										
										
										
											2019-07-04 16:24:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-03 22:59:56 +00:00
										 |  |  |     if not postId: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         statusNumber, published = getStatusNumber() | 
					
						
							|  |  |  |         postId = \ | 
					
						
							|  |  |  |             httpPrefix + '://' + originalDomain + '/users/' + nickname + \ | 
					
						
							|  |  |  |             '/statuses/' + statusNumber | 
					
						
							|  |  |  |         postJsonObject['id'] = postId + '/activity' | 
					
						
							| 
									
										
										
										
											2019-07-14 16:57:06 +00:00
										 |  |  |     if postJsonObject.get('object'): | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         if isinstance(postJsonObject['object'], dict): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             postJsonObject['object']['id'] = postId | 
					
						
							|  |  |  |             postJsonObject['object']['atomUri'] = postId | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     boxDir = createPersonDir(nickname, domain, baseDir, boxname) | 
					
						
							|  |  |  |     filename = boxDir + '/' + postId.replace('/', '#') + '.json' | 
					
						
							|  |  |  |     saveJson(postJsonObject, filename) | 
					
						
							| 
									
										
										
										
											2019-08-01 11:43:22 +00:00
										 |  |  |     return filename | 
					
						
							| 
									
										
										
										
											2019-07-03 22:16:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def updateHashtagsIndex(baseDir: str, tag: {}, newPostId: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-08-09 11:12:08 +00:00
										 |  |  |     """Writes the post url for hashtags to a file
 | 
					
						
							|  |  |  |     This allows posts for a hashtag to be quickly looked up | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if tag['type'] != 'Hashtag': | 
					
						
							| 
									
										
										
										
											2019-08-09 17:42:11 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-12-17 10:24:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |     # create hashtags directory | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     tagsDir = baseDir + '/tags' | 
					
						
							| 
									
										
										
										
											2019-08-09 11:12:08 +00:00
										 |  |  |     if not os.path.isdir(tagsDir): | 
					
						
							|  |  |  |         os.mkdir(tagsDir) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     tagName = tag['name'] | 
					
						
							|  |  |  |     tagsFilename = tagsDir + '/' + tagName[1:] + '.txt' | 
					
						
							|  |  |  |     tagline = newPostId + '\n' | 
					
						
							| 
									
										
										
										
											2019-12-17 10:24:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not os.path.isfile(tagsFilename): | 
					
						
							|  |  |  |         # create a new tags index file | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         tagsFile = open(tagsFilename, "w+") | 
					
						
							| 
									
										
										
										
											2019-12-17 10:24:52 +00:00
										 |  |  |         if tagsFile: | 
					
						
							|  |  |  |             tagsFile.write(tagline) | 
					
						
							|  |  |  |             tagsFile.close() | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         # prepend to tags index file | 
					
						
							|  |  |  |         if tagline not in open(tagsFilename).read(): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with open(tagsFilename, 'r+') as tagsFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     content = tagsFile.read() | 
					
						
							| 
									
										
										
										
											2019-12-17 10:24:52 +00:00
										 |  |  |                     tagsFile.seek(0, 0) | 
					
						
							|  |  |  |                     tagsFile.write(tagline+content) | 
					
						
							|  |  |  |             except Exception as e: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print('WARN: Failed to write entry to tags file ' + | 
					
						
							|  |  |  |                       tagsFilename + ' ' + str(e)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-09 11:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def addSchedulePost(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                     eventDateStr: str, postId: str) -> None: | 
					
						
							| 
									
										
										
										
											2020-01-13 10:49:03 +00:00
										 |  |  |     """Adds a scheduled post to the index
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							|  |  |  |     scheduleIndexFilename = baseDir + '/accounts/' + handle + '/schedule.index' | 
					
						
							| 
									
										
										
										
											2020-01-13 10:49:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     indexStr = eventDateStr + ' ' + postId.replace('/', '#') | 
					
						
							| 
									
										
										
										
											2020-01-13 10:49:03 +00:00
										 |  |  |     if os.path.isfile(scheduleIndexFilename): | 
					
						
							|  |  |  |         if indexStr not in open(scheduleIndexFilename).read(): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with open(scheduleIndexFilename, 'r+') as scheduleFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     content = scheduleFile.read() | 
					
						
							| 
									
										
										
										
											2020-01-13 10:49:03 +00:00
										 |  |  |                     scheduleFile.seek(0, 0) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     scheduleFile.write(indexStr + '\n' + content) | 
					
						
							| 
									
										
										
										
											2020-01-13 11:45:36 +00:00
										 |  |  |                     print('DEBUG: scheduled post added to index') | 
					
						
							| 
									
										
										
										
											2020-01-13 10:49:03 +00:00
										 |  |  |             except Exception as e: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print('WARN: Failed to write entry to scheduled posts index ' + | 
					
						
							|  |  |  |                       scheduleIndexFilename + ' ' + str(e)) | 
					
						
							| 
									
										
										
										
											2020-01-13 10:49:03 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-07-12 20:04:58 +00:00
										 |  |  |         scheduleFile = open(scheduleIndexFilename, 'w+') | 
					
						
							| 
									
										
										
										
											2020-01-13 10:49:03 +00:00
										 |  |  |         if scheduleFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             scheduleFile.write(indexStr + '\n') | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |             scheduleFile.close() | 
					
						
							| 
									
										
										
										
											2020-01-13 10:49:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-22 09:15:56 +00:00
										 |  |  | def appendEventFields(newPost: {}, | 
					
						
							|  |  |  |                       eventUUID: str, eventStatus: str, | 
					
						
							|  |  |  |                       anonymousParticipationEnabled: bool, | 
					
						
							|  |  |  |                       repliesModerationOption: str, | 
					
						
							|  |  |  |                       category: str, | 
					
						
							|  |  |  |                       joinMode: str, | 
					
						
							|  |  |  |                       eventDateStr: str, | 
					
						
							|  |  |  |                       endDateStr: str, | 
					
						
							|  |  |  |                       location: str, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                       maximumAttendeeCapacity: int, | 
					
						
							| 
									
										
										
										
											2020-08-23 19:04:11 +00:00
										 |  |  |                       ticketUrl: str, | 
					
						
							|  |  |  |                       subject: str) -> None: | 
					
						
							| 
									
										
										
										
											2020-08-22 09:15:56 +00:00
										 |  |  |     """Appends Mobilizon-type event fields to a post
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not eventUUID: | 
					
						
							| 
									
										
										
										
											2020-08-23 15:11:42 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-08-22 09:15:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # add attributes for Mobilizon-type events | 
					
						
							|  |  |  |     newPost['uuid'] = eventUUID | 
					
						
							|  |  |  |     if eventStatus: | 
					
						
							|  |  |  |         newPost['ical:status'] = eventStatus | 
					
						
							|  |  |  |     if anonymousParticipationEnabled: | 
					
						
							|  |  |  |         newPost['anonymousParticipationEnabled'] = \ | 
					
						
							|  |  |  |             anonymousParticipationEnabled | 
					
						
							|  |  |  |     if repliesModerationOption: | 
					
						
							|  |  |  |         newPost['repliesModerationOption'] = repliesModerationOption | 
					
						
							|  |  |  |     if category: | 
					
						
							|  |  |  |         newPost['category'] = category | 
					
						
							|  |  |  |     if joinMode: | 
					
						
							|  |  |  |         newPost['joinMode'] = joinMode | 
					
						
							|  |  |  |     newPost['startTime'] = eventDateStr | 
					
						
							|  |  |  |     newPost['endTime'] = endDateStr | 
					
						
							|  |  |  |     if location: | 
					
						
							|  |  |  |         newPost['location'] = location | 
					
						
							|  |  |  |     if maximumAttendeeCapacity: | 
					
						
							|  |  |  |         newPost['maximumAttendeeCapacity'] = maximumAttendeeCapacity | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |     if ticketUrl: | 
					
						
							|  |  |  |         newPost['ticketUrl'] = ticketUrl | 
					
						
							| 
									
										
										
										
											2020-08-23 19:04:11 +00:00
										 |  |  |     if subject: | 
					
						
							|  |  |  |         newPost['name'] = subject | 
					
						
							| 
									
										
										
										
											2020-08-23 19:06:49 +00:00
										 |  |  |         newPost['summary'] = None | 
					
						
							|  |  |  |         newPost['sensitive'] = False | 
					
						
							| 
									
										
										
										
											2020-08-22 09:15:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-07 22:08:15 +00:00
										 |  |  | def validContentWarning(cw: str) -> str: | 
					
						
							| 
									
										
										
										
											2020-08-25 19:35:55 +00:00
										 |  |  |     """Returns a validated content warning
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     cw = removeHtml(cw) | 
					
						
							|  |  |  |     # hashtags within content warnings apparently cause a lot of trouble | 
					
						
							|  |  |  |     # so remove them | 
					
						
							|  |  |  |     if '#' in cw: | 
					
						
							|  |  |  |         cw = cw.replace('#', '').replace('  ', ' ') | 
					
						
							|  |  |  |     return cw | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-13 18:56:41 +00:00
										 |  |  | def loadAutoCW(baseDir: str, nickname: str, domain: str) -> []: | 
					
						
							|  |  |  |     """Loads automatic CWs file and returns a list containing
 | 
					
						
							|  |  |  |     the lines of the file | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     filename = baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |         nickname + '@' + domain + '/autocw.txt' | 
					
						
							|  |  |  |     if not os.path.isfile(filename): | 
					
						
							|  |  |  |         return [] | 
					
						
							|  |  |  |     with open(filename, "r") as f: | 
					
						
							|  |  |  |         return f.readlines() | 
					
						
							|  |  |  |     return [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def addAutoCW(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |               subject: str, content: str) -> str: | 
					
						
							|  |  |  |     """Appends any automatic CW to the subject line
 | 
					
						
							|  |  |  |     and returns the new subject line | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     newSubject = subject | 
					
						
							|  |  |  |     autoCWList = loadAutoCW(baseDir, nickname, domain) | 
					
						
							|  |  |  |     for cwRule in autoCWList: | 
					
						
							|  |  |  |         if '->' not in cwRule: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         match = cwRule.split('->')[0].strip() | 
					
						
							|  |  |  |         if match not in content: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         cwStr = cwRule.split('->')[1].strip() | 
					
						
							|  |  |  |         if newSubject: | 
					
						
							|  |  |  |             if cwStr not in newSubject: | 
					
						
							|  |  |  |                 newSubject += ', ' + cwStr | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             newSubject = cwStr | 
					
						
							|  |  |  |     return newSubject | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def createPostBase(baseDir: str, nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                    toUrl: str, ccUrl: str, httpPrefix: str, content: str, | 
					
						
							|  |  |  |                    followersOnly: bool, saveToFile: bool, clientToServer: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                    commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                    attachImageFilename: str, | 
					
						
							|  |  |  |                    mediaType: str, imageDescription: str, | 
					
						
							|  |  |  |                    useBlurhash: bool, isModerationReport: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                    isArticle: bool, | 
					
						
							|  |  |  |                    inReplyTo=None, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                    inReplyToAtomUri=None, subject=None, schedulePost=False, | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  |                    eventDate=None, eventTime=None, location=None, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                    eventUUID=None, category=None, joinMode=None, | 
					
						
							|  |  |  |                    endDate=None, endTime=None, | 
					
						
							|  |  |  |                    maximumAttendeeCapacity=None, | 
					
						
							|  |  |  |                    repliesModerationOption=None, | 
					
						
							|  |  |  |                    anonymousParticipationEnabled=None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                    eventStatus=None, ticketUrl=None) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-01 12:14:49 +00:00
										 |  |  |     """Creates a message
 | 
					
						
							| 
									
										
										
										
											2019-06-29 22:29:18 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-09-13 18:56:41 +00:00
										 |  |  |     subject = addAutoCW(baseDir, nickname, domain, subject, content) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 11:38:52 +00:00
										 |  |  |     if nickname != 'news': | 
					
						
							|  |  |  |         mentionedRecipients = \ | 
					
						
							|  |  |  |             getMentionedPeople(baseDir, httpPrefix, content, domain, False) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         mentionedRecipients = '' | 
					
						
							| 
									
										
										
										
											2019-08-19 09:37:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     tags = [] | 
					
						
							|  |  |  |     hashtagsDict = {} | 
					
						
							| 
									
										
										
										
											2019-07-15 14:41:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domain = domain + ':' + str(port) | 
					
						
							| 
									
										
										
										
											2019-11-01 10:19:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # add tags | 
					
						
							| 
									
										
										
										
											2020-10-10 11:38:52 +00:00
										 |  |  |     if nickname != 'news': | 
					
						
							|  |  |  |         content = \ | 
					
						
							|  |  |  |             addHtmlTags(baseDir, httpPrefix, | 
					
						
							|  |  |  |                         nickname, domain, content, | 
					
						
							|  |  |  |                         mentionedRecipients, | 
					
						
							|  |  |  |                         hashtagsDict, True) | 
					
						
							| 
									
										
										
										
											2020-02-21 15:17:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # replace emoji with unicode | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     tags = [] | 
					
						
							|  |  |  |     for tagName, tag in hashtagsDict.items(): | 
					
						
							| 
									
										
										
										
											2020-02-21 15:17:55 +00:00
										 |  |  |         tags.append(tag) | 
					
						
							|  |  |  |     # get list of tags | 
					
						
							| 
									
										
										
										
											2020-10-10 11:38:52 +00:00
										 |  |  |     if nickname != 'news': | 
					
						
							|  |  |  |         content = replaceEmojiFromTags(content, tags, 'content') | 
					
						
							| 
									
										
										
										
											2020-02-21 15:17:55 +00:00
										 |  |  |     # remove replaced emoji | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     hashtagsDictCopy = hashtagsDict.copy() | 
					
						
							|  |  |  |     for tagName, tag in hashtagsDictCopy.items(): | 
					
						
							| 
									
										
										
										
											2020-02-21 15:17:55 +00:00
										 |  |  |         if tag.get('name'): | 
					
						
							|  |  |  |             if tag['name'].startswith(':'): | 
					
						
							|  |  |  |                 if tag['name'] not in content: | 
					
						
							|  |  |  |                     del hashtagsDict[tagName] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     statusNumber, published = getStatusNumber() | 
					
						
							|  |  |  |     newPostId = \ | 
					
						
							|  |  |  |         httpPrefix + '://' + domain + '/users/' + \ | 
					
						
							|  |  |  |         nickname + '/statuses/' + statusNumber | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sensitive = False | 
					
						
							|  |  |  |     summary = None | 
					
						
							| 
									
										
										
										
											2019-06-29 10:23:40 +00:00
										 |  |  |     if subject: | 
					
						
							| 
									
										
										
										
											2020-08-25 19:35:55 +00:00
										 |  |  |         summary = validContentWarning(subject) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         sensitive = True | 
					
						
							| 
									
										
										
										
											2019-07-15 14:41:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     toRecipients = [] | 
					
						
							|  |  |  |     toCC = [] | 
					
						
							| 
									
										
										
										
											2019-08-11 18:32:29 +00:00
										 |  |  |     if toUrl: | 
					
						
							|  |  |  |         if not isinstance(toUrl, str): | 
					
						
							|  |  |  |             print('ERROR: toUrl is not a string') | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         toRecipients = [toUrl] | 
					
						
							| 
									
										
										
										
											2019-08-11 18:32:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-05 16:56:32 +00:00
										 |  |  |     # who to send to | 
					
						
							| 
									
										
										
										
											2019-08-19 12:40:59 +00:00
										 |  |  |     if mentionedRecipients: | 
					
						
							|  |  |  |         for mention in mentionedRecipients: | 
					
						
							| 
									
										
										
										
											2019-11-04 12:09:59 +00:00
										 |  |  |             if mention not in toCC: | 
					
						
							|  |  |  |                 toCC.append(mention) | 
					
						
							| 
									
										
										
										
											2019-08-09 11:12:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # create a list of hashtags | 
					
						
							| 
									
										
										
										
											2019-09-05 11:37:41 +00:00
										 |  |  |     # Only posts which are #Public are searchable by hashtag | 
					
						
							| 
									
										
										
										
											2019-08-10 16:55:17 +00:00
										 |  |  |     if hashtagsDict: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         isPublic = False | 
					
						
							| 
									
										
										
										
											2019-08-10 16:55:17 +00:00
										 |  |  |         for recipient in toRecipients: | 
					
						
							|  |  |  |             if recipient.endswith('#Public'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 isPublic = True | 
					
						
							| 
									
										
										
										
											2019-08-10 16:55:17 +00:00
										 |  |  |                 break | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         for tagName, tag in hashtagsDict.items(): | 
					
						
							| 
									
										
										
										
											2019-08-09 11:12:08 +00:00
										 |  |  |             tags.append(tag) | 
					
						
							| 
									
										
										
										
											2019-08-10 11:51:54 +00:00
										 |  |  |             if isPublic: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 updateHashtagsIndex(baseDir, tag, newPostId) | 
					
						
							|  |  |  |         print('Content tags: ' + str(tags)) | 
					
						
							| 
									
										
										
										
											2019-10-02 14:40:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if inReplyTo and not sensitive: | 
					
						
							|  |  |  |         # locate the post which this is a reply to and check if | 
					
						
							|  |  |  |         # it has a content warning. If it does then reproduce | 
					
						
							|  |  |  |         # the same warning | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         replyPostFilename = \ | 
					
						
							|  |  |  |             locatePost(baseDir, nickname, domain, inReplyTo) | 
					
						
							| 
									
										
										
										
											2019-10-02 14:40:39 +00:00
										 |  |  |         if replyPostFilename: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             replyToJson = loadJson(replyPostFilename) | 
					
						
							| 
									
										
										
										
											2019-10-02 14:40:39 +00:00
										 |  |  |             if replyToJson: | 
					
						
							|  |  |  |                 if replyToJson.get('object'): | 
					
						
							|  |  |  |                     if replyToJson['object'].get('sensitive'): | 
					
						
							|  |  |  |                         if replyToJson['object']['sensitive']: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             sensitive = True | 
					
						
							| 
									
										
										
										
											2019-10-02 14:40:39 +00:00
										 |  |  |                             if replyToJson['object'].get('summary'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                 summary = replyToJson['object']['summary'] | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the ending date and time | 
					
						
							|  |  |  |     endDateStr = None | 
					
						
							|  |  |  |     if endDate: | 
					
						
							|  |  |  |         eventName = summary | 
					
						
							|  |  |  |         if not eventName: | 
					
						
							|  |  |  |             eventName = content | 
					
						
							|  |  |  |         endDateStr = endDate | 
					
						
							|  |  |  |         if endTime: | 
					
						
							|  |  |  |             if endTime.endswith('Z'): | 
					
						
							|  |  |  |                 endDateStr = endDate + 'T' + endTime | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 endDateStr = endDate + 'T' + endTime + \ | 
					
						
							|  |  |  |                     ':00' + strftime("%z", gmtime()) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             endDateStr = endDate + 'T12:00:00Z' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # get the starting date and time | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     eventDateStr = None | 
					
						
							| 
									
										
										
										
											2019-10-10 13:12:13 +00:00
										 |  |  |     if eventDate: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         eventName = summary | 
					
						
							| 
									
										
										
										
											2019-10-10 13:12:13 +00:00
										 |  |  |         if not eventName: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             eventName = content | 
					
						
							|  |  |  |         eventDateStr = eventDate | 
					
						
							| 
									
										
										
										
											2019-10-10 13:12:13 +00:00
										 |  |  |         if eventTime: | 
					
						
							| 
									
										
										
										
											2019-10-10 13:24:29 +00:00
										 |  |  |             if eventTime.endswith('Z'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 eventDateStr = eventDate + 'T' + eventTime | 
					
						
							| 
									
										
										
										
											2019-10-10 13:24:29 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 eventDateStr = eventDate + 'T' + eventTime + \ | 
					
						
							|  |  |  |                     ':00' + strftime("%z", gmtime()) | 
					
						
							| 
									
										
										
										
											2019-10-10 13:12:13 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             eventDateStr = eventDate + 'T12:00:00Z' | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |         if not endDateStr: | 
					
						
							|  |  |  |             endDateStr = eventDateStr | 
					
						
							|  |  |  |         if not schedulePost and not eventUUID: | 
					
						
							| 
									
										
										
										
											2020-01-12 13:19:03 +00:00
										 |  |  |             tags.append({ | 
					
						
							| 
									
										
										
										
											2019-10-10 13:12:13 +00:00
										 |  |  |                 "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							|  |  |  |                 "type": "Event", | 
					
						
							|  |  |  |                 "name": eventName, | 
					
						
							|  |  |  |                 "startTime": eventDateStr, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                 "endTime": endDateStr | 
					
						
							| 
									
										
										
										
											2020-01-12 13:19:03 +00:00
										 |  |  |             }) | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |     if location and not eventUUID: | 
					
						
							| 
									
										
										
										
											2020-01-12 13:16:02 +00:00
										 |  |  |         tags.append({ | 
					
						
							|  |  |  |             "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							|  |  |  |             "type": "Place", | 
					
						
							|  |  |  |             "name": location | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2019-10-19 15:59:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postContext = [ | 
					
						
							| 
									
										
										
										
											2019-10-19 15:59:49 +00:00
										 |  |  |         'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             'Hashtag': 'as:Hashtag', | 
					
						
							|  |  |  |             'sensitive': 'as:sensitive', | 
					
						
							|  |  |  |             'toot': 'http://joinmastodon.org/ns#', | 
					
						
							|  |  |  |             'votersCount': 'toot:votersCount' | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     ] | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-07 13:35:22 +00:00
										 |  |  |     # make sure that CC doesn't also contain a To address | 
					
						
							|  |  |  |     # eg. To: [ "https://mydomain/users/foo/followers" ] | 
					
						
							|  |  |  |     #     CC: [ "X", "Y", "https://mydomain/users/foo", "Z" ] | 
					
						
							|  |  |  |     removeFromCC = [] | 
					
						
							|  |  |  |     for ccRecipient in toCC: | 
					
						
							|  |  |  |         for sendToActor in toRecipients: | 
					
						
							| 
									
										
										
										
											2020-06-07 18:02:20 +00:00
										 |  |  |             if ccRecipient in sendToActor and \ | 
					
						
							|  |  |  |                ccRecipient not in removeFromCC: | 
					
						
							|  |  |  |                 removeFromCC.append(ccRecipient) | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2020-06-07 13:35:22 +00:00
										 |  |  |     for ccRemoval in removeFromCC: | 
					
						
							|  |  |  |         toCC.remove(ccRemoval) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  |     # the type of post to be made | 
					
						
							|  |  |  |     postObjectType = 'Note' | 
					
						
							|  |  |  |     if eventUUID: | 
					
						
							|  |  |  |         postObjectType = 'Event' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |     if not clientToServer: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         actorUrl = httpPrefix + '://' + domain + '/users/' + nickname | 
					
						
							| 
									
										
										
										
											2019-07-06 10:33:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         idStr = \ | 
					
						
							|  |  |  |             httpPrefix + '://' + domain + '/users/' + nickname + \ | 
					
						
							|  |  |  |             '/statuses/' + statusNumber + '/replies' | 
					
						
							|  |  |  |         newPost = { | 
					
						
							| 
									
										
										
										
											2020-05-03 14:39:21 +00:00
										 |  |  |             '@context': postContext, | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |             'id': newPostId + '/activity', | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |             'type': 'Create', | 
					
						
							| 
									
										
										
										
											2019-07-06 10:33:57 +00:00
										 |  |  |             'actor': actorUrl, | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |             'published': published, | 
					
						
							| 
									
										
										
										
											2019-11-04 12:09:59 +00:00
										 |  |  |             'to': toRecipients, | 
					
						
							|  |  |  |             'cc': toCC, | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |             'object': { | 
					
						
							|  |  |  |                 'id': newPostId, | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  |                 'type': postObjectType, | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |                 'summary': summary, | 
					
						
							|  |  |  |                 'inReplyTo': inReplyTo, | 
					
						
							|  |  |  |                 'published': published, | 
					
						
							| 
									
										
										
										
											2019-07-03 19:00:03 +00:00
										 |  |  |                 'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber, | 
					
						
							|  |  |  |                 'attributedTo': httpPrefix+'://'+domain+'/users/'+nickname, | 
					
						
							| 
									
										
										
										
											2019-08-05 16:56:32 +00:00
										 |  |  |                 'to': toRecipients, | 
					
						
							| 
									
										
										
										
											2019-11-04 12:09:59 +00:00
										 |  |  |                 'cc': toCC, | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |                 'sensitive': sensitive, | 
					
						
							| 
									
										
										
										
											2019-07-03 22:59:56 +00:00
										 |  |  |                 'atomUri': newPostId, | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |                 'inReplyToAtomUri': inReplyToAtomUri, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                 'commentsEnabled': commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-05-03 14:39:21 +00:00
										 |  |  |                 'mediaType': 'text/html', | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |                 'content': content, | 
					
						
							|  |  |  |                 'contentMap': { | 
					
						
							|  |  |  |                     'en': content | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 'attachment': [], | 
					
						
							| 
									
										
										
										
											2019-08-09 11:12:08 +00:00
										 |  |  |                 'tag': tags, | 
					
						
							| 
									
										
										
										
											2019-07-11 13:46:12 +00:00
										 |  |  |                 'replies': { | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     'id': idStr, | 
					
						
							| 
									
										
										
										
											2019-07-11 13:46:12 +00:00
										 |  |  |                     'type': 'Collection', | 
					
						
							|  |  |  |                     'first': { | 
					
						
							|  |  |  |                         'type': 'CollectionPage', | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         'partOf': idStr, | 
					
						
							| 
									
										
										
										
											2019-07-11 13:46:12 +00:00
										 |  |  |                         'items': [] | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-07-12 19:08:46 +00:00
										 |  |  |         if attachImageFilename: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             newPost['object'] = \ | 
					
						
							|  |  |  |                 attachMedia(baseDir, httpPrefix, domain, port, | 
					
						
							|  |  |  |                             newPost['object'], attachImageFilename, | 
					
						
							|  |  |  |                             mediaType, imageDescription, useBlurhash) | 
					
						
							| 
									
										
										
										
											2020-08-23 15:11:42 +00:00
										 |  |  |         appendEventFields(newPost['object'], eventUUID, eventStatus, | 
					
						
							|  |  |  |                           anonymousParticipationEnabled, | 
					
						
							|  |  |  |                           repliesModerationOption, | 
					
						
							|  |  |  |                           category, joinMode, | 
					
						
							|  |  |  |                           eventDateStr, endDateStr, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                           location, maximumAttendeeCapacity, | 
					
						
							| 
									
										
										
										
											2020-08-23 19:04:11 +00:00
										 |  |  |                           ticketUrl, subject) | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         idStr = \ | 
					
						
							|  |  |  |             httpPrefix + '://' + domain + '/users/' + nickname + \ | 
					
						
							|  |  |  |             '/statuses/' + statusNumber + '/replies' | 
					
						
							|  |  |  |         newPost = { | 
					
						
							| 
									
										
										
										
											2019-10-19 15:59:49 +00:00
										 |  |  |             "@context": postContext, | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |             'id': newPostId, | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  |             'type': postObjectType, | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |             'summary': summary, | 
					
						
							|  |  |  |             'inReplyTo': inReplyTo, | 
					
						
							|  |  |  |             'published': published, | 
					
						
							| 
									
										
										
										
											2019-07-03 19:00:03 +00:00
										 |  |  |             'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber, | 
					
						
							|  |  |  |             'attributedTo': httpPrefix+'://'+domain+'/users/'+nickname, | 
					
						
							| 
									
										
										
										
											2019-08-05 16:56:32 +00:00
										 |  |  |             'to': toRecipients, | 
					
						
							| 
									
										
										
										
											2019-11-04 12:09:59 +00:00
										 |  |  |             'cc': toCC, | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |             'sensitive': sensitive, | 
					
						
							| 
									
										
										
										
											2019-07-03 22:59:56 +00:00
										 |  |  |             'atomUri': newPostId, | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |             'inReplyToAtomUri': inReplyToAtomUri, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |             'commentsEnabled': commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-05-03 14:40:59 +00:00
										 |  |  |             'mediaType': 'text/html', | 
					
						
							| 
									
										
										
										
											2019-07-03 15:10:18 +00:00
										 |  |  |             'content': content, | 
					
						
							|  |  |  |             'contentMap': { | 
					
						
							|  |  |  |                 'en': content | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             'attachment': [], | 
					
						
							| 
									
										
										
										
											2019-08-09 11:12:08 +00:00
										 |  |  |             'tag': tags, | 
					
						
							| 
									
										
										
										
											2019-07-12 19:08:46 +00:00
										 |  |  |             'replies': { | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 'id': idStr, | 
					
						
							| 
									
										
										
										
											2019-07-12 19:08:46 +00:00
										 |  |  |                 'type': 'Collection', | 
					
						
							|  |  |  |                 'first': { | 
					
						
							|  |  |  |                     'type': 'CollectionPage', | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     'partOf': idStr, | 
					
						
							| 
									
										
										
										
											2019-07-12 19:08:46 +00:00
										 |  |  |                     'items': [] | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-07-12 19:08:46 +00:00
										 |  |  |         if attachImageFilename: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             newPost = \ | 
					
						
							|  |  |  |                 attachMedia(baseDir, httpPrefix, domain, port, | 
					
						
							|  |  |  |                             newPost, attachImageFilename, | 
					
						
							|  |  |  |                             mediaType, imageDescription, useBlurhash) | 
					
						
							| 
									
										
										
										
											2020-08-23 15:11:42 +00:00
										 |  |  |         appendEventFields(newPost, eventUUID, eventStatus, | 
					
						
							|  |  |  |                           anonymousParticipationEnabled, | 
					
						
							|  |  |  |                           repliesModerationOption, | 
					
						
							|  |  |  |                           category, joinMode, | 
					
						
							|  |  |  |                           eventDateStr, endDateStr, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                           location, maximumAttendeeCapacity, | 
					
						
							| 
									
										
										
										
											2020-08-23 19:04:11 +00:00
										 |  |  |                           ticketUrl, subject) | 
					
						
							| 
									
										
										
										
											2019-07-01 12:14:49 +00:00
										 |  |  |     if ccUrl: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if len(ccUrl) > 0: | 
					
						
							|  |  |  |             newPost['cc'] = [ccUrl] | 
					
						
							| 
									
										
										
										
											2019-07-19 18:12:50 +00:00
										 |  |  |             if newPost.get('object'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 newPost['object']['cc'] = [ccUrl] | 
					
						
							| 
									
										
										
										
											2019-08-11 20:38:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # if this is a moderation report then add a status | 
					
						
							|  |  |  |     if isModerationReport: | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |         # add status | 
					
						
							| 
									
										
										
										
											2019-08-11 20:38:10 +00:00
										 |  |  |         if newPost.get('object'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             newPost['object']['moderationStatus'] = 'pending' | 
					
						
							| 
									
										
										
										
											2019-08-11 20:38:10 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             newPost['moderationStatus'] = 'pending' | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |         # save to index file | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         moderationIndexFile = baseDir + '/accounts/moderation.txt' | 
					
						
							|  |  |  |         modFile = open(moderationIndexFile, "a+") | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |         if modFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             modFile.write(newPostId + '\n') | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |             modFile.close() | 
					
						
							| 
									
										
										
										
											2019-08-11 20:38:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-03 12:52:13 +00:00
										 |  |  |     # If a patch has been posted - i.e. the output from | 
					
						
							| 
									
										
										
										
											2020-05-03 12:39:54 +00:00
										 |  |  |     # git format-patch - then convert the activitypub type | 
					
						
							| 
									
										
										
										
											2020-05-03 12:52:13 +00:00
										 |  |  |     convertPostToPatch(baseDir, nickname, domain, newPost) | 
					
						
							| 
									
										
										
										
											2020-05-03 12:39:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-12 20:53:00 +00:00
										 |  |  |     if schedulePost: | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |         if eventDate and eventTime: | 
					
						
							| 
									
										
										
										
											2020-01-12 20:53:00 +00:00
										 |  |  |             # add an item to the scheduled post index file | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             addSchedulePost(baseDir, nickname, domain, eventDateStr, newPostId) | 
					
						
							|  |  |  |             savePostToBox(baseDir, httpPrefix, newPostId, | 
					
						
							|  |  |  |                           nickname, domain, newPost, 'scheduled') | 
					
						
							| 
									
										
										
										
											2020-01-12 20:53:00 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('Unable to create scheduled post without ' + | 
					
						
							|  |  |  |                   'date and time values') | 
					
						
							| 
									
										
										
										
											2020-01-12 20:53:00 +00:00
										 |  |  |             return newPost | 
					
						
							|  |  |  |     elif saveToFile: | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |         if isArticle: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             savePostToBox(baseDir, httpPrefix, newPostId, | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |                           nickname, domain, newPost, 'tlblogs') | 
					
						
							|  |  |  |         elif eventUUID: | 
					
						
							|  |  |  |             savePostToBox(baseDir, httpPrefix, newPostId, | 
					
						
							|  |  |  |                           nickname, domain, newPost, 'tlevents') | 
					
						
							| 
									
										
										
										
											2020-02-24 22:34:54 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             savePostToBox(baseDir, httpPrefix, newPostId, | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |                           nickname, domain, newPost, 'outbox') | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     return newPost | 
					
						
							| 
									
										
										
										
											2019-06-29 10:08:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def outboxMessageCreateWrap(httpPrefix: str, | 
					
						
							|  |  |  |                             nickname: str, domain: str, port: int, | 
					
						
							| 
									
										
										
										
											2019-07-06 17:00:22 +00:00
										 |  |  |                             messageJson: {}) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-03 21:37:46 +00:00
										 |  |  |     """Wraps a received message in a Create
 | 
					
						
							|  |  |  |     https://www.w3.org/TR/activitypub/#object-without-create | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domain = domain + ':' + str(port) | 
					
						
							|  |  |  |     statusNumber, published = getStatusNumber() | 
					
						
							| 
									
										
										
										
											2019-07-03 21:37:46 +00:00
										 |  |  |     if messageJson.get('published'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         published = messageJson['published'] | 
					
						
							|  |  |  |     newPostId = \ | 
					
						
							|  |  |  |         httpPrefix + '://' + domain + '/users/' + nickname + \ | 
					
						
							|  |  |  |         '/statuses/' + statusNumber | 
					
						
							|  |  |  |     cc = [] | 
					
						
							| 
									
										
										
										
											2019-07-03 21:37:46 +00:00
										 |  |  |     if messageJson.get('cc'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         cc = messageJson['cc'] | 
					
						
							|  |  |  |     newPost = { | 
					
						
							| 
									
										
										
										
											2019-08-18 11:07:06 +00:00
										 |  |  |         "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |         'id': newPostId + '/activity', | 
					
						
							| 
									
										
										
										
											2019-07-03 21:37:46 +00:00
										 |  |  |         'type': 'Create', | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |         'actor': httpPrefix + '://' + domain + '/users/' + nickname, | 
					
						
							| 
									
										
										
										
											2019-07-03 21:37:46 +00:00
										 |  |  |         'published': published, | 
					
						
							|  |  |  |         'to': messageJson['to'], | 
					
						
							|  |  |  |         'cc': cc, | 
					
						
							|  |  |  |         'object': messageJson | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     newPost['object']['id'] = newPost['id'] | 
					
						
							|  |  |  |     newPost['object']['url'] = \ | 
					
						
							|  |  |  |         httpPrefix + '://' + domain + '/@' + nickname + '/' + statusNumber | 
					
						
							|  |  |  |     newPost['object']['atomUri'] = \ | 
					
						
							|  |  |  |         httpPrefix + '://' + domain + '/users/' + nickname + \ | 
					
						
							|  |  |  |         '/statuses/' + statusNumber | 
					
						
							| 
									
										
										
										
											2019-07-03 21:37:46 +00:00
										 |  |  |     return newPost | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  | def postIsAddressedToFollowers(baseDir: str, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                nickname: str, domain: str, port: int, | 
					
						
							| 
									
										
										
										
											2019-12-12 09:58:06 +00:00
										 |  |  |                                httpPrefix: str, | 
					
						
							| 
									
										
										
										
											2019-07-14 16:57:06 +00:00
										 |  |  |                                postJsonObject: {}) -> bool: | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  |     """Returns true if the given post is addressed to followers of the nickname
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domain = domain + ':' + str(port) | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-14 16:57:06 +00:00
										 |  |  |     if not postJsonObject.get('object'): | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     toList = [] | 
					
						
							|  |  |  |     ccList = [] | 
					
						
							|  |  |  |     if postJsonObject['type'] != 'Update' and \ | 
					
						
							| 
									
										
										
										
											2019-08-20 21:09:56 +00:00
										 |  |  |        isinstance(postJsonObject['object'], dict): | 
					
						
							| 
									
										
										
										
											2019-11-04 12:46:51 +00:00
										 |  |  |         if postJsonObject['object'].get('to'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             toList = postJsonObject['object']['to'] | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         if postJsonObject['object'].get('cc'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             ccList = postJsonObject['object']['cc'] | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2019-11-04 12:46:51 +00:00
										 |  |  |         if postJsonObject.get('to'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             toList = postJsonObject['to'] | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |         if postJsonObject.get('cc'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             ccList = postJsonObject['cc'] | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     followersUrl = httpPrefix + '://' + domain + '/users/' + \ | 
					
						
							|  |  |  |         nickname + '/followers' | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # does the followers url exist in 'to' or 'cc' lists? | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     addressedToFollowers = False | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |     if followersUrl in toList: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         addressedToFollowers = True | 
					
						
							| 
									
										
										
										
											2019-11-04 12:46:51 +00:00
										 |  |  |     elif followersUrl in ccList: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         addressedToFollowers = True | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  |     return addressedToFollowers | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def postIsAddressedToPublic(baseDir: str, postJsonObject: {}) -> bool: | 
					
						
							| 
									
										
										
										
											2019-07-15 17:22:51 +00:00
										 |  |  |     """Returns true if the given post is addressed to public
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not postJsonObject.get('object'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not postJsonObject['object'].get('to'): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     publicUrl = 'https://www.w3.org/ns/activitystreams#Public' | 
					
						
							| 
									
										
										
										
											2019-07-15 17:22:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # does the public url exist in 'to' or 'cc' lists? | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     addressedToPublic = False | 
					
						
							| 
									
										
										
										
											2019-07-15 17:22:51 +00:00
										 |  |  |     if publicUrl in postJsonObject['object']['to']: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         addressedToPublic = True | 
					
						
							| 
									
										
										
										
											2019-07-15 17:22:51 +00:00
										 |  |  |     if not addressedToPublic: | 
					
						
							|  |  |  |         if not postJsonObject['object'].get('cc'): | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         if publicUrl in postJsonObject['object']['cc']: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             addressedToPublic = True | 
					
						
							| 
									
										
										
										
											2019-07-15 17:22:51 +00:00
										 |  |  |     return addressedToPublic | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def createPublicPost(baseDir: str, | 
					
						
							|  |  |  |                      nickname: str, domain: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |                      content: str, followersOnly: bool, saveToFile: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                      clientToServer: bool, commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                      attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                      imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                      inReplyTo=None, inReplyToAtomUri=None, subject=None, | 
					
						
							|  |  |  |                      schedulePost=False, | 
					
						
							|  |  |  |                      eventDate=None, eventTime=None, location=None) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |     """Public post
 | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     domainFull = domain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domainFull = domain + ':' + str(port) | 
					
						
							|  |  |  |     return createPostBase(baseDir, nickname, domain, port, | 
					
						
							|  |  |  |                           'https://www.w3.org/ns/activitystreams#Public', | 
					
						
							|  |  |  |                           httpPrefix + '://' + domainFull + '/users/' + | 
					
						
							|  |  |  |                           nickname + '/followers', | 
					
						
							|  |  |  |                           httpPrefix, content, followersOnly, saveToFile, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                           clientToServer, commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                           attachImageFilename, mediaType, | 
					
						
							|  |  |  |                           imageDescription, useBlurhash, | 
					
						
							|  |  |  |                           False, False, inReplyTo, inReplyToAtomUri, subject, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                           schedulePost, eventDate, eventTime, location, | 
					
						
							|  |  |  |                           None, None, None, None, None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                           None, None, None, None, None) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def createBlogPost(baseDir: str, | 
					
						
							|  |  |  |                    nickname: str, domain: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |                    content: str, followersOnly: bool, saveToFile: bool, | 
					
						
							| 
									
										
										
										
											2020-10-13 13:46:16 +00:00
										 |  |  |                    clientToServer: bool, commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                    attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                    imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                    inReplyTo=None, inReplyToAtomUri=None, subject=None, | 
					
						
							|  |  |  |                    schedulePost=False, | 
					
						
							|  |  |  |                    eventDate=None, eventTime=None, location=None) -> {}: | 
					
						
							|  |  |  |     blog = \ | 
					
						
							|  |  |  |         createPublicPost(baseDir, | 
					
						
							|  |  |  |                          nickname, domain, port, httpPrefix, | 
					
						
							|  |  |  |                          content, followersOnly, saveToFile, | 
					
						
							| 
									
										
										
										
											2020-10-07 22:29:05 +00:00
										 |  |  |                          clientToServer, commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                          attachImageFilename, mediaType, | 
					
						
							|  |  |  |                          imageDescription, useBlurhash, | 
					
						
							|  |  |  |                          inReplyTo, inReplyToAtomUri, subject, | 
					
						
							|  |  |  |                          schedulePost, | 
					
						
							|  |  |  |                          eventDate, eventTime, location) | 
					
						
							| 
									
										
										
										
											2020-10-07 21:26:03 +00:00
										 |  |  |     blog['object']['type'] = 'Article' | 
					
						
							| 
									
										
										
										
											2020-11-06 11:21:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # append citations tags, stored in a file | 
					
						
							|  |  |  |     citationsFilename = \ | 
					
						
							|  |  |  |         baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |         nickname + '@' + domain + '/.citations.txt' | 
					
						
							|  |  |  |     if os.path.isfile(citationsFilename): | 
					
						
							|  |  |  |         citationsSeparator = '#####' | 
					
						
							|  |  |  |         with open(citationsFilename, "r") as f: | 
					
						
							|  |  |  |             citations = f.readlines() | 
					
						
							|  |  |  |             for line in citations: | 
					
						
							| 
									
										
										
										
											2020-11-06 11:24:25 +00:00
										 |  |  |                 if citationsSeparator not in line: | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2020-11-06 11:22:50 +00:00
										 |  |  |                 sections = line.strip().split(citationsSeparator) | 
					
						
							| 
									
										
										
										
											2020-11-06 11:23:42 +00:00
										 |  |  |                 if len(sections) != 3: | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2020-11-06 11:53:59 +00:00
										 |  |  |                 # dateStr = sections[0] | 
					
						
							| 
									
										
										
										
											2020-11-06 11:21:41 +00:00
										 |  |  |                 title = sections[1] | 
					
						
							|  |  |  |                 link = sections[2] | 
					
						
							|  |  |  |                 tagJson = { | 
					
						
							|  |  |  |                     "type": "Article", | 
					
						
							| 
									
										
										
										
											2020-11-06 11:25:23 +00:00
										 |  |  |                     "name": title, | 
					
						
							| 
									
										
										
										
											2020-11-06 11:21:41 +00:00
										 |  |  |                     "url": link | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 blog['object']['tag'].append(tagJson) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-07 21:26:03 +00:00
										 |  |  |     return blog | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def createNewsPost(baseDir: str, | 
					
						
							| 
									
										
										
										
											2020-10-07 22:25:30 +00:00
										 |  |  |                    domain: str, port: int, httpPrefix: str, | 
					
						
							| 
									
										
										
										
											2020-10-07 21:26:03 +00:00
										 |  |  |                    content: str, followersOnly: bool, saveToFile: bool, | 
					
						
							|  |  |  |                    attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                    imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                    subject: str) -> {}: | 
					
						
							|  |  |  |     clientToServer = False | 
					
						
							|  |  |  |     inReplyTo = None | 
					
						
							|  |  |  |     inReplyToAtomUri = None | 
					
						
							| 
									
										
										
										
											2020-10-07 21:40:52 +00:00
										 |  |  |     schedulePost = False | 
					
						
							| 
									
										
										
										
											2020-10-07 21:26:03 +00:00
										 |  |  |     eventDate = None | 
					
						
							|  |  |  |     eventTime = None | 
					
						
							|  |  |  |     location = None | 
					
						
							|  |  |  |     blog = \ | 
					
						
							|  |  |  |         createPublicPost(baseDir, | 
					
						
							| 
									
										
										
										
											2020-10-07 22:29:05 +00:00
										 |  |  |                          'news', domain, port, httpPrefix, | 
					
						
							|  |  |  |                          content, followersOnly, saveToFile, | 
					
						
							|  |  |  |                          clientToServer, False, | 
					
						
							|  |  |  |                          attachImageFilename, mediaType, | 
					
						
							|  |  |  |                          imageDescription, useBlurhash, | 
					
						
							|  |  |  |                          inReplyTo, inReplyToAtomUri, subject, | 
					
						
							|  |  |  |                          schedulePost, | 
					
						
							|  |  |  |                          eventDate, eventTime, location) | 
					
						
							| 
									
										
										
										
											2020-10-07 12:05:49 +00:00
										 |  |  |     blog['object']['type'] = 'Article' | 
					
						
							|  |  |  |     return blog | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-25 22:34:26 +00:00
										 |  |  | def createQuestionPost(baseDir: str, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        nickname: str, domain: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |                        content: str, qOptions: [], | 
					
						
							|  |  |  |                        followersOnly: bool, saveToFile: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        clientToServer: bool, commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                        imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                        subject: str, durationDays: int) -> {}: | 
					
						
							| 
									
										
										
										
											2019-11-25 22:34:26 +00:00
										 |  |  |     """Question post with multiple choice options
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     domainFull = domain | 
					
						
							| 
									
										
										
										
											2019-11-25 22:34:26 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-11-25 22:34:26 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domainFull = domain + ':' + str(port) | 
					
						
							|  |  |  |     messageJson = \ | 
					
						
							|  |  |  |         createPostBase(baseDir, nickname, domain, port, | 
					
						
							|  |  |  |                        'https://www.w3.org/ns/activitystreams#Public', | 
					
						
							|  |  |  |                        httpPrefix + '://' + domainFull + '/users/' + | 
					
						
							|  |  |  |                        nickname + '/followers', | 
					
						
							|  |  |  |                        httpPrefix, content, followersOnly, saveToFile, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        clientToServer, commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        attachImageFilename, mediaType, | 
					
						
							|  |  |  |                        imageDescription, useBlurhash, | 
					
						
							|  |  |  |                        False, False, None, None, subject, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        False, None, None, None, None, None, | 
					
						
							|  |  |  |                        None, None, None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                        None, None, None, None, None) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     messageJson['object']['type'] = 'Question' | 
					
						
							|  |  |  |     messageJson['object']['oneOf'] = [] | 
					
						
							|  |  |  |     messageJson['object']['votersCount'] = 0 | 
					
						
							|  |  |  |     currTime = datetime.datetime.utcnow() | 
					
						
							|  |  |  |     daysSinceEpoch = \ | 
					
						
							|  |  |  |         int((currTime - datetime.datetime(1970, 1, 1)).days + durationDays) | 
					
						
							|  |  |  |     endTime = datetime.datetime(1970, 1, 1) + \ | 
					
						
							|  |  |  |         datetime.timedelta(daysSinceEpoch) | 
					
						
							|  |  |  |     messageJson['object']['endTime'] = endTime.strftime("%Y-%m-%dT%H:%M:%SZ") | 
					
						
							| 
									
										
										
										
											2019-11-25 22:34:26 +00:00
										 |  |  |     for questionOption in qOptions: | 
					
						
							| 
									
										
										
										
											2019-11-29 13:54:25 +00:00
										 |  |  |         messageJson['object']['oneOf'].append({ | 
					
						
							| 
									
										
										
										
											2019-11-25 22:34:26 +00:00
										 |  |  |             "type": "Note", | 
					
						
							|  |  |  |             "name": questionOption, | 
					
						
							|  |  |  |             "replies": { | 
					
						
							|  |  |  |                 "type": "Collection", | 
					
						
							|  |  |  |                 "totalItems": 0 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |     return messageJson | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-24 13:32:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-28 11:08:14 +00:00
										 |  |  | def createUnlistedPost(baseDir: str, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        nickname: str, domain: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |                        content: str, followersOnly: bool, saveToFile: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        clientToServer: bool, commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                        imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                        inReplyTo=None, inReplyToAtomUri=None, subject=None, | 
					
						
							|  |  |  |                        schedulePost=False, | 
					
						
							|  |  |  |                        eventDate=None, eventTime=None, location=None) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-28 11:08:14 +00:00
										 |  |  |     """Unlisted post. This has the #Public and followers links inverted.
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     domainFull = domain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domainFull = domain + ':' + str(port) | 
					
						
							|  |  |  |     return createPostBase(baseDir, nickname, domain, port, | 
					
						
							|  |  |  |                           httpPrefix + '://' + domainFull + '/users/' + | 
					
						
							|  |  |  |                           nickname + '/followers', | 
					
						
							|  |  |  |                           'https://www.w3.org/ns/activitystreams#Public', | 
					
						
							|  |  |  |                           httpPrefix, content, followersOnly, saveToFile, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                           clientToServer, commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                           attachImageFilename, mediaType, | 
					
						
							|  |  |  |                           imageDescription, useBlurhash, | 
					
						
							|  |  |  |                           False, False, inReplyTo, inReplyToAtomUri, subject, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                           schedulePost, eventDate, eventTime, location, | 
					
						
							|  |  |  |                           None, None, None, None, None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                           None, None, None, None, None) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-28 11:08:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  | def createFollowersOnlyPost(baseDir: str, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                             httpPrefix: str, | 
					
						
							|  |  |  |                             content: str, followersOnly: bool, | 
					
						
							|  |  |  |                             saveToFile: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                             clientToServer: bool, commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                             imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                             inReplyTo=None, inReplyToAtomUri=None, | 
					
						
							|  |  |  |                             subject=None, schedulePost=False, | 
					
						
							|  |  |  |                             eventDate=None, eventTime=None, | 
					
						
							|  |  |  |                             location=None) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |     """Followers only post
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     domainFull = domain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domainFull = domain + ':' + str(port) | 
					
						
							|  |  |  |     return createPostBase(baseDir, nickname, domain, port, | 
					
						
							|  |  |  |                           httpPrefix + '://' + domainFull + '/users/' + | 
					
						
							|  |  |  |                           nickname + '/followers', | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |                           None, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                           httpPrefix, content, followersOnly, saveToFile, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                           clientToServer, commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                           attachImageFilename, mediaType, | 
					
						
							|  |  |  |                           imageDescription, useBlurhash, | 
					
						
							|  |  |  |                           False, False, inReplyTo, inReplyToAtomUri, subject, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                           schedulePost, eventDate, eventTime, location, | 
					
						
							|  |  |  |                           None, None, None, None, None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                           None, None, None, None, None) | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def createEventPost(baseDir: str, | 
					
						
							|  |  |  |                     nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                     httpPrefix: str, | 
					
						
							|  |  |  |                     content: str, followersOnly: bool, | 
					
						
							|  |  |  |                     saveToFile: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                     clientToServer: bool, commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  |                     attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                     imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                     subject=None, schedulePost=False, | 
					
						
							|  |  |  |                     eventDate=None, eventTime=None, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                     location=None, category=None, joinMode=None, | 
					
						
							|  |  |  |                     endDate=None, endTime=None, | 
					
						
							|  |  |  |                     maximumAttendeeCapacity=None, | 
					
						
							|  |  |  |                     repliesModerationOption=None, | 
					
						
							|  |  |  |                     anonymousParticipationEnabled=None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                     eventStatus=None, ticketUrl=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  |     """Mobilizon-type Event post
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not attachImageFilename: | 
					
						
							| 
									
										
										
										
											2020-08-25 12:39:17 +00:00
										 |  |  |         print('Event has no attached image') | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |     if not category: | 
					
						
							| 
									
										
										
										
											2020-08-25 12:39:17 +00:00
										 |  |  |         print('Event has no category') | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  |     domainFull = domain | 
					
						
							|  |  |  |     if port: | 
					
						
							|  |  |  |         if port != 80 and port != 443: | 
					
						
							|  |  |  |             if ':' not in domain: | 
					
						
							|  |  |  |                 domainFull = domain + ':' + str(port) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # create event uuid | 
					
						
							|  |  |  |     eventUUID = str(uuid.uuid1()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     toStr1 = 'https://www.w3.org/ns/activitystreams#Public' | 
					
						
							|  |  |  |     toStr2 = httpPrefix + '://' + domainFull + '/users/' + \ | 
					
						
							|  |  |  |         nickname + '/followers', | 
					
						
							|  |  |  |     if followersOnly: | 
					
						
							|  |  |  |         toStr1 = toStr2 | 
					
						
							|  |  |  |         toStr2 = None | 
					
						
							| 
									
										
										
										
											2020-08-25 12:39:17 +00:00
										 |  |  |     return createPostBase(baseDir, nickname, domain, port, | 
					
						
							|  |  |  |                           toStr1, toStr2, | 
					
						
							|  |  |  |                           httpPrefix, content, followersOnly, saveToFile, | 
					
						
							|  |  |  |                           clientToServer, commentsEnabled, | 
					
						
							|  |  |  |                           attachImageFilename, mediaType, | 
					
						
							|  |  |  |                           imageDescription, useBlurhash, | 
					
						
							|  |  |  |                           False, False, None, None, subject, | 
					
						
							|  |  |  |                           schedulePost, eventDate, eventTime, location, | 
					
						
							|  |  |  |                           eventUUID, category, joinMode, | 
					
						
							|  |  |  |                           endDate, endTime, maximumAttendeeCapacity, | 
					
						
							|  |  |  |                           repliesModerationOption, | 
					
						
							|  |  |  |                           anonymousParticipationEnabled, | 
					
						
							|  |  |  |                           eventStatus, ticketUrl) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def getMentionedPeople(baseDir: str, httpPrefix: str, | 
					
						
							|  |  |  |                        content: str, domain: str, debug: bool) -> []: | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |     """Extracts a list of mentioned actors from the given message content
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if '@' not in content: | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     mentions = [] | 
					
						
							|  |  |  |     words = content.split(' ') | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |     for wrd in words: | 
					
						
							|  |  |  |         if wrd.startswith('@'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             handle = wrd[1:] | 
					
						
							| 
									
										
										
										
											2019-08-19 09:11:25 +00:00
										 |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print('DEBUG: mentioned handle ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |             if '@' not in handle: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 handle = handle + '@' + domain | 
					
						
							|  |  |  |                 if not os.path.isdir(baseDir + '/accounts/' + handle): | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |                     continue | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 externalDomain = handle.split('@')[1] | 
					
						
							|  |  |  |                 if not ('.' in externalDomain or | 
					
						
							|  |  |  |                         externalDomain == 'localhost'): | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             mentionedNickname = handle.split('@')[0] | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |             mentionedDomain = handle.split('@')[1].strip('\n').strip('\r') | 
					
						
							| 
									
										
										
										
											2019-08-23 13:47:29 +00:00
										 |  |  |             if ':' in mentionedDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 mentionedDomain = mentionedDomain.split(':')[0] | 
					
						
							|  |  |  |             if not validNickname(mentionedDomain, mentionedNickname): | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             actor = \ | 
					
						
							|  |  |  |                 httpPrefix + '://' + handle.split('@')[1] + \ | 
					
						
							|  |  |  |                 '/users/' + mentionedNickname | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |             mentions.append(actor) | 
					
						
							| 
									
										
										
										
											2019-08-19 09:16:33 +00:00
										 |  |  |     return mentions | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  | def createDirectMessagePost(baseDir: str, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                             httpPrefix: str, | 
					
						
							|  |  |  |                             content: str, followersOnly: bool, | 
					
						
							|  |  |  |                             saveToFile: bool, clientToServer: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                             commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                             imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                             inReplyTo=None, inReplyToAtomUri=None, | 
					
						
							|  |  |  |                             subject=None, debug=False, | 
					
						
							|  |  |  |                             schedulePost=False, | 
					
						
							|  |  |  |                             eventDate=None, eventTime=None, | 
					
						
							|  |  |  |                             location=None) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |     """Direct Message post
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-06-29 19:15:51 +00:00
										 |  |  |     content = resolvePetnames(baseDir, nickname, domain, content) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     mentionedPeople = \ | 
					
						
							|  |  |  |         getMentionedPeople(baseDir, httpPrefix, content, domain, debug) | 
					
						
							| 
									
										
										
										
											2019-08-19 09:11:25 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         print('mentionedPeople: ' + str(mentionedPeople)) | 
					
						
							| 
									
										
										
										
											2019-07-27 22:48:34 +00:00
										 |  |  |     if not mentionedPeople: | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postTo = None | 
					
						
							|  |  |  |     postCc = None | 
					
						
							|  |  |  |     messageJson = \ | 
					
						
							|  |  |  |         createPostBase(baseDir, nickname, domain, port, | 
					
						
							|  |  |  |                        postTo, postCc, | 
					
						
							|  |  |  |                        httpPrefix, content, followersOnly, saveToFile, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        clientToServer, commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        attachImageFilename, mediaType, | 
					
						
							|  |  |  |                        imageDescription, useBlurhash, | 
					
						
							|  |  |  |                        False, False, inReplyTo, inReplyToAtomUri, subject, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        schedulePost, eventDate, eventTime, location, | 
					
						
							|  |  |  |                        None, None, None, None, None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                        None, None, None, None, None) | 
					
						
							| 
									
										
										
										
											2019-11-10 12:28:12 +00:00
										 |  |  |     # mentioned recipients go into To rather than Cc | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     messageJson['to'] = messageJson['object']['cc'] | 
					
						
							| 
									
										
										
										
											2020-06-24 12:33:06 +00:00
										 |  |  |     messageJson['object']['to'] = messageJson['to'] | 
					
						
							|  |  |  |     messageJson['cc'] = [] | 
					
						
							|  |  |  |     messageJson['object']['cc'] = [] | 
					
						
							| 
									
										
										
										
											2020-06-24 11:53:43 +00:00
										 |  |  |     if schedulePost: | 
					
						
							|  |  |  |         savePostToBox(baseDir, httpPrefix, messageJson['object']['id'], | 
					
						
							|  |  |  |                       nickname, domain, messageJson, 'scheduled') | 
					
						
							|  |  |  |     return messageJson | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  | def createReportPost(baseDir: str, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                      nickname: str, domain: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |                      content: str, followersOnly: bool, saveToFile: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                      clientToServer: bool, commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                      attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                      imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                      debug: bool, subject=None) -> {}: | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |     """Send a report to moderators
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     domainFull = domain | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domainFull = domain + ':' + str(port) | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-11 11:33:29 +00:00
										 |  |  |     # add a title to distinguish moderation reports from other posts | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     reportTitle = 'Moderation Report' | 
					
						
							| 
									
										
										
										
											2019-08-11 11:33:29 +00:00
										 |  |  |     if not subject: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         subject = reportTitle | 
					
						
							| 
									
										
										
										
											2019-08-11 11:33:29 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if not subject.startswith(reportTitle): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             subject = reportTitle + ': ' + subject | 
					
						
							| 
									
										
										
										
											2019-08-11 11:33:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-11 13:02:36 +00:00
										 |  |  |     # create the list of moderators from the moderators file | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     moderatorsList = [] | 
					
						
							|  |  |  |     moderatorsFile = baseDir + '/accounts/moderators.txt' | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |     if os.path.isfile(moderatorsFile): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         with open(moderatorsFile, "r") as fileHandler: | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |             for line in fileHandler: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                 line = line.strip('\n').strip('\r') | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |                 if line.startswith('#'): | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 if line.startswith('/users/'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     line = line.replace('users', '') | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |                 if line.startswith('@'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     line = line[1:] | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |                 if '@' in line: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     moderatorActor = httpPrefix + '://' + domainFull + \ | 
					
						
							|  |  |  |                         '/users/' + line.split('@')[0] | 
					
						
							|  |  |  |                     if moderatorActor not in moderatorsList: | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |                         moderatorsList.append(moderatorActor) | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 if line.startswith('http') or line.startswith('dat'): | 
					
						
							|  |  |  |                     # must be a local address - no remote moderators | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     if '://' + domainFull + '/' in line: | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |                         if line not in moderatorsList: | 
					
						
							|  |  |  |                             moderatorsList.append(line) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     if '/' not in line: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         moderatorActor = httpPrefix + '://' + domainFull + \ | 
					
						
							|  |  |  |                             '/users/' + line | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |                         if moderatorActor not in moderatorsList: | 
					
						
							|  |  |  |                             moderatorsList.append(moderatorActor) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if len(moderatorsList) == 0: | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |         # if there are no moderators then the admin becomes the moderator | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         adminNickname = getConfigParam(baseDir, 'admin') | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |         if adminNickname: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             moderatorsList.append(httpPrefix + '://' + domainFull + | 
					
						
							|  |  |  |                                   '/users/' + adminNickname) | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  |     if not moderatorsList: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: Sending report to moderators') | 
					
						
							|  |  |  |         print(str(moderatorsList)) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postTo = moderatorsList | 
					
						
							|  |  |  |     postCc = None | 
					
						
							|  |  |  |     postJsonObject = None | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |     for toUrl in postTo: | 
					
						
							| 
									
										
										
										
											2019-11-16 22:09:54 +00:00
										 |  |  |         # who is this report going to? | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         toNickname = toUrl.split('/users/')[1] | 
					
						
							|  |  |  |         handle = toNickname + '@' + domain | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         postJsonObject = \ | 
					
						
							|  |  |  |             createPostBase(baseDir, nickname, domain, port, | 
					
						
							|  |  |  |                            toUrl, postCc, | 
					
						
							|  |  |  |                            httpPrefix, content, followersOnly, saveToFile, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                            clientToServer, commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                            attachImageFilename, mediaType, | 
					
						
							|  |  |  |                            imageDescription, useBlurhash, | 
					
						
							|  |  |  |                            True, False, None, None, subject, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                            False, None, None, None, None, None, | 
					
						
							|  |  |  |                            None, None, None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                            None, None, None, None, None) | 
					
						
							| 
									
										
										
										
											2019-11-16 15:24:07 +00:00
										 |  |  |         if not postJsonObject: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2019-11-16 18:14:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-16 18:11:30 +00:00
										 |  |  |         # update the inbox index with the report filename | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |         # indexFilename = baseDir+'/accounts/'+handle+'/inbox.index' | 
					
						
							|  |  |  |         # indexEntry = \ | 
					
						
							|  |  |  |         #     removeIdEnding(postJsonObject['id']).replace('/','#') + '.json' | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         # if indexEntry not in open(indexFilename).read(): | 
					
						
							|  |  |  |         #     try: | 
					
						
							|  |  |  |         #         with open(indexFilename, 'a+') as fp: | 
					
						
							|  |  |  |         #             fp.write(indexEntry) | 
					
						
							|  |  |  |         #     except: | 
					
						
							|  |  |  |         #         pass | 
					
						
							| 
									
										
										
										
											2019-11-16 18:11:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-16 15:24:07 +00:00
										 |  |  |         # save a notification file so that the moderator | 
					
						
							|  |  |  |         # knows something new has appeared | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         newReportFile = baseDir + '/accounts/' + handle + '/.newReport' | 
					
						
							| 
									
										
										
										
											2019-11-16 15:24:07 +00:00
										 |  |  |         if os.path.isfile(newReportFile): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2020-07-12 20:04:58 +00:00
										 |  |  |             with open(newReportFile, 'w+') as fp: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 fp.write(toUrl + '/moderation') | 
					
						
							|  |  |  |         except BaseException: | 
					
						
							| 
									
										
										
										
											2019-11-16 15:24:07 +00:00
										 |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-11 18:32:29 +00:00
										 |  |  |     return postJsonObject | 
					
						
							| 
									
										
										
										
											2019-08-11 11:25:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def threadSendPost(session, postJsonStr: str, federationList: [], | 
					
						
							|  |  |  |                    inboxUrl: str, baseDir: str, | 
					
						
							|  |  |  |                    signatureHeaderJson: {}, postLog: [], | 
					
						
							|  |  |  |                    debug: bool) -> None: | 
					
						
							| 
									
										
										
										
											2019-10-23 18:28:04 +00:00
										 |  |  |     """Sends a with retries
 | 
					
						
							| 
									
										
										
										
											2019-06-30 13:38:01 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     tries = 0 | 
					
						
							|  |  |  |     sendIntervalSec = 30 | 
					
						
							| 
									
										
										
										
											2019-06-30 13:38:01 +00:00
										 |  |  |     for attempt in range(20): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postResult = None | 
					
						
							|  |  |  |         unauthorized = False | 
					
						
							| 
									
										
										
										
											2019-10-14 21:05:14 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             postResult, unauthorized = \ | 
					
						
							|  |  |  |                 postJsonString(session, postJsonStr, federationList, | 
					
						
							|  |  |  |                                inboxUrl, signatureHeaderJson, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                                debug) | 
					
						
							| 
									
										
										
										
											2019-10-14 21:05:14 +00:00
										 |  |  |         except Exception as e: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('ERROR: postJsonString failed ' + str(e)) | 
					
						
							|  |  |  |         if unauthorized: | 
					
						
							| 
									
										
										
										
											2019-10-23 18:44:03 +00:00
										 |  |  |             print(postJsonStr) | 
					
						
							|  |  |  |             print('threadSendPost: Post is unauthorized') | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2019-08-21 21:05:37 +00:00
										 |  |  |         if postResult: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             logStr = 'Success on try ' + str(tries) + ': ' + postJsonStr | 
					
						
							| 
									
										
										
										
											2019-08-21 21:05:37 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             logStr = 'Retry ' + str(tries) + ': ' + postJsonStr | 
					
						
							| 
									
										
										
										
											2019-08-21 21:05:37 +00:00
										 |  |  |         postLog.append(logStr) | 
					
						
							|  |  |  |         # keep the length of the log finite | 
					
						
							|  |  |  |         # Don't accumulate massive files on systems with limited resources | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         while len(postLog) > 16: | 
					
						
							| 
									
										
										
										
											2019-09-01 10:11:06 +00:00
										 |  |  |             postLog.pop(0) | 
					
						
							| 
									
										
										
										
											2019-10-16 11:27:43 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             # save the log file | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             postLogFilename = baseDir + '/post.log' | 
					
						
							| 
									
										
										
										
											2019-10-16 11:27:43 +00:00
										 |  |  |             with open(postLogFilename, "a+") as logFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 logFile.write(logStr + '\n') | 
					
						
							| 
									
										
										
										
											2019-08-21 21:05:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 13:38:01 +00:00
										 |  |  |         if postResult: | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print('DEBUG: successful json post to ' + inboxUrl) | 
					
						
							| 
									
										
										
										
											2019-06-30 13:38:01 +00:00
										 |  |  |             # our work here is done | 
					
						
							| 
									
										
										
										
											2019-06-30 13:20:23 +00:00
										 |  |  |             break | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2019-08-18 09:58:28 +00:00
										 |  |  |             print(postJsonStr) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: json post to ' + inboxUrl + | 
					
						
							|  |  |  |                   ' failed. Waiting for ' + | 
					
						
							|  |  |  |                   str(sendIntervalSec) + ' seconds.') | 
					
						
							| 
									
										
										
										
											2019-10-23 18:28:04 +00:00
										 |  |  |         time.sleep(sendIntervalSec) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         tries += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def sendPost(projectVersion: str, | 
					
						
							|  |  |  |              session, baseDir: str, nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |              toNickname: str, toDomain: str, toPort: int, cc: str, | 
					
						
							|  |  |  |              httpPrefix: str, content: str, followersOnly: bool, | 
					
						
							|  |  |  |              saveToFile: bool, clientToServer: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |              commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |              attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |              imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |              federationList: [], sendThreads: [], postLog: [], | 
					
						
							|  |  |  |              cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |              isArticle: bool, | 
					
						
							|  |  |  |              debug=False, inReplyTo=None, | 
					
						
							|  |  |  |              inReplyToAtomUri=None, subject=None) -> int: | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |     """Post to another inbox
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     withDigest = True | 
					
						
							| 
									
										
										
										
											2019-07-01 09:31:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if toNickname == 'inbox': | 
					
						
							| 
									
										
										
										
											2019-08-23 14:08:10 +00:00
										 |  |  |         # shared inbox actor on @domain@domain | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         toNickname = toDomain | 
					
						
							| 
									
										
										
										
											2019-08-23 14:08:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if toPort: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if toPort != 80 and toPort != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in toDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 toDomain = toDomain + ':' + str(toPort) | 
					
						
							| 
									
										
										
										
											2019-06-30 22:56:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     handle = httpPrefix + '://' + toDomain + '/@' + toNickname | 
					
						
							| 
									
										
										
										
											2019-06-30 22:56:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     wfRequest = webfingerHandle(session, handle, httpPrefix, | 
					
						
							|  |  |  |                                 cachedWebfingers, | 
					
						
							|  |  |  |                                 domain, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         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-06-30 10:14:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     if not clientToServer: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postToBox = 'inbox' | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postToBox = 'outbox' | 
					
						
							| 
									
										
										
										
											2020-02-24 22:34:54 +00:00
										 |  |  |         if isArticle: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             postToBox = 'tlblogs' | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 22:56:37 +00:00
										 |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     (inboxUrl, pubKeyId, pubKey, | 
					
						
							|  |  |  |      toPersonId, sharedInbox, | 
					
						
							|  |  |  |      avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, | 
					
						
							|  |  |  |                                             personCache, | 
					
						
							|  |  |  |                                             projectVersion, httpPrefix, | 
					
						
							|  |  |  |                                             nickname, domain, postToBox) | 
					
						
							| 
									
										
										
										
											2019-07-05 14:39:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         return 3 | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     if not pubKey: | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |         return 4 | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     if not toPersonId: | 
					
						
							|  |  |  |         return 5 | 
					
						
							| 
									
										
										
										
											2020-09-27 18:35:35 +00:00
										 |  |  |     # sharedInbox is optional | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postJsonObject = \ | 
					
						
							|  |  |  |         createPostBase(baseDir, nickname, domain, port, | 
					
						
							|  |  |  |                        toPersonId, cc, httpPrefix, content, | 
					
						
							|  |  |  |                        followersOnly, saveToFile, clientToServer, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        attachImageFilename, mediaType, | 
					
						
							|  |  |  |                        imageDescription, useBlurhash, | 
					
						
							|  |  |  |                        False, isArticle, inReplyTo, | 
					
						
							|  |  |  |                        inReplyToAtomUri, subject, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        False, None, None, None, None, None, | 
					
						
							|  |  |  |                        None, None, None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                        None, None, None, None, None) | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 22:56:37 +00:00
										 |  |  |     # get the senders private key | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private') | 
					
						
							|  |  |  |     if len(privateKeyPem) == 0: | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |         return 6 | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     if toDomain not in inboxUrl: | 
					
						
							|  |  |  |         return 7 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postPath = inboxUrl.split(toDomain, 1)[1] | 
					
						
							| 
									
										
										
										
											2019-08-17 10:15:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-15 13:38:21 +00:00
										 |  |  |     if not postJsonObject.get('signature'): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             signedPostJsonObject = jsonldSign(postJsonObject, privateKeyPem) | 
					
						
							|  |  |  |             postJsonObject = signedPostJsonObject | 
					
						
							| 
									
										
										
										
											2020-10-11 14:08:16 +00:00
										 |  |  |         except Exception as e: | 
					
						
							|  |  |  |             print('WARN: failed to JSON-LD sign post, ' + str(e)) | 
					
						
							| 
									
										
										
										
											2020-06-15 13:38:21 +00:00
										 |  |  |             pass | 
					
						
							| 
									
										
										
										
											2020-06-15 13:08:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 10:15:01 +00:00
										 |  |  |     # convert json to string so that there are no | 
					
						
							|  |  |  |     # subsequent conversions after creating message body digest | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postJsonStr = json.dumps(postJsonObject) | 
					
						
							| 
									
										
										
										
											2019-08-17 10:15:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # construct the http header, including the message body digest | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     signatureHeaderJson = \ | 
					
						
							|  |  |  |         createSignedHeader(privateKeyPem, nickname, domain, port, | 
					
						
							|  |  |  |                            toDomain, toPort, | 
					
						
							|  |  |  |                            postPath, httpPrefix, withDigest, postJsonStr) | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Keep the number of threads being used small | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     while len(sendThreads) > 1000: | 
					
						
							| 
									
										
										
										
											2019-10-16 14:46:29 +00:00
										 |  |  |         print('WARN: Maximum threads reached - killing send thread') | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  |         sendThreads[0].kill() | 
					
						
							|  |  |  |         sendThreads.pop(0) | 
					
						
							| 
									
										
										
										
											2019-10-16 14:46:29 +00:00
										 |  |  |         print('WARN: thread killed') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     thr = \ | 
					
						
							|  |  |  |         threadWithTrace(target=threadSendPost, | 
					
						
							|  |  |  |                         args=(session, | 
					
						
							|  |  |  |                               postJsonStr, | 
					
						
							|  |  |  |                               federationList, | 
					
						
							|  |  |  |                               inboxUrl, baseDir, | 
					
						
							|  |  |  |                               signatureHeaderJson.copy(), | 
					
						
							| 
									
										
										
										
											2019-12-12 09:58:06 +00:00
										 |  |  |                               postLog, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                               debug), daemon=True) | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  |     sendThreads.append(thr) | 
					
						
							|  |  |  |     thr.start() | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def sendPostViaServer(projectVersion: str, | 
					
						
							|  |  |  |                       baseDir: str, session, fromNickname: str, password: str, | 
					
						
							|  |  |  |                       fromDomain: str, fromPort: int, | 
					
						
							|  |  |  |                       toNickname: str, toDomain: str, toPort: int, cc: str, | 
					
						
							|  |  |  |                       httpPrefix: str, content: str, followersOnly: bool, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                       commentsEnabled: bool, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                       attachImageFilename: str, mediaType: str, | 
					
						
							|  |  |  |                       imageDescription: str, useBlurhash: bool, | 
					
						
							|  |  |  |                       cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                       isArticle: bool, debug=False, inReplyTo=None, | 
					
						
							|  |  |  |                       inReplyToAtomUri=None, subject=None) -> int: | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |     """Send a post via a proxy (c2s)
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-07-16 11:33:40 +00:00
										 |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendPostViaServer') | 
					
						
							|  |  |  |         return 6 | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if toPort: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if toPort != 80 and toPort != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in fromDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 fromDomain = fromDomain + ':' + str(fromPort) | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     handle = httpPrefix + '://' + fromDomain + '/@' + fromNickname | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     wfRequest = \ | 
					
						
							|  |  |  |         webfingerHandle(session, handle, httpPrefix, cachedWebfingers, | 
					
						
							|  |  |  |                         fromDomain, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: webfinger failed for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +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 10:19:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postToBox = 'outbox' | 
					
						
							| 
									
										
										
										
											2020-02-24 22:34:54 +00:00
										 |  |  |     if isArticle: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postToBox = 'tlblogs' | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     (inboxUrl, pubKeyId, pubKey, | 
					
						
							|  |  |  |      fromPersonId, sharedInbox, | 
					
						
							|  |  |  |      avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, | 
					
						
							|  |  |  |                                             personCache, | 
					
						
							|  |  |  |                                             projectVersion, httpPrefix, | 
					
						
							|  |  |  |                                             fromNickname, | 
					
						
							|  |  |  |                                             fromDomain, postToBox) | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: No ' + postToBox + ' was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |         return 3 | 
					
						
							|  |  |  |     if not fromPersonId: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: No actor was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |         return 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Get the json for the c2s post, not saving anything to file | 
					
						
							|  |  |  |     # Note that baseDir is set to None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     saveToFile = False | 
					
						
							|  |  |  |     clientToServer = True | 
					
						
							| 
									
										
										
										
											2019-07-17 14:43:51 +00:00
										 |  |  |     if toDomain.lower().endswith('public'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         toPersonId = 'https://www.w3.org/ns/activitystreams#Public' | 
					
						
							|  |  |  |         fromDomainFull = fromDomain | 
					
						
							| 
									
										
										
										
											2019-07-17 14:43:51 +00:00
										 |  |  |         if fromPort: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             if fromPort != 80 and fromPort != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |                 if ':' not in fromDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     fromDomainFull = fromDomain + ':' + str(fromPort) | 
					
						
							|  |  |  |         cc = httpPrefix + '://' + fromDomainFull + '/users/' + \ | 
					
						
							|  |  |  |             fromNickname + '/followers' | 
					
						
							| 
									
										
										
										
											2019-07-17 14:43:51 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if toDomain.lower().endswith('followers') or \ | 
					
						
							|  |  |  |            toDomain.lower().endswith('followersonly'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             toPersonId = \ | 
					
						
							|  |  |  |                 httpPrefix + '://' + \ | 
					
						
							|  |  |  |                 fromDomainFull + '/users/' + fromNickname + '/followers' | 
					
						
							| 
									
										
										
										
											2019-07-17 14:43:51 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             toDomainFull = toDomain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if toPort: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 if toPort != 80 and toPort != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |                     if ':' not in toDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         toDomainFull = toDomain + ':' + str(toPort) | 
					
						
							|  |  |  |             toPersonId = httpPrefix + '://' + toDomainFull + \ | 
					
						
							|  |  |  |                 '/users/' + toNickname | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     postJsonObject = \ | 
					
						
							|  |  |  |         createPostBase(baseDir, | 
					
						
							|  |  |  |                        fromNickname, fromDomain, fromPort, | 
					
						
							|  |  |  |                        toPersonId, cc, httpPrefix, content, | 
					
						
							|  |  |  |                        followersOnly, saveToFile, clientToServer, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        commentsEnabled, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        attachImageFilename, mediaType, | 
					
						
							|  |  |  |                        imageDescription, useBlurhash, | 
					
						
							|  |  |  |                        False, isArticle, inReplyTo, | 
					
						
							|  |  |  |                        inReplyToAtomUri, subject, | 
					
						
							| 
									
										
										
										
											2020-08-21 16:10:47 +00:00
										 |  |  |                        False, None, None, None, None, None, | 
					
						
							|  |  |  |                        None, None, None, | 
					
						
							| 
									
										
										
										
											2020-08-23 17:50:49 +00:00
										 |  |  |                        None, None, None, None, None) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     authHeader = createBasicAuthHeader(fromNickname, password) | 
					
						
							| 
									
										
										
										
											2019-07-16 14:23:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if attachImageFilename: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         headers = { | 
					
						
							|  |  |  |             'host': fromDomain, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |             'Authorization': authHeader | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postResult = \ | 
					
						
							|  |  |  |             postImage(session, attachImageFilename, [], | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                       inboxUrl, headers) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if not postResult: | 
					
						
							|  |  |  |             if debug: | 
					
						
							|  |  |  |                 print('DEBUG: Failed to upload image') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:08:37 +00:00
										 |  |  | #            return 9 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     headers = { | 
					
						
							|  |  |  |         'host': fromDomain, | 
					
						
							|  |  |  |         'Content-type': 'application/json', | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'Authorization': authHeader | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postResult = \ | 
					
						
							|  |  |  |         postJsonString(session, json.dumps(postJsonObject), [], | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                        inboxUrl, headers, debug) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if not postResult: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: POST failed for c2s to '+inboxUrl) | 
					
						
							|  |  |  |         return 5 | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST success') | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def groupFollowersByDomain(baseDir: str, nickname: str, domain: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-08 08:51:33 +00:00
										 |  |  |     """Returns a dictionary with followers grouped by domain
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							|  |  |  |     followersFilename = baseDir + '/accounts/' + handle + '/followers.txt' | 
					
						
							| 
									
										
										
										
											2019-07-08 08:51:33 +00:00
										 |  |  |     if not os.path.isfile(followersFilename): | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     grouped = {} | 
					
						
							| 
									
										
										
										
											2019-07-08 08:51:33 +00:00
										 |  |  |     with open(followersFilename, "r") as f: | 
					
						
							|  |  |  |         for followerHandle in f: | 
					
						
							|  |  |  |             if '@' in followerHandle: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                 fHandle = \ | 
					
						
							|  |  |  |                     followerHandle.strip().replace('\n', '').replace('\r', '') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 followerDomain = fHandle.split('@')[1] | 
					
						
							| 
									
										
										
										
											2019-07-08 08:51:33 +00:00
										 |  |  |                 if not grouped.get(followerDomain): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     grouped[followerDomain] = [fHandle] | 
					
						
							| 
									
										
										
										
											2019-07-08 08:51:33 +00:00
										 |  |  |                 else: | 
					
						
							|  |  |  |                     grouped[followerDomain].append(fHandle) | 
					
						
							|  |  |  |     return grouped | 
					
						
							| 
									
										
										
										
											2019-10-16 10:58:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-16 10:58:31 +00:00
										 |  |  | def addFollowersToPublicPost(postJsonObject: {}) -> None: | 
					
						
							|  |  |  |     """Adds followers entry to cc if it doesn't exist
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not postJsonObject.get('actor'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if isinstance(postJsonObject['object'], str): | 
					
						
							|  |  |  |         if not postJsonObject.get('to'): | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if len(postJsonObject['to']) > 1: | 
					
						
							| 
									
										
										
										
											2019-10-16 10:58:31 +00:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if len(postJsonObject['to']) == 0: | 
					
						
							| 
									
										
										
										
											2019-10-16 10:58:31 +00:00
										 |  |  |             return | 
					
						
							|  |  |  |         if not postJsonObject['to'][0].endswith('#Public'): | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         if postJsonObject.get('cc'): | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postJsonObject['cc'] = postJsonObject['actor'] + '/followers' | 
					
						
							| 
									
										
										
										
											2019-10-16 10:58:31 +00:00
										 |  |  |     elif isinstance(postJsonObject['object'], dict): | 
					
						
							|  |  |  |         if not postJsonObject['object'].get('to'): | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if len(postJsonObject['object']['to']) > 1: | 
					
						
							| 
									
										
										
										
											2019-10-16 10:58:31 +00:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if len(postJsonObject['object']['to']) == 0: | 
					
						
							| 
									
										
										
										
											2019-10-16 10:58:31 +00:00
										 |  |  |             return | 
					
						
							|  |  |  |         if not postJsonObject['object']['to'][0].endswith('#Public'): | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         if postJsonObject['object'].get('cc'): | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postJsonObject['object']['cc'] = postJsonObject['actor'] + '/followers' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def sendSignedJson(postJsonObject: {}, session, baseDir: str, | 
					
						
							|  |  |  |                    nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                    toNickname: str, toDomain: str, toPort: int, cc: str, | 
					
						
							|  |  |  |                    httpPrefix: str, saveToFile: bool, clientToServer: bool, | 
					
						
							|  |  |  |                    federationList: [], | 
					
						
							|  |  |  |                    sendThreads: [], postLog: [], cachedWebfingers: {}, | 
					
						
							|  |  |  |                    personCache: {}, debug: bool, projectVersion: str) -> int: | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  |     """Sends a signed json object to an inbox/outbox
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: sendSignedJson start') | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session specified for sendSignedJson') | 
					
						
							|  |  |  |         return 8 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     withDigest = True | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-19 22:50:41 +00:00
										 |  |  |     if toDomain.endswith('.onion') or toDomain.endswith('.i2p'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         httpPrefix = 'http' | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | #    sharedInbox = False | 
					
						
							|  |  |  |     if toNickname == 'inbox': | 
					
						
							| 
									
										
										
										
											2019-08-23 13:47:29 +00:00
										 |  |  |         # shared inbox actor on @domain@domain | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         toNickname = toDomain | 
					
						
							|  |  |  | #        sharedInbox = True | 
					
						
							| 
									
										
										
										
											2019-08-16 20:04:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if toPort: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if toPort != 80 and toPort != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:04:24 +00:00
										 |  |  |             if ':' not in toDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 toDomain = toDomain + ':' + str(toPort) | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-23 09:46:38 +00:00
										 |  |  |     toDomainUrl = httpPrefix + '://' + toDomain | 
					
						
							|  |  |  |     if not siteIsActive(toDomainUrl): | 
					
						
							|  |  |  |         print('Domain is inactive: ' + toDomainUrl) | 
					
						
							|  |  |  |         return 9 | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:12 +00:00
										 |  |  |     print('Domain is active: ' + toDomainUrl) | 
					
						
							| 
									
										
										
										
											2020-06-23 09:46:38 +00:00
										 |  |  |     handleBase = toDomainUrl + '/@' | 
					
						
							| 
									
										
										
										
											2019-10-21 14:12:22 +00:00
										 |  |  |     if toNickname: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         handle = handleBase + toNickname | 
					
						
							| 
									
										
										
										
											2019-10-21 14:12:22 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         singleUserInstanceNickname = 'dev' | 
					
						
							| 
									
										
										
										
											2020-05-17 12:16:40 +00:00
										 |  |  |         handle = handleBase + singleUserInstanceNickname | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         print('DEBUG: handle - ' + handle + ' toPort ' + str(toPort)) | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-23 13:47:29 +00:00
										 |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     wfRequest = webfingerHandle(session, handle, httpPrefix, cachedWebfingers, | 
					
						
							|  |  |  |                                 domain, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-08-23 13:47:29 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: webfinger for ' + handle + ' failed') | 
					
						
							| 
									
										
										
										
											2019-08-23 13:47:29 +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-05 18:57:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-17 14:41:47 +00:00
										 |  |  |     if wfRequest.get('errors'): | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: webfinger for ' + handle + | 
					
						
							|  |  |  |                   ' failed with errors ' + str(wfRequest['errors'])) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     if not clientToServer: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postToBox = 'inbox' | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postToBox = 'outbox' | 
					
						
							| 
									
										
										
										
											2019-08-22 20:26:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 18:35:35 +00:00
										 |  |  |     # get the actor inbox/outbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |     (inboxUrl, pubKeyId, pubKey, toPersonId, sharedInboxUrl, avatarUrl, | 
					
						
							| 
									
										
										
										
											2020-05-17 12:16:40 +00:00
										 |  |  |      displayName) = getPersonBox(baseDir, session, wfRequest, | 
					
						
							|  |  |  |                                  personCache, | 
					
						
							|  |  |  |                                  projectVersion, httpPrefix, | 
					
						
							|  |  |  |                                  nickname, domain, postToBox) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 18:35:35 +00:00
										 |  |  |     print("inboxUrl: " + str(inboxUrl)) | 
					
						
							|  |  |  |     print("toPersonId: " + str(toPersonId)) | 
					
						
							|  |  |  |     print("sharedInboxUrl: " + str(sharedInboxUrl)) | 
					
						
							|  |  |  |     if inboxUrl: | 
					
						
							|  |  |  |         if inboxUrl.endswith('/actor/inbox'): | 
					
						
							|  |  |  |             inboxUrl = sharedInboxUrl | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  |     if not inboxUrl: | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: missing inboxUrl') | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  |         return 3 | 
					
						
							| 
									
										
										
										
											2019-08-04 21:26:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         print('DEBUG: Sending to endpoint ' + inboxUrl) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     if not pubKey: | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: missing pubkey') | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  |         return 4 | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     if not toPersonId: | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: missing personId') | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |         return 5 | 
					
						
							| 
									
										
										
										
											2020-09-27 18:35:35 +00:00
										 |  |  |     # sharedInbox is optional | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the senders private key | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private', debug) | 
					
						
							|  |  |  |     if len(privateKeyPem) == 0: | 
					
						
							| 
									
										
										
										
											2019-07-06 13:49:25 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: Private key not found for ' + | 
					
						
							|  |  |  |                   nickname + '@' + domain + ' in ' + baseDir + '/keys/private') | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |         return 6 | 
					
						
							| 
									
										
										
										
											2019-07-05 18:57:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |     if toDomain not in inboxUrl: | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: ' + toDomain + ' is not in ' + inboxUrl) | 
					
						
							| 
									
										
										
										
											2019-07-05 22:13:20 +00:00
										 |  |  |         return 7 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postPath = inboxUrl.split(toDomain, 1)[1] | 
					
						
							| 
									
										
										
										
											2019-08-17 10:15:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-16 10:58:31 +00:00
										 |  |  |     addFollowersToPublicPost(postJsonObject) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-15 13:38:21 +00:00
										 |  |  |     if not postJsonObject.get('signature'): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             signedPostJsonObject = jsonldSign(postJsonObject, privateKeyPem) | 
					
						
							|  |  |  |             postJsonObject = signedPostJsonObject | 
					
						
							| 
									
										
										
										
											2020-10-11 14:08:16 +00:00
										 |  |  |         except Exception as e: | 
					
						
							|  |  |  |             print('WARN: failed to JSON-LD sign post, ' + str(e)) | 
					
						
							| 
									
										
										
										
											2020-06-15 13:38:21 +00:00
										 |  |  |             pass | 
					
						
							| 
									
										
										
										
											2020-06-15 13:08:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 10:15:01 +00:00
										 |  |  |     # convert json to string so that there are no | 
					
						
							|  |  |  |     # subsequent conversions after creating message body digest | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postJsonStr = json.dumps(postJsonObject) | 
					
						
							| 
									
										
										
										
											2019-08-17 10:15:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # construct the http header, including the message body digest | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     signatureHeaderJson = \ | 
					
						
							|  |  |  |         createSignedHeader(privateKeyPem, nickname, domain, port, | 
					
						
							|  |  |  |                            toDomain, toPort, | 
					
						
							|  |  |  |                            postPath, httpPrefix, withDigest, postJsonStr) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 13:20:23 +00:00
										 |  |  |     # Keep the number of threads being used small | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     while len(sendThreads) > 1000: | 
					
						
							| 
									
										
										
										
											2019-10-04 12:22:56 +00:00
										 |  |  |         print('WARN: Maximum threads reached - killing send thread') | 
					
						
							| 
									
										
										
										
											2019-06-30 15:03:26 +00:00
										 |  |  |         sendThreads[0].kill() | 
					
						
							| 
									
										
										
										
											2019-06-30 13:38:01 +00:00
										 |  |  |         sendThreads.pop(0) | 
					
						
							| 
									
										
										
										
											2019-10-04 12:22:56 +00:00
										 |  |  |         print('WARN: thread killed') | 
					
						
							| 
									
										
										
										
											2019-10-16 18:19:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: starting thread to send post') | 
					
						
							| 
									
										
										
										
											2019-07-18 11:35:48 +00:00
										 |  |  |         pprint(postJsonObject) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     thr = \ | 
					
						
							|  |  |  |         threadWithTrace(target=threadSendPost, | 
					
						
							|  |  |  |                         args=(session, | 
					
						
							|  |  |  |                               postJsonStr, | 
					
						
							|  |  |  |                               federationList, | 
					
						
							|  |  |  |                               inboxUrl, baseDir, | 
					
						
							|  |  |  |                               signatureHeaderJson.copy(), | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |                               postLog, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                               debug), daemon=True) | 
					
						
							| 
									
										
										
										
											2019-06-30 13:20:23 +00:00
										 |  |  |     sendThreads.append(thr) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     # thr.start() | 
					
						
							| 
									
										
										
										
											2019-06-30 10:14:02 +00:00
										 |  |  |     return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def addToField(activityType: str, postJsonObject: {}, | 
					
						
							|  |  |  |                debug: bool) -> ({}, bool): | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |     """The Follow activity doesn't have a 'to' field and so one
 | 
					
						
							|  |  |  |     needs to be added so that activity distribution happens in a consistent way | 
					
						
							|  |  |  |     Returns true if a 'to' field exists or was added | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if postJsonObject.get('to'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         return postJsonObject, True | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |     if debug: | 
					
						
							|  |  |  |         pprint(postJsonObject) | 
					
						
							|  |  |  |         print('DEBUG: no "to" field when sending to named addresses 2') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     isSameType = False | 
					
						
							|  |  |  |     toFieldAdded = False | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |     if postJsonObject.get('object'): | 
					
						
							|  |  |  |         if isinstance(postJsonObject['object'], str): | 
					
						
							|  |  |  |             if postJsonObject.get('type'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 if postJsonObject['type'] == activityType: | 
					
						
							|  |  |  |                     isSameType = True | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |                     if debug: | 
					
						
							|  |  |  |                         print('DEBUG: "to" field assigned to Follow') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     toAddress = postJsonObject['object'] | 
					
						
							| 
									
										
										
										
											2019-08-18 16:49:35 +00:00
										 |  |  |                     if '/statuses/' in toAddress: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         toAddress = toAddress.split('/statuses/')[0] | 
					
						
							|  |  |  |                     postJsonObject['to'] = [toAddress] | 
					
						
							|  |  |  |                     toFieldAdded = True | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |         elif isinstance(postJsonObject['object'], dict): | 
					
						
							|  |  |  |             if postJsonObject['object'].get('type'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 if postJsonObject['object']['type'] == activityType: | 
					
						
							|  |  |  |                     isSameType = True | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |                     if isinstance(postJsonObject['object']['object'], str): | 
					
						
							|  |  |  |                         if debug: | 
					
						
							|  |  |  |                             print('DEBUG: "to" field assigned to Follow') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         toAddress = postJsonObject['object']['object'] | 
					
						
							| 
									
										
										
										
											2019-08-18 16:49:35 +00:00
										 |  |  |                         if '/statuses/' in toAddress: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             toAddress = toAddress.split('/statuses/')[0] | 
					
						
							|  |  |  |                         postJsonObject['object']['to'] = [toAddress] | 
					
						
							|  |  |  |                         postJsonObject['to'] = \ | 
					
						
							| 
									
										
										
										
											2019-12-12 09:58:06 +00:00
										 |  |  |                             [postJsonObject['object']['object']] | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         toFieldAdded = True | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not isSameType: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         return postJsonObject, True | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |     if toFieldAdded: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         return postJsonObject, True | 
					
						
							|  |  |  |     return postJsonObject, False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def sendToNamedAddresses(session, baseDir: str, | 
					
						
							| 
									
										
										
										
											2020-07-11 22:36:52 +00:00
										 |  |  |                          nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |                          onionDomain: str, i2pDomain: str, port: int, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                          httpPrefix: str, federationList: [], | 
					
						
							|  |  |  |                          sendThreads: [], postLog: [], | 
					
						
							|  |  |  |                          cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                          postJsonObject: {}, debug: bool, | 
					
						
							| 
									
										
										
										
											2019-08-14 20:12:27 +00:00
										 |  |  |                          projectVersion: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  |     """sends a post to the specific named addresses in to/cc
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendToNamedAddresses') | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  |     if not postJsonObject.get('object'): | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-08-20 20:35:15 +00:00
										 |  |  |     if isinstance(postJsonObject['object'], dict): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         isProfileUpdate = False | 
					
						
							| 
									
										
										
										
											2019-08-20 20:35:15 +00:00
										 |  |  |         # for actor updates there is no 'to' within the object | 
					
						
							|  |  |  |         if postJsonObject['object'].get('type') and postJsonObject.get('type'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             if (postJsonObject['type'] == 'Update' and | 
					
						
							|  |  |  |                 (postJsonObject['object']['type'] == 'Person' or | 
					
						
							|  |  |  |                  postJsonObject['object']['type'] == 'Application' or | 
					
						
							|  |  |  |                  postJsonObject['object']['type'] == 'Group' or | 
					
						
							|  |  |  |                  postJsonObject['object']['type'] == 'Service')): | 
					
						
							| 
									
										
										
										
											2019-08-20 20:35:15 +00:00
										 |  |  |                 # use the original object, which has a 'to' | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 recipientsObject = postJsonObject | 
					
						
							|  |  |  |                 isProfileUpdate = True | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-20 20:35:15 +00:00
										 |  |  |         if not isProfileUpdate: | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |             if not postJsonObject['object'].get('to'): | 
					
						
							| 
									
										
										
										
											2019-08-20 20:35:15 +00:00
										 |  |  |                 if debug: | 
					
						
							|  |  |  |                     pprint(postJsonObject) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     print('DEBUG: ' + | 
					
						
							|  |  |  |                           'no "to" field when sending to named addresses') | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |                 if postJsonObject['object'].get('type'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     if postJsonObject['object']['type'] == 'Follow': | 
					
						
							| 
									
										
										
										
											2019-08-20 20:35:15 +00:00
										 |  |  |                         if isinstance(postJsonObject['object']['object'], str): | 
					
						
							|  |  |  |                             if debug: | 
					
						
							|  |  |  |                                 print('DEBUG: "to" field assigned to Follow') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             postJsonObject['object']['to'] = \ | 
					
						
							| 
									
										
										
										
											2019-12-12 09:58:06 +00:00
										 |  |  |                                 [postJsonObject['object']['object']] | 
					
						
							| 
									
										
										
										
											2019-08-20 20:35:15 +00:00
										 |  |  |                 if not postJsonObject['object'].get('to'): | 
					
						
							|  |  |  |                     return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             recipientsObject = postJsonObject['object'] | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postJsonObject, fieldAdded = \ | 
					
						
							|  |  |  |             addToField('Follow', postJsonObject, debug) | 
					
						
							| 
									
										
										
										
											2019-08-18 16:49:35 +00:00
										 |  |  |         if not fieldAdded: | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postJsonObject, fieldAdded = addToField('Like', postJsonObject, debug) | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |         if not fieldAdded: | 
					
						
							| 
									
										
										
										
											2019-07-16 19:07:45 +00:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         recipientsObject = postJsonObject | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     recipients = [] | 
					
						
							|  |  |  |     recipientType = ('to', 'cc') | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  |     for rType in recipientType: | 
					
						
							| 
									
										
										
										
											2019-08-18 09:39:12 +00:00
										 |  |  |         if not recipientsObject.get(rType): | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2019-08-18 20:54:33 +00:00
										 |  |  |         if isinstance(recipientsObject[rType], list): | 
					
						
							| 
									
										
										
										
											2019-08-18 21:08:38 +00:00
										 |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2019-08-19 08:58:04 +00:00
										 |  |  |                 pprint(recipientsObject) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print('recipientsObject: ' + str(recipientsObject[rType])) | 
					
						
							| 
									
										
										
										
											2019-08-18 20:54:33 +00:00
										 |  |  |             for address in recipientsObject[rType]: | 
					
						
							| 
									
										
										
										
											2019-08-18 21:15:09 +00:00
										 |  |  |                 if not address: | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2019-08-18 21:12:37 +00:00
										 |  |  |                 if '/' not in address: | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2019-08-18 20:54:33 +00:00
										 |  |  |                 if address.endswith('#Public'): | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 if address.endswith('/followers'): | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 recipients.append(address) | 
					
						
							|  |  |  |         elif isinstance(recipientsObject[rType], str): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             address = recipientsObject[rType] | 
					
						
							| 
									
										
										
										
											2019-08-18 21:15:09 +00:00
										 |  |  |             if address: | 
					
						
							|  |  |  |                 if '/' in address: | 
					
						
							|  |  |  |                     if address.endswith('#Public'): | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     if address.endswith('/followers'): | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     recipients.append(address) | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  |     if not recipients: | 
					
						
							| 
									
										
										
										
											2019-08-18 20:54:33 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: no individual recipients') | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-07-15 18:29:30 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         print('DEBUG: Sending individually addressed posts: ' + | 
					
						
							|  |  |  |               str(recipients)) | 
					
						
							| 
									
										
										
										
											2019-07-15 18:29:30 +00:00
										 |  |  |     # this is after the message has arrived at the server | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     clientToServer = False | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  |     for address in recipients: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         toNickname = getNicknameFromActor(address) | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  |         if not toNickname: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         toDomain, toPort = getDomainFromActor(address) | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  |         if not toDomain: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2019-07-15 18:29:30 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             domainFull = domain | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |             if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |                     if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         domainFull = domain + ':' + str(port) | 
					
						
							|  |  |  |             toDomainFull = toDomain | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |             if toPort: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 if toPort != 80 and toPort != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |                     if ':' not in toDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         toDomainFull = toDomain + ':' + str(toPort) | 
					
						
							|  |  |  |             print('DEBUG: Post sending s2s: ' + nickname + '@' + domainFull + | 
					
						
							|  |  |  |                   ' to ' + toNickname + '@' + toDomainFull) | 
					
						
							| 
									
										
										
										
											2020-03-02 16:11:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # if we have an alt onion domain and we are sending to | 
					
						
							|  |  |  |         # another onion domain then switch the clearnet | 
					
						
							|  |  |  |         # domain for the onion one | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         fromDomain = domain | 
					
						
							|  |  |  |         fromHttpPrefix = httpPrefix | 
					
						
							| 
									
										
										
										
											2020-03-02 16:11:34 +00:00
										 |  |  |         if onionDomain: | 
					
						
							|  |  |  |             if toDomain.endswith('.onion'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 fromDomain = onionDomain | 
					
						
							|  |  |  |                 fromHttpPrefix = 'http' | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |         elif i2pDomain: | 
					
						
							|  |  |  |             if toDomain.endswith('.i2p'): | 
					
						
							|  |  |  |                 fromDomain = i2pDomain | 
					
						
							| 
									
										
										
										
											2020-06-19 22:50:41 +00:00
										 |  |  |                 fromHttpPrefix = 'http' | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         cc = [] | 
					
						
							|  |  |  |         sendSignedJson(postJsonObject, session, baseDir, | 
					
						
							|  |  |  |                        nickname, fromDomain, port, | 
					
						
							|  |  |  |                        toNickname, toDomain, toPort, | 
					
						
							|  |  |  |                        cc, fromHttpPrefix, True, clientToServer, | 
					
						
							|  |  |  |                        federationList, | 
					
						
							|  |  |  |                        sendThreads, postLog, cachedWebfingers, | 
					
						
							|  |  |  |                        personCache, debug, projectVersion) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def hasSharedInbox(session, httpPrefix: str, domain: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  |     """Returns true if the given domain has a shared inbox
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     wfRequest = webfingerHandle(session, domain + '@' + domain, | 
					
						
							|  |  |  |                                 httpPrefix, {}, | 
					
						
							|  |  |  |                                 None, __version__) | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  |     if wfRequest: | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:12 +00:00
										 |  |  |         if isinstance(wfRequest, dict): | 
					
						
							|  |  |  |             if not wfRequest.get('errors'): | 
					
						
							|  |  |  |                 return True | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  |     return False | 
					
						
							| 
									
										
										
										
											2019-11-04 10:43:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def sendToFollowers(session, baseDir: str, | 
					
						
							|  |  |  |                     nickname: str, | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |                     domain: str, | 
					
						
							|  |  |  |                     onionDomain: str, i2pDomain: str, port: int, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     httpPrefix: str, federationList: [], | 
					
						
							|  |  |  |                     sendThreads: [], postLog: [], | 
					
						
							|  |  |  |                     cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                     postJsonObject: {}, debug: bool, | 
					
						
							| 
									
										
										
										
											2019-08-14 20:12:27 +00:00
										 |  |  |                     projectVersion: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  |     """sends a post to the followers of the given nickname
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-08-20 21:04:24 +00:00
										 |  |  |     print('sendToFollowers') | 
					
						
							| 
									
										
										
										
											2019-07-16 10:19:04 +00:00
										 |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendToFollowers') | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if not postIsAddressedToFollowers(baseDir, nickname, domain, | 
					
						
							|  |  |  |                                       port, httpPrefix, | 
					
						
							|  |  |  |                                       postJsonObject): | 
					
						
							| 
									
										
										
										
											2019-07-15 18:29:30 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('Post is not addressed to followers') | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-08-20 21:04:24 +00:00
										 |  |  |     print('Post is addressed to followers') | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     grouped = groupFollowersByDomain(baseDir, nickname, domain) | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  |     if not grouped: | 
					
						
							| 
									
										
										
										
											2019-07-15 18:29:30 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('Post to followers did not resolve any domains') | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-08-20 21:04:24 +00:00
										 |  |  |     print('Post to followers resolved domains') | 
					
						
							| 
									
										
										
										
											2019-08-26 13:34:41 +00:00
										 |  |  |     print(str(grouped)) | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-15 18:29:30 +00:00
										 |  |  |     # this is after the message has arrived at the server | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     clientToServer = False | 
					
						
							| 
									
										
										
										
											2019-07-15 18:20:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  |     # for each instance | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     for followerDomain, followerHandles in grouped.items(): | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('DEBUG: follower handles for ' + followerDomain) | 
					
						
							| 
									
										
										
										
											2019-07-16 22:57:45 +00:00
										 |  |  |             pprint(followerHandles) | 
					
						
							| 
									
										
										
										
											2020-06-23 09:46:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # check that the follower's domain is active | 
					
						
							|  |  |  |         followerDomainUrl = httpPrefix + '://' + followerDomain | 
					
						
							|  |  |  |         if not siteIsActive(followerDomainUrl): | 
					
						
							|  |  |  |             print('Domain is inactive: ' + followerDomainUrl) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         print('Domain is active: ' + followerDomainUrl) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         withSharedInbox = hasSharedInbox(session, httpPrefix, followerDomain) | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2019-08-26 17:44:21 +00:00
										 |  |  |             if withSharedInbox: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print(followerDomain + ' has shared inbox') | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print(followerDomain + ' does not have a shared inbox') | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         toPort = port | 
					
						
							|  |  |  |         index = 0 | 
					
						
							|  |  |  |         toDomain = followerHandles[index].split('@')[1] | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  |         if ':' in toDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             toPort = toDomain.split(':')[1] | 
					
						
							|  |  |  |             toDomain = toDomain.split(':')[0] | 
					
						
							| 
									
										
										
										
											2019-08-22 19:47:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         cc = '' | 
					
						
							| 
									
										
										
										
											2019-11-07 20:51:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-02 16:23:30 +00:00
										 |  |  |         # if we are sending to an onion domain and we | 
					
						
							|  |  |  |         # have an alt onion domain then use the alt | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         fromDomain = domain | 
					
						
							|  |  |  |         fromHttpPrefix = httpPrefix | 
					
						
							| 
									
										
										
										
											2020-03-02 16:23:30 +00:00
										 |  |  |         if onionDomain: | 
					
						
							| 
									
										
										
										
											2020-03-02 19:31:41 +00:00
										 |  |  |             if toDomain.endswith('.onion'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 fromDomain = onionDomain | 
					
						
							|  |  |  |                 fromHttpPrefix = 'http' | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |         elif i2pDomain: | 
					
						
							|  |  |  |             if toDomain.endswith('.i2p'): | 
					
						
							|  |  |  |                 fromDomain = i2pDomain | 
					
						
							| 
									
										
										
										
											2020-06-19 22:50:41 +00:00
										 |  |  |                 fromHttpPrefix = 'http' | 
					
						
							| 
									
										
										
										
											2020-03-02 16:23:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-07 21:12:53 +00:00
										 |  |  |         if withSharedInbox: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             toNickname = followerHandles[index].split('@')[0] | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # if there are more than one followers on the domain | 
					
						
							|  |  |  |             # then send the post to the shared inbox | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             if len(followerHandles) > 1: | 
					
						
							|  |  |  |                 toNickname = 'inbox' | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             if toNickname != 'inbox' and postJsonObject.get('type'): | 
					
						
							|  |  |  |                 if postJsonObject['type'] == 'Update': | 
					
						
							| 
									
										
										
										
											2019-11-07 21:12:53 +00:00
										 |  |  |                     if postJsonObject.get('object'): | 
					
						
							|  |  |  |                         if isinstance(postJsonObject['object'], dict): | 
					
						
							|  |  |  |                             if postJsonObject['object'].get('type'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                 typ = postJsonObject['object']['type'] | 
					
						
							|  |  |  |                                 if typ == 'Person' or \ | 
					
						
							|  |  |  |                                    typ == 'Application' or \ | 
					
						
							|  |  |  |                                    typ == 'Group' or \ | 
					
						
							|  |  |  |                                    typ == 'Service': | 
					
						
							|  |  |  |                                     print('Sending profile update to ' + | 
					
						
							|  |  |  |                                           'shared inbox of ' + toDomain) | 
					
						
							|  |  |  |                                     toNickname = 'inbox' | 
					
						
							| 
									
										
										
										
											2020-02-05 11:46:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  |             if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print('DEBUG: Sending from ' + nickname + '@' + domain + | 
					
						
							|  |  |  |                       ' to ' + toNickname + '@' + toDomain) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             sendSignedJson(postJsonObject, session, baseDir, | 
					
						
							|  |  |  |                            nickname, fromDomain, port, | 
					
						
							|  |  |  |                            toNickname, toDomain, toPort, | 
					
						
							|  |  |  |                            cc, fromHttpPrefix, True, clientToServer, | 
					
						
							|  |  |  |                            federationList, | 
					
						
							|  |  |  |                            sendThreads, postLog, cachedWebfingers, | 
					
						
							|  |  |  |                            personCache, debug, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-08-26 17:42:06 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             # send to individual followers without using a shared inbox | 
					
						
							|  |  |  |             for handle in followerHandles: | 
					
						
							| 
									
										
										
										
											2019-11-07 19:23:56 +00:00
										 |  |  |                 if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     print('DEBUG: Sending to ' + handle) | 
					
						
							|  |  |  |                 toNickname = handle.split('@')[0] | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-07 12:56:00 +00:00
										 |  |  |                 if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     if postJsonObject['type'] != 'Update': | 
					
						
							|  |  |  |                         print('DEBUG: Sending from ' + | 
					
						
							|  |  |  |                               nickname + '@' + domain + ' to ' + | 
					
						
							|  |  |  |                               toNickname + '@' + toDomain) | 
					
						
							| 
									
										
										
										
											2019-11-07 12:56:00 +00:00
										 |  |  |                     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         print('DEBUG: Sending profile update from ' + | 
					
						
							|  |  |  |                               nickname + '@' + domain + ' to ' + | 
					
						
							|  |  |  |                               toNickname + '@' + toDomain) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 sendSignedJson(postJsonObject, session, baseDir, | 
					
						
							|  |  |  |                                nickname, fromDomain, port, | 
					
						
							|  |  |  |                                toNickname, toDomain, toPort, | 
					
						
							|  |  |  |                                cc, fromHttpPrefix, True, clientToServer, | 
					
						
							|  |  |  |                                federationList, | 
					
						
							|  |  |  |                                sendThreads, postLog, cachedWebfingers, | 
					
						
							|  |  |  |                                personCache, debug, projectVersion) | 
					
						
							| 
									
										
										
										
											2020-02-05 11:46:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-07 20:51:29 +00:00
										 |  |  |         time.sleep(4) | 
					
						
							| 
									
										
										
										
											2019-11-04 10:43:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-07 21:16:40 +00:00
										 |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: End of sendToFollowers') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def sendToFollowersThread(session, baseDir: str, | 
					
						
							|  |  |  |                           nickname: str, | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |                           domain: str, | 
					
						
							|  |  |  |                           onionDomain: str, i2pDomain: str, port: int, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                           httpPrefix: str, federationList: [], | 
					
						
							|  |  |  |                           sendThreads: [], postLog: [], | 
					
						
							|  |  |  |                           cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                           postJsonObject: {}, debug: bool, | 
					
						
							| 
									
										
										
										
											2019-11-04 10:43:19 +00:00
										 |  |  |                           projectVersion: str): | 
					
						
							|  |  |  |     """Returns a thread used to send a post to followers
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     sendThread = \ | 
					
						
							|  |  |  |         threadWithTrace(target=sendToFollowers, | 
					
						
							|  |  |  |                         args=(session, baseDir, | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |                               nickname, domain, | 
					
						
							|  |  |  |                               onionDomain, i2pDomain, port, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                               httpPrefix, federationList, | 
					
						
							|  |  |  |                               sendThreads, postLog, | 
					
						
							|  |  |  |                               cachedWebfingers, personCache, | 
					
						
							|  |  |  |                               postJsonObject.copy(), debug, | 
					
						
							|  |  |  |                               projectVersion), daemon=True) | 
					
						
							| 
									
										
										
										
											2020-06-23 14:48:10 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         sendThread.start() | 
					
						
							|  |  |  |     except SocketError as e: | 
					
						
							|  |  |  |         print('WARN: socket error while starting ' + | 
					
						
							|  |  |  |               'thread to send to followers. ' + str(e)) | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-06-23 21:39:19 +00:00
										 |  |  |     except ValueError as e: | 
					
						
							| 
									
										
										
										
											2020-06-23 14:48:10 +00:00
										 |  |  |         print('WARN: error while starting ' + | 
					
						
							|  |  |  |               'thread to send to followers. ' + str(e)) | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2019-11-04 10:43:19 +00:00
										 |  |  |     return sendThread | 
					
						
							| 
									
										
										
										
											2019-07-08 13:30:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def createInbox(recentPostsCache: {}, | 
					
						
							|  |  |  |                 session, baseDir: str, nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                 httpPrefix: str, itemsPerPage: int, headerOnly: bool, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                 pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     return createBoxIndexed(recentPostsCache, | 
					
						
							|  |  |  |                             session, baseDir, 'inbox', | 
					
						
							|  |  |  |                             nickname, domain, port, httpPrefix, | 
					
						
							|  |  |  |                             itemsPerPage, headerOnly, True, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                             0, False, 0, pageNumber) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def createBookmarksTimeline(session, baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                             port: int, httpPrefix: str, itemsPerPage: int, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                             headerOnly: bool, pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     return createBoxIndexed({}, session, baseDir, 'tlbookmarks', | 
					
						
							|  |  |  |                             nickname, domain, | 
					
						
							|  |  |  |                             port, httpPrefix, itemsPerPage, headerOnly, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                             True, 0, False, 0, pageNumber) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 10:21:24 +00:00
										 |  |  | def createEventsTimeline(recentPostsCache: {}, | 
					
						
							|  |  |  |                          session, baseDir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |                          port: int, httpPrefix: str, itemsPerPage: int, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                          headerOnly: bool, pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-08-26 10:21:24 +00:00
										 |  |  |     return createBoxIndexed(recentPostsCache, session, baseDir, 'tlevents', | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |                             nickname, domain, | 
					
						
							|  |  |  |                             port, httpPrefix, itemsPerPage, headerOnly, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                             True, 0, False, 0, pageNumber) | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 10:21:24 +00:00
										 |  |  | def createDMTimeline(recentPostsCache: {}, | 
					
						
							|  |  |  |                      session, baseDir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                      port: int, httpPrefix: str, itemsPerPage: int, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                      headerOnly: bool, pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-08-26 10:21:24 +00:00
										 |  |  |     return createBoxIndexed(recentPostsCache, | 
					
						
							|  |  |  |                             session, baseDir, 'dm', nickname, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             domain, port, httpPrefix, itemsPerPage, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                             headerOnly, True, 0, False, 0, pageNumber) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 10:21:24 +00:00
										 |  |  | def createRepliesTimeline(recentPostsCache: {}, | 
					
						
							|  |  |  |                           session, baseDir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                           port: int, httpPrefix: str, itemsPerPage: int, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                           headerOnly: bool, pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-08-26 10:21:24 +00:00
										 |  |  |     return createBoxIndexed(recentPostsCache, session, baseDir, 'tlreplies', | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             nickname, domain, port, httpPrefix, | 
					
						
							|  |  |  |                             itemsPerPage, headerOnly, True, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                             0, False, 0, pageNumber) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def createBlogsTimeline(session, baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                         port: int, httpPrefix: str, itemsPerPage: int, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                         headerOnly: bool, pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     return createBoxIndexed({}, session, baseDir, 'tlblogs', nickname, | 
					
						
							|  |  |  |                             domain, port, httpPrefix, | 
					
						
							|  |  |  |                             itemsPerPage, headerOnly, True, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                             0, False, 0, pageNumber) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def createMediaTimeline(session, baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                         port: int, httpPrefix: str, itemsPerPage: int, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                         headerOnly: bool, pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     return createBoxIndexed({}, session, baseDir, 'tlmedia', nickname, | 
					
						
							|  |  |  |                             domain, port, httpPrefix, | 
					
						
							|  |  |  |                             itemsPerPage, headerOnly, True, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                             0, False, 0, pageNumber) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-07 09:10:42 +00:00
										 |  |  | def createNewsTimeline(session, baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                        port: int, httpPrefix: str, itemsPerPage: int, | 
					
						
							| 
									
										
										
										
											2020-10-08 19:47:23 +00:00
										 |  |  |                        headerOnly: bool, newswireVotesThreshold: int, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                        positiveVoting: bool, votingTimeMins: int, | 
					
						
							|  |  |  |                        pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-10-07 18:05:08 +00:00
										 |  |  |     return createBoxIndexed({}, session, baseDir, 'outbox', 'news', | 
					
						
							| 
									
										
										
										
											2020-10-07 09:10:42 +00:00
										 |  |  |                             domain, port, httpPrefix, | 
					
						
							|  |  |  |                             itemsPerPage, headerOnly, True, | 
					
						
							| 
									
										
										
										
											2020-10-08 19:47:23 +00:00
										 |  |  |                             newswireVotesThreshold, positiveVoting, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                             votingTimeMins, pageNumber) | 
					
						
							| 
									
										
										
										
											2020-10-07 09:10:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def createOutbox(session, baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                  port: int, httpPrefix: str, | 
					
						
							|  |  |  |                  itemsPerPage: int, headerOnly: bool, authorized: bool, | 
					
						
							|  |  |  |                  pageNumber=None) -> {}: | 
					
						
							|  |  |  |     return createBoxIndexed({}, session, baseDir, 'outbox', | 
					
						
							|  |  |  |                             nickname, domain, port, httpPrefix, | 
					
						
							|  |  |  |                             itemsPerPage, headerOnly, authorized, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                             0, False, 0, pageNumber) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def createModeration(baseDir: str, nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                      httpPrefix: str, itemsPerPage: int, headerOnly: bool, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                      pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     boxDir = createPersonDir(nickname, domain, baseDir, 'inbox') | 
					
						
							|  |  |  |     boxname = 'moderation' | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domain = domain + ':' + str(port) | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not pageNumber: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         pageNumber = 1 | 
					
						
							| 
									
										
										
										
											2019-11-16 22:09:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     pageStr = '?page=' + str(pageNumber) | 
					
						
							|  |  |  |     boxUrl = httpPrefix+'://'+domain+'/users/'+nickname+'/'+boxname | 
					
						
							|  |  |  |     boxHeader = { | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         '@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         'first': boxUrl+'?page=true', | 
					
						
							|  |  |  |         'id': boxUrl, | 
					
						
							|  |  |  |         'last': boxUrl+'?page=true', | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'totalItems': 0, | 
					
						
							|  |  |  |         'type': 'OrderedCollection' | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     boxItems = { | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         '@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         'id': boxUrl+pageStr, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'orderedItems': [ | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         'partOf': boxUrl, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'type': 'OrderedCollectionPage' | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if isModerator(baseDir, nickname): | 
					
						
							|  |  |  |         moderationIndexFile = baseDir + '/accounts/moderation.txt' | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |         if os.path.isfile(moderationIndexFile): | 
					
						
							|  |  |  |             with open(moderationIndexFile, "r") as f: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 lines = f.readlines() | 
					
						
							|  |  |  |             boxHeader['totalItems'] = len(lines) | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |             if headerOnly: | 
					
						
							|  |  |  |                 return boxHeader | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             pageLines = [] | 
					
						
							|  |  |  |             if len(lines) > 0: | 
					
						
							|  |  |  |                 endLineNumber = len(lines) - 1 - int(itemsPerPage * pageNumber) | 
					
						
							|  |  |  |                 if endLineNumber < 0: | 
					
						
							|  |  |  |                     endLineNumber = 0 | 
					
						
							|  |  |  |                 startLineNumber = \ | 
					
						
							|  |  |  |                     len(lines) - 1 - int(itemsPerPage * (pageNumber - 1)) | 
					
						
							|  |  |  |                 if startLineNumber < 0: | 
					
						
							|  |  |  |                     startLineNumber = 0 | 
					
						
							|  |  |  |                 lineNumber = startLineNumber | 
					
						
							|  |  |  |                 while lineNumber >= endLineNumber: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                     pageLines.append(lines[lineNumber].strip('\n').strip('\r')) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     lineNumber -= 1 | 
					
						
							| 
									
										
										
										
											2019-11-16 22:09:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |             for postUrl in pageLines: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 postFilename = \ | 
					
						
							|  |  |  |                     boxDir + '/' + postUrl.replace('/', '#') + '.json' | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |                 if os.path.isfile(postFilename): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     postJsonObject = loadJson(postFilename) | 
					
						
							| 
									
										
										
										
											2019-10-22 11:55:06 +00:00
										 |  |  |                     if postJsonObject: | 
					
						
							|  |  |  |                         boxItems['orderedItems'].append(postJsonObject) | 
					
						
							| 
									
										
										
										
											2019-09-17 12:14:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |     if headerOnly: | 
					
						
							|  |  |  |         return boxHeader | 
					
						
							|  |  |  |     return boxItems | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-14 09:17:50 +00:00
										 |  |  | def getStatusNumberFromPostFilename(filename) -> int: | 
					
						
							|  |  |  |     """Gets the status number from a post filename
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     eg. https:##testdomain.com:8085#users#testuser567# | 
					
						
							|  |  |  |     statuses#1562958506952068.json | 
					
						
							| 
									
										
										
										
											2019-07-14 09:17:50 +00:00
										 |  |  |     returns 156295850695206 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if '#statuses#' not in filename: | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     return int(filename.split('#')[-1].replace('.json', '')) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-14 09:17:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-25 16:09:56 +00:00
										 |  |  | def isDM(postJsonObject: {}) -> bool: | 
					
						
							|  |  |  |     """Returns true if the given post is a DM
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if postJsonObject['type'] != 'Create': | 
					
						
							| 
									
										
										
										
											2019-08-25 16:09:56 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  |     if not postJsonObject.get('object'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not isinstance(postJsonObject['object'], dict): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if postJsonObject['object']['type'] != 'Note' and \ | 
					
						
							| 
									
										
										
										
											2020-05-03 12:52:13 +00:00
										 |  |  |        postJsonObject['object']['type'] != 'Patch' and \ | 
					
						
							| 
									
										
										
										
											2020-08-05 12:16:15 +00:00
										 |  |  |        postJsonObject['object']['type'] != 'EncryptedMessage' and \ | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |        postJsonObject['object']['type'] != 'Article': | 
					
						
							| 
									
										
										
										
											2019-08-25 16:09:56 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-11-16 17:29:02 +00:00
										 |  |  |     if postJsonObject['object'].get('moderationStatus'): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     fields = ('to', 'cc') | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |     for f in fields: | 
					
						
							| 
									
										
										
										
											2019-08-25 16:09:56 +00:00
										 |  |  |         if not postJsonObject['object'].get(f): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         for toAddress in postJsonObject['object'][f]: | 
					
						
							|  |  |  |             if toAddress.endswith('#Public'): | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |             if toAddress.endswith('followers'): | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def isImageMedia(session, baseDir: str, httpPrefix: str, | 
					
						
							|  |  |  |                  nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-08-02 09:51:20 +00:00
										 |  |  |                  postJsonObject: {}, translate: {}, | 
					
						
							|  |  |  |                  YTReplacementDomain: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-09-28 11:29:42 +00:00
										 |  |  |     """Returns true if the given post has attached image media
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if postJsonObject['type'] == 'Announce': | 
					
						
							|  |  |  |         postJsonAnnounce = \ | 
					
						
							|  |  |  |             downloadAnnounce(session, baseDir, httpPrefix, | 
					
						
							|  |  |  |                              nickname, domain, postJsonObject, | 
					
						
							| 
									
										
										
										
											2020-08-02 09:51:20 +00:00
										 |  |  |                              __version__, translate, | 
					
						
							|  |  |  |                              YTReplacementDomain) | 
					
						
							| 
									
										
										
										
											2019-09-28 16:21:43 +00:00
										 |  |  |         if postJsonAnnounce: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             postJsonObject = postJsonAnnounce | 
					
						
							|  |  |  |     if postJsonObject['type'] != 'Create': | 
					
						
							| 
									
										
										
										
											2019-09-28 11:29:42 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  |     if not postJsonObject.get('object'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not isinstance(postJsonObject['object'], dict): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-11-16 22:20:16 +00:00
										 |  |  |     if postJsonObject['object'].get('moderationStatus'): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if postJsonObject['object']['type'] != 'Note' and \ | 
					
						
							| 
									
										
										
										
											2020-08-21 11:08:31 +00:00
										 |  |  |        postJsonObject['object']['type'] != 'Event' and \ | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |        postJsonObject['object']['type'] != 'Article': | 
					
						
							| 
									
										
										
										
											2019-09-28 11:29:42 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  |     if not postJsonObject['object'].get('attachment'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not isinstance(postJsonObject['object']['attachment'], list): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     for attach in postJsonObject['object']['attachment']: | 
					
						
							|  |  |  |         if attach.get('mediaType') and attach.get('url'): | 
					
						
							| 
									
										
										
										
											2019-10-23 13:24:09 +00:00
										 |  |  |             if attach['mediaType'].startswith('image/') or \ | 
					
						
							|  |  |  |                attach['mediaType'].startswith('audio/') or \ | 
					
						
							|  |  |  |                attach['mediaType'].startswith('video/'): | 
					
						
							| 
									
										
										
										
											2019-09-28 11:29:42 +00:00
										 |  |  |                 return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def isReply(postJsonObject: {}, actor: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-09-23 19:53:18 +00:00
										 |  |  |     """Returns true if the given post is a reply to the given actor
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if postJsonObject['type'] != 'Create': | 
					
						
							| 
									
										
										
										
											2019-11-09 21:39:04 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  |     if not postJsonObject.get('object'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not isinstance(postJsonObject['object'], dict): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-11-16 22:18:20 +00:00
										 |  |  |     if postJsonObject['object'].get('moderationStatus'): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if postJsonObject['object']['type'] != 'Note' and \ | 
					
						
							| 
									
										
										
										
											2020-08-05 12:24:09 +00:00
										 |  |  |        postJsonObject['object']['type'] != 'EncryptedMessage' and \ | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |        postJsonObject['object']['type'] != 'Article': | 
					
						
							| 
									
										
										
										
											2019-11-09 21:39:04 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  |     if postJsonObject['object'].get('inReplyTo'): | 
					
						
							| 
									
										
										
										
											2020-08-28 14:45:07 +00:00
										 |  |  |         if isinstance(postJsonObject['object']['inReplyTo'], str): | 
					
						
							|  |  |  |             if postJsonObject['object']['inReplyTo'].startswith(actor): | 
					
						
							|  |  |  |                 return True | 
					
						
							| 
									
										
										
										
											2019-11-09 21:39:04 +00:00
										 |  |  |     if not postJsonObject['object'].get('tag'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not isinstance(postJsonObject['object']['tag'], list): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     for tag in postJsonObject['object']['tag']: | 
					
						
							|  |  |  |         if not tag.get('type'): | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if tag['type'] == 'Mention': | 
					
						
							| 
									
										
										
										
											2019-11-09 21:39:04 +00:00
										 |  |  |             if not tag.get('href'): | 
					
						
							| 
									
										
										
										
											2019-10-22 19:07:23 +00:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2019-11-09 21:39:04 +00:00
										 |  |  |             if actor in tag['href']: | 
					
						
							|  |  |  |                 return True | 
					
						
							| 
									
										
										
										
											2019-10-22 19:07:23 +00:00
										 |  |  |     return False | 
					
						
							| 
									
										
										
										
											2019-09-23 19:53:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def createBoxIndex(boxDir: str, postsInBoxDict: {}) -> int: | 
					
						
							| 
									
										
										
										
											2019-10-20 09:22:40 +00:00
										 |  |  |     """ Creates an index for the given box
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postsCtr = 0 | 
					
						
							|  |  |  |     postsInPersonInbox = os.scandir(boxDir) | 
					
						
							| 
									
										
										
										
											2019-10-20 09:22:40 +00:00
										 |  |  |     for postFilename in postsInPersonInbox: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postFilename = postFilename.name | 
					
						
							| 
									
										
										
										
											2019-10-20 09:22:40 +00:00
										 |  |  |         if not postFilename.endswith('.json'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         # extract the status number | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         statusNumber = getStatusNumberFromPostFilename(postFilename) | 
					
						
							| 
									
										
										
										
											2019-10-20 09:22:40 +00:00
										 |  |  |         if statusNumber: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             postsInBoxDict[statusNumber] = os.path.join(boxDir, postFilename) | 
					
						
							|  |  |  |             postsCtr += 1 | 
					
						
							| 
									
										
										
										
											2019-10-20 09:22:40 +00:00
										 |  |  |     return postsCtr | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def createSharedInboxIndex(baseDir: str, sharedBoxDir: str, | 
					
						
							|  |  |  |                            postsInBoxDict: {}, postsCtr: int, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |                            nickname: str, domain: str) -> int: | 
					
						
							| 
									
										
										
										
											2019-10-20 09:36:07 +00:00
										 |  |  |     """ Creates an index for the given shared inbox
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							|  |  |  |     followingFilename = baseDir + '/accounts/' + handle + '/following.txt' | 
					
						
							|  |  |  |     postsInSharedInbox = os.scandir(sharedBoxDir) | 
					
						
							|  |  |  |     followingHandles = None | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |     for postFilename in postsInSharedInbox: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postFilename = postFilename.name | 
					
						
							| 
									
										
										
										
											2019-10-20 09:36:07 +00:00
										 |  |  |         if not postFilename.endswith('.json'): | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         statusNumber = getStatusNumberFromPostFilename(postFilename) | 
					
						
							| 
									
										
										
										
											2019-10-20 09:36:07 +00:00
										 |  |  |         if not statusNumber: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         sharedInboxFilename = os.path.join(sharedBoxDir, postFilename) | 
					
						
							| 
									
										
										
										
											2019-10-20 09:36:07 +00:00
										 |  |  |         # get the actor from the shared post | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postJsonObject = loadJson(sharedInboxFilename, 0) | 
					
						
							| 
									
										
										
										
											2019-11-23 10:08:00 +00:00
										 |  |  |         if not postJsonObject: | 
					
						
							|  |  |  |             print('WARN: json load exception createSharedInboxIndex') | 
					
						
							| 
									
										
										
										
											2019-10-20 09:36:07 +00:00
										 |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         actorNickname = getNicknameFromActor(postJsonObject['actor']) | 
					
						
							| 
									
										
										
										
											2019-10-20 09:51:32 +00:00
										 |  |  |         if not actorNickname: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         actorDomain, actorPort = getDomainFromActor(postJsonObject['actor']) | 
					
						
							| 
									
										
										
										
											2019-10-20 09:51:32 +00:00
										 |  |  |         if not actorDomain: | 
					
						
							| 
									
										
										
										
											2019-10-20 09:36:07 +00:00
										 |  |  |             continue | 
					
						
							| 
									
										
										
										
											2019-10-20 09:47:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 09:36:07 +00:00
										 |  |  |         # is the actor followed by this account? | 
					
						
							| 
									
										
										
										
											2019-10-20 09:47:06 +00:00
										 |  |  |         if not followingHandles: | 
					
						
							|  |  |  |             with open(followingFilename, 'r') as followingFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 followingHandles = followingFile.read() | 
					
						
							|  |  |  |         if actorNickname + '@' + actorDomain not in followingHandles: | 
					
						
							| 
									
										
										
										
											2019-10-20 09:36:07 +00:00
										 |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-27 18:35:35 +00:00
										 |  |  |         postsInBoxDict[statusNumber] = sharedInboxFilename | 
					
						
							|  |  |  |         postsCtr += 1 | 
					
						
							| 
									
										
										
										
											2019-10-20 09:36:07 +00:00
										 |  |  |     return postsCtr | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def addPostStringToTimeline(postStr: str, boxname: str, | 
					
						
							|  |  |  |                             postsInBox: [], boxActor: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |     """ is this a valid timeline post?
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-05-03 13:18:35 +00:00
										 |  |  |     # must be a recognized ActivityPub type | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if ('"Note"' in postStr or | 
					
						
							| 
									
										
										
										
											2020-08-05 12:24:09 +00:00
										 |  |  |         '"EncryptedMessage"' in postStr or | 
					
						
							| 
									
										
										
										
											2020-08-26 12:12:43 +00:00
										 |  |  |         '"Event"' in postStr or | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         '"Article"' in postStr or | 
					
						
							| 
									
										
										
										
											2020-05-03 12:52:13 +00:00
										 |  |  |         '"Patch"' in postStr or | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         '"Announce"' in postStr or | 
					
						
							|  |  |  |         ('"Question"' in postStr and | 
					
						
							|  |  |  |          ('"Create"' in postStr or '"Update"' in postStr))): | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if boxname == 'dm': | 
					
						
							| 
									
										
										
										
											2019-11-24 12:12:29 +00:00
										 |  |  |             if '#Public' in postStr or '/followers' in postStr: | 
					
						
							|  |  |  |                 return False | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         elif boxname == 'tlreplies': | 
					
						
							| 
									
										
										
										
											2019-11-24 12:12:29 +00:00
										 |  |  |             if boxActor not in postStr: | 
					
						
							|  |  |  |                 return False | 
					
						
							| 
									
										
										
										
											2020-10-07 09:10:42 +00:00
										 |  |  |         elif boxname == 'tlblogs' or boxname == 'tlnews': | 
					
						
							| 
									
										
										
										
											2020-02-24 14:39:25 +00:00
										 |  |  |             if '"Create"' not in postStr: | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |             if '"Article"' not in postStr: | 
					
						
							|  |  |  |                 return False | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         elif boxname == 'tlmedia': | 
					
						
							| 
									
										
										
										
											2019-11-24 12:12:29 +00:00
										 |  |  |             if '"Create"' in postStr: | 
					
						
							|  |  |  |                 if 'mediaType' not in postStr or 'image/' not in postStr: | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |                     return False | 
					
						
							| 
									
										
										
										
											2019-11-24 12:12:29 +00:00
										 |  |  |         # add the post to the dictionary | 
					
						
							|  |  |  |         postsInBox.append(postStr) | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def addPostToTimeline(filePath: str, boxname: str, | 
					
						
							|  |  |  |                       postsInBox: [], boxActor: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-11-24 12:12:29 +00:00
										 |  |  |     """ Reads a post from file and decides whether it is valid
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     with open(filePath, 'r') as postFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postStr = postFile.read() | 
					
						
							|  |  |  |         return addPostStringToTimeline(postStr, boxname, postsInBox, boxActor) | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def createBoxIndexed(recentPostsCache: {}, | 
					
						
							|  |  |  |                      session, baseDir: str, boxname: str, | 
					
						
							|  |  |  |                      nickname: str, domain: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |                      itemsPerPage: int, headerOnly: bool, authorized: bool, | 
					
						
							| 
									
										
										
										
											2020-10-08 19:47:23 +00:00
										 |  |  |                      newswireVotesThreshold: int, positiveVoting: bool, | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                      votingTimeMins: int, pageNumber=None) -> {}: | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |     """Constructs the box feed for a person with the given nickname
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not authorized or not pageNumber: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         pageNumber = 1 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if boxname != 'inbox' and boxname != 'dm' and \ | 
					
						
							|  |  |  |        boxname != 'tlreplies' and boxname != 'tlmedia' and \ | 
					
						
							| 
									
										
										
										
											2020-10-07 09:10:42 +00:00
										 |  |  |        boxname != 'tlblogs' and boxname != 'tlnews' and \ | 
					
						
							| 
									
										
										
										
											2020-05-21 20:48:51 +00:00
										 |  |  |        boxname != 'outbox' and boxname != 'tlbookmarks' and \ | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |        boxname != 'bookmarks' and \ | 
					
						
							| 
									
										
										
										
											2020-08-26 09:29:51 +00:00
										 |  |  |        boxname != 'tlevents': | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |     # bookmarks and events timelines are like the inbox | 
					
						
							|  |  |  |     # but have their own separate index | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     indexBoxName = boxname | 
					
						
							| 
									
										
										
										
											2020-05-21 22:02:27 +00:00
										 |  |  |     if boxname == "tlbookmarks": | 
					
						
							|  |  |  |         boxname = "bookmarks" | 
					
						
							|  |  |  |         indexBoxName = boxname | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domain = domain + ':' + str(port) | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     boxActor = httpPrefix + '://' + domain + '/users/' + nickname | 
					
						
							| 
									
										
										
										
											2020-01-19 20:19:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     pageStr = '?page=true' | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |     if pageNumber: | 
					
						
							| 
									
										
										
										
											2020-05-21 21:43:33 +00:00
										 |  |  |         if pageNumber < 1: | 
					
						
							|  |  |  |             pageNumber = 1 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             pageStr = '?page=' + str(pageNumber) | 
					
						
							|  |  |  |         except BaseException: | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |             pass | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     boxUrl = httpPrefix + '://' + domain + '/users/' + nickname + '/' + boxname | 
					
						
							|  |  |  |     boxHeader = { | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         '@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-05-21 21:43:33 +00:00
										 |  |  |         'first': boxUrl + '?page=true', | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         'id': boxUrl, | 
					
						
							| 
									
										
										
										
											2020-05-21 21:43:33 +00:00
										 |  |  |         'last': boxUrl + '?page=true', | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'totalItems': 0, | 
					
						
							|  |  |  |         'type': 'OrderedCollection' | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     boxItems = { | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         '@context': 'https://www.w3.org/ns/activitystreams', | 
					
						
							| 
									
										
										
										
											2020-05-21 21:43:33 +00:00
										 |  |  |         'id': boxUrl + pageStr, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'orderedItems': [ | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         'partOf': boxUrl, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'type': 'OrderedCollectionPage' | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postsInBox = [] | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     indexFilename = \ | 
					
						
							|  |  |  |         baseDir + '/accounts/' + nickname + '@' + domain + \ | 
					
						
							|  |  |  |         '/' + indexBoxName + '.index' | 
					
						
							|  |  |  |     postsCtr = 0 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |     if os.path.isfile(indexFilename): | 
					
						
							| 
									
										
										
										
											2020-05-21 19:28:09 +00:00
										 |  |  |         maxPostCtr = itemsPerPage * pageNumber | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |         with open(indexFilename, 'r') as indexFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             while postsCtr < maxPostCtr: | 
					
						
							|  |  |  |                 postFilename = indexFile.readline() | 
					
						
							| 
									
										
										
										
											2019-11-18 12:40:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:04:08 +00:00
										 |  |  |                 if not postFilename: | 
					
						
							| 
									
										
										
										
											2020-05-21 21:53:12 +00:00
										 |  |  |                     break | 
					
						
							| 
									
										
										
										
											2019-11-18 15:04:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-08 19:47:23 +00:00
										 |  |  |                 # apply votes within this timeline | 
					
						
							|  |  |  |                 if newswireVotesThreshold > 0: | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                     # note that the presence of an arrival file also indicates | 
					
						
							|  |  |  |                     # that this post is moderated | 
					
						
							|  |  |  |                     arrivalDate = \ | 
					
						
							|  |  |  |                         locateNewsArrival(baseDir, domain, postFilename) | 
					
						
							|  |  |  |                     if arrivalDate: | 
					
						
							|  |  |  |                         # how long has elapsed since this post arrived? | 
					
						
							| 
									
										
										
										
											2020-10-09 12:25:24 +00:00
										 |  |  |                         currDate = datetime.datetime.utcnow() | 
					
						
							| 
									
										
										
										
											2020-10-09 12:15:20 +00:00
										 |  |  |                         timeDiffMins = \ | 
					
						
							|  |  |  |                             int((currDate - arrivalDate).total_seconds() / 60) | 
					
						
							|  |  |  |                         # has the voting time elapsed? | 
					
						
							| 
									
										
										
										
											2020-10-09 12:48:13 +00:00
										 |  |  |                         if timeDiffMins < votingTimeMins: | 
					
						
							|  |  |  |                             # voting is still happening, so don't add this | 
					
						
							|  |  |  |                             # post to the timeline | 
					
						
							|  |  |  |                             continue | 
					
						
							|  |  |  |                         # if there a votes file for this post? | 
					
						
							|  |  |  |                         votesFilename = \ | 
					
						
							|  |  |  |                             locateNewsVotes(baseDir, domain, postFilename) | 
					
						
							|  |  |  |                         if votesFilename: | 
					
						
							|  |  |  |                             # load the votes file and count the votes | 
					
						
							|  |  |  |                             votesJson = loadJson(votesFilename, 0, 2) | 
					
						
							|  |  |  |                             if votesJson: | 
					
						
							|  |  |  |                                 if not positiveVoting: | 
					
						
							|  |  |  |                                     if votesOnNewswireItem(votesJson) >= \ | 
					
						
							|  |  |  |                                        newswireVotesThreshold: | 
					
						
							|  |  |  |                                         # Too many veto votes. | 
					
						
							|  |  |  |                                         # Continue without incrementing | 
					
						
							|  |  |  |                                         # the posts counter | 
					
						
							|  |  |  |                                         continue | 
					
						
							|  |  |  |                                 else: | 
					
						
							|  |  |  |                                     if votesOnNewswireItem < \ | 
					
						
							|  |  |  |                                        newswireVotesThreshold: | 
					
						
							|  |  |  |                                         # Not enough votes. | 
					
						
							|  |  |  |                                         # Continue without incrementing | 
					
						
							|  |  |  |                                         # the posts counter | 
					
						
							|  |  |  |                                         continue | 
					
						
							| 
									
										
										
										
											2020-10-08 19:47:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 12:40:38 +00:00
										 |  |  |                 # Skip through any posts previous to the current page | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 if postsCtr < int((pageNumber - 1) * itemsPerPage): | 
					
						
							|  |  |  |                     postsCtr += 1 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |                     continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 12:54:41 +00:00
										 |  |  |                 # if this is a full path then remove the directories | 
					
						
							|  |  |  |                 if '/' in postFilename: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     postFilename = postFilename.split('/')[-1] | 
					
						
							| 
									
										
										
										
											2019-11-18 12:54:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |                 # filename of the post without any extension or path | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 # This should also correspond to any index entry in | 
					
						
							|  |  |  |                 # the posts cache | 
					
						
							|  |  |  |                 postUrl = \ | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                     postFilename.replace('\n', '').replace('\r', '') | 
					
						
							|  |  |  |                 postUrl = postUrl.replace('.json', '').strip() | 
					
						
							| 
									
										
										
										
											2019-11-24 12:12:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-25 10:10:59 +00:00
										 |  |  |                 # is the post cached in memory? | 
					
						
							| 
									
										
										
										
											2019-11-24 12:12:29 +00:00
										 |  |  |                 if recentPostsCache.get('index'): | 
					
						
							|  |  |  |                     if postUrl in recentPostsCache['index']: | 
					
						
							|  |  |  |                         if recentPostsCache['json'].get(postUrl): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                             url = recentPostsCache['json'][postUrl] | 
					
						
							|  |  |  |                             addPostStringToTimeline(url, | 
					
						
							|  |  |  |                                                     boxname, postsInBox, | 
					
						
							|  |  |  |                                                     boxActor) | 
					
						
							| 
									
										
										
										
											2020-05-21 19:28:09 +00:00
										 |  |  |                             postsCtr += 1 | 
					
						
							|  |  |  |                             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # read the post from file | 
					
						
							|  |  |  |                 fullPostFilename = \ | 
					
						
							|  |  |  |                     locatePost(baseDir, nickname, | 
					
						
							|  |  |  |                                domain, postUrl, False) | 
					
						
							|  |  |  |                 if fullPostFilename: | 
					
						
							|  |  |  |                     addPostToTimeline(fullPostFilename, boxname, | 
					
						
							|  |  |  |                                       postsInBox, boxActor) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     print('WARN: unable to locate post ' + postUrl) | 
					
						
							| 
									
										
										
										
											2019-11-24 12:12:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 postsCtr += 1 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Generate first and last entries within header | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if postsCtr > 0: | 
					
						
							|  |  |  |         lastPage = int(postsCtr / itemsPerPage) | 
					
						
							|  |  |  |         if lastPage < 1: | 
					
						
							|  |  |  |             lastPage = 1 | 
					
						
							|  |  |  |         boxHeader['last'] = \ | 
					
						
							|  |  |  |             httpPrefix + '://' + domain + '/users/' + \ | 
					
						
							|  |  |  |             nickname + '/' + boxname + '?page=' + str(lastPage) | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if headerOnly: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         boxHeader['totalItems'] = len(postsInBox) | 
					
						
							|  |  |  |         prevPageStr = 'true' | 
					
						
							|  |  |  |         if pageNumber > 1: | 
					
						
							|  |  |  |             prevPageStr = str(pageNumber - 1) | 
					
						
							|  |  |  |         boxHeader['prev'] = \ | 
					
						
							|  |  |  |             httpPrefix + '://' + domain + '/users/' + \ | 
					
						
							|  |  |  |             nickname + '/' + boxname + '?page=' + prevPageStr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         nextPageStr = str(pageNumber + 1) | 
					
						
							|  |  |  |         boxHeader['next'] = \ | 
					
						
							|  |  |  |             httpPrefix + '://' + domain + '/users/' + \ | 
					
						
							|  |  |  |             nickname + '/' + boxname + '?page=' + nextPageStr | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |         return boxHeader | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:55:27 +00:00
										 |  |  |     for postStr in postsInBox: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         p = None | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             p = json.loads(postStr) | 
					
						
							|  |  |  |         except BaseException: | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         # Don't show likes, replies or shares (announces) to | 
					
						
							|  |  |  |         # unauthorized viewers | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |         if not authorized: | 
					
						
							|  |  |  |             if p.get('object'): | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |                 if isinstance(p['object'], dict): | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |                     if p['object'].get('likes'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         p['likes'] = {'items': []} | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |                     if p['object'].get('replies'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         p['replies'] = {} | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |                     if p['object'].get('shares'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         p['shares'] = {} | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  |                     if p['object'].get('bookmarks'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         p['bookmarks'] = {} | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 12:02:55 +00:00
										 |  |  |         boxItems['orderedItems'].append(p) | 
					
						
							| 
									
										
										
										
											2019-11-18 11:28:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return boxItems | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def expireCache(baseDir: str, personCache: {}, | 
					
						
							| 
									
										
										
										
											2020-06-24 13:30:50 +00:00
										 |  |  |                 httpPrefix: str, archiveDir: str, | 
					
						
							|  |  |  |                 recentPostsCache: {}, | 
					
						
							|  |  |  |                 maxPostsInBox=32000): | 
					
						
							| 
									
										
										
										
											2019-08-20 11:51:29 +00:00
										 |  |  |     """Thread used to expire actors from the cache and archive old posts
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     while True: | 
					
						
							|  |  |  |         # once per day | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         time.sleep(60 * 60 * 24) | 
					
						
							|  |  |  |         expirePersonCache(baseDir, personCache) | 
					
						
							| 
									
										
										
										
											2020-06-24 13:30:50 +00:00
										 |  |  |         archivePosts(baseDir, httpPrefix, archiveDir, recentPostsCache, | 
					
						
							|  |  |  |                      maxPostsInBox) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-20 11:51:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def archivePosts(baseDir: str, httpPrefix: str, archiveDir: str, | 
					
						
							| 
									
										
										
										
											2020-06-24 13:30:50 +00:00
										 |  |  |                  recentPostsCache: {}, | 
					
						
							| 
									
										
										
										
											2019-12-12 09:58:06 +00:00
										 |  |  |                  maxPostsInBox=32000) -> None: | 
					
						
							| 
									
										
										
										
											2019-07-12 20:43:55 +00:00
										 |  |  |     """Archives posts for all accounts
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if archiveDir: | 
					
						
							|  |  |  |         if not os.path.isdir(archiveDir): | 
					
						
							|  |  |  |             os.mkdir(archiveDir) | 
					
						
							|  |  |  |     if archiveDir: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if not os.path.isdir(archiveDir + '/accounts'): | 
					
						
							|  |  |  |             os.mkdir(archiveDir + '/accounts') | 
					
						
							| 
									
										
										
										
											2019-07-12 20:43:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     for subdir, dirs, files in os.walk(baseDir + '/accounts'): | 
					
						
							| 
									
										
										
										
											2019-07-12 20:43:55 +00:00
										 |  |  |         for handle in dirs: | 
					
						
							|  |  |  |             if '@' in handle: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 nickname = handle.split('@')[0] | 
					
						
							|  |  |  |                 domain = handle.split('@')[1] | 
					
						
							|  |  |  |                 archiveSubdir = None | 
					
						
							| 
									
										
										
										
											2019-07-12 20:43:55 +00:00
										 |  |  |                 if archiveDir: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     if not os.path.isdir(archiveDir + '/accounts/' + handle): | 
					
						
							|  |  |  |                         os.mkdir(archiveDir + '/accounts/' + handle) | 
					
						
							|  |  |  |                     if not os.path.isdir(archiveDir + '/accounts/' + | 
					
						
							|  |  |  |                                          handle + '/inbox'): | 
					
						
							|  |  |  |                         os.mkdir(archiveDir + '/accounts/' + | 
					
						
							|  |  |  |                                  handle + '/inbox') | 
					
						
							|  |  |  |                     if not os.path.isdir(archiveDir + '/accounts/' + | 
					
						
							|  |  |  |                                          handle + '/outbox'): | 
					
						
							|  |  |  |                         os.mkdir(archiveDir + '/accounts/' + | 
					
						
							|  |  |  |                                  handle + '/outbox') | 
					
						
							|  |  |  |                     archiveSubdir = archiveDir + '/accounts/' + \ | 
					
						
							|  |  |  |                         handle + '/inbox' | 
					
						
							|  |  |  |                 archivePostsForPerson(httpPrefix, nickname, domain, baseDir, | 
					
						
							|  |  |  |                                       'inbox', archiveSubdir, | 
					
						
							| 
									
										
										
										
											2020-06-24 13:30:50 +00:00
										 |  |  |                                       recentPostsCache, maxPostsInBox) | 
					
						
							| 
									
										
										
										
											2019-07-12 20:43:55 +00:00
										 |  |  |                 if archiveDir: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     archiveSubdir = archiveDir + '/accounts/' + \ | 
					
						
							|  |  |  |                         handle + '/outbox' | 
					
						
							|  |  |  |                 archivePostsForPerson(httpPrefix, nickname, domain, baseDir, | 
					
						
							|  |  |  |                                       'outbox', archiveSubdir, | 
					
						
							| 
									
										
										
										
											2020-06-24 13:30:50 +00:00
										 |  |  |                                       recentPostsCache, maxPostsInBox) | 
					
						
							| 
									
										
										
										
											2019-07-12 20:43:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def archivePostsForPerson(httpPrefix: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                           baseDir: str, | 
					
						
							|  |  |  |                           boxname: str, archiveDir: str, | 
					
						
							| 
									
										
										
										
											2020-06-24 13:30:50 +00:00
										 |  |  |                           recentPostsCache: {}, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                           maxPostsInBox=32000) -> None: | 
					
						
							| 
									
										
										
										
											2019-07-04 16:24:23 +00:00
										 |  |  |     """Retain a maximum number of posts within the given box
 | 
					
						
							| 
									
										
										
										
											2019-06-29 13:44:21 +00:00
										 |  |  |     Move any others to an archive directory | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if boxname != 'inbox' and boxname != 'outbox': | 
					
						
							| 
									
										
										
										
											2019-07-04 16:24:23 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-07-12 20:43:55 +00:00
										 |  |  |     if archiveDir: | 
					
						
							|  |  |  |         if not os.path.isdir(archiveDir): | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |             os.mkdir(archiveDir) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     boxDir = createPersonDir(nickname, domain, baseDir, boxname) | 
					
						
							|  |  |  |     postsInBox = os.scandir(boxDir) | 
					
						
							|  |  |  |     noOfPosts = 0 | 
					
						
							| 
									
										
										
										
											2019-10-19 10:19:19 +00:00
										 |  |  |     for f in postsInBox: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         noOfPosts += 1 | 
					
						
							|  |  |  |     if noOfPosts <= maxPostsInBox: | 
					
						
							|  |  |  |         print('Checked ' + str(noOfPosts) + ' ' + boxname + | 
					
						
							|  |  |  |               ' posts for ' + nickname + '@' + domain) | 
					
						
							| 
									
										
										
										
											2019-06-29 13:44:21 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-09-14 11:18:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-20 11:18:25 +00:00
										 |  |  |     # remove entries from the index | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							|  |  |  |     indexFilename = baseDir + '/accounts/' + handle + '/' + boxname + '.index' | 
					
						
							| 
									
										
										
										
											2019-10-20 11:18:25 +00:00
										 |  |  |     if os.path.isfile(indexFilename): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         indexCtr = 0 | 
					
						
							| 
									
										
										
										
											2019-10-20 11:18:25 +00:00
										 |  |  |         # get the existing index entries as a string | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         newIndex = '' | 
					
						
							| 
									
										
										
										
											2019-10-20 11:18:25 +00:00
										 |  |  |         with open(indexFilename, 'r') as indexFile: | 
					
						
							|  |  |  |             for postId in indexFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 newIndex += postId | 
					
						
							|  |  |  |                 indexCtr += 1 | 
					
						
							|  |  |  |                 if indexCtr >= maxPostsInBox: | 
					
						
							| 
									
										
										
										
											2019-10-20 11:18:25 +00:00
										 |  |  |                     break | 
					
						
							|  |  |  |         # save the new index file | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if len(newIndex) > 0: | 
					
						
							|  |  |  |             indexFile = open(indexFilename, 'w+') | 
					
						
							| 
									
										
										
										
											2019-10-20 11:18:25 +00:00
										 |  |  |             if indexFile: | 
					
						
							|  |  |  |                 indexFile.write(newIndex) | 
					
						
							|  |  |  |                 indexFile.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postsInBoxDict = {} | 
					
						
							|  |  |  |     postsCtr = 0 | 
					
						
							|  |  |  |     postsInBox = os.scandir(boxDir) | 
					
						
							| 
									
										
										
										
											2019-09-14 11:18:34 +00:00
										 |  |  |     for postFilename in postsInBox: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postFilename = postFilename.name | 
					
						
							| 
									
										
										
										
											2019-09-14 11:18:34 +00:00
										 |  |  |         if not postFilename.endswith('.json'): | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2019-11-06 13:35:25 +00:00
										 |  |  |         # Time of file creation | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         fullFilename = os.path.join(boxDir, postFilename) | 
					
						
							| 
									
										
										
										
											2019-11-06 14:50:17 +00:00
										 |  |  |         if os.path.isfile(fullFilename): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             content = open(fullFilename).read() | 
					
						
							| 
									
										
										
										
											2019-11-06 14:50:17 +00:00
										 |  |  |             if '"published":' in content: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 publishedStr = content.split('"published":')[1] | 
					
						
							| 
									
										
										
										
											2019-11-06 14:50:17 +00:00
										 |  |  |                 if '"' in publishedStr: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                     publishedStr = publishedStr.split('"')[1] | 
					
						
							| 
									
										
										
										
											2019-11-06 14:54:17 +00:00
										 |  |  |                     if publishedStr.endswith('Z'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                         postsInBoxDict[publishedStr] = postFilename | 
					
						
							|  |  |  |                         postsCtr += 1 | 
					
						
							| 
									
										
										
										
											2019-09-14 11:18:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     noOfPosts = postsCtr | 
					
						
							|  |  |  |     if noOfPosts <= maxPostsInBox: | 
					
						
							|  |  |  |         print('Checked ' + str(noOfPosts) + ' ' + boxname + | 
					
						
							|  |  |  |               ' posts for ' + nickname + '@' + domain) | 
					
						
							| 
									
										
										
										
											2019-09-14 11:18:34 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-11-06 14:50:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 11:18:34 +00:00
										 |  |  |     # sort the list in ascending order of date | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postsInBoxSorted = \ | 
					
						
							|  |  |  |         OrderedDict(sorted(postsInBoxDict.items(), reverse=False)) | 
					
						
							| 
									
										
										
										
											2019-09-14 17:12:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-19 10:10:52 +00:00
										 |  |  |     # directory containing cached html posts | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postCacheDir = boxDir.replace('/' + boxname, '/postcache') | 
					
						
							| 
									
										
										
										
											2019-10-19 10:10:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     removeCtr = 0 | 
					
						
							|  |  |  |     for publishedStr, postFilename in postsInBoxSorted.items(): | 
					
						
							|  |  |  |         filePath = os.path.join(boxDir, postFilename) | 
					
						
							| 
									
										
										
										
											2019-09-24 21:16:44 +00:00
										 |  |  |         if not os.path.isfile(filePath): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if archiveDir: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             archivePath = os.path.join(archiveDir, postFilename) | 
					
						
							|  |  |  |             os.rename(filePath, archivePath) | 
					
						
							| 
									
										
										
										
											2020-10-21 10:39:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             extensions = ('replies', 'votes', 'arrived', 'muted') | 
					
						
							|  |  |  |             for ext in extensions: | 
					
						
							|  |  |  |                 extPath = filePath.replace('.json', '.' + ext) | 
					
						
							|  |  |  |                 if os.path.isfile(extPath): | 
					
						
							|  |  |  |                     os.rename(extPath, | 
					
						
							|  |  |  |                               archivePath.replace('.json', '.' + ext)) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     extPath = filePath.replace('.json', | 
					
						
							|  |  |  |                                                '.json.' + ext) | 
					
						
							|  |  |  |                     if os.path.isfile(extPath): | 
					
						
							|  |  |  |                         os.rename(extPath, | 
					
						
							|  |  |  |                                   archivePath.replace('.json', '.json.' + ext)) | 
					
						
							| 
									
										
										
										
											2019-09-24 21:16:44 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-06-24 13:30:50 +00:00
										 |  |  |             deletePost(baseDir, httpPrefix, nickname, domain, | 
					
						
							|  |  |  |                        filePath, False, recentPostsCache) | 
					
						
							| 
									
										
										
										
											2019-10-19 10:10:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # remove cached html posts | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postCacheFilename = \ | 
					
						
							|  |  |  |             os.path.join(postCacheDir, postFilename).replace('.json', '.html') | 
					
						
							| 
									
										
										
										
											2019-10-19 10:10:52 +00:00
										 |  |  |         if os.path.isfile(postCacheFilename): | 
					
						
							|  |  |  |             os.remove(postCacheFilename) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         noOfPosts -= 1 | 
					
						
							|  |  |  |         removeCtr += 1 | 
					
						
							|  |  |  |         if noOfPosts <= maxPostsInBox: | 
					
						
							| 
									
										
										
										
											2019-09-24 21:16:44 +00:00
										 |  |  |             break | 
					
						
							| 
									
										
										
										
											2020-02-26 20:39:18 +00:00
										 |  |  |     if archiveDir: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         print('Archived ' + str(removeCtr) + ' ' + boxname + | 
					
						
							|  |  |  |               ' posts for ' + nickname + '@' + domain) | 
					
						
							| 
									
										
										
										
											2020-02-26 20:39:18 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         print('Removed ' + str(removeCtr) + ' ' + boxname + | 
					
						
							|  |  |  |               ' posts for ' + nickname + '@' + domain) | 
					
						
							|  |  |  |     print(nickname + '@' + domain + ' has ' + str(noOfPosts) + | 
					
						
							|  |  |  |           ' in ' + boxname) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-03 10:31:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def getPublicPostsOfPerson(baseDir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-06-09 11:03:59 +00:00
										 |  |  |                            raw: bool, simple: bool, proxyType: str, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                            port: int, httpPrefix: str, | 
					
						
							|  |  |  |                            debug: bool, projectVersion: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-07-03 10:31:02 +00:00
										 |  |  |     """ This is really just for test purposes
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-06-24 09:04:58 +00:00
										 |  |  |     print('Starting new session for getting public posts') | 
					
						
							| 
									
										
										
										
											2020-06-09 11:03:59 +00:00
										 |  |  |     session = createSession(proxyType) | 
					
						
							| 
									
										
										
										
											2020-06-08 20:22:18 +00:00
										 |  |  |     if not session: | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     personCache = {} | 
					
						
							|  |  |  |     cachedWebfingers = {} | 
					
						
							|  |  |  |     federationList = [] | 
					
						
							| 
									
										
										
										
											2019-07-03 10:31:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     domainFull = domain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 domainFull = domain + ':' + str(port) | 
					
						
							|  |  |  |     handle = httpPrefix + "://" + domainFull + "/@" + nickname | 
					
						
							|  |  |  |     wfRequest = \ | 
					
						
							|  |  |  |         webfingerHandle(session, handle, httpPrefix, cachedWebfingers, | 
					
						
							|  |  |  |                         domain, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-07-03 10:31:02 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         sys.exit() | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:12 +00:00
										 |  |  |     if not isinstance(wfRequest, dict): | 
					
						
							|  |  |  |         print('Webfinger for ' + handle + ' did not return a dict. ' + | 
					
						
							|  |  |  |               str(wfRequest)) | 
					
						
							|  |  |  |         sys.exit() | 
					
						
							| 
									
										
										
										
											2019-07-03 10:31:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     (personUrl, pubKeyId, pubKey, | 
					
						
							|  |  |  |      personId, shaedInbox, | 
					
						
							|  |  |  |      avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, | 
					
						
							|  |  |  |                                             personCache, | 
					
						
							|  |  |  |                                             projectVersion, httpPrefix, | 
					
						
							|  |  |  |                                             nickname, domain, 'outbox') | 
					
						
							|  |  |  |     maxMentions = 10 | 
					
						
							|  |  |  |     maxEmoji = 10 | 
					
						
							|  |  |  |     maxAttachments = 5 | 
					
						
							|  |  |  |     getPosts(session, personUrl, 30, maxMentions, maxEmoji, | 
					
						
							|  |  |  |              maxAttachments, federationList, | 
					
						
							|  |  |  |              personCache, raw, simple, debug, | 
					
						
							|  |  |  |              projectVersion, httpPrefix, domain) | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-25 10:05:23 +00:00
										 |  |  | def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-07-08 12:28:41 +00:00
										 |  |  |                          proxyType: str, port: int, httpPrefix: str, | 
					
						
							| 
									
										
										
										
											2020-07-08 10:30:29 +00:00
										 |  |  |                          debug: bool, projectVersion: str, | 
					
						
							|  |  |  |                          domainList=[]) -> []: | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |     """ Returns a list of domains referenced within public posts
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-09-25 10:05:23 +00:00
										 |  |  |     if not session: | 
					
						
							|  |  |  |         session = createSession(proxyType) | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |     if not session: | 
					
						
							| 
									
										
										
										
											2020-07-08 10:30:29 +00:00
										 |  |  |         return domainList | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |     personCache = {} | 
					
						
							|  |  |  |     cachedWebfingers = {} | 
					
						
							|  |  |  |     federationList = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     domainFull = domain | 
					
						
							|  |  |  |     if port: | 
					
						
							|  |  |  |         if port != 80 and port != 443: | 
					
						
							|  |  |  |             if ':' not in domain: | 
					
						
							|  |  |  |                 domainFull = domain + ':' + str(port) | 
					
						
							|  |  |  |     handle = httpPrefix + "://" + domainFull + "/@" + nickname | 
					
						
							|  |  |  |     wfRequest = \ | 
					
						
							|  |  |  |         webfingerHandle(session, handle, httpPrefix, cachedWebfingers, | 
					
						
							|  |  |  |                         domain, projectVersion) | 
					
						
							|  |  |  |     if not wfRequest: | 
					
						
							| 
									
										
										
										
											2020-07-08 10:30:29 +00:00
										 |  |  |         return domainList | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |     if not isinstance(wfRequest, dict): | 
					
						
							|  |  |  |         print('Webfinger for ' + handle + ' did not return a dict. ' + | 
					
						
							|  |  |  |               str(wfRequest)) | 
					
						
							| 
									
										
										
										
											2020-07-08 10:30:29 +00:00
										 |  |  |         return domainList | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     (personUrl, pubKeyId, pubKey, | 
					
						
							| 
									
										
										
										
											2020-09-25 13:09:20 +00:00
										 |  |  |      personId, sharedInbox, | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |      avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, | 
					
						
							|  |  |  |                                             personCache, | 
					
						
							|  |  |  |                                             projectVersion, httpPrefix, | 
					
						
							|  |  |  |                                             nickname, domain, 'outbox') | 
					
						
							|  |  |  |     maxMentions = 99 | 
					
						
							|  |  |  |     maxEmoji = 99 | 
					
						
							|  |  |  |     maxAttachments = 5 | 
					
						
							|  |  |  |     postDomains = \ | 
					
						
							| 
									
										
										
										
											2020-07-08 10:30:29 +00:00
										 |  |  |         getPostDomains(session, personUrl, 64, maxMentions, maxEmoji, | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |                        maxAttachments, federationList, | 
					
						
							| 
									
										
										
										
											2020-07-08 12:28:41 +00:00
										 |  |  |                        personCache, debug, | 
					
						
							| 
									
										
										
										
											2020-07-08 10:30:29 +00:00
										 |  |  |                        projectVersion, httpPrefix, domain, domainList) | 
					
						
							| 
									
										
										
										
											2020-07-08 10:09:51 +00:00
										 |  |  |     postDomains.sort() | 
					
						
							|  |  |  |     return postDomains | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-25 10:05:23 +00:00
										 |  |  | def getPublicPostDomainsBlocked(session, baseDir: str, | 
					
						
							|  |  |  |                                 nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-09-25 09:52:13 +00:00
										 |  |  |                                 proxyType: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |                                 debug: bool, projectVersion: str, | 
					
						
							|  |  |  |                                 domainList=[]) -> []: | 
					
						
							|  |  |  |     """ Returns a list of domains referenced within public posts which
 | 
					
						
							|  |  |  |     are globally blocked on this instance | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     postDomains = \ | 
					
						
							| 
									
										
										
										
											2020-09-25 10:05:23 +00:00
										 |  |  |         getPublicPostDomains(session, baseDir, nickname, domain, | 
					
						
							| 
									
										
										
										
											2020-09-25 09:52:13 +00:00
										 |  |  |                              proxyType, port, httpPrefix, | 
					
						
							|  |  |  |                              debug, projectVersion, | 
					
						
							|  |  |  |                              domainList) | 
					
						
							|  |  |  |     if not postDomains: | 
					
						
							|  |  |  |         return [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     blockingFilename = baseDir + '/accounts/blocking.txt' | 
					
						
							|  |  |  |     if not os.path.isfile(blockingFilename): | 
					
						
							|  |  |  |         return [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # read the blocked domains as a single string | 
					
						
							|  |  |  |     blockedStr = '' | 
					
						
							|  |  |  |     with open(blockingFilename, 'r') as fp: | 
					
						
							|  |  |  |         blockedStr = fp.read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     blockedDomains = [] | 
					
						
							|  |  |  |     for domainName in postDomains: | 
					
						
							|  |  |  |         if '@' not in domainName: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         # get the domain after the @ | 
					
						
							|  |  |  |         domainName = domainName.split('@')[1].strip() | 
					
						
							| 
									
										
										
										
											2020-09-25 10:12:36 +00:00
										 |  |  |         if isEvil(domainName): | 
					
						
							|  |  |  |             blockedDomains.append(domainName) | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2020-09-25 09:52:13 +00:00
										 |  |  |         if domainName in blockedStr: | 
					
						
							|  |  |  |             blockedDomains.append(domainName) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return blockedDomains | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  | def getNonMutualsOfPerson(baseDir: str, | 
					
						
							|  |  |  |                           nickname: str, domain: str) -> []: | 
					
						
							|  |  |  |     """Returns the followers who are not mutuals of a person
 | 
					
						
							|  |  |  |     i.e. accounts which follow you but you don't follow them | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     followers = \ | 
					
						
							| 
									
										
										
										
											2020-09-25 14:14:59 +00:00
										 |  |  |         getFollowersList(baseDir, nickname, domain, 'followers.txt') | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |     following = \ | 
					
						
							| 
									
										
										
										
											2020-09-25 14:14:59 +00:00
										 |  |  |         getFollowersList(baseDir, nickname, domain, 'following.txt') | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |     nonMutuals = [] | 
					
						
							| 
									
										
										
										
											2020-09-25 14:33:20 +00:00
										 |  |  |     for handle in followers: | 
					
						
							|  |  |  |         if handle not in following: | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |             nonMutuals.append(handle) | 
					
						
							|  |  |  |     return nonMutuals | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def checkDomains(session, baseDir: str, | 
					
						
							|  |  |  |                  nickname: str, domain: str, | 
					
						
							|  |  |  |                  proxyType: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |                  debug: bool, projectVersion: str, | 
					
						
							|  |  |  |                  maxBlockedDomains: int, singleCheck: bool): | 
					
						
							|  |  |  |     """Checks follower accounts for references to globally blocked domains
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     nonMutuals = getNonMutualsOfPerson(baseDir, nickname, domain) | 
					
						
							|  |  |  |     if not nonMutuals: | 
					
						
							| 
									
										
										
										
											2020-09-25 13:33:44 +00:00
										 |  |  |         print('No non-mutual followers were found') | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |         return | 
					
						
							|  |  |  |     followerWarningFilename = baseDir + '/accounts/followerWarnings.txt' | 
					
						
							|  |  |  |     updateFollowerWarnings = False | 
					
						
							|  |  |  |     followerWarningStr = '' | 
					
						
							|  |  |  |     if os.path.isfile(followerWarningFilename): | 
					
						
							|  |  |  |         with open(followerWarningFilename, 'r') as fp: | 
					
						
							|  |  |  |             followerWarningStr = fp.read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if singleCheck: | 
					
						
							|  |  |  |         # checks a single random non-mutual | 
					
						
							|  |  |  |         index = random.randrange(0, len(nonMutuals)) | 
					
						
							| 
									
										
										
										
											2020-09-25 14:23:33 +00:00
										 |  |  |         handle = nonMutuals[index] | 
					
						
							|  |  |  |         if '@' in handle: | 
					
						
							|  |  |  |             nonMutualNickname = handle.split('@')[0] | 
					
						
							|  |  |  |             nonMutualDomain = handle.split('@')[1].strip() | 
					
						
							|  |  |  |             blockedDomains = \ | 
					
						
							|  |  |  |                 getPublicPostDomainsBlocked(session, baseDir, | 
					
						
							|  |  |  |                                             nonMutualNickname, | 
					
						
							|  |  |  |                                             nonMutualDomain, | 
					
						
							|  |  |  |                                             proxyType, port, httpPrefix, | 
					
						
							|  |  |  |                                             debug, projectVersion, []) | 
					
						
							|  |  |  |             if blockedDomains: | 
					
						
							|  |  |  |                 if len(blockedDomains) > maxBlockedDomains: | 
					
						
							|  |  |  |                     followerWarningStr += handle + '\n' | 
					
						
							|  |  |  |                     updateFollowerWarnings = True | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         # checks all non-mutuals | 
					
						
							| 
									
										
										
										
											2020-09-25 14:23:33 +00:00
										 |  |  |         for handle in nonMutuals: | 
					
						
							|  |  |  |             if '@' not in handle: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if handle in followerWarningStr: | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2020-09-25 14:23:33 +00:00
										 |  |  |             nonMutualNickname = handle.split('@')[0] | 
					
						
							|  |  |  |             nonMutualDomain = handle.split('@')[1].strip() | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |             blockedDomains = \ | 
					
						
							|  |  |  |                 getPublicPostDomainsBlocked(session, baseDir, | 
					
						
							| 
									
										
										
										
											2020-09-25 14:23:33 +00:00
										 |  |  |                                             nonMutualNickname, | 
					
						
							|  |  |  |                                             nonMutualDomain, | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |                                             proxyType, port, httpPrefix, | 
					
						
							|  |  |  |                                             debug, projectVersion, []) | 
					
						
							|  |  |  |             if blockedDomains: | 
					
						
							| 
									
										
										
										
											2020-09-25 14:23:33 +00:00
										 |  |  |                 print(handle) | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |                 for d in blockedDomains: | 
					
						
							|  |  |  |                     print('  ' + d) | 
					
						
							|  |  |  |                 if len(blockedDomains) > maxBlockedDomains: | 
					
						
							| 
									
										
										
										
											2020-09-25 14:23:33 +00:00
										 |  |  |                     followerWarningStr += handle + '\n' | 
					
						
							| 
									
										
										
										
											2020-09-25 13:21:56 +00:00
										 |  |  |                     updateFollowerWarnings = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if updateFollowerWarnings and followerWarningStr: | 
					
						
							|  |  |  |         with open(followerWarningFilename, 'w+') as fp: | 
					
						
							|  |  |  |             fp.write(followerWarningStr) | 
					
						
							|  |  |  |         if not singleCheck: | 
					
						
							|  |  |  |             print(followerWarningStr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def populateRepliesJson(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                         postRepliesFilename: str, authorized: bool, | 
					
						
							| 
									
										
										
										
											2019-09-28 11:29:42 +00:00
										 |  |  |                         repliesJson: {}) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     pubStr = 'https://www.w3.org/ns/activitystreams#Public' | 
					
						
							| 
									
										
										
										
											2019-08-02 18:37:23 +00:00
										 |  |  |     # populate the items list with replies | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     repliesBoxes = ('outbox', 'inbox') | 
					
						
							|  |  |  |     with open(postRepliesFilename, 'r') as repliesFile: | 
					
						
							| 
									
										
										
										
											2019-08-02 18:37:23 +00:00
										 |  |  |         for messageId in repliesFile: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             replyFound = False | 
					
						
							| 
									
										
										
										
											2019-08-02 18:37:23 +00:00
										 |  |  |             # examine inbox and outbox | 
					
						
							|  |  |  |             for boxname in repliesBoxes: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                 messageId2 = messageId.replace('\n', '').replace('\r', '') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 searchFilename = \ | 
					
						
							|  |  |  |                     baseDir + \ | 
					
						
							|  |  |  |                     '/accounts/' + nickname + '@' + \ | 
					
						
							|  |  |  |                     domain+'/' + \ | 
					
						
							|  |  |  |                     boxname+'/' + \ | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                     messageId2.replace('/', '#') + '.json' | 
					
						
							| 
									
										
										
										
											2019-08-02 18:37:23 +00:00
										 |  |  |                 if os.path.isfile(searchFilename): | 
					
						
							|  |  |  |                     if authorized or \ | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        pubStr in open(searchFilename).read(): | 
					
						
							|  |  |  |                         postJsonObject = loadJson(searchFilename) | 
					
						
							| 
									
										
										
										
											2019-10-22 11:55:06 +00:00
										 |  |  |                         if postJsonObject: | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |                             if postJsonObject['object'].get('cc'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                 pjo = postJsonObject | 
					
						
							|  |  |  |                                 if (authorized or | 
					
						
							|  |  |  |                                     (pubStr in pjo['object']['to'] or | 
					
						
							|  |  |  |                                      pubStr in pjo['object']['cc'])): | 
					
						
							|  |  |  |                                     repliesJson['orderedItems'].append(pjo) | 
					
						
							|  |  |  |                                     replyFound = True | 
					
						
							| 
									
										
										
										
											2019-08-02 18:37:23 +00:00
										 |  |  |                             else: | 
					
						
							|  |  |  |                                 if authorized or \ | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                    pubStr in postJsonObject['object']['to']: | 
					
						
							|  |  |  |                                     pjo = postJsonObject | 
					
						
							|  |  |  |                                     repliesJson['orderedItems'].append(pjo) | 
					
						
							|  |  |  |                                     replyFound = True | 
					
						
							| 
									
										
										
										
											2019-08-02 18:37:23 +00:00
										 |  |  |                     break | 
					
						
							|  |  |  |             # if not in either inbox or outbox then examine the shared inbox | 
					
						
							|  |  |  |             if not replyFound: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                 messageId2 = messageId.replace('\n', '').replace('\r', '') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 searchFilename = \ | 
					
						
							|  |  |  |                     baseDir + \ | 
					
						
							|  |  |  |                     '/accounts/inbox@' + \ | 
					
						
							|  |  |  |                     domain+'/inbox/' + \ | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |                     messageId2.replace('/', '#') + '.json' | 
					
						
							| 
									
										
										
										
											2019-08-02 18:37:23 +00:00
										 |  |  |                 if os.path.isfile(searchFilename): | 
					
						
							|  |  |  |                     if authorized or \ | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                        pubStr in open(searchFilename).read(): | 
					
						
							|  |  |  |                         # get the json of the reply and append it to | 
					
						
							|  |  |  |                         # the collection | 
					
						
							|  |  |  |                         postJsonObject = loadJson(searchFilename) | 
					
						
							| 
									
										
										
										
											2019-10-22 11:55:06 +00:00
										 |  |  |                         if postJsonObject: | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |                             if postJsonObject['object'].get('cc'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                 pjo = postJsonObject | 
					
						
							|  |  |  |                                 if (authorized or | 
					
						
							|  |  |  |                                     (pubStr in pjo['object']['to'] or | 
					
						
							|  |  |  |                                      pubStr in pjo['object']['cc'])): | 
					
						
							|  |  |  |                                     pjo = postJsonObject | 
					
						
							|  |  |  |                                     repliesJson['orderedItems'].append(pjo) | 
					
						
							| 
									
										
										
										
											2019-08-02 18:37:23 +00:00
										 |  |  |                             else: | 
					
						
							|  |  |  |                                 if authorized or \ | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                                    pubStr in postJsonObject['object']['to']: | 
					
						
							|  |  |  |                                     pjo = postJsonObject | 
					
						
							|  |  |  |                                     repliesJson['orderedItems'].append(pjo) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-28 16:58:21 +00:00
										 |  |  | def rejectAnnounce(announceFilename: str): | 
					
						
							|  |  |  |     """Marks an announce as rejected
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if not os.path.isfile(announceFilename + '.reject'): | 
					
						
							|  |  |  |         rejectAnnounceFile = open(announceFilename + '.reject', "w+") | 
					
						
							| 
									
										
										
										
											2020-10-14 09:35:14 +00:00
										 |  |  |         if rejectAnnounceFile: | 
					
						
							|  |  |  |             rejectAnnounceFile.write('\n') | 
					
						
							|  |  |  |             rejectAnnounceFile.close() | 
					
						
							| 
									
										
										
										
											2019-09-28 16:58:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def downloadAnnounce(session, baseDir: str, httpPrefix: str, | 
					
						
							|  |  |  |                      nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2020-06-12 11:50:49 +00:00
										 |  |  |                      postJsonObject: {}, projectVersion: str, | 
					
						
							| 
									
										
										
										
											2020-08-02 09:51:20 +00:00
										 |  |  |                      translate: {}, YTReplacementDomain: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |     """Download the post referenced by an announce
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not postJsonObject.get('object'): | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     if not isinstance(postJsonObject['object'], str): | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # get the announced post | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     announceCacheDir = baseDir + '/cache/announce/' + nickname | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |     if not os.path.isdir(announceCacheDir): | 
					
						
							|  |  |  |         os.mkdir(announceCacheDir) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     announceFilename = \ | 
					
						
							|  |  |  |         announceCacheDir + '/' + \ | 
					
						
							|  |  |  |         postJsonObject['object'].replace('/', '#') + '.json' | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     if os.path.isfile(announceFilename + '.reject'): | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if os.path.isfile(announceFilename): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         print('Reading cached Announce content for ' + | 
					
						
							|  |  |  |               postJsonObject['object']) | 
					
						
							|  |  |  |         postJsonObject = loadJson(announceFilename) | 
					
						
							| 
									
										
										
										
											2019-10-22 11:55:06 +00:00
										 |  |  |         if postJsonObject: | 
					
						
							|  |  |  |             return postJsonObject | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         profileStr = 'https://www.w3.org/ns/activitystreams' | 
					
						
							|  |  |  |         asHeader = { | 
					
						
							|  |  |  |             'Accept': 'application/activity+json; profile="' + profileStr + '"' | 
					
						
							| 
									
										
										
										
											2020-03-31 11:07:58 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-13 16:19:35 +00:00
										 |  |  |         if '/channel/' in postJsonObject['actor'] or \ | 
					
						
							|  |  |  |            '/accounts/' in postJsonObject['actor']: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             asHeader = { | 
					
						
							|  |  |  |                 'Accept': 'application/ld+json; profile="' + profileStr + '"' | 
					
						
							| 
									
										
										
										
											2020-03-31 11:07:58 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         actorNickname = getNicknameFromActor(postJsonObject['actor']) | 
					
						
							|  |  |  |         actorDomain, actorPort = getDomainFromActor(postJsonObject['actor']) | 
					
						
							| 
									
										
										
										
											2020-03-01 10:06:55 +00:00
										 |  |  |         if not actorDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('Announce actor does not contain a ' + | 
					
						
							|  |  |  |                   'valid domain or port number: ' + | 
					
						
							| 
									
										
										
										
											2020-03-01 10:06:55 +00:00
										 |  |  |                   str(postJsonObject['actor'])) | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if isBlocked(baseDir, nickname, domain, actorNickname, actorDomain): | 
					
						
							|  |  |  |             print('Announce download blocked actor: ' + | 
					
						
							|  |  |  |                   actorNickname + '@' + actorDomain) | 
					
						
							| 
									
										
										
										
											2020-01-18 10:39:51 +00:00
										 |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         objectNickname = getNicknameFromActor(postJsonObject['object']) | 
					
						
							|  |  |  |         objectDomain, objectPort = getDomainFromActor(postJsonObject['object']) | 
					
						
							| 
									
										
										
										
											2020-03-01 10:06:55 +00:00
										 |  |  |         if not objectDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('Announce object does not contain a ' + | 
					
						
							|  |  |  |                   'valid domain or port number: ' + | 
					
						
							| 
									
										
										
										
											2020-03-01 10:06:55 +00:00
										 |  |  |                   str(postJsonObject['object'])) | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if isBlocked(baseDir, nickname, domain, objectNickname, objectDomain): | 
					
						
							| 
									
										
										
										
											2020-02-19 18:55:29 +00:00
										 |  |  |             if objectNickname and objectDomain: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print('Announce download blocked object: ' + | 
					
						
							|  |  |  |                       objectNickname + '@' + objectDomain) | 
					
						
							| 
									
										
										
										
											2020-02-19 18:55:29 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print('Announce download blocked object: ' + | 
					
						
							| 
									
										
										
										
											2020-03-31 11:07:58 +00:00
										 |  |  |                       str(postJsonObject['object'])) | 
					
						
							| 
									
										
										
										
											2020-02-05 11:46:05 +00:00
										 |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         print('Downloading Announce content for ' + postJsonObject['object']) | 
					
						
							|  |  |  |         announcedJson = \ | 
					
						
							|  |  |  |             getJson(session, postJsonObject['object'], asHeader, | 
					
						
							|  |  |  |                     None, projectVersion, httpPrefix, domain) | 
					
						
							| 
									
										
										
										
											2020-01-19 20:19:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |         if not announcedJson: | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2019-12-04 09:44:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if not isinstance(announcedJson, dict): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('WARN: announce json is not a dict - ' + | 
					
						
							| 
									
										
										
										
											2020-03-31 11:07:58 +00:00
										 |  |  |                   postJsonObject['object']) | 
					
						
							| 
									
										
										
										
											2019-12-04 09:47:35 +00:00
										 |  |  |             rejectAnnounce(announceFilename) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |             return None | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |         if not announcedJson.get('id'): | 
					
						
							|  |  |  |             rejectAnnounce(announceFilename) | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         if '/statuses/' not in announcedJson['id']: | 
					
						
							|  |  |  |             rejectAnnounce(announceFilename) | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2019-10-17 22:26:47 +00:00
										 |  |  |         if '/users/' not in announcedJson['id'] and \ | 
					
						
							| 
									
										
										
										
											2020-08-13 16:19:35 +00:00
										 |  |  |            '/accounts/' not in announcedJson['id'] and \ | 
					
						
							| 
									
										
										
										
											2019-10-17 22:26:47 +00:00
										 |  |  |            '/channel/' not in announcedJson['id'] and \ | 
					
						
							|  |  |  |            '/profile/' not in announcedJson['id']: | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |             rejectAnnounce(announceFilename) | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         if not announcedJson.get('type'): | 
					
						
							|  |  |  |             rejectAnnounce(announceFilename) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             # pprint(announcedJson) | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if announcedJson['type'] != 'Note' and \ | 
					
						
							|  |  |  |            announcedJson['type'] != 'Article': | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |             rejectAnnounce(announceFilename) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             # pprint(announcedJson) | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-02-05 14:57:10 +00:00
										 |  |  |         if not announcedJson.get('content'): | 
					
						
							|  |  |  |             rejectAnnounce(announceFilename) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if isFiltered(baseDir, nickname, domain, announcedJson['content']): | 
					
						
							| 
									
										
										
										
											2020-02-05 14:57:10 +00:00
										 |  |  |             rejectAnnounce(announceFilename) | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-05-17 09:44:42 +00:00
										 |  |  |         # remove any long words | 
					
						
							|  |  |  |         announcedJson['content'] = \ | 
					
						
							|  |  |  |             removeLongWords(announcedJson['content'], 40, []) | 
					
						
							| 
									
										
										
										
											2020-01-19 20:19:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-14 13:25:38 +00:00
										 |  |  |         # remove text formatting, such as bold/italics | 
					
						
							|  |  |  |         announcedJson['content'] = \ | 
					
						
							|  |  |  |             removeTextFormatting(announcedJson['content']) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |         # wrap in create to be consistent with other posts | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         announcedJson = \ | 
					
						
							|  |  |  |             outboxMessageCreateWrap(httpPrefix, | 
					
						
							|  |  |  |                                     actorNickname, actorDomain, actorPort, | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |                                     announcedJson) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if announcedJson['type'] != 'Create': | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |             rejectAnnounce(announceFilename) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             # pprint(announcedJson) | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 20:29:17 +00:00
										 |  |  |         # labelAccusatoryPost(postJsonObject, translate) | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |         # set the id to the original status | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         announcedJson['id'] = postJsonObject['object'] | 
					
						
							|  |  |  |         announcedJson['object']['id'] = postJsonObject['object'] | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |         # check that the repeat isn't for a blocked account | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         attributedNickname = \ | 
					
						
							| 
									
										
										
										
											2019-12-12 09:58:06 +00:00
										 |  |  |             getNicknameFromActor(announcedJson['object']['id']) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         attributedDomain, attributedPort = \ | 
					
						
							| 
									
										
										
										
											2019-12-12 09:58:06 +00:00
										 |  |  |             getDomainFromActor(announcedJson['object']['id']) | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |         if attributedNickname and attributedDomain: | 
					
						
							|  |  |  |             if attributedPort: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 if attributedPort != 80 and attributedPort != 443: | 
					
						
							|  |  |  |                     attributedDomain = \ | 
					
						
							|  |  |  |                         attributedDomain + ':' + str(attributedPort) | 
					
						
							|  |  |  |             if isBlocked(baseDir, nickname, domain, | 
					
						
							|  |  |  |                          attributedNickname, attributedDomain): | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |                 rejectAnnounce(announceFilename) | 
					
						
							|  |  |  |                 return None | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postJsonObject = announcedJson | 
					
						
							| 
									
										
										
										
											2020-08-02 09:51:20 +00:00
										 |  |  |         replaceYouTube(postJsonObject, YTReplacementDomain) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         if saveJson(postJsonObject, announceFilename): | 
					
						
							| 
									
										
										
										
											2019-10-22 11:55:06 +00:00
										 |  |  |             return postJsonObject | 
					
						
							| 
									
										
										
										
											2019-09-28 16:10:45 +00:00
										 |  |  |     return None | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-27 17:40:09 +00:00
										 |  |  | def isMuted(baseDir: str, nickname: str, domain: str, postId: str) -> bool: | 
					
						
							|  |  |  |     """Returns true if the given post is muted
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     postFilename = locatePost(baseDir, nickname, domain, postId) | 
					
						
							|  |  |  |     if not postFilename: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if os.path.isfile(postFilename + '.muted'): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def mutePost(baseDir: str, nickname: str, domain: str, postId: str, | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  |              recentPostsCache: {}) -> None: | 
					
						
							|  |  |  |     """ Mutes the given post
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postFilename = locatePost(baseDir, nickname, domain, postId) | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  |     if not postFilename: | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postJsonObject = loadJson(postFilename) | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  |     if not postJsonObject: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-31 09:38:23 +00:00
										 |  |  |     # remove cached post so that the muted version gets recreated | 
					
						
							|  |  |  |     # without its content text and/or image | 
					
						
							| 
									
										
										
										
											2020-08-31 09:05:20 +00:00
										 |  |  |     cachedPostFilename = \ | 
					
						
							|  |  |  |         getCachedPostFilename(baseDir, nickname, domain, postJsonObject) | 
					
						
							|  |  |  |     if cachedPostFilename: | 
					
						
							| 
									
										
										
										
											2020-08-31 09:38:23 +00:00
										 |  |  |         if os.path.isfile(cachedPostFilename): | 
					
						
							|  |  |  |             os.remove(cachedPostFilename) | 
					
						
							| 
									
										
										
										
											2020-08-31 09:05:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-29 11:14:19 +00:00
										 |  |  |     muteFile = open(postFilename + '.muted', 'w+') | 
					
						
							| 
									
										
										
										
											2019-12-01 14:03:18 +00:00
										 |  |  |     if muteFile: | 
					
						
							|  |  |  |         muteFile.write('\n') | 
					
						
							|  |  |  |         muteFile.close() | 
					
						
							| 
									
										
										
										
											2020-08-31 09:16:49 +00:00
										 |  |  |         print('MUTE: ' + postFilename + '.muted file added') | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-01 14:34:10 +00:00
										 |  |  |     # if the post is in the recent posts cache then mark it as muted | 
					
						
							| 
									
										
										
										
											2019-12-01 14:43:09 +00:00
										 |  |  |     if recentPostsCache.get('index'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |         postId = \ | 
					
						
							| 
									
										
										
										
											2020-08-23 11:13:35 +00:00
										 |  |  |             removeIdEnding(postJsonObject['id']).replace('/', '#') | 
					
						
							| 
									
										
										
										
											2019-12-01 14:43:09 +00:00
										 |  |  |         if postId in recentPostsCache['index']: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |             print('MUTE: ' + postId + ' is in recent posts cache') | 
					
						
							| 
									
										
										
										
											2019-12-01 14:43:09 +00:00
										 |  |  |             if recentPostsCache['json'].get(postId): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 postJsonObject['muted'] = True | 
					
						
							|  |  |  |                 recentPostsCache['json'][postId] = json.dumps(postJsonObject) | 
					
						
							| 
									
										
										
										
											2020-08-31 09:05:20 +00:00
										 |  |  |                 if recentPostsCache.get('html'): | 
					
						
							|  |  |  |                     if recentPostsCache['html'].get(postId): | 
					
						
							| 
									
										
										
										
											2020-08-31 09:58:29 +00:00
										 |  |  |                         del recentPostsCache['html'][postId] | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |                 print('MUTE: ' + postId + | 
					
						
							| 
									
										
										
										
											2020-08-31 09:16:49 +00:00
										 |  |  |                       ' marked as muted in recent posts memory cache') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  | def unmutePost(baseDir: str, nickname: str, domain: str, postId: str, | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  |                recentPostsCache: {}) -> None: | 
					
						
							|  |  |  |     """ Unmutes the given post
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postFilename = locatePost(baseDir, nickname, domain, postId) | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  |     if not postFilename: | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     postJsonObject = loadJson(postFilename) | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  |     if not postJsonObject: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     muteFilename = postFilename + '.muted' | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  |     if os.path.isfile(muteFilename): | 
					
						
							|  |  |  |         os.remove(muteFilename) | 
					
						
							| 
									
										
										
										
											2020-08-31 09:16:49 +00:00
										 |  |  |         print('UNMUTE: ' + muteFilename + ' file removed') | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-31 09:38:23 +00:00
										 |  |  |     # remove cached post so that the muted version gets recreated | 
					
						
							|  |  |  |     # with its content text and/or image | 
					
						
							| 
									
										
										
										
											2020-04-04 10:05:27 +00:00
										 |  |  |     cachedPostFilename = \ | 
					
						
							|  |  |  |         getCachedPostFilename(baseDir, nickname, domain, postJsonObject) | 
					
						
							| 
									
										
										
										
											2019-12-01 13:45:30 +00:00
										 |  |  |     if cachedPostFilename: | 
					
						
							| 
									
										
										
										
											2020-08-31 09:38:23 +00:00
										 |  |  |         if os.path.isfile(cachedPostFilename): | 
					
						
							|  |  |  |             os.remove(cachedPostFilename) | 
					
						
							| 
									
										
										
										
											2020-08-31 09:05:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-31 10:02:45 +00:00
										 |  |  |     # if the post is in the recent posts cache then mark it as unmuted | 
					
						
							| 
									
										
										
										
											2020-08-31 09:05:20 +00:00
										 |  |  |     if recentPostsCache.get('index'): | 
					
						
							|  |  |  |         postId = \ | 
					
						
							|  |  |  |             removeIdEnding(postJsonObject['id']).replace('/', '#') | 
					
						
							|  |  |  |         if postId in recentPostsCache['index']: | 
					
						
							|  |  |  |             print('UNMUTE: ' + postId + ' is in recent posts cache') | 
					
						
							|  |  |  |             if recentPostsCache['json'].get(postId): | 
					
						
							|  |  |  |                 postJsonObject['muted'] = False | 
					
						
							|  |  |  |                 recentPostsCache['json'][postId] = json.dumps(postJsonObject) | 
					
						
							|  |  |  |                 if recentPostsCache.get('html'): | 
					
						
							|  |  |  |                     if recentPostsCache['html'].get(postId): | 
					
						
							| 
									
										
										
										
											2020-08-31 09:58:29 +00:00
										 |  |  |                         del recentPostsCache['html'][postId] | 
					
						
							| 
									
										
										
										
											2020-08-31 09:05:20 +00:00
										 |  |  |                 print('UNMUTE: ' + postId + | 
					
						
							|  |  |  |                       ' marked as unmuted in recent posts cache') | 
					
						
							| 
									
										
										
										
											2020-04-01 20:13:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def sendBlockViaServer(baseDir: str, session, | 
					
						
							|  |  |  |                        fromNickname: str, password: str, | 
					
						
							|  |  |  |                        fromDomain: str, fromPort: int, | 
					
						
							|  |  |  |                        httpPrefix: str, blockedUrl: str, | 
					
						
							|  |  |  |                        cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                        debug: bool, projectVersion: str) -> {}: | 
					
						
							|  |  |  |     """Creates a block via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendBlockViaServer') | 
					
						
							|  |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fromDomainFull = fromDomain | 
					
						
							|  |  |  |     if fromPort: | 
					
						
							|  |  |  |         if fromPort != 80 and fromPort != 443: | 
					
						
							|  |  |  |             if ':' not in fromDomain: | 
					
						
							|  |  |  |                 fromDomainFull = fromDomain + ':' + str(fromPort) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     toUrl = 'https://www.w3.org/ns/activitystreams#Public' | 
					
						
							|  |  |  |     ccUrl = httpPrefix + '://' + fromDomainFull + '/users/' + \ | 
					
						
							|  |  |  |         fromNickname + '/followers' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     blockActor = httpPrefix + '://' + fromDomainFull + '/users/' + fromNickname | 
					
						
							|  |  |  |     newBlockJson = { | 
					
						
							|  |  |  |         "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							|  |  |  |         'type': 'Block', | 
					
						
							|  |  |  |         'actor': blockActor, | 
					
						
							|  |  |  |         'object': blockedUrl, | 
					
						
							|  |  |  |         'to': [toUrl], | 
					
						
							|  |  |  |         'cc': [ccUrl] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							|  |  |  |     wfRequest = webfingerHandle(session, handle, httpPrefix, | 
					
						
							|  |  |  |                                 cachedWebfingers, | 
					
						
							|  |  |  |                                 fromDomain, projectVersion) | 
					
						
							|  |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: announce webfinger failed for ' + handle) | 
					
						
							|  |  |  |         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 | 
					
						
							| 
									
										
										
										
											2020-04-01 20:13:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     postToBox = 'outbox' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							|  |  |  |     (inboxUrl, pubKeyId, pubKey, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |      fromPersonId, sharedInbox, avatarUrl, | 
					
						
							| 
									
										
										
										
											2020-04-01 20:13:42 +00:00
										 |  |  |      displayName) = getPersonBox(baseDir, session, wfRequest, | 
					
						
							|  |  |  |                                  personCache, | 
					
						
							|  |  |  |                                  projectVersion, httpPrefix, fromNickname, | 
					
						
							|  |  |  |                                  fromDomain, postToBox) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: No ' + postToBox + ' was found for ' + handle) | 
					
						
							|  |  |  |         return 3 | 
					
						
							|  |  |  |     if not fromPersonId: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: No actor was found for ' + handle) | 
					
						
							|  |  |  |         return 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     authHeader = createBasicAuthHeader(fromNickname, password) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     headers = { | 
					
						
							|  |  |  |         'host': fromDomain, | 
					
						
							|  |  |  |         'Content-type': 'application/json', | 
					
						
							|  |  |  |         'Authorization': authHeader | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |     postResult = postJson(session, newBlockJson, [], inboxUrl, headers) | 
					
						
							| 
									
										
										
										
											2020-04-01 20:13:42 +00:00
										 |  |  |     if not postResult: | 
					
						
							|  |  |  |         print('WARN: Unable to post block') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST block success') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return newBlockJson | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def sendUndoBlockViaServer(baseDir: str, session, | 
					
						
							|  |  |  |                            fromNickname: str, password: str, | 
					
						
							|  |  |  |                            fromDomain: str, fromPort: int, | 
					
						
							|  |  |  |                            httpPrefix: str, blockedUrl: str, | 
					
						
							|  |  |  |                            cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                            debug: bool, projectVersion: str) -> {}: | 
					
						
							|  |  |  |     """Creates a block via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendBlockViaServer') | 
					
						
							|  |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fromDomainFull = fromDomain | 
					
						
							|  |  |  |     if fromPort: | 
					
						
							|  |  |  |         if fromPort != 80 and fromPort != 443: | 
					
						
							|  |  |  |             if ':' not in fromDomain: | 
					
						
							|  |  |  |                 fromDomainFull = fromDomain + ':' + str(fromPort) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     toUrl = 'https://www.w3.org/ns/activitystreams#Public' | 
					
						
							|  |  |  |     ccUrl = httpPrefix + '://' + fromDomainFull + '/users/' + \ | 
					
						
							|  |  |  |         fromNickname + '/followers' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     blockActor = httpPrefix + '://' + fromDomainFull + '/users/' + fromNickname | 
					
						
							|  |  |  |     newBlockJson = { | 
					
						
							|  |  |  |         "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							|  |  |  |         'type': 'Undo', | 
					
						
							|  |  |  |         'actor': blockActor, | 
					
						
							|  |  |  |         'object': { | 
					
						
							|  |  |  |             'type': 'Block', | 
					
						
							|  |  |  |             'actor': blockActor, | 
					
						
							|  |  |  |             'object': blockedUrl, | 
					
						
							|  |  |  |             'to': [toUrl], | 
					
						
							|  |  |  |             'cc': [ccUrl] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							|  |  |  |     wfRequest = webfingerHandle(session, handle, httpPrefix, | 
					
						
							|  |  |  |                                 cachedWebfingers, | 
					
						
							|  |  |  |                                 fromDomain, projectVersion) | 
					
						
							|  |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: announce webfinger failed for ' + handle) | 
					
						
							|  |  |  |         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 | 
					
						
							| 
									
										
										
										
											2020-04-01 20:13:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     postToBox = 'outbox' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							|  |  |  |     (inboxUrl, pubKeyId, pubKey, | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |      fromPersonId, sharedInbox, avatarUrl, | 
					
						
							| 
									
										
										
										
											2020-04-01 20:13:42 +00:00
										 |  |  |      displayName) = getPersonBox(baseDir, session, wfRequest, personCache, | 
					
						
							|  |  |  |                                  projectVersion, httpPrefix, fromNickname, | 
					
						
							|  |  |  |                                  fromDomain, postToBox) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: No ' + postToBox + ' was found for ' + handle) | 
					
						
							|  |  |  |         return 3 | 
					
						
							|  |  |  |     if not fromPersonId: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: No actor was found for ' + handle) | 
					
						
							|  |  |  |         return 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     authHeader = createBasicAuthHeader(fromNickname, password) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     headers = { | 
					
						
							|  |  |  |         'host': fromDomain, | 
					
						
							|  |  |  |         'Content-type': 'application/json', | 
					
						
							|  |  |  |         'Authorization': authHeader | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |     postResult = postJson(session, newBlockJson, [], inboxUrl, headers) | 
					
						
							| 
									
										
										
										
											2020-04-01 20:13:42 +00:00
										 |  |  |     if not postResult: | 
					
						
							|  |  |  |         print('WARN: Unable to post block') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST block success') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return newBlockJson | 
					
						
							| 
									
										
										
										
											2020-11-09 19:41:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def postIsMuted(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                 postJsonObject: {}, messageId: str) -> bool: | 
					
						
							|  |  |  |     """ Returns true if the given post is muted
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     isMuted = postJsonObject.get('muted') | 
					
						
							|  |  |  |     if isMuted is True or isMuted is False: | 
					
						
							|  |  |  |         return isMuted | 
					
						
							|  |  |  |     postDir = baseDir + '/accounts/' + nickname + '@' + domain | 
					
						
							|  |  |  |     muteFilename = \ | 
					
						
							|  |  |  |         postDir + '/inbox/' + messageId.replace('/', '#') + '.json.muted' | 
					
						
							|  |  |  |     if os.path.isfile(muteFilename): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     muteFilename = \ | 
					
						
							|  |  |  |         postDir + '/outbox/' + messageId.replace('/', '#') + '.json.muted' | 
					
						
							|  |  |  |     if os.path.isfile(muteFilename): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     muteFilename = \ | 
					
						
							|  |  |  |         baseDir + '/accounts/cache/announce/' + nickname + \ | 
					
						
							|  |  |  |         '/' + messageId.replace('/', '#') + '.json.muted' | 
					
						
							|  |  |  |     if os.path.isfile(muteFilename): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     return False |