diff --git a/acceptreject.py b/acceptreject.py index 6aa4fc3d0..8db41534c 100644 --- a/acceptreject.py +++ b/acceptreject.py @@ -7,6 +7,7 @@ __email__ = "bob@freedombone.net" __status__ = "Production" import os +from utils import hasUsersPath from utils import getFullDomain from utils import urlPermitted from utils import getDomainFromActor @@ -182,10 +183,7 @@ def receiveAcceptReject(session, baseDir: str, if debug: print('DEBUG: ' + messageJson['type'] + ' has no actor') return False - if '/users/' not in messageJson['actor'] and \ - '/accounts/' not in messageJson['actor'] and \ - '/channel/' not in messageJson['actor'] and \ - '/profile/' not in messageJson['actor']: + if not hasUsersPath(messageJson['actor']): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + messageJson['type'] + '. Assuming single user instance.') diff --git a/announce.py b/announce.py index 5364ba483..08b1bdd20 100644 --- a/announce.py +++ b/announce.py @@ -6,6 +6,7 @@ __maintainer__ = "Bob Mottram" __email__ = "bob@freedombone.net" __status__ = "Production" +from utils import hasUsersPath from utils import getFullDomain from utils import getStatusNumber from utils import createOutboxDir @@ -143,10 +144,7 @@ def createAnnounce(session, baseDir: str, federationList: [], announceNickname = None announceDomain = None announcePort = None - if '/users/' in objectUrl or \ - '/accounts/' in objectUrl or \ - '/channel/' in objectUrl or \ - '/profile/' in objectUrl: + if hasUsersPath(objectUrl): announceNickname = getNicknameFromActor(objectUrl) announceDomain, announcePort = getDomainFromActor(objectUrl) diff --git a/auth.py b/auth.py index 841141279..e0690a983 100644 --- a/auth.py +++ b/auth.py @@ -12,6 +12,7 @@ import binascii import os import secrets from utils import isSystemAccount +from utils import hasUsersPath def _hashPassword(password: str) -> str: @@ -89,10 +90,7 @@ def authorizeBasic(baseDir: str, path: str, authHeader: str, print('DEBUG: basic auth - Authorixation header does not ' + 'contain a space character') return False - if '/users/' not in path and \ - '/accounts/' not in path and \ - '/channel/' not in path and \ - '/profile/' not in path: + if not hasUsersPath(path): if debug: print('DEBUG: basic auth - ' + 'path for Authorization does not contain a user') diff --git a/blocking.py b/blocking.py index c34641fc2..6fa7af3dd 100644 --- a/blocking.py +++ b/blocking.py @@ -7,6 +7,7 @@ __email__ = "bob@freedombone.net" __status__ = "Production" import os +from utils import hasUsersPath from utils import getFullDomain from utils import removeIdEnding from utils import isEvil @@ -246,10 +247,7 @@ def outboxBlock(baseDir: str, httpPrefix: str, if debug: print('DEBUG: c2s block object is not a status') return - if '/users/' not in messageId and \ - '/accounts/' not in messageId and \ - '/channel/' not in messageId and \ - '/profile/' not in messageId: + if not hasUsersPath(messageId): if debug: print('DEBUG: c2s block object has no nickname') return @@ -321,10 +319,7 @@ def outboxUndoBlock(baseDir: str, httpPrefix: str, if debug: print('DEBUG: c2s undo block object is not a status') return - if '/users/' not in messageId and \ - '/accounts/' not in messageId and \ - '/channel/' not in messageId and \ - '/profile/' not in messageId: + if not hasUsersPath(messageId): if debug: print('DEBUG: c2s undo block object has no nickname') return diff --git a/blog.py b/blog.py index ec92e825a..bd6df769f 100644 --- a/blog.py +++ b/blog.py @@ -158,6 +158,7 @@ def _htmlBlogPostContent(authorized: bool, nickname: str, domain: str, domainFull: str, postJsonObject: {}, handle: str, restrictToDomain: bool, + peertubeInstances: [], blogSeparator='
' @@ -417,7 +421,8 @@ def htmlBlogPost(authorized: bool, def htmlBlogPage(authorized: bool, session, baseDir: str, httpPrefix: str, translate: {}, nickname: str, domain: str, port: int, - noOfItems: int, pageNumber: int) -> str: + noOfItems: int, pageNumber: int, + peertubeInstances: []) -> str: """Returns a html blog page containing posts """ if ' ' in nickname or '@' in nickname or \ @@ -477,7 +482,8 @@ def htmlBlogPage(authorized: bool, session, httpPrefix, translate, nickname, domain, domainFull, item, - None, True) + None, True, + peertubeInstances) if len(timelineJson['orderedItems']) >= noOfItems: blogStr += navigateStr @@ -638,7 +644,8 @@ def _singleBlogAccountNickname(baseDir: str) -> str: def htmlBlogView(authorized: bool, session, baseDir: str, httpPrefix: str, translate: {}, domain: str, port: int, - noOfItems: int) -> str: + noOfItems: int, + peertubeInstances: []) -> str: """Show the blog main page """ blogStr = '' @@ -654,7 +661,7 @@ def htmlBlogView(authorized: bool, return htmlBlogPage(authorized, session, baseDir, httpPrefix, translate, nickname, domain, port, - noOfItems, 1) + noOfItems, 1, peertubeInstances) domainFull = getFullDomain(domain, port) diff --git a/bookmarks.py b/bookmarks.py index a9bf0c457..d6f9817c0 100644 --- a/bookmarks.py +++ b/bookmarks.py @@ -8,6 +8,7 @@ __status__ = "Production" import os from pprint import pprint +from utils import hasUsersPath from utils import getFullDomain from utils import removeIdEnding from utils import removePostFromCache @@ -255,10 +256,7 @@ def bookmark(recentPostsCache: {}, bookmarkedPostNickname = getNicknameFromActor(acBm) bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm) else: - if '/users/' in objectUrl or \ - '/accounts/' in objectUrl or \ - '/channel/' in objectUrl or \ - '/profile/' in objectUrl: + if hasUsersPath(objectUrl): ou = objectUrl bookmarkedPostNickname = getNicknameFromActor(ou) bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou) @@ -322,10 +320,7 @@ def undoBookmark(recentPostsCache: {}, bookmarkedPostNickname = getNicknameFromActor(acBm) bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm) else: - if '/users/' in objectUrl or \ - '/accounts/' in objectUrl or \ - '/channel/' in objectUrl or \ - '/profile/' in objectUrl: + if hasUsersPath(objectUrl): ou = objectUrl bookmarkedPostNickname = getNicknameFromActor(ou) bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou) diff --git a/briar.py b/briar.py new file mode 100644 index 000000000..4df6c09d5 --- /dev/null +++ b/briar.py @@ -0,0 +1,103 @@ +__filename__ = "briar.py" +__author__ = "Bob Mottram" +__license__ = "AGPL3+" +__version__ = "1.1.0" +__maintainer__ = "Bob Mottram" +__email__ = "bob@freedombone.net" +__status__ = "Production" + + +def getBriarAddress(actorJson: {}) -> str: + """Returns briar address for the given actor + """ + if not actorJson.get('attachment'): + return '' + for propertyValue in actorJson['attachment']: + if not propertyValue.get('name'): + continue + if not propertyValue['name'].lower().startswith('briar'): + continue + if not propertyValue.get('type'): + continue + if not propertyValue.get('value'): + continue + if propertyValue['type'] != 'PropertyValue': + continue + propertyValue['value'] = propertyValue['value'].strip() + if len(propertyValue['value']) < 50: + continue + if not propertyValue['value'].startswith('briar://'): + continue + if propertyValue['value'].lower() != propertyValue['value']: + continue + if '"' in propertyValue['value']: + continue + if ' ' in propertyValue['value']: + continue + if ',' in propertyValue['value']: + continue + if '.' in propertyValue['value']: + continue + return propertyValue['value'] + return '' + + +def setBriarAddress(actorJson: {}, briarAddress: str) -> None: + """Sets an briar address for the given actor + """ + notBriarAddress = False + + if len(briarAddress) < 50: + notBriarAddress = True + if not briarAddress.startswith('briar://'): + notBriarAddress = True + if briarAddress.lower() != briarAddress: + notBriarAddress = True + if '"' in briarAddress: + notBriarAddress = True + if ' ' in briarAddress: + notBriarAddress = True + if '.' in briarAddress: + notBriarAddress = True + if ',' in briarAddress: + notBriarAddress = True + if '<' in briarAddress: + notBriarAddress = True + + if not actorJson.get('attachment'): + actorJson['attachment'] = [] + + # remove any existing value + propertyFound = None + for propertyValue in actorJson['attachment']: + if not propertyValue.get('name'): + continue + if not propertyValue.get('type'): + continue + if not propertyValue['name'].lower().startswith('briar'): + continue + propertyFound = propertyValue + break + if propertyFound: + actorJson['attachment'].remove(propertyFound) + if notBriarAddress: + return + + for propertyValue in actorJson['attachment']: + if not propertyValue.get('name'): + continue + if not propertyValue.get('type'): + continue + if not propertyValue['name'].lower().startswith('briar'): + continue + if propertyValue['type'] != 'PropertyValue': + continue + propertyValue['value'] = briarAddress + return + + newBriarAddress = { + "name": "Briar", + "type": "PropertyValue", + "value": briarAddress + } + actorJson['attachment'].append(newBriarAddress) diff --git a/daemon.py b/daemon.py index 8537ea5b5..1553440e6 100644 --- a/daemon.py +++ b/daemon.py @@ -39,6 +39,8 @@ from ssb import getSSBAddress from ssb import setSSBAddress from tox import getToxAddress from tox import setToxAddress +from briar import getBriarAddress +from briar import setBriarAddress from jami import getJamiAddress from jami import setJamiAddress from matrix import getMatrixAddress @@ -136,6 +138,7 @@ from webapp_timeline import htmlInboxBlogs from webapp_timeline import htmlInboxNews from webapp_timeline import htmlInboxFeatures from webapp_timeline import htmlOutbox +from webapp_media import loadPeertubeInstances from webapp_moderation import htmlAccountInfo from webapp_moderation import htmlModeration from webapp_moderation import htmlModerationInfo @@ -171,9 +174,10 @@ from shares import getSharesFeedForPerson from shares import addShare from shares import removeShare from shares import expireShares +from categories import setHashtagCategory +from utils import hasUsersPath from utils import getFullDomain from utils import removeHtml -from categories import setHashtagCategory from utils import isEditor from utils import getImageExtensions from utils import mediaFileMimeType @@ -580,7 +584,8 @@ class PubServer(BaseHTTPRequestHandler): def _set_headers_etag(self, mediaFilename: str, fileFormat: str, data, cookie: str, callingDomain: str) -> None: - self._set_headers_base(fileFormat, len(data), cookie, callingDomain) + datalen = len(data) + self._set_headers_base(fileFormat, datalen, cookie, callingDomain) self.send_header('Cache-Control', 'public, max-age=86400') etag = None if os.path.isfile(mediaFilename + '.etag'): @@ -664,7 +669,8 @@ class PubServer(BaseHTTPRequestHandler): msg = msg.encode('utf-8') self.send_response(httpCode) self.send_header('Content-Type', 'text/html; charset=utf-8') - self.send_header('Content-Length', str(len(msg))) + msgLenStr = str(len(msg)) + self.send_header('Content-Length', msgLenStr) self.send_header('X-Robots-Tag', 'noindex') self.end_headers() if not self._write(msg): @@ -742,7 +748,8 @@ class PubServer(BaseHTTPRequestHandler): return False msg = 'User-agent: *\nDisallow: /' msg = msg.encode('utf-8') - self._set_headers('text/plain; charset=utf-8', len(msg), + msglen = len(msg) + self._set_headers('text/plain; charset=utf-8', msglen, None, self.server.domainFull) self._write(msg) return True @@ -788,15 +795,16 @@ class PubServer(BaseHTTPRequestHandler): self.server.systemLanguage, self.server.projectVersion) msg = json.dumps(instanceJson).encode('utf-8') + msglen = len(msg) if self._hasAccept(callingDomain): if 'application/ld+json' in self.headers['Accept']: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) else: - self._set_headers('application/json', len(msg), + self._set_headers('application/json', msglen, None, callingDomain) else: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) self._write(msg) print('instance metadata sent') @@ -809,15 +817,16 @@ class PubServer(BaseHTTPRequestHandler): # information about the interests of a small number of accounts msg = json.dumps(['mastodon.social', self.server.domainFull]).encode('utf-8') + msglen = len(msg) if self._hasAccept(callingDomain): if 'application/ld+json' in self.headers['Accept']: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) else: - self._set_headers('application/json', len(msg), + self._set_headers('application/json', msglen, None, callingDomain) else: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) self._write(msg) print('instance peers metadata sent') @@ -825,15 +834,16 @@ class PubServer(BaseHTTPRequestHandler): if self.path.startswith('/api/v1/instance/activity'): # This is just a dummy result. msg = json.dumps([]).encode('utf-8') + msglen = len(msg) if self._hasAccept(callingDomain): if 'application/ld+json' in self.headers['Accept']: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) else: - self._set_headers('application/json', len(msg), + self._set_headers('application/json', msglen, None, callingDomain) else: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) self._write(msg) print('instance activity metadata sent') @@ -851,15 +861,16 @@ class PubServer(BaseHTTPRequestHandler): self.server.projectVersion) if info: msg = json.dumps(info).encode('utf-8') + msglen = len(msg) if self._hasAccept(callingDomain): if 'application/ld+json' in self.headers['Accept']: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) else: - self._set_headers('application/json', len(msg), + self._set_headers('application/json', msglen, None, callingDomain) else: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) self._write(msg) print('nodeinfo sent') @@ -890,7 +901,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.domainFull) if wfResult: msg = wfResult.encode('utf-8') - self._set_headers('application/xrd+xml', len(msg), + msglen = len(msg) + self._set_headers('application/xrd+xml', msglen, None, callingDomain) self._write(msg) return True @@ -911,15 +923,16 @@ class PubServer(BaseHTTPRequestHandler): self.server.domainFull) if wfResult: msg = json.dumps(wfResult).encode('utf-8') + msglen = len(msg) if self._hasAccept(callingDomain): if 'application/ld+json' in self.headers['Accept']: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) else: - self._set_headers('application/json', len(msg), + self._set_headers('application/json', msglen, None, callingDomain) else: - self._set_headers('application/ld+json', len(msg), + self._set_headers('application/ld+json', msglen, None, callingDomain) self._write(msg) return True @@ -935,7 +948,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.port, self.server.debug) if wfResult: msg = json.dumps(wfResult).encode('utf-8') - self._set_headers('application/jrd+json', len(msg), + msglen = len(msg) + self._set_headers('application/jrd+json', msglen, None, callingDomain) self._write(msg) else: @@ -1309,8 +1323,9 @@ class PubServer(BaseHTTPRequestHandler): msg = \ htmlSuspended(self.server.cssCache, baseDir).encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) self.server.POSTbusy = False return @@ -1483,8 +1498,9 @@ class PubServer(BaseHTTPRequestHandler): baseDir, httpPrefix, nickname) msg = msg.encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) self.server.POSTbusy = False return @@ -1735,9 +1751,10 @@ class PubServer(BaseHTTPRequestHandler): chooserNickname, domain, handle, petname) - self._redirect_headers(usersPath + '/' + - self.server.defaultTimeline + - '?page='+str(pageNumber), cookie, + usersPathStr = \ + usersPath + '/' + self.server.defaultTimeline + \ + '?page=' + str(pageNumber) + self._redirect_headers(usersPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -1754,9 +1771,10 @@ class PubServer(BaseHTTPRequestHandler): chooserNickname, domain, handle, personNotes) - self._redirect_headers(usersPath + '/' + - self.server.defaultTimeline + - '?page='+str(pageNumber), cookie, + usersPathStr = \ + usersPath + '/' + self.server.defaultTimeline + \ + '?page=' + str(pageNumber) + self._redirect_headers(usersPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -1781,9 +1799,10 @@ class PubServer(BaseHTTPRequestHandler): domain, optionsNickname, optionsDomainFull) - self._redirect_headers(usersPath + '/' + - self.server.defaultTimeline + - '?page='+str(pageNumber), cookie, + usersPathStr = \ + usersPath + '/' + self.server.defaultTimeline + \ + '?page=' + str(pageNumber) + self._redirect_headers(usersPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -1813,9 +1832,10 @@ class PubServer(BaseHTTPRequestHandler): if noNewswireFile: noNewswireFile.write('\n') noNewswireFile.close() - self._redirect_headers(usersPath + '/' + - self.server.defaultTimeline + - '?page='+str(pageNumber), cookie, + usersPathStr = \ + usersPath + '/' + self.server.defaultTimeline + \ + '?page=' + str(pageNumber) + self._redirect_headers(usersPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -1846,9 +1866,10 @@ class PubServer(BaseHTTPRequestHandler): if modNewswireFile: modNewswireFile.write('\n') modNewswireFile.close() - self._redirect_headers(usersPath + '/' + - self.server.defaultTimeline + - '?page='+str(pageNumber), cookie, + usersPathStr = \ + usersPath + '/' + self.server.defaultTimeline + \ + '?page=' + str(pageNumber) + self._redirect_headers(usersPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -1875,7 +1896,8 @@ class PubServer(BaseHTTPRequestHandler): usersPath, optionsActor, optionsAvatarUrl).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.POSTbusy = False @@ -1893,7 +1915,8 @@ class PubServer(BaseHTTPRequestHandler): usersPath, optionsActor, optionsAvatarUrl).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.POSTbusy = False @@ -1910,7 +1933,8 @@ class PubServer(BaseHTTPRequestHandler): usersPath, optionsActor, optionsAvatarUrl).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.POSTbusy = False @@ -1935,7 +1959,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.defaultTimeline, self.server.newswire, self.server.themeName).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.POSTbusy = False @@ -1957,7 +1982,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.port, optionsActor, self.server.debug).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.POSTbusy = False @@ -1981,9 +2007,10 @@ class PubServer(BaseHTTPRequestHandler): thisActor = 'http://' + onionDomain + usersPath elif (callingDomain.endswith('.i2p') and i2pDomain): thisActor = 'http://' + i2pDomain + usersPath - self._redirect_headers(thisActor + '/' + - self.server.defaultTimeline + - '?page='+str(pageNumber), cookie, + actorPathStr = \ + thisActor + '/' + self.server.defaultTimeline + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -2003,9 +2030,10 @@ class PubServer(BaseHTTPRequestHandler): thisActor = 'http://' + onionDomain + usersPath elif (callingDomain.endswith('.i2p') and i2pDomain): thisActor = 'http://' + i2pDomain + usersPath - self._redirect_headers(thisActor + '/' + - self.server.defaultTimeline + - '?page=' + str(pageNumber), cookie, + actorPathStr = \ + thisActor + '/' + self.server.defaultTimeline + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -2029,7 +2057,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.defaultTimeline, self.server.newswire, self.server.themeName).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.POSTbusy = False @@ -2464,11 +2493,13 @@ class PubServer(BaseHTTPRequestHandler): httpPrefix, self.server.projectVersion, self.server.YTReplacementDomain, - self.server.showPublishedDateOnly) + self.server.showPublishedDateOnly, + self.server.peertubeInstances) if hashtagStr: msg = hashtagStr.encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) self.server.POSTbusy = False return @@ -2486,8 +2517,9 @@ class PubServer(BaseHTTPRequestHandler): 64) if skillStr: msg = skillStr.encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) self.server.POSTbusy = False return @@ -2513,20 +2545,19 @@ class PubServer(BaseHTTPRequestHandler): self.server.personCache, port, self.server.YTReplacementDomain, - self.server.showPublishedDateOnly) + self.server.showPublishedDateOnly, + self.server.peertubeInstances) if historyStr: msg = historyStr.encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) self.server.POSTbusy = False return elif ('@' in searchStr or ('://' in searchStr and - ('/users/' in searchStr or - '/profile/' in searchStr or - '/accounts/' in searchStr or - '/channel/' in searchStr))): + hasUsersPath(searchStr))): # profile search nickname = getNicknameFromActor(actorStr) if not self.server.session: @@ -2559,11 +2590,13 @@ class PubServer(BaseHTTPRequestHandler): self.server.projectVersion, self.server.YTReplacementDomain, self.server.showPublishedDateOnly, - self.server.defaultTimeline) + self.server.defaultTimeline, + self.server.peertubeInstances) if profileStr: msg = profileStr.encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) self.server.POSTbusy = False return @@ -2591,8 +2624,9 @@ class PubServer(BaseHTTPRequestHandler): searchStr) if emojiStr: msg = emojiStr.encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) self.server.POSTbusy = False return @@ -2609,8 +2643,9 @@ class PubServer(BaseHTTPRequestHandler): actorStr, callingDomain) if sharedItemsStr: msg = sharedItemsStr.encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) self.server.POSTbusy = False return @@ -2649,9 +2684,10 @@ class PubServer(BaseHTTPRequestHandler): actor = 'http://' + onionDomain + usersPath elif (callingDomain.endswith('.i2p') and i2pDomain): actor = 'http://' + i2pDomain + usersPath - self._redirect_headers(actor + '/' + - self.server.defaultTimeline + - '?page=' + str(pageNumber), + actorPathStr = \ + actor + '/' + self.server.defaultTimeline + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -2701,9 +2737,10 @@ class PubServer(BaseHTTPRequestHandler): actor = 'http://' + onionDomain + usersPath elif (callingDomain.endswith('.i2p') and i2pDomain): actor = 'http://' + i2pDomain + usersPath - self._redirect_headers(actor + '/' + - self.server.defaultTimeline + - '?page=' + str(pageNumber), cookie, + actorPathStr = \ + actor + '/' + self.server.defaultTimeline + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -2930,8 +2967,9 @@ class PubServer(BaseHTTPRequestHandler): self._redirect_headers(originPathStr + '/outbox', cookie, callingDomain) else: - self._redirect_headers(originPathStr + '/outbox?page=' + - str(pageNumber), + pageNumberStr = str(pageNumber) + actorPathStr = originPathStr + '/outbox?page=' + pageNumberStr + self._redirect_headers(actorPathStr, cookie, callingDomain) self.server.POSTbusy = False @@ -4060,6 +4098,18 @@ class PubServer(BaseHTTPRequestHandler): setToxAddress(actorJson, '') actorChanged = True + # change briar address + currentBriarAddress = getBriarAddress(actorJson) + if fields.get('briarAddress'): + if fields['briarAddress'] != currentBriarAddress: + setBriarAddress(actorJson, + fields['briarAddress']) + actorChanged = True + else: + if currentBriarAddress: + setBriarAddress(actorJson, '') + actorChanged = True + # change jami address currentJamiAddress = getJamiAddress(actorJson) if fields.get('jamiAddress'): @@ -4529,6 +4579,33 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(allowedInstancesFilename): os.remove(allowedInstancesFilename) + # save peertube instances list + peertubeInstancesFile = \ + baseDir + '/accounts/peertube.txt' + if fields.get('ptInstances'): + adminNickname = \ + getConfigParam(baseDir, 'admin') + if adminNickname and \ + path.startswith('/users/' + + adminNickname + '/'): + self.server.peertubeInstances.clear() + with open(peertubeInstancesFile, 'w+') as aFile: + aFile.write(fields['ptInstances']) + ptInstancesList = \ + fields['ptInstances'].split('\n') + if ptInstancesList: + for url in ptInstancesList: + url = url.strip() + if not url: + continue + if url in self.server.peertubeInstances: + continue + self.server.peertubeInstances.append(url) + else: + if os.path.isfile(peertubeInstancesFile): + os.remove(peertubeInstancesFile) + self.server.peertubeInstances.clear() + # save git project names list gitProjectsFilename = \ baseDir + '/accounts/' + \ @@ -4700,7 +4777,8 @@ class PubServer(BaseHTTPRequestHandler): } msg = json.dumps(manifest, ensure_ascii=False).encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) if self.server.debug: @@ -4862,7 +4940,8 @@ class PubServer(BaseHTTPRequestHandler): True) if msg is not None: msg = msg.encode('utf-8') - self._set_headers('text/xml', len(msg), + msglen = len(msg) + self._set_headers('text/xml', msglen, None, callingDomain) self._write(msg) if debug: @@ -4923,7 +5002,8 @@ class PubServer(BaseHTTPRequestHandler): 'Site', translate) + msg + rss2Footer() msg = msg.encode('utf-8') - self._set_headers('text/xml', len(msg), + msglen = len(msg) + self._set_headers('text/xml', msglen, None, callingDomain) self._write(msg) if debug: @@ -4962,7 +5042,8 @@ class PubServer(BaseHTTPRequestHandler): 'Newswire', self.server.translate) if msg: msg = msg.encode('utf-8') - self._set_headers('text/xml', len(msg), + msglen = len(msg) + self._set_headers('text/xml', msglen, None, callingDomain) self._write(msg) if debug: @@ -4997,7 +5078,8 @@ class PubServer(BaseHTTPRequestHandler): getHashtagCategoriesFeed(baseDir, hashtagCategories) if msg: msg = msg.encode('utf-8') - self._set_headers('text/xml', len(msg), + msglen = len(msg) + self._set_headers('text/xml', msglen, None, callingDomain) self._write(msg) if debug: @@ -5041,8 +5123,9 @@ class PubServer(BaseHTTPRequestHandler): maxPostsInRSSFeed, 1) if msg is not None: msg = msg.encode('utf-8') + msglen = len(msg) self._set_headers('text/plain; charset=utf-8', - len(msg), None, callingDomain) + msglen, None, callingDomain) self._write(msg) if self.server.debug: print('Sent rss3 feed: ' + @@ -5093,6 +5176,7 @@ class PubServer(BaseHTTPRequestHandler): matrixAddress = None blogAddress = None toxAddress = None + briarAddress = None jamiAddress = None ssbAddress = None emailAddress = None @@ -5107,6 +5191,7 @@ class PubServer(BaseHTTPRequestHandler): ssbAddress = getSSBAddress(actorJson) blogAddress = getBlogAddress(actorJson) toxAddress = getToxAddress(actorJson) + briarAddress = getBriarAddress(actorJson) jamiAddress = getJamiAddress(actorJson) emailAddress = getEmailAddress(actorJson) PGPpubKey = getPGPpubKey(actorJson) @@ -5123,12 +5208,14 @@ class PubServer(BaseHTTPRequestHandler): pageNumber, donateUrl, xmppAddress, matrixAddress, ssbAddress, blogAddress, - toxAddress, jamiAddress, + toxAddress, briarAddress, + jamiAddress, PGPpubKey, PGPfingerprint, emailAddress, self.server.dormantMonths, backToPath).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -5245,8 +5332,9 @@ class PubServer(BaseHTTPRequestHandler): return if self.server.iconsCache.get(mediaStr): mediaBinary = self.server.iconsCache[mediaStr] + mimeTypeStr = mediaFileMimeType(mediaFilename) self._set_headers_etag(mediaFilename, - mediaFileMimeType(mediaFilename), + mimeTypeStr, mediaBinary, None, callingDomain) self._write(mediaBinary) @@ -5316,7 +5404,8 @@ class PubServer(BaseHTTPRequestHandler): print('BLOCK: hashtag #' + hashtag) msg = htmlHashtagBlocked(self.server.cssCache, baseDir, self.server.translate).encode('utf-8') - self._login_headers('text/html', len(msg), callingDomain) + msglen = len(msg) + self._login_headers('text/html', msglen, callingDomain) self._write(msg) self.server.GETbusy = False return @@ -5339,10 +5428,12 @@ class PubServer(BaseHTTPRequestHandler): httpPrefix, self.server.projectVersion, self.server.YTReplacementDomain, - self.server.showPublishedDateOnly) + self.server.showPublishedDateOnly, + self.server.peertubeInstances) if hashtagStr: msg = hashtagStr.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) else: @@ -5396,7 +5487,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.YTReplacementDomain) if hashtagStr: msg = hashtagStr.encode('utf-8') - self._set_headers('text/xml', len(msg), + msglen = len(msg) + self._set_headers('text/xml', msglen, cookie, callingDomain) self._write(msg) else: @@ -5461,8 +5553,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif (callingDomain.endswith('.i2p') and i2pDomain): actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + timelineStr + - '?page=' + str(pageNumber), cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) return if not self.server.session: @@ -5506,10 +5600,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif callingDomain.endswith('.i2p') and i2pDomain: actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + - timelineStr + '?page=' + - str(pageNumber) + - timelineBookmark, cookie, callingDomain) + actorPathStr = \ + actorAbsolute + '/' + timelineStr + '?page=' + \ + str(pageNumber) + timelineBookmark + self._redirect_headers(actorPathStr, cookie, callingDomain) self._benchmarkGETtimings(GETstartTime, GETtimings, 'emoji search shown done', 'show announce') @@ -5557,9 +5651,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif (callingDomain.endswith('.i2p') and i2pDomain): actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + - timelineStr + '?page=' + - str(pageNumber), cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + '?page=' + \ + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) return if not self.server.session: @@ -5599,10 +5694,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif (callingDomain.endswith('.i2p') and i2pDomain): actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + - timelineStr + '?page=' + - str(pageNumber) + - timelineBookmark, cookie, callingDomain) + actorPathStr = \ + actorAbsolute + '/' + timelineStr + '?page=' + \ + str(pageNumber) + timelineBookmark + self._redirect_headers(actorPathStr, cookie, callingDomain) self._benchmarkGETtimings(GETstartTime, GETtimings, 'show announce done', 'unannounce') @@ -5852,9 +5947,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif (callingDomain.endswith('.i2p') and i2pDomain): actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + timelineStr + - '?page=' + str(pageNumber) + - timelineBookmark, cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + \ + '?page=' + str(pageNumber) + timelineBookmark + self._redirect_headers(actorPathStr, cookie, callingDomain) return if not self.server.session: @@ -5906,9 +6002,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif (callingDomain.endswith('.i2p') and i2pDomain): actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + timelineStr + - '?page=' + str(pageNumber) + - timelineBookmark, cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + \ + '?page=' + str(pageNumber) + timelineBookmark + self._redirect_headers(actorPathStr, cookie, callingDomain) self._benchmarkGETtimings(GETstartTime, GETtimings, 'follow deny done', @@ -5957,8 +6054,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif (callingDomain.endswith('.i2p') and onionDomain): actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + timelineStr + - '?page=' + str(pageNumber), cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) return if not self.server.session: @@ -6009,9 +6108,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif callingDomain.endswith('.i2p') and i2pDomain: actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + timelineStr + - '?page=' + str(pageNumber) + - timelineBookmark, cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + \ + '?page=' + str(pageNumber) + timelineBookmark + self._redirect_headers(actorPathStr, cookie, callingDomain) self._benchmarkGETtimings(GETstartTime, GETtimings, 'like shown done', @@ -6061,8 +6161,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif callingDomain.endswith('.i2p') and i2pDomain: actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + timelineStr + - '?page=' + str(pageNumber), cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) return if not self.server.session: @@ -6103,9 +6205,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif callingDomain.endswith('.i2p') and i2pDomain: actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + timelineStr + - '?page=' + str(pageNumber) + - timelineBookmark, cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + \ + '?page=' + str(pageNumber) + timelineBookmark + self._redirect_headers(actorPathStr, cookie, callingDomain) self._benchmarkGETtimings(GETstartTime, GETtimings, 'unlike shown done', @@ -6154,8 +6257,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif callingDomain.endswith('.i2p') and i2pDomain: actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + timelineStr + - '?page=' + str(pageNumber), cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) return if not self.server.session: @@ -6196,9 +6301,10 @@ class PubServer(BaseHTTPRequestHandler): actorAbsolute = 'http://' + onionDomain + actor elif callingDomain.endswith('.i2p') and i2pDomain: actorAbsolute = 'http://' + i2pDomain + actor - self._redirect_headers(actorAbsolute + '/' + timelineStr + - '?page=' + str(pageNumber) + - timelineBookmark, cookie, + actorPathStr = \ + actorAbsolute + '/' + timelineStr + \ + '?page=' + str(pageNumber) + timelineBookmark + self._redirect_headers(actorPathStr, cookie, callingDomain) self._benchmarkGETtimings(GETstartTime, GETtimings, 'bookmark shown done', @@ -6284,9 +6390,11 @@ class PubServer(BaseHTTPRequestHandler): __version__, self.server.cachedWebfingers, self.server.personCache, callingDomain, self.server.YTReplacementDomain, - self.server.showPublishedDateOnly) + self.server.showPublishedDateOnly, + self.server.peertubeInstances) if deleteStr: - self._set_headers('text/html', len(deleteStr), + deleteStrLen = len(deleteStr) + self._set_headers('text/html', deleteStrLen, cookie, callingDomain) self._write(deleteStr.encode('utf-8')) self.server.GETbusy = False @@ -6469,6 +6577,7 @@ class PubServer(BaseHTTPRequestHandler): personCache = self.server.personCache projectVersion = self.server.projectVersion ytDomain = self.server.YTReplacementDomain + peertubeInstances = self.server.peertubeInstances msg = \ htmlPostReplies(self.server.cssCache, recentPostsCache, @@ -6485,9 +6594,11 @@ class PubServer(BaseHTTPRequestHandler): httpPrefix, projectVersion, ytDomain, - self.server.showPublishedDateOnly) + self.server.showPublishedDateOnly, + peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) else: @@ -6495,7 +6606,8 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(repliesJson, ensure_ascii=False) msg = msg.encode('utf-8') protocolStr = 'application/json' - self._set_headers(protocolStr, len(msg), None, + msglen = len(msg) + self._set_headers(protocolStr, msglen, None, callingDomain) self._write(msg) else: @@ -6551,6 +6663,7 @@ class PubServer(BaseHTTPRequestHandler): personCache = self.server.personCache projectVersion = self.server.projectVersion ytDomain = self.server.YTReplacementDomain + peertubeInstances = self.server.peertubeInstances msg = \ htmlPostReplies(self.server.cssCache, recentPostsCache, @@ -6567,9 +6680,11 @@ class PubServer(BaseHTTPRequestHandler): httpPrefix, projectVersion, ytDomain, - self.server.showPublishedDateOnly) + self.server.showPublishedDateOnly, + peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, @@ -6582,7 +6697,8 @@ class PubServer(BaseHTTPRequestHandler): ensure_ascii=False) msg = msg.encode('utf-8') protocolStr = 'application/json' - self._set_headers(protocolStr, len(msg), + msglen = len(msg) + self._set_headers(protocolStr, msglen, None, callingDomain) self._write(msg) else: @@ -6651,10 +6767,12 @@ class PubServer(BaseHTTPRequestHandler): self.server.newswire, self.server.themeName, self.server.dormantMonths, + self.server.peertubeInstances, actorJson['roles'], None, None) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -6665,7 +6783,8 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(actorJson['roles'], ensure_ascii=False) msg = msg.encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) else: @@ -6732,10 +6851,12 @@ class PubServer(BaseHTTPRequestHandler): self.server.newswire, self.server.themeName, self.server.dormantMonths, + self.server.peertubeInstances, actorJson['skills'], None, None) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, @@ -6747,8 +6868,9 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(actorJson['skills'], ensure_ascii=False) msg = msg.encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), None, + msglen, None, callingDomain) self._write(msg) else: @@ -6834,6 +6956,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.YTReplacementDomain showPublishedDateOnly = \ self.server.showPublishedDateOnly + peertubeInstances = \ + self.server.peertubeInstances cssCache = self.server.cssCache msg = \ htmlIndividualPost(cssCache, @@ -6853,9 +6977,11 @@ class PubServer(BaseHTTPRequestHandler): projectVersion, likedBy, ytDomain, - showPublishedDateOnly) + showPublishedDateOnly, + peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) else: @@ -6863,8 +6989,9 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(postJsonObject, ensure_ascii=False) msg = msg.encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), + msglen, None, callingDomain) self._write(msg) else: @@ -6947,6 +7074,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.YTReplacementDomain showPublishedDateOnly = \ self.server.showPublishedDateOnly + peertubeInstances = \ + self.server.peertubeInstances msg = \ htmlIndividualPost(self.server.cssCache, recentPostsCache, @@ -6965,9 +7094,11 @@ class PubServer(BaseHTTPRequestHandler): projectVersion, likedBy, ytDomain, - showPublishedDateOnly) + showPublishedDateOnly, + peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, @@ -6980,8 +7111,9 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(postJsonObject, ensure_ascii=False) msg = msg.encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), + msglen, None, callingDomain) self._write(msg) else: @@ -7095,7 +7227,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.rssIconAtTop, self.server.publishButtonAtTop, authorized, - self.server.themeName) + self.server.themeName, + self.server.peertubeInstances) if GETstartTime: self._benchmarkGETtimings(GETstartTime, GETtimings, 'show status done', @@ -7103,7 +7236,8 @@ class PubServer(BaseHTTPRequestHandler): if msg: msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) @@ -7116,7 +7250,8 @@ class PubServer(BaseHTTPRequestHandler): # there is already the authorization check msg = json.dumps(inboxFeed, ensure_ascii=False) msg = msg.encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -7219,9 +7354,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.iconsAsButtons, self.server.rssIconAtTop, self.server.publishButtonAtTop, - authorized, self.server.themeName) + authorized, self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -7232,8 +7369,9 @@ class PubServer(BaseHTTPRequestHandler): # there is already the authorization check msg = json.dumps(inboxDMFeed, ensure_ascii=False) msg = msg.encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), + msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -7336,9 +7474,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.iconsAsButtons, self.server.rssIconAtTop, self.server.publishButtonAtTop, - authorized, self.server.themeName) + authorized, self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -7350,7 +7490,8 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(inboxRepliesFeed, ensure_ascii=False) msg = msg.encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -7454,9 +7595,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.rssIconAtTop, self.server.publishButtonAtTop, authorized, - self.server.themeName) + self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -7468,7 +7611,8 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(inboxMediaFeed, ensure_ascii=False) msg = msg.encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -7572,9 +7716,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.rssIconAtTop, self.server.publishButtonAtTop, authorized, - self.server.themeName) + self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -7586,8 +7732,9 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(inboxBlogsFeed, ensure_ascii=False) msg = msg.encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), + msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -7699,9 +7846,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.rssIconAtTop, self.server.publishButtonAtTop, authorized, - self.server.themeName) + self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -7713,8 +7862,9 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(inboxNewsFeed, ensure_ascii=False) msg = msg.encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), + msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -7822,9 +7972,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.rssIconAtTop, self.server.publishButtonAtTop, authorized, - self.server.themeName) + self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -7836,8 +7988,9 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(inboxFeaturesFeed, ensure_ascii=False) msg = msg.encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), + msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -7906,9 +8059,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.iconsAsButtons, self.server.rssIconAtTop, self.server.publishButtonAtTop, - authorized, self.server.themeName) + authorized, self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -8008,9 +8163,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.rssIconAtTop, self.server.publishButtonAtTop, authorized, - self.server.themeName) + self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -8022,7 +8179,8 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(bookmarksFeed, ensure_ascii=False) msg = msg.encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -8129,9 +8287,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.rssIconAtTop, self.server.publishButtonAtTop, authorized, - self.server.themeName) + self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -8143,7 +8303,8 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(eventsFeed, ensure_ascii=False) msg = msg.encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -8242,9 +8403,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.rssIconAtTop, self.server.publishButtonAtTop, authorized, - self.server.themeName) + self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -8255,7 +8418,8 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(outboxFeed, ensure_ascii=False) msg = msg.encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) else: @@ -8345,9 +8509,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.rssIconAtTop, self.server.publishButtonAtTop, authorized, moderationActionStr, - self.server.themeName) + self.server.themeName, + self.server.peertubeInstances) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -8359,7 +8525,8 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(moderationFeed, ensure_ascii=False) msg = msg.encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) self.server.GETbusy = False @@ -8442,10 +8609,12 @@ class PubServer(BaseHTTPRequestHandler): self.server.newswire, self.server.themeName, self.server.dormantMonths, + self.server.peertubeInstances, shares, pageNumber, sharesPerPage) msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -8458,7 +8627,8 @@ class PubServer(BaseHTTPRequestHandler): msg = json.dumps(shares, ensure_ascii=False) msg = msg.encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) else: @@ -8535,11 +8705,13 @@ class PubServer(BaseHTTPRequestHandler): self.server.newswire, self.server.themeName, self.server.dormantMonths, + self.server.peertubeInstances, following, pageNumber, followsPerPage).encode('utf-8') + msglen = len(msg) self._set_headers('text/html', - len(msg), cookie, callingDomain) + msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -8550,7 +8722,8 @@ class PubServer(BaseHTTPRequestHandler): if self._fetchAuthenticated(): msg = json.dumps(following, ensure_ascii=False).encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) else: @@ -8628,10 +8801,12 @@ class PubServer(BaseHTTPRequestHandler): self.server.newswire, self.server.themeName, self.server.dormantMonths, + self.server.peertubeInstances, followers, pageNumber, followsPerPage).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False @@ -8643,7 +8818,8 @@ class PubServer(BaseHTTPRequestHandler): if self._fetchAuthenticated(): msg = json.dumps(followers, ensure_ascii=False).encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) else: @@ -8696,8 +8872,10 @@ class PubServer(BaseHTTPRequestHandler): self.server.newswire, self.server.themeName, self.server.dormantMonths, + self.server.peertubeInstances, None, None).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -8707,7 +8885,8 @@ class PubServer(BaseHTTPRequestHandler): if self._fetchAuthenticated(): msg = json.dumps(getPerson, ensure_ascii=False).encode('utf-8') - self._set_headers('application/json', len(msg), + msglen = len(msg) + self._set_headers('application/json', msglen, None, callingDomain) self._write(msg) else: @@ -8759,10 +8938,12 @@ class PubServer(BaseHTTPRequestHandler): translate, nickname, domain, port, - maxPostsInBlogsFeed, pageNumber) + maxPostsInBlogsFeed, pageNumber, + self.server.peertubeInstances) if msg is not None: msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -8852,7 +9033,8 @@ class PubServer(BaseHTTPRequestHandler): time.sleep(1) tries += 1 msg = css.encode('utf-8') - self._set_headers('text/css', len(msg), + msglen = len(msg) + self._set_headers('text/css', msglen, None, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -9177,7 +9359,8 @@ class PubServer(BaseHTTPRequestHandler): 'calendar delete shown') return True msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False @@ -9224,7 +9407,8 @@ class PubServer(BaseHTTPRequestHandler): self._404() self.server.GETbusy = False return True - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False @@ -9241,6 +9425,7 @@ class PubServer(BaseHTTPRequestHandler): """Show the edit profile screen """ if '/users/' in path and path.endswith('/editprofile'): + peertubeInstances = self.server.peertubeInstances msg = htmlEditProfile(self.server.cssCache, translate, baseDir, @@ -9248,9 +9433,11 @@ class PubServer(BaseHTTPRequestHandler): port, httpPrefix, self.server.defaultTimeline, - self.server.themeName).encode('utf-8') + self.server.themeName, + peertubeInstances).encode('utf-8') if msg: - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) else: @@ -9275,7 +9462,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.defaultTimeline, theme).encode('utf-8') if msg: - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) else: @@ -9300,7 +9488,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.defaultTimeline, self.server.themeName).encode('utf-8') if msg: - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) else: @@ -9334,7 +9523,8 @@ class PubServer(BaseHTTPRequestHandler): httpPrefix, postUrl).encode('utf-8') if msg: - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) else: @@ -9373,7 +9563,8 @@ class PubServer(BaseHTTPRequestHandler): # postUrl) if msg: msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False @@ -9410,15 +9601,15 @@ class PubServer(BaseHTTPRequestHandler): return self._benchmarkGETtimings(GETstartTime, GETtimings, - 'start', '_nodeinfo(callingDomain)') + 'start', '_nodeinfo[callingDomain]') # minimal mastodon api if self._mastoApi(callingDomain): return self._benchmarkGETtimings(GETstartTime, GETtimings, - '_nodeinfo(callingDomain)', - '_mastoApi(callingDomain)') + '_nodeinfo[callingDomain]', + '_mastoApi[callingDomain]') if self.path == '/logout': if not self.server.newsInstance: @@ -9426,7 +9617,8 @@ class PubServer(BaseHTTPRequestHandler): htmlLogin(self.server.cssCache, self.server.translate, self.server.baseDir, False).encode('utf-8') - self._logout_headers('text/html', len(msg), callingDomain) + msglen = len(msg) + self._logout_headers('text/html', msglen, callingDomain) self._write(msg) else: if callingDomain.endswith('.onion') and \ @@ -9448,12 +9640,12 @@ class PubServer(BaseHTTPRequestHandler): '/users/news', None, callingDomain) self._benchmarkGETtimings(GETstartTime, GETtimings, - '_nodeinfo(callingDomain)', + '_nodeinfo[callingDomain]', 'logout') return self._benchmarkGETtimings(GETstartTime, GETtimings, - '_nodeinfo(callingDomain)', + '_nodeinfo[callingDomain]', 'show logout') # replace https://domain/@nick with https://domain/users/nick @@ -9663,10 +9855,12 @@ class PubServer(BaseHTTPRequestHandler): self.server.translate, self.server.domain, self.server.port, - maxPostsInBlogsFeed) + maxPostsInBlogsFeed, + self.server.peertubeInstances) if msg is not None: msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -9711,8 +9905,9 @@ class PubServer(BaseHTTPRequestHandler): self.server.httpPrefix) msg = json.dumps(devJson, ensure_ascii=False).encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), + msglen, None, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -9757,10 +9952,12 @@ class PubServer(BaseHTTPRequestHandler): self.server.translate, nickname, self.server.domain, self.server.domainFull, - postJsonObject) + postJsonObject, + self.server.peertubeInstances) if msg is not None: msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -9797,7 +9994,8 @@ class PubServer(BaseHTTPRequestHandler): self._redirect_headers(actor + '/tlshares', cookie, callingDomain) return - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -9826,7 +10024,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.httpPrefix, self.server.domainFull) msg = msg.encode('utf-8') - self._login_headers('text/html', len(msg), callingDomain) + msglen = len(msg) + self._login_headers('text/html', msglen, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, 'blog post 2 done', @@ -9849,7 +10048,8 @@ class PubServer(BaseHTTPRequestHandler): return msg = htmlFollowingList(self.server.cssCache, self.server.baseDir, followingFilename) - self._login_headers('text/html', len(msg), callingDomain) + msglen = len(msg) + self._login_headers('text/html', msglen, callingDomain) self._write(msg.encode('utf-8')) self._benchmarkGETtimings(GETstartTime, GETtimings, 'terms of service done', @@ -9881,7 +10081,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.domainFull, self.server.onionDomain) msg = msg.encode('utf-8') - self._login_headers('text/html', len(msg), callingDomain) + msglen = len(msg) + self._login_headers('text/html', msglen, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, 'following accounts done', @@ -10034,8 +10235,9 @@ class PubServer(BaseHTTPRequestHandler): time.sleep(1) tries += 1 if mediaBinary: + mimeTypeStr = mediaFileMimeType(iconFilename) self._set_headers_etag(iconFilename, - mediaFileMimeType(iconFilename), + mimeTypeStr, mediaBinary, cookie, callingDomain) self._write(mediaBinary) @@ -10221,7 +10423,8 @@ class PubServer(BaseHTTPRequestHandler): msg = htmlLogin(self.server.cssCache, self.server.translate, self.server.baseDir).encode('utf-8') - self._login_headers('text/html', len(msg), callingDomain) + msglen = len(msg) + self._login_headers('text/html', msglen, callingDomain) self._write(msg) self.server.GETbusy = False self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -10293,7 +10496,8 @@ class PubServer(BaseHTTPRequestHandler): iconsAsButtons, defaultTimeline, self.server.themeName).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False @@ -10325,7 +10529,8 @@ class PubServer(BaseHTTPRequestHandler): iconsAsButtons, defaultTimeline, self.server.themeName).encode('utf-8') - self._set_headers('text/html', len(msg), cookie, callingDomain) + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False return @@ -10394,7 +10599,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.domain, self.server.defaultTimeline, self.server.themeName).encode('utf-8') - self._set_headers('text/html', len(msg), cookie, callingDomain) + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -10411,7 +10617,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.themeName) if msg: msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), cookie, callingDomain) + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -10432,7 +10639,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.baseDir, self.path, self.server.httpPrefix, self.server.domainFull).encode('utf-8') - self._set_headers('text/html', len(msg), cookie, callingDomain) + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -10472,7 +10680,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.translate, self.server.baseDir, self.path).encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False @@ -10862,7 +11071,8 @@ class PubServer(BaseHTTPRequestHandler): postUrl) if msg: msg = msg.encode('utf-8') - self._set_headers('text/html', len(msg), + msglen = len(msg) + self._set_headers('text/html', msglen, cookie, callingDomain) self._write(msg) self.server.GETbusy = False @@ -11238,8 +11448,9 @@ class PubServer(BaseHTTPRequestHandler): searchHandle, self.server.debug) msg = msg.encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) return @@ -11271,8 +11482,9 @@ class PubServer(BaseHTTPRequestHandler): searchHandle, self.server.debug) msg = msg.encode('utf-8') + msglen = len(msg) self._login_headers('text/html', - len(msg), callingDomain) + msglen, callingDomain) self._write(msg) return @@ -11463,8 +11675,9 @@ class PubServer(BaseHTTPRequestHandler): contentJson = json.loads(content) msg = json.dumps(contentJson, ensure_ascii=False).encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), + msglen, None, callingDomain) self._write(msg) self._benchmarkGETtimings(GETstartTime, GETtimings, @@ -11735,8 +11948,9 @@ class PubServer(BaseHTTPRequestHandler): self.server.themeName) if messageJson: messageJson = messageJson.encode('utf-8') + messageJsonLen = len(messageJson) self._set_headers('text/html', - len(messageJson), + messageJsonLen, cookie, callingDomain) self._write(messageJson) return 1 @@ -12339,8 +12553,9 @@ class PubServer(BaseHTTPRequestHandler): msg = \ json.dumps(devicesList, ensure_ascii=False).encode('utf-8') + msglen = len(msg) self._set_headers('application/json', - len(msg), + msglen, None, callingDomain) self._write(msg) return True @@ -12776,26 +12991,26 @@ class PubServer(BaseHTTPRequestHandler): if callingDomain.endswith('.onion') and \ self.server.onionDomain: - self._redirect_headers('http://' + - self.server.onionDomain + - '/users/' + nickname + - '/' + postRedirect + - '?page=' + str(pageNumber), cookie, + actorPathStr = \ + 'http://' + self.server.onionDomain + \ + '/users/' + nickname + '/' + postRedirect + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) elif (callingDomain.endswith('.i2p') and self.server.i2pDomain): - self._redirect_headers('http://' + - self.server.i2pDomain + - '/users/' + nickname + - '/' + postRedirect + - '?page=' + str(pageNumber), cookie, + actorPathStr = \ + 'http://' + self.server.i2pDomain + \ + '/users/' + nickname + '/' + postRedirect + \ + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) else: - self._redirect_headers(self.server.httpPrefix + '://' + - self.server.domainFull + - '/users/' + nickname + - '/' + postRedirect + - '?page=' + str(pageNumber), cookie, + actorPathStr = \ + self.server.httpPrefix + '://' + \ + self.server.domainFull + '/users/' + nickname + \ + '/' + postRedirect + '?page=' + str(pageNumber) + self._redirect_headers(actorPathStr, cookie, callingDomain) self.server.POSTbusy = False return @@ -13467,6 +13682,10 @@ def runDaemon(sendThreadsTimeoutMins: int, httpd.iconsCache = {} httpd.fontsCache = {} + # load peertube instances from file into a list + httpd.peertubeInstances = [] + loadPeertubeInstances(baseDir, httpd.peertubeInstances) + createInitialLastSeen(baseDir, httpPrefix) print('Creating inbox queue') @@ -13487,7 +13706,8 @@ def runDaemon(sendThreadsTimeoutMins: int, httpd.showPublishedDateOnly, httpd.allowNewsFollowers, httpd.maxFollowers, - httpd.allowLocalNetworkAccess), daemon=True) + httpd.allowLocalNetworkAccess, + httpd.peertubeInstances), daemon=True) print('Creating scheduled post thread') httpd.thrPostSchedule = \ diff --git a/delete.py b/delete.py index 97b1aaa1c..240845a89 100644 --- a/delete.py +++ b/delete.py @@ -8,6 +8,7 @@ __status__ = "Production" import os from datetime import datetime +from utils import hasUsersPath from utils import getFullDomain from utils import removeIdEnding from utils import getNicknameFromActor @@ -139,10 +140,7 @@ def outboxDelete(baseDir: str, httpPrefix: str, if debug: print('DEBUG: c2s delete object is not a status') return - if '/users/' not in messageId and \ - '/accounts/' not in messageId and \ - '/channel/' not in messageId and \ - '/profile/' not in messageId: + if not hasUsersPath(messageId): if debug: print('DEBUG: c2s delete object has no nickname') return diff --git a/epicyon.py b/epicyon.py index 6b06ef495..3c111e4bf 100644 --- a/epicyon.py +++ b/epicyon.py @@ -47,6 +47,7 @@ from tests import testClientToServer from tests import runAllTests from auth import storeBasicCredentials from auth import createPassword +from utils import hasUsersPath from utils import getFullDomain from utils import setConfigParam from utils import getConfigParam @@ -1318,10 +1319,7 @@ if args.actor: for prefix in prefixes: args.actor = args.actor.replace(prefix, '') args.actor = args.actor.replace('/@', '/users/') - if '/users/' not in args.actor and \ - '/accounts/' not in args.actor and \ - '/channel/' not in args.actor and \ - '/profile/' not in args.actor: + if not hasUsersPath(args.actor): print('Expected actor format: ' + 'https://domain/@nick or https://domain/users/nick') sys.exit() @@ -1391,10 +1389,7 @@ if args.actor: personUrl = None if wfRequest.get('errors'): print('wfRequest error: ' + str(wfRequest['errors'])) - if '/users/' in args.actor or \ - '/accounts/' in args.actor or \ - '/profile/' in args.actor or \ - '/channel/' in args.actor: + if hasUsersPath(args.actor): personUrl = originalActor else: sys.exit() diff --git a/follow.py b/follow.py index 04a6a7db4..f3c209670 100644 --- a/follow.py +++ b/follow.py @@ -8,6 +8,7 @@ __status__ = "Production" from pprint import pprint import os +from utils import hasUsersPath from utils import getFullDomain from utils import isSystemAccount from utils import getFollowersList @@ -316,10 +317,7 @@ def _getNoOfFollows(baseDir: str, nickname: str, domain: str, ctr += 1 elif ((line.startswith('http') or line.startswith('dat')) and - ('/users/' in line or - '/profile/' in line or - '/accounts/' in line or - '/channel/' in line)): + hasUsersPath(line)): ctr += 1 return ctr @@ -438,10 +436,7 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str, following['orderedItems'].append(url) elif ((line.startswith('http') or line.startswith('dat')) and - ('/users/' in line or - '/profile/' in line or - '/accounts/' in line or - '/channel/' in line)): + hasUsersPath(line)): # https://domain/users/nickname pageCtr += 1 totalCtr += 1 @@ -616,10 +611,7 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str, if debug: print('DEBUG: follow request has no actor') return False - if '/users/' not in messageJson['actor'] and \ - '/accounts/' not in messageJson['actor'] and \ - '/channel/' not in messageJson['actor'] and \ - '/profile/' not in messageJson['actor']: + if not hasUsersPath(messageJson['actor']): if debug: print('DEBUG: users/profile/accounts/channel missing from actor') return False @@ -641,10 +633,7 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str, 'nickname. Assuming single user instance.') if not messageJson.get('to'): messageJson['to'] = messageJson['object'] - if '/users/' not in messageJson['object'] and \ - '/accounts/' not in messageJson['object'] and \ - '/channel/' not in messageJson['object'] and \ - '/profile/' not in messageJson['object']: + if not hasUsersPath(messageJson['object']): if debug: print('DEBUG: users/profile/channel/accounts ' + 'not found within object') diff --git a/inbox.py b/inbox.py index 680132308..eb04fe079 100644 --- a/inbox.py +++ b/inbox.py @@ -10,6 +10,7 @@ import json import os import datetime import time +from utils import hasUsersPath from utils import validPostDate from utils import getFullDomain from utils import isEventPost @@ -145,7 +146,8 @@ def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int, nickname: str, domain: str, port: int, postJsonObject: {}, allowDeletion: bool, boxname: str, - showPublishedDateOnly: bool) -> None: + showPublishedDateOnly: bool, + peertubeInstances: []) -> None: """Converts the json post into html and stores it in a cache This enables the post to be quickly displayed later """ @@ -170,6 +172,7 @@ def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int, avatarUrl, True, allowDeletion, httpPrefix, __version__, boxname, None, showPublishedDateOnly, + peertubeInstances, not isDM(postJsonObject), True, True, False, True) @@ -604,10 +607,7 @@ def _receiveUndoFollow(session, baseDir: str, httpPrefix: str, if debug: print('DEBUG: follow request has no actor within object') return False - if '/users/' not in messageJson['object']['actor'] and \ - '/accounts/' not in messageJson['object']['actor'] and \ - '/channel/' not in messageJson['object']['actor'] and \ - '/profile/' not in messageJson['object']['actor']: + if not hasUsersPath(messageJson['object']['actor']): if debug: print('DEBUG: "users" or "profile" missing ' + 'from actor within object') @@ -668,10 +668,7 @@ def _receiveUndo(session, baseDir: str, httpPrefix: str, if debug: print('DEBUG: follow request has no actor') return False - if '/users/' not in messageJson['actor'] and \ - '/accounts/' not in messageJson['actor'] and \ - '/channel/' not in messageJson['actor'] and \ - '/profile/' not in messageJson['actor']: + if not hasUsersPath(messageJson['actor']): if debug: print('DEBUG: "users" or "profile" missing from actor') return False @@ -735,19 +732,19 @@ def _personReceiveUpdate(baseDir: str, ' ' + str(personJson)) domainFull = getFullDomain(domain, port) updateDomainFull = getFullDomain(updateDomain, updatePort) - actor = updateDomainFull + '/users/' + updateNickname - if actor not in personJson['id']: - actor = updateDomainFull + '/profile/' + updateNickname - if actor not in personJson['id']: - actor = updateDomainFull + '/channel/' + updateNickname - if actor not in personJson['id']: - actor = updateDomainFull + '/accounts/' + updateNickname - if actor not in personJson['id']: - if debug: - print('actor: ' + actor) - print('id: ' + personJson['id']) - print('DEBUG: Actor does not match id') - return False + usersPaths = ('users', 'profile', 'channel', 'accounts') + usersStrFound = False + for usersStr in usersPaths: + actor = updateDomainFull + '/' + usersStr + '/' + updateNickname + if actor in personJson['id']: + usersStrFound = True + break + if not usersStrFound: + if debug: + print('actor: ' + actor) + print('id: ' + personJson['id']) + print('DEBUG: Actor does not match id') + return False if updateDomainFull == domainFull: if debug: print('DEBUG: You can only receive actor updates ' + @@ -859,10 +856,7 @@ def _receiveUpdate(recentPostsCache: {}, session, baseDir: str, if debug: print('DEBUG: ' + messageJson['type'] + ' object has no type') return False - if '/users/' not in messageJson['actor'] and \ - '/accounts/' not in messageJson['actor'] and \ - '/channel/' not in messageJson['actor'] and \ - '/profile/' not in messageJson['actor']: + if not hasUsersPath(messageJson['actor']): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + messageJson['type']) @@ -943,10 +937,7 @@ def _receiveLike(recentPostsCache: {}, if debug: print('DEBUG: ' + messageJson['type'] + ' has no "to" list') return False - if '/users/' not in messageJson['actor'] and \ - '/accounts/' not in messageJson['actor'] and \ - '/channel/' not in messageJson['actor'] and \ - '/profile/' not in messageJson['actor']: + if not hasUsersPath(messageJson['actor']): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + messageJson['type']) @@ -1014,10 +1005,7 @@ def _receiveUndoLike(recentPostsCache: {}, print('DEBUG: ' + messageJson['type'] + ' like object is not a string') return False - if '/users/' not in messageJson['actor'] and \ - '/accounts/' not in messageJson['actor'] and \ - '/channel/' not in messageJson['actor'] and \ - '/profile/' not in messageJson['actor']: + if not hasUsersPath(messageJson['actor']): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + messageJson['type'] + ' like') @@ -1219,10 +1207,7 @@ def _receiveDelete(session, handle: str, isGroup: bool, baseDir: str, if debug: print('DEBUG: ' + messageJson['type'] + ' has no "to" list') return False - if '/users/' not in messageJson['actor'] and \ - '/accounts/' not in messageJson['actor'] and \ - '/channel/' not in messageJson['actor'] and \ - '/profile/' not in messageJson['actor']: + if not hasUsersPath(messageJson['actor']): if debug: print('DEBUG: ' + '"users" or "profile" missing from actor in ' + @@ -1303,19 +1288,13 @@ def _receiveAnnounce(recentPostsCache: {}, if debug: print('DEBUG: ' + messageJson['type'] + ' has no "to" list') return False - if '/users/' not in messageJson['actor'] and \ - '/accounts/' not in messageJson['actor'] and \ - '/channel/' not in messageJson['actor'] and \ - '/profile/' not in messageJson['actor']: + if not hasUsersPath(messageJson['actor']): if debug: print('DEBUG: ' + '"users" or "profile" missing from actor in ' + messageJson['type']) return False - if '/users/' not in messageJson['object'] and \ - '/accounts/' not in messageJson['object'] and \ - '/channel/' not in messageJson['object'] and \ - '/profile/' not in messageJson['object']: + if not hasUsersPath(messageJson['object']): if debug: print('DEBUG: ' + '"users", "channel" or "profile" missing in ' + @@ -1387,10 +1366,7 @@ def _receiveAnnounce(recentPostsCache: {}, if isinstance(attrib, str): lookupActor = attrib if lookupActor: - if '/users/' in lookupActor or \ - '/accounts/' in lookupActor or \ - '/channel/' in lookupActor or \ - '/profile/' in lookupActor: + if hasUsersPath(lookupActor): if '/statuses/' in lookupActor: lookupActor = lookupActor.split('/statuses/')[0] @@ -1439,10 +1415,7 @@ def _receiveUndoAnnounce(recentPostsCache: {}, return False if messageJson['object']['type'] != 'Announce': return False - if '/users/' not in messageJson['actor'] and \ - '/accounts/' not in messageJson['actor'] and \ - '/channel/' not in messageJson['actor'] and \ - '/profile/' not in messageJson['actor']: + if not hasUsersPath(messageJson['actor']): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + messageJson['type'] + ' announce') @@ -1688,10 +1661,7 @@ def _obtainAvatarForReplyPost(session, baseDir: str, httpPrefix: str, if not isinstance(lookupActor, str): return - if not ('/users/' in lookupActor or - '/accounts/' in lookupActor or - '/channel/' in lookupActor or - '/profile/' in lookupActor): + if not hasUsersPath(lookupActor): return if '/statuses/' in lookupActor: @@ -2071,7 +2041,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, maxMentions: int, maxEmoji: int, translate: {}, unitTest: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, - allowLocalNetworkAccess: bool) -> bool: + allowLocalNetworkAccess: bool, + peertubeInstances: []) -> bool: """ Anything which needs to be done after initial checks have passed """ actor = keyId @@ -2378,7 +2349,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, postJsonObject, allowDeletion, boxname, - showPublishedDateOnly) + showPublishedDateOnly, + peertubeInstances) if debug: timeDiff = \ str(int((time.time() - htmlCacheStartTime) * @@ -2478,7 +2450,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int, YTReplacementDomain: str, showPublishedDateOnly: bool, allowNewsFollowers: bool, - maxFollowers: int, allowLocalNetworkAccess: bool) -> None: + maxFollowers: int, allowLocalNetworkAccess: bool, + peertubeInstances: []) -> None: """Processes received items and moves them to the appropriate directories """ @@ -2895,7 +2868,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int, translate, unitTest, YTReplacementDomain, showPublishedDateOnly, - allowLocalNetworkAccess) + allowLocalNetworkAccess, + peertubeInstances) if debug: pprint(queueJson['post']) diff --git a/like.py b/like.py index 29efeda3f..289c930c9 100644 --- a/like.py +++ b/like.py @@ -6,6 +6,7 @@ __maintainer__ = "Bob Mottram" __email__ = "bob@freedombone.net" __status__ = "Production" +from utils import hasUsersPath from utils import getFullDomain from utils import removeIdEnding from utils import urlPermitted @@ -87,10 +88,7 @@ def _like(recentPostsCache: {}, likedPostNickname = getNicknameFromActor(actorLiked) likedPostDomain, likedPostPort = getDomainFromActor(actorLiked) else: - if '/users/' in objectUrl or \ - '/accounts/' in objectUrl or \ - '/channel/' in objectUrl or \ - '/profile/' in objectUrl: + if hasUsersPath(objectUrl): likedPostNickname = getNicknameFromActor(objectUrl) likedPostDomain, likedPostPort = getDomainFromActor(objectUrl) diff --git a/posts.py b/posts.py index 895c50c7e..c402e883c 100644 --- a/posts.py +++ b/posts.py @@ -30,6 +30,7 @@ from session import postJsonString from session import postImage from webfinger import webfingerHandle from httpsig import createSignedHeader +from utils import hasUsersPath from utils import validPostDate from utils import getFullDomain from utils import getFollowersList @@ -155,10 +156,7 @@ def getUserUrl(wfRequest: {}, sourceId=0) -> str: continue if link['type'] != 'application/activity+json': continue - if not ('/users/' in link['href'] or - '/accounts/' in link['href'] or - '/profile/' in link['href'] or - '/channel/' in link['href']): + if not hasUsersPath(link['href']): print('getUserUrl webfinger activity+json ' + 'contains single user instance actor ' + str(sourceId) + ' ' + str(link)) diff --git a/tests.py b/tests.py index 5bd93560e..32dd0b01a 100644 --- a/tests.py +++ b/tests.py @@ -854,7 +854,7 @@ def testFollowBetweenServers(): True, __version__, False) print('sendResult: ' + str(sendResult)) - for t in range(10): + for t in range(16): if os.path.isfile(bobDir + '/accounts/bob@' + bobDomain + '/followers.txt'): if os.path.isfile(aliceDir + '/accounts/alice@' + @@ -2613,9 +2613,10 @@ def getFunctionCalls(name: str, lines: [], startLineCtr: int, callsFunctions = [] functionContentStr = '' for lineCtr in range(startLineCtr + 1, len(lines)): - if lines[lineCtr].startswith('def '): + lineStr = lines[lineCtr].strip() + if lineStr.startswith('def '): break - if lines[lineCtr].startswith('class '): + if lineStr.startswith('class '): break functionContentStr += lines[lineCtr] for funcName, properties in functionProperties.items(): @@ -2635,14 +2636,14 @@ def functionArgsMatch(callArgs: [], funcArgs: []): for a in callArgs: if a == 'self': continue - if '=' not in a: + if '=' not in a or a.startswith("'"): callArgsCtr += 1 funcArgsCtr = 0 for a in funcArgs: if a == 'self': continue - if '=' not in a: + if '=' not in a or a.startswith("'"): funcArgsCtr += 1 return callArgsCtr >= funcArgsCtr @@ -2670,7 +2671,7 @@ def testFunctions(): lines = f.readlines() modules[modName]['lines'] = lines for line in lines: - if not line.startswith('def '): + if not line.strip().startswith('def '): continue methodName = line.split('def ', 1)[1].split('(')[0] methodArgs = \ @@ -2694,7 +2695,9 @@ def testFunctions(): 'pyjsonld' ] excludeFuncs = [ - 'link' + 'link', + 'set', + 'get' ] # which modules is each function used within? for modName, modProperties in modules.items(): @@ -2702,7 +2705,11 @@ def testFunctions(): for name, properties in functionProperties.items(): lineCtr = 0 for line in modules[modName]['lines']: - if line.startswith('def '): + lineStr = line.strip() + if lineStr.startswith('def '): + lineCtr += 1 + continue + if lineStr.startswith('class '): lineCtr += 1 continue if name + '(' in line: @@ -2735,7 +2742,22 @@ def testFunctions(): # don't check these functions, because they are procedurally called exclusions = [ + 'do_GET', + 'do_POST', + 'do_HEAD', + '__run', + 'globaltrace', + 'localtrace', + 'kill', + 'clone', + 'unregister_rdf_parser', 'set_document_loader', + 'has_property', + 'has_value', + 'add_value', + 'get_values', + 'remove_property', + 'remove_value', 'normalize', 'get_document_loader', 'runInboxQueueWatchdog', @@ -2764,17 +2786,26 @@ def testFunctions(): 'setOrganizationScheme' ] excludeImports = [ - 'link' + 'link', + 'start' ] excludeLocal = [ 'pyjsonld', 'daemon', 'tests' ] + excludeMods = [ + 'pyjsonld' + ] # check that functions are called somewhere for name, properties in functionProperties.items(): + if name.startswith('__'): + if name.endswith('__'): + continue if name in exclusions: continue + if properties['module'] in excludeMods: + continue isLocalFunction = False if not properties['calledInModule']: print('function ' + name + @@ -2815,18 +2846,80 @@ def testFunctions(): assert False print('Function: ' + name + ' ✓') - print('Constructing call graph') + print('Constructing function call graph') + moduleColors = ('red', 'green', 'yellow', 'orange', 'purple', 'cyan', + 'darkgoldenrod3', 'darkolivegreen1', 'darkorange1', + 'darkorchid1', 'darkseagreen', 'darkslategray4', + 'deeppink1', 'deepskyblue1', 'dimgrey', 'gold1', + 'goldenrod', 'burlywood2', 'bisque1', 'brown1', + 'chartreuse2', 'cornsilk', 'darksalmon') + maxModuleCalls = 1 + maxFunctionCalls = 1 + colorCtr = 0 for modName, modProperties in modules.items(): lineCtr = 0 + modules[modName]['color'] = moduleColors[colorCtr] + colorCtr += 1 + if colorCtr >= len(moduleColors): + colorCtr = 0 for line in modules[modName]['lines']: - if line.startswith('def '): + if line.strip().startswith('def '): name = line.split('def ')[1].split('(')[0] callsList = \ getFunctionCalls(name, modules[modName]['lines'], lineCtr, functionProperties) functionProperties[name]['calls'] = callsList.copy() + if len(callsList) > maxFunctionCalls: + maxFunctionCalls = len(callsList) + # keep track of which module calls which other module + for fn in callsList: + modCall = functionProperties[fn]['module'] + if modCall != modName: + if modules[modName].get('calls'): + if modCall not in modules[modName]['calls']: + modules[modName]['calls'].append(modCall) + if len(modules[modName]['calls']) > \ + maxModuleCalls: + maxModuleCalls = \ + len(modules[modName]['calls']) + else: + modules[modName]['calls'] = [modCall] lineCtr += 1 + callGraphStr = 'digraph EpicyonModules {\n\n' + callGraphStr += ' graph [fontsize=10 fontname="Verdana" compound=true];\n' + callGraphStr += ' node [shape=record fontsize=10 fontname="Verdana"];\n\n' + # colors of modules nodes + for modName, modProperties in modules.items(): + if not modProperties.get('calls'): + callGraphStr += ' "' + modName + \ + '" [fillcolor=yellow style=filled];\n' + continue + if len(modProperties['calls']) <= int(maxModuleCalls / 8): + callGraphStr += ' "' + modName + \ + '" [fillcolor=green style=filled];\n' + elif len(modProperties['calls']) < int(maxModuleCalls / 4): + callGraphStr += ' "' + modName + \ + '" [fillcolor=orange style=filled];\n' + else: + callGraphStr += ' "' + modName + \ + '" [fillcolor=red style=filled];\n' + callGraphStr += '\n' + # connections between modules + for modName, modProperties in modules.items(): + if not modProperties.get('calls'): + continue + for modCall in modProperties['calls']: + callGraphStr += ' "' + modName + '" -> "' + modCall + '";\n' + callGraphStr += '\n}\n' + with open('epicyon_modules.dot', 'w+') as fp: + fp.write(callGraphStr) + print('Modules call graph saved to epicyon_modules.dot') + print('Plot using: ' + + 'sfdp -x -Goverlap=false -Goverlap_scaling=2 ' + + '-Gsep=+100 -Tx11 epicyon_modules.dot') + callGraphStr = 'digraph Epicyon {\n\n' + callGraphStr += ' size="8,6"; ratio=fill;\n' callGraphStr += ' graph [fontsize=10 fontname="Verdana" compound=true];\n' callGraphStr += ' node [shape=record fontsize=10 fontname="Verdana"];\n\n' @@ -2834,25 +2927,52 @@ def testFunctions(): callGraphStr += ' subgraph cluster_' + modName + ' {\n' callGraphStr += ' label = "' + modName + '";\n' callGraphStr += ' node [style=filled];\n' - callGraphStr += ' ' + moduleFunctionsStr = '' for name in modProperties['functions']: - callGraphStr += '"' + name + '" ' - callGraphStr += ';\n' + if name.startswith('test'): + continue + if name not in excludeFuncs: + if not functionProperties[name]['calls']: + moduleFunctionsStr += \ + ' "' + name + '" [fillcolor=yellow style=filled];\n' + continue + noOfCalls = len(functionProperties[name]['calls']) + if noOfCalls < int(maxFunctionCalls / 4): + moduleFunctionsStr += ' "' + name + \ + '" [fillcolor=orange style=filled];\n' + else: + moduleFunctionsStr += ' "' + name + \ + '" [fillcolor=red style=filled];\n' + + if moduleFunctionsStr: + callGraphStr += moduleFunctionsStr + '\n' callGraphStr += ' color=blue;\n' callGraphStr += ' }\n\n' for name, properties in functionProperties.items(): if not properties['calls']: continue + noOfCalls = len(properties['calls']) + if noOfCalls <= int(maxFunctionCalls / 8): + modColor = 'blue' + elif noOfCalls < int(maxFunctionCalls / 4): + modColor = 'green' + else: + modColor = 'red' for calledFunc in properties['calls']: - callGraphStr += ' "' + name + '" -> "' + calledFunc + '";\n' + if calledFunc.startswith('test'): + continue + if calledFunc not in excludeFuncs: + callGraphStr += ' "' + name + '" -> "' + calledFunc + \ + '" [color=' + modColor + '];\n' callGraphStr += '\n}\n' with open('epicyon.dot', 'w+') as fp: fp.write(callGraphStr) print('Call graph saved to epicyon.dot') - print('Convert to image with: ' + - 'dot -Tjpg epicyon.dot -o epicyon_diagram.jpg') + print('Plot using: ' + + 'sfdp -x -Goverlap=prism -Goverlap_scaling=8 ' + + '-Gsep=+120 -Tx11 epicyon.dot') def runAllTests(): diff --git a/theme/rc3/icons/separator_right.png b/theme/rc3/icons/separator_right.png new file mode 100644 index 000000000..3f31f0fce Binary files /dev/null and b/theme/rc3/icons/separator_right.png differ diff --git a/theme/rc3/theme.json b/theme/rc3/theme.json index 46df93ea7..da23786e1 100644 --- a/theme/rc3/theme.json +++ b/theme/rc3/theme.json @@ -1,4 +1,6 @@ { + "post-separator-margin-top": "10px", + "post-separator-margin-bottom": "10px", "calendar-header-font-style": "normal", "italic-font-style": "normal", "calendar-header-font": "'Orbitron'", @@ -22,8 +24,6 @@ "publish-button-at-top": "False", "main-visited-color": "#46eed5", "options-main-visited-color": "#46eed5", - "post-separator-margin-top": "9%", - "post-separator-margin-bottom": "9%", "post-separator-width": "80%", "post-separator-height": "10%", "column-left-header-background": "#6800e7", diff --git a/translations/ar.json b/translations/ar.json index 630067626..c0288c1e5 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -347,5 +347,7 @@ "Filter out words": "تصفية الكلمات", "Unfilter": "غير مرشح", "Unfilter words": "الكلمات غير المصفاة", - "Show Accounts": "إظهار الحسابات" + "Show Accounts": "إظهار الحسابات", + "Peertube Instances": "مثيلات Peertube", + "Show video previews for the following Peertube sites.": "إظهار معاينات الفيديو لمواقع Peertube التالية." } diff --git a/translations/ca.json b/translations/ca.json index 853f94914..ffc4725d9 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -347,5 +347,7 @@ "Filter out words": "Filtra les paraules", "Unfilter": "Sense filtre", "Unfilter words": "Paraules sense filtre", - "Show Accounts": "Mostra comptes" + "Show Accounts": "Mostra comptes", + "Peertube Instances": "Instàncies de Peertube", + "Show video previews for the following Peertube sites.": "Mostra les previsualitzacions de vídeo dels següents llocs de Peertube." } diff --git a/translations/cy.json b/translations/cy.json index eafc25d65..cd659af7a 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -347,5 +347,7 @@ "Filter out words": "Hidlo geiriau", "Unfilter": "Di-hid", "Unfilter words": "Geiriau di-hid", - "Show Accounts": "Dangos Cyfrifon" + "Show Accounts": "Dangos Cyfrifon", + "Peertube Instances": "Camau Peertube", + "Show video previews for the following Peertube sites.": "Dangos rhagolygon fideo ar gyfer y safleoedd Peertube canlynol." } diff --git a/translations/de.json b/translations/de.json index 6749671f9..e0e757b7d 100644 --- a/translations/de.json +++ b/translations/de.json @@ -347,5 +347,7 @@ "Filter out words": "Wörter herausfiltern", "Unfilter": "Filter entfernen", "Unfilter words": "Wörter herausfiltern", - "Show Accounts": "Konten anzeigen" + "Show Accounts": "Konten anzeigen", + "Peertube Instances": "Peertube-Instanzen", + "Show video previews for the following Peertube sites.": "Zeigen Sie eine Videovorschau für die folgenden Peertube-Websites an." } diff --git a/translations/en.json b/translations/en.json index 6f3c33440..6ea42b2c6 100644 --- a/translations/en.json +++ b/translations/en.json @@ -347,5 +347,7 @@ "Filter out words": "Filter out words", "Unfilter": "Unfilter", "Unfilter words": "Unfilter words", - "Show Accounts": "Show Accounts" + "Show Accounts": "Show Accounts", + "Peertube Instances": "Peertube Instances", + "Show video previews for the following Peertube sites.": "Show video previews for the following Peertube sites." } diff --git a/translations/es.json b/translations/es.json index dcf167a97..49293f2e5 100644 --- a/translations/es.json +++ b/translations/es.json @@ -347,5 +347,7 @@ "Filter out words": "Filtrar palabras", "Unfilter": "Unfilter", "Unfilter words": "Palabras sin filtrar", - "Show Accounts": "Mostrar cuentas" + "Show Accounts": "Mostrar cuentas", + "Peertube Instances": "Instancias de Peertube", + "Show video previews for the following Peertube sites.": "Muestre vistas previas de video para los siguientes sitios de Peertube." } diff --git a/translations/fr.json b/translations/fr.json index 3d8dc2b55..ede3e55fa 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -347,5 +347,7 @@ "Filter out words": "Filtrer les mots", "Unfilter": "Non filtrer", "Unfilter words": "Mots non filtrés", - "Show Accounts": "Afficher les comptes" + "Show Accounts": "Afficher les comptes", + "Peertube Instances": "Instances Peertube", + "Show video previews for the following Peertube sites.": "Afficher des aperçus vidéo pour les sites Peertube suivants." } diff --git a/translations/ga.json b/translations/ga.json index a4e46b1f0..af58fe18d 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -347,5 +347,7 @@ "Filter out words": "Scag focail amach", "Unfilter": "Neamhleithleach", "Unfilter words": "Focail neamhleithleacha", - "Show Accounts": "Taispeáin Cuntais" + "Show Accounts": "Taispeáin Cuntais", + "Peertube Instances": "Imeachtaí Peertube", + "Show video previews for the following Peertube sites.": "Taispeáin réamhamharcanna físe do na suíomhanna Peertube seo a leanas." } diff --git a/translations/hi.json b/translations/hi.json index 49f6d60e2..9c0f78c50 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -347,5 +347,7 @@ "Filter out words": "शब्दों को फ़िल्टर करें", "Unfilter": "Unfilter", "Unfilter words": "अनफ़िल्टर शब्द", - "Show Accounts": "खाते दिखाएं" + "Show Accounts": "खाते दिखाएं", + "Peertube Instances": "Peertube उदाहरण", + "Show video previews for the following Peertube sites.": "निम्नलिखित Peertube साइटों के लिए वीडियो पूर्वावलोकन दिखाएं।" } diff --git a/translations/it.json b/translations/it.json index bd4b3db9c..36b2fdc10 100644 --- a/translations/it.json +++ b/translations/it.json @@ -347,5 +347,7 @@ "Filter out words": "Filtra le parole", "Unfilter": "Unfilter", "Unfilter words": "Parole non filtrate", - "Show Accounts": "Mostra account" + "Show Accounts": "Mostra account", + "Peertube Instances": "Istanze di Peertube", + "Show video previews for the following Peertube sites.": "Mostra le anteprime dei video per i seguenti siti Peertube." } diff --git a/translations/ja.json b/translations/ja.json index e2029f181..079f7bd07 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -347,5 +347,7 @@ "Filter out words": "単語を除外する", "Unfilter": "フィルタリング解除", "Unfilter words": "単語のフィルタリングを解除する", - "Show Accounts": "アカウントを表示する" + "Show Accounts": "アカウントを表示する", + "Peertube Instances": "Peertubeインスタンス", + "Show video previews for the following Peertube sites.": "次のPeertubeサイトのビデオプレビューを表示します。" } diff --git a/translations/oc.json b/translations/oc.json index 0468223b1..2b7e26f7e 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -343,5 +343,7 @@ "Filter out words": "Filter out words", "Unfilter": "Unfilter", "Unfilter words": "Unfilter words", - "Show Accounts": "Show Accounts" + "Show Accounts": "Show Accounts", + "Peertube Instances": "Peertube Instances", + "Show video previews for the following Peertube sites.": "Show video previews for the following Peertube sites." } diff --git a/translations/pt.json b/translations/pt.json index b4cb1996a..67b1f3891 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -347,5 +347,7 @@ "Filter out words": "Filtrar palavras", "Unfilter": "Unfilter", "Unfilter words": "Palavras sem filtro", - "Show Accounts": "Mostrar contas" + "Show Accounts": "Mostrar contas", + "Peertube Instances": "Instâncias Peertube", + "Show video previews for the following Peertube sites.": "Mostrar visualizações de vídeo para os seguintes sites Peertube." } diff --git a/translations/ru.json b/translations/ru.json index a95083395..3236b46fa 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -347,5 +347,7 @@ "Filter out words": "Отфильтровать слова", "Unfilter": "Нефильтровать", "Unfilter words": "Не фильтровать слова", - "Show Accounts": "Показать счета" + "Show Accounts": "Показать счета", + "Peertube Instances": "Экземпляры Peertube", + "Show video previews for the following Peertube sites.": "Показать превью видео для следующих сайтов Peertube." } diff --git a/translations/zh.json b/translations/zh.json index 36ea2b053..fe7a8e92e 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -347,5 +347,7 @@ "Filter out words": "过滤掉单词", "Unfilter": "取消过滤", "Unfilter words": "未过滤字词", - "Show Accounts": "显示帐户" + "Show Accounts": "显示帐户", + "Peertube Instances": "Peertube实例", + "Show video previews for the following Peertube sites.": "显示以下Peertube网站的视频预览。" } diff --git a/utils.py b/utils.py index ff89afd02..2bdcbff74 100644 --- a/utils.py +++ b/utils.py @@ -19,6 +19,16 @@ from calendar import monthrange from followingCalendar import addPersonToCalendar +def hasUsersPath(pathStr: str) -> bool: + """Whether there is a /users/ path (or equivalent) in the given string + """ + usersList = ('users', 'accounts', 'channel', 'profile') + for usersStr in usersList: + if '/' + usersStr + '/' in pathStr: + return True + return False + + def validPostDate(published: str, maxAgeDays=7) -> bool: """Returns true if the published date is recent and is not in the future """ diff --git a/webapp_confirm.py b/webapp_confirm.py index a0f87f744..3649c256d 100644 --- a/webapp_confirm.py +++ b/webapp_confirm.py @@ -28,7 +28,8 @@ def htmlConfirmDelete(cssCache: {}, wfRequest: {}, personCache: {}, callingDomain: str, YTReplacementDomain: str, - showPublishedDateOnly: bool) -> str: + showPublishedDateOnly: bool, + peertubeInstances: []) -> str: """Shows a screen asking to confirm the deletion of a post """ if '/statuses/' not in messageId: @@ -66,6 +67,7 @@ def htmlConfirmDelete(cssCache: {}, httpPrefix, projectVersion, 'outbox', YTReplacementDomain, showPublishedDateOnly, + peertubeInstances, False, False, False, False, False) deletePostStr += '
Tox: ' + removeHtml(toxAddress) + '
\n' + if briarAddress: + if briarAddress.startswith('briar://'): + optionsStr += \ + '' + \ + removeHtml(briarAddress) + '
\n' + else: + optionsStr += \ + 'briar://' + \ + removeHtml(briarAddress) + '
\n' if jamiAddress: optionsStr += \ 'Jami: ' + removeHtml(jamiAddress) + '
\n' diff --git a/webapp_post.py b/webapp_post.py index 274a7840c..2daff3307 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -1076,6 +1076,7 @@ def individualPostAsHtml(allowDownloads: bool, httpPrefix: str, projectVersion: str, boxName: str, YTReplacementDomain: str, showPublishedDateOnly: bool, + peertubeInstances: [], showRepeats=True, showIcons=False, manuallyApprovesFollowers=False, @@ -1483,7 +1484,8 @@ def individualPostAsHtml(allowDownloads: bool, if not postIsSensitive: contentStr = objectContent + attachmentStr - contentStr = addEmbeddedElements(translate, contentStr) + contentStr = addEmbeddedElements(translate, contentStr, + peertubeInstances) contentStr = insertQuestion(baseDir, translate, nickname, domain, port, contentStr, postJsonObject, @@ -1499,7 +1501,8 @@ def individualPostAsHtml(allowDownloads: bool, # get the content warning text cwContentStr = objectContent + attachmentStr if not isPatch: - cwContentStr = addEmbeddedElements(translate, cwContentStr) + cwContentStr = addEmbeddedElements(translate, cwContentStr, + peertubeInstances) cwContentStr = \ insertQuestion(baseDir, translate, nickname, domain, port, cwContentStr, postJsonObject, pageNumber) @@ -1571,7 +1574,8 @@ def htmlIndividualPost(cssCache: {}, postJsonObject: {}, httpPrefix: str, projectVersion: str, likedBy: str, YTReplacementDomain: str, - showPublishedDateOnly: bool) -> str: + showPublishedDateOnly: bool, + peertubeInstances: []) -> str: """Show an individual post as html """ postStr = '' @@ -1611,6 +1615,7 @@ def htmlIndividualPost(cssCache: {}, httpPrefix, projectVersion, 'inbox', YTReplacementDomain, showPublishedDateOnly, + peertubeInstances, False, authorized, False, False, False) messageId = removeIdEnding(postJsonObject['id']) @@ -1636,6 +1641,7 @@ def htmlIndividualPost(cssCache: {}, httpPrefix, projectVersion, 'inbox', YTReplacementDomain, showPublishedDateOnly, + peertubeInstances, False, authorized, False, False, False) + postStr @@ -1664,6 +1670,7 @@ def htmlIndividualPost(cssCache: {}, httpPrefix, projectVersion, 'inbox', YTReplacementDomain, showPublishedDateOnly, + peertubeInstances, False, authorized, False, False, False) cssFilename = baseDir + '/epicyon-profile.css' @@ -1680,7 +1687,8 @@ def htmlPostReplies(cssCache: {}, nickname: str, domain: str, port: int, repliesJson: {}, httpPrefix: str, projectVersion: str, YTReplacementDomain: str, - showPublishedDateOnly: bool) -> str: + showPublishedDateOnly: bool, + peertubeInstances: []) -> str: """Show the replies to an individual post as html """ repliesStr = '' @@ -1696,6 +1704,7 @@ def htmlPostReplies(cssCache: {}, httpPrefix, projectVersion, 'inbox', YTReplacementDomain, showPublishedDateOnly, + peertubeInstances, False, False, False, False, False) cssFilename = baseDir + '/epicyon-profile.css' diff --git a/webapp_profile.py b/webapp_profile.py index 5cc8866db..e1e05727f 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -8,6 +8,7 @@ __status__ = "Production" import os from pprint import pprint +from utils import hasUsersPath from utils import getFullDomain from utils import isDormant from utils import getNicknameFromActor @@ -33,6 +34,7 @@ from pgp import getEmailAddress from pgp import getPGPfingerprint from pgp import getPGPpubKey from tox import getToxAddress +from briar import getBriarAddress from jami import getJamiAddress from filters import isFiltered from webapp_frontscreen import htmlFrontScreen @@ -58,14 +60,11 @@ def htmlProfileAfterSearch(cssCache: {}, debug: bool, projectVersion: str, YTReplacementDomain: str, showPublishedDateOnly: bool, - defaultTimeline: str) -> str: + defaultTimeline: str, + peertubeInstances: []) -> str: """Show a profile page after a search for a fediverse address """ - if '/users/' in profileHandle or \ - '/accounts/' in profileHandle or \ - '/channel/' in profileHandle or \ - '/profile/' in profileHandle or \ - '/@' in profileHandle: + if hasUsersPath(profileHandle) or '/@' in profileHandle: searchNickname = getNicknameFromActor(profileHandle) searchDomain, searchPort = getDomainFromActor(profileHandle) else: @@ -279,6 +278,7 @@ def htmlProfileAfterSearch(cssCache: {}, httpPrefix, projectVersion, 'inbox', YTReplacementDomain, showPublishedDateOnly, + peertubeInstances, False, False, False, False, False) i += 1 if i >= 20: @@ -372,6 +372,7 @@ def htmlProfile(rssIconAtTop: bool, YTReplacementDomain: str, showPublishedDateOnly: bool, newswire: {}, theme: str, dormantMonths: int, + peertubeInstances: [], extraJson=None, pageNumber=None, maxItemsPerPage=None) -> str: """Show the profile page as html @@ -443,9 +444,11 @@ def htmlProfile(rssIconAtTop: bool, matrixAddress = getMatrixAddress(profileJson) ssbAddress = getSSBAddress(profileJson) toxAddress = getToxAddress(profileJson) + briarAddress = getBriarAddress(profileJson) jamiAddress = getJamiAddress(profileJson) if donateUrl or xmppAddress or matrixAddress or \ - ssbAddress or toxAddress or jamiAddress or PGPpubKey or \ + ssbAddress or toxAddress or briarAddress or \ + jamiAddress or PGPpubKey or \ PGPfingerprint or emailAddress: donateSection = 'Tox:
\n' + if briarAddress: + if briarAddress.startswith('briar://'): + donateSection += \ + '\n' + else: + donateSection += \ + 'briar://
\n' if jamiAddress: donateSection += \ 'Jami: \n' editProfileForm += skillsStr + themesDropdown - editProfileForm += moderatorsStr + editorsStr + editProfileForm += moderatorsStr + editorsStr + peertubeStr editProfileForm += '