diff --git a/acceptreject.py b/acceptreject.py index 1202d1e50..bd6c7f366 100644 --- a/acceptreject.py +++ b/acceptreject.py @@ -7,6 +7,7 @@ __email__ = "bob@freedombone.net" __status__ = "Production" import os +from utils import getFullDomain from utils import urlPermitted from utils import getDomainFromActor from utils import getNicknameFromActor @@ -30,10 +31,7 @@ def createAcceptReject(baseDir: str, federationList: [], if not urlPermitted(objectJson['actor'], federationList): return None - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) newAccept = { "@context": "https://www.w3.org/ns/activitystreams", diff --git a/announce.py b/announce.py index 799e8689a..386a63866 100644 --- a/announce.py +++ b/announce.py @@ -6,6 +6,7 @@ __maintainer__ = "Bob Mottram" __email__ = "bob@freedombone.net" __status__ = "Production" +from utils import getFullDomain from utils import getStatusNumber from utils import createOutboxDir from utils import urlPermitted @@ -113,11 +114,7 @@ def createAnnounce(session, baseDir: str, federationList: [], if ':' in domain: domain = domain.split(':')[0] - fullDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) + fullDomain = getFullDomain(domain, port) statusNumber, published = getStatusNumber() newAnnounceId = httpPrefix + '://' + fullDomain + \ @@ -172,11 +169,7 @@ def announcePublic(session, baseDir: str, federationList: [], debug: bool, projectVersion: str) -> {}: """Makes a public announcement """ - fromDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fromDomain = domain + ':' + str(port) + fromDomain = getFullDomain(domain, port) toUrl = 'https://www.w3.org/ns/activitystreams#Public' ccUrl = httpPrefix + '://' + fromDomain + '/users/' + nickname + \ @@ -200,11 +193,7 @@ def repeatPost(session, baseDir: str, federationList: [], debug: bool, projectVersion: str) -> {}: """Repeats a given status post """ - announcedDomain = announceDomain - if announcePort: - if announcePort != 80 and announcePort != 443: - if ':' not in announcedDomain: - announcedDomain = announcedDomain + ':' + str(announcePort) + announcedDomain = getFullDomain(announceDomain, announcePort) objectUrl = announceHttpsPrefix + '://' + announcedDomain + '/users/' + \ announceNickname + '/statuses/' + str(announceStatusNumber) @@ -236,11 +225,7 @@ def undoAnnounce(session, baseDir: str, federationList: [], if ':' in domain: domain = domain.split(':')[0] - fullDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) + fullDomain = getFullDomain(domain, port) newUndoAnnounce = { "@context": "https://www.w3.org/ns/activitystreams", @@ -290,11 +275,7 @@ def undoAnnouncePublic(session, baseDir: str, federationList: [], debug: bool) -> {}: """Undoes a public announcement """ - fromDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fromDomain = domain + ':' + str(port) + fromDomain = getFullDomain(domain, port) toUrl = 'https://www.w3.org/ns/activitystreams#Public' ccUrl = httpPrefix + '://' + fromDomain + '/users/' + nickname + \ @@ -318,11 +299,7 @@ def undoRepeatPost(session, baseDir: str, federationList: [], debug: bool) -> {}: """Undoes a status post repeat """ - announcedDomain = announceDomain - if announcePort: - if announcePort != 80 and announcePort != 443: - if ':' not in announcedDomain: - announcedDomain = announcedDomain + ':' + str(announcePort) + announcedDomain = getFullDomain(announceDomain, announcePort) objectUrl = announceHttpsPrefix + '://' + announcedDomain + '/users/' + \ announceNickname + '/statuses/' + str(announceStatusNumber) @@ -347,11 +324,7 @@ def sendAnnounceViaServer(baseDir: str, session, print('WARN: No session for sendAnnounceViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) toUrl = 'https://www.w3.org/ns/activitystreams#Public' ccUrl = httpPrefix + '://' + fromDomainFull + '/users/' + fromNickname + \ diff --git a/availability.py b/availability.py index 201e0d06e..b7739e86e 100644 --- a/availability.py +++ b/availability.py @@ -11,6 +11,7 @@ from webfinger import webfingerHandle from auth import createBasicAuthHeader from posts import getPersonBox from session import postJson +from utils import getFullDomain from utils import getNicknameFromActor from utils import getDomainFromActor from utils import loadJson @@ -85,11 +86,7 @@ def sendAvailabilityViaServer(baseDir: str, session, print('WARN: No session for sendAvailabilityViaServer') return 6 - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) toUrl = httpPrefix + '://' + domainFull + '/users/' + nickname ccUrl = httpPrefix + '://' + domainFull + '/users/' + nickname + \ diff --git a/blocking.py b/blocking.py index 8cb23e5b8..c34641fc2 100644 --- a/blocking.py +++ b/blocking.py @@ -7,6 +7,7 @@ __email__ = "bob@freedombone.net" __status__ = "Production" import os +from utils import getFullDomain from utils import removeIdEnding from utils import isEvil from utils import locatePost @@ -265,11 +266,7 @@ def outboxBlock(baseDir: str, httpPrefix: str, print('WARN: unable to find nickname in ' + messageJson['object']) return domainBlocked, portBlocked = getDomainFromActor(messageJson['object']) - domainBlockedFull = domainBlocked - if portBlocked: - if portBlocked != 80 and portBlocked != 443: - if ':' not in domainBlocked: - domainBlockedFull = domainBlocked + ':' + str(portBlocked) + domainBlockedFull = getFullDomain(domainBlocked, portBlocked) addBlock(baseDir, nickname, domain, nicknameBlocked, domainBlockedFull) @@ -346,11 +343,7 @@ def outboxUndoBlock(baseDir: str, httpPrefix: str, return domainObject = messageJson['object']['object'] domainBlocked, portBlocked = getDomainFromActor(domainObject) - domainBlockedFull = domainBlocked - if portBlocked: - if portBlocked != 80 and portBlocked != 443: - if ':' not in domainBlocked: - domainBlockedFull = domainBlocked + ':' + str(portBlocked) + domainBlockedFull = getFullDomain(domainBlocked, portBlocked) removeBlock(baseDir, nickname, domain, nicknameBlocked, domainBlockedFull) diff --git a/blog.py b/blog.py index 3216f9b8a..36fc1c4ed 100644 --- a/blog.py +++ b/blog.py @@ -14,6 +14,7 @@ from webapp_utils import htmlHeaderWithExternalStyle from webapp_utils import htmlFooter from webapp_utils import getPostAttachmentsAsHtml from webapp_media import addEmbeddedElements +from utils import getFullDomain from utils import getMediaFormats from utils import getNicknameFromActor from utils import getDomainFromActor @@ -443,10 +444,7 @@ def htmlBlogPage(authorized: bool, session, if not timelineJson: return blogStr + htmlFooter() - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) # show previous and next buttons if pageNumber is not None: @@ -513,10 +511,7 @@ def htmlBlogPageRSS2(authorized: bool, session, '\n' in nickname or '\r' in nickname: return None - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) blogRSS2 = '' if includeHeader: @@ -571,10 +566,7 @@ def htmlBlogPageRSS3(authorized: bool, session, '\n' in nickname or '\r' in nickname: return None - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) blogRSS3 = '' @@ -682,10 +674,7 @@ def htmlBlogView(authorized: bool, nickname, domain, port, noOfItems, 1) - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) for subdir, dirs, files in os.walk(baseDir + '/accounts'): for acct in dirs: diff --git a/bookmarks.py b/bookmarks.py index 43415adb6..c0ef808a1 100644 --- a/bookmarks.py +++ b/bookmarks.py @@ -8,6 +8,7 @@ __status__ = "Production" import os from pprint import pprint +from utils import getFullDomain from utils import removeIdEnding from utils import removePostFromCache from utils import urlPermitted @@ -237,11 +238,7 @@ def bookmark(recentPostsCache: {}, if not urlPermitted(objectUrl, federationList): return None - fullDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) + fullDomain = getFullDomain(domain, port) newBookmarkJson = { "@context": "https://www.w3.org/ns/activitystreams", @@ -298,11 +295,7 @@ def bookmarkPost(recentPostsCache: {}, debug: bool, projectVersion: str) -> {}: """Bookmarks a given status post. This is only used by unit tests """ - bookmarkedomain = bookmarkedomain - if bookmarkPort: - if bookmarkPort != 80 and bookmarkPort != 443: - if ':' not in bookmarkedomain: - bookmarkedomain = bookmarkedomain + ':' + str(bookmarkPort) + bookmarkedomain = getFullDomain(bookmarkedomain, bookmarkPort) actorBookmarked = httpPrefix + '://' + bookmarkedomain + \ '/users/' + bookmarkNickname @@ -333,11 +326,7 @@ def undoBookmark(recentPostsCache: {}, if not urlPermitted(objectUrl, federationList): return None - fullDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) + fullDomain = getFullDomain(domain, port) newUndoBookmarkJson = { "@context": "https://www.w3.org/ns/activitystreams", @@ -396,11 +385,7 @@ def undoBookmarkPost(session, baseDir: str, federationList: [], debug: bool) -> {}: """Removes a bookmarked post """ - bookmarkedomain = bookmarkedomain - if bookmarkPort: - if bookmarkPort != 80 and bookmarkPort != 443: - if ':' not in bookmarkedomain: - bookmarkedomain = bookmarkedomain + ':' + str(bookmarkPort) + bookmarkedomain = getFullDomain(bookmarkedomain, bookmarkPort) objectUrl = httpPrefix + '://' + bookmarkedomain + \ '/users/' + bookmarkNickname + \ @@ -425,11 +410,7 @@ def sendBookmarkViaServer(baseDir: str, session, print('WARN: No session for sendBookmarkViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) newBookmarkJson = { "@context": "https://www.w3.org/ns/activitystreams", @@ -503,11 +484,7 @@ def sendUndoBookmarkViaServer(baseDir: str, session, print('WARN: No session for sendUndoBookmarkViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) newUndoBookmarkJson = { "@context": "https://www.w3.org/ns/activitystreams", diff --git a/daemon.py b/daemon.py index cb8add174..6c76b5a2e 100644 --- a/daemon.py +++ b/daemon.py @@ -172,6 +172,7 @@ from shares import getSharesFeedForPerson from shares import addShare from shares import removeShare from shares import expireShares +from utils import getFullDomain from utils import removeHtml from utils import setHashtagCategory from utils import isEditor @@ -1404,12 +1405,21 @@ class PubServer(BaseHTTPRequestHandler): domain: str, domainFull: str, port: int, onionDomain: str, i2pDomain: str, debug: bool) -> None: - """Actions on the moderator screeen + """Actions on the moderator screen """ usersPath = path.replace('/moderationaction', '') nickname = usersPath.replace('/users/', '') - actorStr = httpPrefix + '://' + domainFull + usersPath + if not isModerator(self.server.baseDir, nickname): + if callingDomain.endswith('.onion') and onionDomain: + actorStr = 'http://' + onionDomain + usersPath + elif (callingDomain.endswith('.i2p') and i2pDomain): + actorStr = 'http://' + i2pDomain + usersPath + self._redirect_headers(actorStr + '/moderation', + cookie, callingDomain) + self.server.POSTbusy = False + return + actorStr = httpPrefix + '://' + domainFull + usersPath length = int(self.headers['Content-length']) try: @@ -1446,8 +1456,30 @@ class PubServer(BaseHTTPRequestHandler): elif moderationStr.startswith('submitInfo'): searchHandle = moderationText if searchHandle: + if '/@' in searchHandle: + searchNickname = \ + getNicknameFromActor(searchHandle) + searchDomain, searchPort = \ + getDomainFromActor(searchHandle) + searchHandle = \ + searchNickname + '@' + searchDomain if '@' not in searchHandle: - searchHandle = None + if searchHandle.startswith('http'): + searchNickname = \ + getNicknameFromActor(searchHandle) + searchDomain, searchPort = \ + getDomainFromActor(searchHandle) + searchHandle = \ + searchNickname + '@' + searchDomain + if '@' not in searchHandle: + # is this a local nickname on this instance? + localHandle = \ + searchHandle + '@' + self.server.domain + if os.path.isdir(self.server.baseDir + + '/accounts/' + localHandle): + searchHandle = localHandle + else: + searchHandle = None if searchHandle: msg = \ htmlAccountInfo(self.server.cssCache, @@ -1501,12 +1533,7 @@ class PubServer(BaseHTTPRequestHandler): # https://domain blockDomain, blockPort = \ getDomainFromActor(moderationText) - fullBlockDomain = blockDomain - if blockPort: - if blockPort != 80 and blockPort != 443: - if ':' not in blockDomain: - fullBlockDomain = \ - blockDomain + ':' + str(blockPort) + fullBlockDomain = getFullDomain(blockDomain, blockPort) if '@' in moderationText: # nick@domain or *@domain fullBlockDomain = moderationText.split('@')[1] @@ -1524,12 +1551,7 @@ class PubServer(BaseHTTPRequestHandler): # https://domain blockDomain, blockPort = \ getDomainFromActor(moderationText) - fullBlockDomain = blockDomain - if blockPort: - if blockPort != 80 and blockPort != 443: - if ':' not in blockDomain: - fullBlockDomain = \ - blockDomain + ':' + str(blockPort) + fullBlockDomain = getFullDomain(blockDomain, blockPort) if '@' in moderationText: # nick@domain or *@domain fullBlockDomain = moderationText.split('@')[1] @@ -1692,12 +1714,7 @@ class PubServer(BaseHTTPRequestHandler): return optionsDomain, optionsPort = getDomainFromActor(optionsActor) - optionsDomainFull = optionsDomain - if optionsPort: - if optionsPort != 80 and optionsPort != 443: - if ':' not in optionsDomain: - optionsDomainFull = optionsDomain + ':' + \ - str(optionsPort) + optionsDomainFull = getFullDomain(optionsDomain, optionsPort) if chooserNickname == optionsNickname and \ optionsDomain == domain and \ optionsPort == port: @@ -1780,23 +1797,61 @@ class PubServer(BaseHTTPRequestHandler): # person options screen, permission to post to newswire # See htmlPersonOptions if '&submitPostToNews=' in optionsConfirmParams: - if isModerator(self.server.baseDir, chooserNickname): + adminNickname = getConfigParam(self.server.baseDir, 'admin') + if (chooserNickname != optionsNickname and + (chooserNickname == adminNickname or + (isModerator(self.server.baseDir, chooserNickname) and + not isModerator(self.server.baseDir, optionsNickname)))): postsToNews = None if 'postsToNews=' in optionsConfirmParams: postsToNews = optionsConfirmParams.split('postsToNews=')[1] if '&' in postsToNews: postsToNews = postsToNews.split('&')[0] - newswireBlockedFilename = \ - self.server.baseDir + '/accounts/' + \ - optionsNickname + '@' + optionsDomain + '/.nonewswire' + accountDir = self.server.baseDir + '/accounts/' + \ + optionsNickname + '@' + optionsDomain + newswireBlockedFilename = accountDir + '/.nonewswire' if postsToNews == 'on': if os.path.isfile(newswireBlockedFilename): os.remove(newswireBlockedFilename) else: - noNewswireFile = open(newswireBlockedFilename, "w+") - if noNewswireFile: - noNewswireFile.write('\n') - noNewswireFile.close() + if os.path.isdir(accountDir): + noNewswireFile = open(newswireBlockedFilename, "w+") + if noNewswireFile: + noNewswireFile.write('\n') + noNewswireFile.close() + self._redirect_headers(usersPath + '/' + + self.server.defaultTimeline + + '?page='+str(pageNumber), cookie, + callingDomain) + self.server.POSTbusy = False + return + + # person options screen, permission to post to newswire + # See htmlPersonOptions + if '&submitModNewsPosts=' in optionsConfirmParams: + adminNickname = getConfigParam(self.server.baseDir, 'admin') + if (chooserNickname != optionsNickname and + (chooserNickname == adminNickname or + (isModerator(self.server.baseDir, chooserNickname) and + not isModerator(self.server.baseDir, optionsNickname)))): + modPostsToNews = None + if 'modNewsPosts=' in optionsConfirmParams: + modPostsToNews = \ + optionsConfirmParams.split('modNewsPosts=')[1] + if '&' in modPostsToNews: + modPostsToNews = modPostsToNews.split('&')[0] + accountDir = self.server.baseDir + '/accounts/' + \ + optionsNickname + '@' + optionsDomain + newswireModFilename = accountDir + '/.newswiremoderated' + if modPostsToNews != 'on': + if os.path.isfile(newswireModFilename): + os.remove(newswireModFilename) + else: + if os.path.isdir(accountDir): + modNewswireFile = open(newswireModFilename, "w+") + if modNewswireFile: + modNewswireFile.write('\n') + modNewswireFile.close() self._redirect_headers(usersPath + '/' + self.server.defaultTimeline + '?page='+str(pageNumber), cookie, @@ -1891,6 +1946,31 @@ class PubServer(BaseHTTPRequestHandler): self.server.POSTbusy = False return + # person options screen, Info button + # See htmlPersonOptions + if '&submitPersonInfo=' in optionsConfirmParams: + if isModerator(self.server.baseDir, chooserNickname): + if debug: + print('Showing info for ' + optionsActor) + msg = \ + htmlAccountInfo(self.server.cssCache, + self.server.translate, + baseDir, + httpPrefix, + chooserNickname, + domain, + self.server.port, + optionsActor, + self.server.debug).encode('utf-8') + self._set_headers('text/html', len(msg), + cookie, callingDomain) + self._write(msg) + self.server.POSTbusy = False + return + else: + self._404() + return + # person options screen, snooze button # See htmlPersonOptions if '&submitSnooze=' in optionsConfirmParams: @@ -2011,11 +2091,7 @@ class PubServer(BaseHTTPRequestHandler): followingNickname = getNicknameFromActor(followingActor) followingDomain, followingPort = \ getDomainFromActor(followingActor) - followingDomainFull = followingDomain - if followingPort: - if followingPort != 80 and followingPort != 443: - followingDomainFull = \ - followingDomain + ':' + str(followingPort) + followingDomainFull = getFullDomain(followingDomain, followingPort) if followerNickname == followingNickname and \ followingDomain == domain and \ followingPort == port: @@ -2208,12 +2284,7 @@ class PubServer(BaseHTTPRequestHandler): return blockingDomain, blockingPort = \ getDomainFromActor(blockingActor) - blockingDomainFull = blockingDomain - if blockingPort: - if blockingPort != 80 and blockingPort != 443: - if ':' not in blockingDomain: - blockingDomainFull = \ - blockingDomain + ':' + str(blockingPort) + blockingDomainFull = getFullDomain(blockingDomain, blockingPort) if blockerNickname == blockingNickname and \ blockingDomain == domain and \ blockingPort == port: @@ -2297,12 +2368,7 @@ class PubServer(BaseHTTPRequestHandler): return blockingDomain, blockingPort = \ getDomainFromActor(blockingActor) - blockingDomainFull = blockingDomain - if blockingPort: - if blockingPort != 80 and blockingPort != 443: - if ':' not in blockingDomain: - blockingDomainFull = \ - blockingDomain + ':' + str(blockingPort) + blockingDomainFull = getFullDomain(blockingDomain, blockingPort) if blockerNickname == blockingNickname and \ blockingDomain == domain and \ blockingPort == port: @@ -3701,6 +3767,11 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(actorFilename): actorJson = loadJson(actorFilename) if actorJson: + if not actorJson.get('discoverable'): + # discoverable in profile directory + # which isn't implemented in Epicyon + actorJson['discoverable'] = False + actorChanged = True # update the avatar/image url file extension uploads = profileMediaTypesUploaded.items() for mType, lastPart in uploads: @@ -3712,6 +3783,13 @@ class PubServer(BaseHTTPRequestHandler): actorJson['icon']['url'] = \ actorJson['icon']['url'].replace(srchStr, repStr) + if '.' in actorJson['icon']['url']: + imgExt = \ + actorJson['icon']['url'].split('.')[-1] + if imgExt == 'jpg': + imgExt = 'jpeg' + actorJson['icon']['mediaType'] = \ + 'image/' + imgExt elif mType == 'image': lastPartOfUrl = \ actorJson['image']['url'].split('/')[-1] @@ -3719,6 +3797,13 @@ class PubServer(BaseHTTPRequestHandler): actorJson['image']['url'] = \ actorJson['image']['url'].replace(srchStr, repStr) + if '.' in actorJson['image']['url']: + imgExt = \ + actorJson['image']['url'].split('.')[-1] + if imgExt == 'jpg': + imgExt = 'jpeg' + actorJson['image']['mediaType'] = \ + 'image/' + imgExt # set skill levels skillCtr = 1 @@ -4451,15 +4536,23 @@ class PubServer(BaseHTTPRequestHandler): actorJson['id'].replace('/', '#') + '.json' saveJson(actorJson, actorCacheFilename) # send profile update to followers - ccStr = 'https://www.w3.org/ns/' + \ + pubStr = 'https://www.w3.org/ns/' + \ 'activitystreams#Public' + pubNumber, pubDate = getStatusNumber() + pubContext = actorJson['@context'].copy() + # remove the context from the actor json and put it + # at the start of the Upgrade activity + del actorJson['@context'] updateActorJson = { + '@context': pubContext, + 'id': actorJson['id'] + '#updates/' + pubNumber, 'type': 'Update', 'actor': actorJson['id'], - 'to': [actorJson['id'] + '/followers'], - 'cc': [ccStr], + 'to': [pubStr], + 'cc': [actorJson['id'] + '/followers'], 'object': actorJson } + print('Sending actor update: ' + str(updateActorJson)) self._postToOutbox(updateActorJson, __version__, nickname) @@ -5531,15 +5624,22 @@ class PubServer(BaseHTTPRequestHandler): """ originPathStr = path.split('/newswirevote=')[0] dateStr = \ - path.split('/newswirevote=')[1].replace('T', ' ') + '+00:00' - nickname = originPathStr.split('/users/')[1] + path.split('/newswirevote=')[1].replace('T', ' ') + dateStr = dateStr.replace(' 00:00', '').replace('+00:00', '') + dateStr = urllib.parse.unquote_plus(dateStr) + '+00:00' + nickname = urllib.parse.unquote_plus(originPathStr.split('/users/')[1]) if '/' in nickname: nickname = nickname.split('/')[0] + print('Newswire item date: ' + dateStr) if newswire.get(dateStr): if isModerator(baseDir, nickname): - if 'vote:' + nickname not in newswire[dateStr][2]: - newswire[dateStr][2].append('vote:' + nickname) - filename = newswire[dateStr][3] + newswireItem = newswire[dateStr] + print('Voting on newswire item: ' + str(newswireItem)) + votesIndex = 2 + filenameIndex = 3 + if 'vote:' + nickname not in newswireItem[votesIndex]: + newswireItem[votesIndex].append('vote:' + nickname) + filename = newswireItem[filenameIndex] newswireStateFilename = \ baseDir + '/accounts/.newswirestate.json' try: @@ -5547,8 +5647,11 @@ class PubServer(BaseHTTPRequestHandler): except Exception as e: print('ERROR saving newswire state, ' + str(e)) if filename: - saveJson(newswire[dateStr][2], + saveJson(newswireItem[votesIndex], filename + '.votes') + else: + print('No newswire item with date: ' + dateStr + ' ' + + str(newswire)) originPathStrAbsolute = \ httpPrefix + '://' + domainFull + originPathStr + '/' + \ @@ -5578,15 +5681,20 @@ class PubServer(BaseHTTPRequestHandler): """ originPathStr = path.split('/newswireunvote=')[0] dateStr = \ - path.split('/newswireunvote=')[1].replace('T', ' ') + '+00:00' - nickname = originPathStr.split('/users/')[1] + path.split('/newswireunvote=')[1].replace('T', ' ') + dateStr = dateStr.replace(' 00:00', '').replace('+00:00', '') + dateStr = urllib.parse.unquote_plus(dateStr) + '+00:00' + nickname = urllib.parse.unquote_plus(originPathStr.split('/users/')[1]) if '/' in nickname: nickname = nickname.split('/')[0] if newswire.get(dateStr): if isModerator(baseDir, nickname): - if 'vote:' + nickname in newswire[dateStr][2]: - newswire[dateStr][2].remove('vote:' + nickname) - filename = newswire[dateStr][3] + votesIndex = 2 + filenameIndex = 3 + newswireItem = newswire[dateStr] + if 'vote:' + nickname in newswireItem[votesIndex]: + newswireItem[votesIndex].remove('vote:' + nickname) + filename = newswireItem[filenameIndex] newswireStateFilename = \ baseDir + '/accounts/.newswirestate.json' try: @@ -5594,8 +5702,11 @@ class PubServer(BaseHTTPRequestHandler): except Exception as e: print('ERROR saving newswire state, ' + str(e)) if filename: - saveJson(newswire[dateStr][2], + saveJson(newswireItem[votesIndex], filename + '.votes') + else: + print('No newswire item with date: ' + dateStr + ' ' + + str(newswire)) originPathStrAbsolute = \ httpPrefix + '://' + domainFull + originPathStr + '/' + \ @@ -13154,11 +13265,7 @@ def runDaemon(dormantMonths: int, httpd.maxPostsInBox = 32000 httpd.domain = domain httpd.port = port - httpd.domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - httpd.domainFull = domain + ':' + str(port) + httpd.domainFull = getFullDomain(domain, port) saveDomainQrcode(baseDir, httpPrefix, httpd.domainFull) httpd.httpPrefix = httpPrefix httpd.debug = debug diff --git a/delete.py b/delete.py index 58dbd5d28..8302da1ed 100644 --- a/delete.py +++ b/delete.py @@ -8,6 +8,7 @@ __status__ = "Production" import os from datetime import datetime +from utils import getFullDomain from utils import removeIdEnding from utils import getStatusNumber from utils import urlPermitted @@ -42,10 +43,7 @@ def createDelete(session, baseDir: str, federationList: [], if ':' in domain: domain = domain.split(':')[0] fullDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) + fullDomain = getFullDomain(domain, port) statusNumber, published = getStatusNumber() newDeleteId = \ @@ -100,11 +98,7 @@ def sendDeleteViaServer(baseDir: str, session, print('WARN: No session for sendDeleteViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) actor = httpPrefix + '://' + fromDomainFull + \ '/users/' + fromNickname @@ -181,11 +175,7 @@ def deletePublic(session, baseDir: str, federationList: [], debug: bool) -> {}: """Makes a public delete activity """ - fromDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fromDomain = domain + ':' + str(port) + fromDomain = getFullDomain(domain, port) toUrl = 'https://www.w3.org/ns/activitystreams#Public' ccUrl = httpPrefix + '://' + fromDomain + \ @@ -209,11 +199,7 @@ def deletePostPub(session, baseDir: str, federationList: [], debug: bool) -> {}: """Deletes a given status post """ - deletedDomain = deleteDomain - if deletePort: - if deletePort != 80 and deletePort != 443: - if ':' not in deletedDomain: - deletedDomain = deletedDomain + ':' + str(deletePort) + deletedDomain = getFullDomain(deleteDomain, deletePort) objectUrl = \ deleteHttpsPrefix + '://' + deletedDomain + '/users/' + \ diff --git a/epicyon.py b/epicyon.py index 214605140..ba8eb64b3 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 getFullDomain from utils import setConfigParam from utils import getConfigParam from utils import getDomainFromActor @@ -501,10 +502,8 @@ if args.posts: if '/users/' in args.posts: postsNickname = getNicknameFromActor(args.posts) postsDomain, postsPort = getDomainFromActor(args.posts) - args.posts = postsNickname + '@' + postsDomain - if postsPort: - if postsPort != 80 and postsPort != 443: - args.posts += ':' + str(postsPort) + args.posts = \ + getFullDomain(postsNickname + '@' + postsDomain, postsPort) else: print('Syntax: --posts nickname@domain') sys.exit() @@ -533,10 +532,8 @@ if args.postDomains: if '/users/' in args.postDomains: postsNickname = getNicknameFromActor(args.postDomains) postsDomain, postsPort = getDomainFromActor(args.postDomains) - args.postDomains = postsNickname + '@' + postsDomain - if postsPort: - if postsPort != 80 and postsPort != 443: - args.postDomains += ':' + str(postsPort) + args.postDomains = \ + getFullDomain(postsNickname + '@' + postsDomain, postsPort) else: print('Syntax: --postDomains nickname@domain') sys.exit() @@ -573,10 +570,8 @@ if args.postDomainsBlocked: postsNickname = getNicknameFromActor(args.postDomainsBlocked) postsDomain, postsPort = \ getDomainFromActor(args.postDomainsBlocked) - args.postDomainsBlocked = postsNickname + '@' + postsDomain - if postsPort: - if postsPort != 80 and postsPort != 443: - args.postDomainsBlocked += ':' + str(postsPort) + args.postDomainsBlocked = \ + getFullDomain(postsNickname + '@' + postsDomain, postsPort) else: print('Syntax: --postDomainsBlocked nickname@domain') sys.exit() @@ -612,10 +607,8 @@ if args.checkDomains: if '/users/' in args.checkDomains: postsNickname = getNicknameFromActor(args.posts) postsDomain, postsPort = getDomainFromActor(args.posts) - args.checkDomains = postsNickname + '@' + postsDomain - if postsPort: - if postsPort != 80 and postsPort != 443: - args.checkDomains += ':' + str(postsPort) + args.checkDomains = \ + getFullDomain(postsNickname + '@' + postsDomain, postsPort) else: print('Syntax: --checkDomains nickname@domain') sys.exit() diff --git a/follow.py b/follow.py index bf44bc83e..58c1dfb6d 100644 --- a/follow.py +++ b/follow.py @@ -8,6 +8,7 @@ __status__ = "Production" from pprint import pprint import os +from utils import getFullDomain from utils import isSystemAccount from utils import getFollowersList from utils import validNickname @@ -145,11 +146,8 @@ def isFollowingActor(baseDir: str, print('WARN: unable to find nickname in ' + actor) return False followingDomain, followingPort = getDomainFromActor(actor) - followingHandle = followingNickname + '@' + followingDomain - if followingPort: - if followingPort != 80 and followingPort != 443: - if ':' not in followingHandle: - followingHandle += ':' + str(followingPort) + followingHandle = \ + getFullDomain(followingNickname + '@' + followingDomain, followingPort) if followingHandle.lower() in open(followingFile).read().lower(): return True return False @@ -374,10 +372,7 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str, if not validNickname(domain, nickname): return None - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) if headerOnly: firstStr = \ @@ -539,12 +534,8 @@ def storeFollowRequest(baseDir: str, return False approveHandle = nickname + '@' + domain - domainFull = domain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in domain: - approveHandle = nickname + '@' + domain + ':' + str(fromPort) - domainFull = domain + ':' + str(fromPort) + domainFull = getFullDomain(domain, fromPort) + approveHandle = getFullDomain(nickname + '@' + domain, fromPort) followersFilename = accountsDir + '/followers.txt' if os.path.isfile(followersFilename): @@ -634,12 +625,9 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str, return False domain, tempPort = getDomainFromActor(messageJson['actor']) fromPort = port - domainFull = domain + domainFull = getFullDomain(domain, tempPort) if tempPort: fromPort = tempPort - if tempPort != 80 and tempPort != 443: - if ':' not in domain: - domainFull = domain + ':' + str(tempPort) if not domainPermitted(domain, federationList): if debug: print('DEBUG: follower from domain not permitted - ' + domain) @@ -666,11 +654,7 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str, if debug: print('DEBUG: follow domain not permitted ' + domainToFollow) return True - domainToFollowFull = domainToFollow - if tempPort: - if tempPort != 80 and tempPort != 443: - if ':' not in domainToFollow: - domainToFollowFull = domainToFollow + ':' + str(tempPort) + domainToFollowFull = getFullDomain(domainToFollow, tempPort) nicknameToFollow = getNicknameFromActor(messageJson['object']) if not nicknameToFollow: if debug: @@ -878,10 +862,7 @@ def followedAccountRejects(session, baseDir: str, httpPrefix: str, ' port ' + str(port) + ' to ' + nickname + '@' + domain + ' port ' + str(fromPort)) clientToServer = False - denyHandle = nickname + '@' + domain - if fromPort: - if fromPort != 80 and fromPort != 443: - denyHandle = denyHandle + ':' + str(fromPort) + denyHandle = getFullDomain(nickname + '@' + domain, fromPort) # remove from the follow requests file removeFromFollowRequests(baseDir, nicknameToFollow, domainToFollow, denyHandle, debug) @@ -913,20 +894,10 @@ def sendFollowRequest(session, baseDir: str, if not domainPermitted(followDomain, federationList): return None - fullDomain = domain - followActor = httpPrefix + '://' + domain + '/users/' + nickname - if port: - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) - followActor = httpPrefix + '://' + \ - fullDomain + '/users/' + nickname + fullDomain = getFullDomain(domain, port) + followActor = httpPrefix + '://' + fullDomain + '/users/' + nickname - requestDomain = followDomain - if followPort: - if followPort != 80 and followPort != 443: - if ':' not in followDomain: - requestDomain = followDomain + ':' + str(followPort) + requestDomain = getFullDomain(followDomain, followPort) statusNumber, published = getStatusNumber() @@ -984,17 +955,9 @@ def sendFollowRequestViaServer(baseDir: str, session, print('WARN: No session for sendFollowRequestViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) - followDomainFull = followDomain - if followPort: - if followPort != 80 and followPort != 443: - if ':' not in followDomain: - followDomainFull = followDomain + ':' + str(followPort) + followDomainFull = getFullDomain(followDomain, followPort) followActor = httpPrefix + '://' + \ fromDomainFull + '/users/' + fromNickname @@ -1077,16 +1040,8 @@ def sendUnfollowRequestViaServer(baseDir: str, session, print('WARN: No session for sendUnfollowRequestViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) - followDomainFull = followDomain - if followPort: - if followPort != 80 and followPort != 443: - if ':' not in followDomain: - followDomainFull = followDomain + ':' + str(followPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) + followDomainFull = getFullDomain(followDomain, followPort) followActor = httpPrefix + '://' + \ fromDomainFull + '/users/' + fromNickname @@ -1241,11 +1196,7 @@ def outboxUndoFollow(baseDir: str, messageJson: {}, debug: bool) -> None: return domainFollower, portFollower = \ getDomainFromActor(messageJson['object']['actor']) - domainFollowerFull = domainFollower - if portFollower: - if portFollower != 80 and portFollower != 443: - if ':' not in domainFollower: - domainFollowerFull = domainFollower + ':' + str(portFollower) + domainFollowerFull = getFullDomain(domainFollower, portFollower) nicknameFollowing = getNicknameFromActor(messageJson['object']['object']) if not nicknameFollowing: @@ -1254,12 +1205,7 @@ def outboxUndoFollow(baseDir: str, messageJson: {}, debug: bool) -> None: return domainFollowing, portFollowing = \ getDomainFromActor(messageJson['object']['object']) - domainFollowingFull = domainFollowing - if portFollowing: - if portFollowing != 80 and portFollowing != 443: - if ':' not in domainFollowing: - domainFollowingFull = \ - domainFollowing + ':' + str(portFollowing) + domainFollowingFull = getFullDomain(domainFollowing, portFollowing) if unfollowPerson(baseDir, nicknameFollower, domainFollowerFull, nicknameFollowing, domainFollowingFull): diff --git a/httpsig.py b/httpsig.py index 97a001d6c..77873c801 100644 --- a/httpsig.py +++ b/httpsig.py @@ -22,6 +22,7 @@ except ImportError: import base64 from time import gmtime, strftime import datetime +from utils import getFullDomain def messageContentDigest(messageBodyJsonStr: str) -> str: @@ -40,15 +41,9 @@ def signPostHeaders(dateStr: str, privateKeyPem: str, """Returns a raw signature string that can be plugged into a header and used to verify the authenticity of an HTTP transmission. """ - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) - if toPort: - if toPort != 80 and toPort != 443: - if ':' not in toDomain: - toDomain = toDomain + ':' + str(port) + toDomain = getFullDomain(toDomain, toPort) if not dateStr: dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime()) @@ -107,12 +102,7 @@ def createSignedHeader(privateKeyPem: str, nickname: str, """Note that the domain is the destination, not the sender """ contentType = 'application/activity+json' - headerDomain = toDomain - - if toPort: - if toPort != 80 and toPort != 443: - if ':' not in headerDomain: - headerDomain = headerDomain + ':' + str(toPort) + headerDomain = getFullDomain(toDomain, toPort) dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime()) if not withDigest: diff --git a/inbox.py b/inbox.py index 4772a763b..9a2536837 100644 --- a/inbox.py +++ b/inbox.py @@ -10,6 +10,7 @@ import json import os import datetime import time +from utils import getFullDomain from utils import isEventPost from utils import removeIdEnding from utils import getProtocolPrefixes @@ -371,10 +372,7 @@ def savePostToInboxQueue(baseDir: str, httpPrefix: str, if debug: print('DEBUG: post from ' + postNickname + ' blocked') return None - if postPort: - if postPort != 80 and postPort != 443: - if ':' not in postDomain: - postDomain = postDomain + ':' + str(postPort) + postDomain = getFullDomain(postDomain, postPort) if postJsonObject.get('object'): if isinstance(postJsonObject['object'], dict): @@ -524,10 +522,7 @@ def inboxPostRecipients(baseDir: str, postJsonObject: {}, if ':' in domain: domain = domain.split(':')[0] domainBase = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) domainMatch = '/' + domain + '/users/' actor = postJsonObject['actor'] @@ -649,11 +644,7 @@ def receiveUndoFollow(session, baseDir: str, httpPrefix: str, return False domainFollower, portFollower = \ getDomainFromActor(messageJson['object']['actor']) - domainFollowerFull = domainFollower - if portFollower: - if portFollower != 80 and portFollower != 443: - if ':' not in domainFollower: - domainFollowerFull = domainFollower + ':' + str(portFollower) + domainFollowerFull = getFullDomain(domainFollower, portFollower) nicknameFollowing = \ getNicknameFromActor(messageJson['object']['object']) @@ -663,12 +654,7 @@ def receiveUndoFollow(session, baseDir: str, httpPrefix: str, return False domainFollowing, portFollowing = \ getDomainFromActor(messageJson['object']['object']) - domainFollowingFull = domainFollowing - if portFollowing: - if portFollowing != 80 and portFollowing != 443: - if ':' not in domainFollowing: - domainFollowingFull = \ - domainFollowing + ':' + str(portFollowing) + domainFollowingFull = getFullDomain(domainFollowing, portFollowing) if unfollowerOfPerson(baseDir, nicknameFollowing, domainFollowingFull, @@ -749,10 +735,7 @@ def receiveEventPost(recentPostsCache: {}, session, baseDir: str, if not isEventPost(messageJson): return print('Receiving event: ' + str(messageJson['object'])) - handle = nickname + '@' + domain - if port: - if port != 80 and port != 443: - handle += ':' + str(port) + handle = getFullDomain(nickname + '@' + domain, port) postId = removeIdEnding(messageJson['id']).replace('/', '#') @@ -766,16 +749,10 @@ def personReceiveUpdate(baseDir: str, personJson: {}, personCache: {}, debug: bool) -> bool: """Changes an actor. eg: avatar or display name change """ - if debug: - print('DEBUG: receiving actor update for ' + personJson['url']) - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) - updateDomainFull = updateDomain - if updatePort: - if updatePort != 80 and updatePort != 443: - updateDomainFull = updateDomain + ':' + str(updatePort) + print('Receiving actor update for ' + personJson['url'] + + ' ' + str(personJson)) + domainFull = getFullDomain(domain, port) + updateDomainFull = getFullDomain(updateDomain, updatePort) actor = updateDomainFull + '/users/' + updateNickname if actor not in personJson['id']: actor = updateDomainFull + '/profile/' + updateNickname @@ -917,7 +894,7 @@ def receiveUpdate(recentPostsCache: {}, session, baseDir: str, if messageJson['type'] == 'Person': if messageJson.get('url') and messageJson.get('id'): - print('Request to update unwrapped actor: ' + messageJson['id']) + print('Request to update actor unwrapped: ' + str(messageJson)) updateNickname = getNicknameFromActor(messageJson['id']) if updateNickname: updateDomain, updatePort = \ @@ -938,7 +915,7 @@ def receiveUpdate(recentPostsCache: {}, session, baseDir: str, messageJson['object']['type'] == 'Service': if messageJson['object'].get('url') and \ messageJson['object'].get('id'): - print('Request to update actor: ' + messageJson['actor']) + print('Request to update actor: ' + str(messageJson)) updateNickname = getNicknameFromActor(messageJson['actor']) if updateNickname: updateDomain, updatePort = \ @@ -1124,10 +1101,7 @@ def receiveBookmark(recentPostsCache: {}, if debug: print('DEBUG: unrecognized domain ' + handle) return False - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) nickname = handle.split('@')[0] if not messageJson['actor'].endswith(domainFull + '/users/' + nickname): if debug: @@ -1192,10 +1166,7 @@ def receiveUndoBookmark(recentPostsCache: {}, print('DEBUG: "statuses" missing from like object in ' + messageJson['type']) return False - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) nickname = handle.split('@')[0] if domain not in handle.split('@')[1]: if debug: @@ -1249,11 +1220,7 @@ def receiveDelete(session, handle: str, isGroup: bool, baseDir: str, if debug: print('DEBUG: ' + messageJson['type'] + ' object is not a string') return False - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) deletePrefix = httpPrefix + '://' + domainFull + '/' if (not allowDeletion and (not messageJson['object'].startswith(deletePrefix) or @@ -1923,23 +1890,15 @@ def sendToGroupMembers(session, baseDir: str, handle: str, port: int, nickname = handle.split('@')[0] # groupname = getGroupName(baseDir, handle) domain = handle.split('@')[1] - domainFull = domain - if ':' not in domain: - if port: - if port != 80 and port != 443: - domain = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) # set sender cc = '' sendingActor = postJsonObject['actor'] sendingActorNickname = getNicknameFromActor(sendingActor) sendingActorDomain, sendingActorPort = \ getDomainFromActor(sendingActor) - sendingActorDomainFull = sendingActorDomain - if ':' in sendingActorDomain: - if sendingActorPort: - if sendingActorPort != 80 and sendingActorPort != 443: - sendingActorDomainFull = \ - sendingActorDomain + ':' + str(sendingActorPort) + sendingActorDomainFull = \ + getFullDomain(sendingActorDomain, sendingActorPort) senderStr = '@' + sendingActorNickname + '@' + sendingActorDomainFull if not postJsonObject['object']['content'].startswith(senderStr): postJsonObject['object']['content'] = \ @@ -2259,9 +2218,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, if isinstance(attributedTo, str): fromNickname = getNicknameFromActor(attributedTo) fromDomain, fromPort = getDomainFromActor(attributedTo) - if fromPort: - if fromPort != 80 and fromPort != 443: - fromDomain += ':' + str(fromPort) + fromDomain = getFullDomain(fromDomain, fromPort) if receiveGitPatch(baseDir, nickname, domain, jsonObj['type'], jsonObj['summary'], @@ -2352,11 +2309,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, nickname + '/dm') # get the actor being replied to - domainFull = domain - if port: - if ':' not in domain: - if port != 80 and port != 443: - domainFull = domainFull + ':' + str(port) + domainFull = getFullDomain(domain, port) actor = httpPrefix + '://' + domainFull + \ '/users/' + handle.split('@')[0] diff --git a/like.py b/like.py index 4a16d0fe3..6076c7299 100644 --- a/like.py +++ b/like.py @@ -6,6 +6,7 @@ __maintainer__ = "Bob Mottram" __email__ = "bob@freedombone.net" __status__ = "Production" +from utils import getFullDomain from utils import removeIdEnding from utils import urlPermitted from utils import getNicknameFromActor @@ -66,11 +67,7 @@ def like(recentPostsCache: {}, if not urlPermitted(objectUrl, federationList): return None - fullDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) + fullDomain = getFullDomain(domain, port) newLikeJson = { "@context": "https://www.w3.org/ns/activitystreams", @@ -132,11 +129,7 @@ def likePost(recentPostsCache: {}, debug: bool, projectVersion: str) -> {}: """Likes a given status post. This is only used by unit tests """ - likeDomain = likeDomain - if likePort: - if likePort != 80 and likePort != 443: - if ':' not in likeDomain: - likeDomain = likeDomain + ':' + str(likePort) + likeDomain = getFullDomain(likeDomain, likePort) actorLiked = httpPrefix + '://' + likeDomain + '/users/' + likeNickname objectUrl = actorLiked + '/statuses/' + str(likeStatusNumber) @@ -165,11 +158,7 @@ def undolike(recentPostsCache: {}, if not urlPermitted(objectUrl, federationList): return None - fullDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) + fullDomain = getFullDomain(domain, port) newUndoLikeJson = { "@context": "https://www.w3.org/ns/activitystreams", @@ -234,11 +223,7 @@ def sendLikeViaServer(baseDir: str, session, print('WARN: No session for sendLikeViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) actor = httpPrefix + '://' + fromDomainFull + '/users/' + fromNickname @@ -313,11 +298,7 @@ def sendUndoLikeViaServer(baseDir: str, session, print('WARN: No session for sendUndoLikeViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) actor = httpPrefix + '://' + fromDomainFull + '/users/' + fromNickname diff --git a/media.py b/media.py index df6409f78..b7c0b849e 100644 --- a/media.py +++ b/media.py @@ -13,6 +13,7 @@ import os import datetime from hashlib import sha1 from auth import createPassword +from utils import getFullDomain from utils import getImageExtensions from utils import getVideoExtensions from utils import getAudioExtensions @@ -163,10 +164,7 @@ def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int, if mediaType == 'audio/mpeg': fileExtension = 'mp3' - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) mPath = getMediaPath() mediaPath = mPath + '/' + createPassword(32) + '.' + fileExtension diff --git a/newsdaemon.py b/newsdaemon.py index 74ee33820..42a69994b 100644 --- a/newsdaemon.py +++ b/newsdaemon.py @@ -26,6 +26,7 @@ from posts import archivePostsForPerson from content import removeHtmlTag from content import dangerousMarkup from content import validHashTag +from utils import getFullDomain from utils import loadJson from utils import saveJson from utils import getStatusNumber @@ -245,10 +246,7 @@ def newswireHashtagProcessing(session, baseDir: str, postJsonObject: {}, with open(rulesFilename, "r") as f: rules = f.readlines() - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) # get the full text content of the post content = '' @@ -584,10 +582,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str, blog['object']['content'] = rssDescription blog['object']['contentMap']['en'] = rssDescription - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) hashtags = item[6] diff --git a/outbox.py b/outbox.py index 141745bb1..8da5d9b38 100644 --- a/outbox.py +++ b/outbox.py @@ -14,6 +14,7 @@ from posts import outboxMessageCreateWrap from posts import savePostToBox from posts import sendToFollowersThread from posts import sendToNamedAddresses +from utils import getFullDomain from utils import removeIdEnding from utils import getDomainFromActor from blocking import isBlockedDomain @@ -113,9 +114,7 @@ def postMessageToOutbox(messageJson: {}, postToNickname: str, str(messageJson)) return False testDomain, testPort = getDomainFromActor(messageJson['actor']) - if testPort: - if testPort != 80 and testPort != 443: - testDomain = testDomain + ':' + str(testPort) + testDomain = getFullDomain(testDomain, testPort) if isBlockedDomain(baseDir, testDomain): if debug: print('DEBUG: domain is blocked: ' + messageJson['actor']) diff --git a/person.py b/person.py index 86f0fe6e2..9fcf099d2 100644 --- a/person.py +++ b/person.py @@ -35,6 +35,7 @@ from auth import storeBasicCredentials from auth import removePassword from roles import setRole from media import removeMetaData +from utils import getFullDomain from utils import validNickname from utils import loadJson from utils import saveJson @@ -68,11 +69,7 @@ def setProfileImage(baseDir: str, httpPrefix: str, nickname: str, domain: str, if ':' in domain: domain = domain.split(':')[0] - fullDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) + fullDomain = getFullDomain(domain, port) handle = nickname + '@' + domain personFilename = baseDir + '/accounts/' + handle + '.json' @@ -193,7 +190,8 @@ def getDefaultPersonContext() -> str: 'identityKey': {'@id': 'toot:identityKey', '@type': '@id'}, 'fingerprintKey': {'@id': 'toot:fingerprintKey', '@type': '@id'}, 'messageFranking': 'toot:messageFranking', - 'publicKeyBase64': 'toot:publicKeyBase64' + 'publicKeyBase64': 'toot:publicKeyBase64', + 'discoverable': 'toot:discoverable' } @@ -213,10 +211,7 @@ def createPersonBase(baseDir: str, nickname: str, domain: str, port: int, handle = nickname + '@' + domain originalDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) personType = 'Person' # Enable follower approval by default @@ -285,6 +280,7 @@ def createPersonBase(baseDir: str, nickname: str, domain: str, port: int, }, 'inbox': inboxStr, 'manuallyApprovesFollowers': approveFollowers, + 'discoverable': False, 'name': personName, 'outbox': personId+'/outbox', 'preferredUsername': personName, @@ -418,10 +414,7 @@ def savePersonQrcode(baseDir: str, nickname + '@' + domain + '/qrcode.png' if os.path.isfile(qrcodeFilename): return - handle = '@' + nickname + '@' + domain - if port: - if port != 80 and port != 443: - handle = handle + ':' + str(port) + handle = getFullDomain('@' + nickname + '@' + domain, port) url = pyqrcode.create(handle) url.png(qrcodeFilename, scale) @@ -868,11 +861,7 @@ def canRemovePost(baseDir: str, nickname: str, if '/statuses/' not in postId: return False - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) # is the post by the admin? adminNickname = getConfigParam(baseDir, 'admin') @@ -898,11 +887,7 @@ def removeTagsForNickname(baseDir: str, nickname: str, """ if not os.path.isdir(baseDir + '/tags'): return - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) matchStr = domainFull + '/users/' + nickname + '/' directory = os.fsencode(baseDir + '/tags/') for f in os.scandir(directory): diff --git a/posts.py b/posts.py index b35c0505b..aefd0564c 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 getFullDomain from utils import getFollowersList from utils import isEvil from utils import removeIdEnding @@ -59,6 +60,7 @@ from content import replaceEmojiFromTags from content import removeTextFormatting from auth import createBasicAuthHeader from blocking import isBlocked +from blocking import isBlockedDomain from filters import isFiltered from git import convertPostToPatch from jsonldsig import jsonldSign @@ -506,6 +508,76 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int, return postDomains +def getPostsForBlockedDomains(baseDir: str, + session, outboxUrl: str, maxPosts: int, + maxMentions: int, + maxEmoji: int, maxAttachments: int, + federationList: [], + personCache: {}, + debug: bool, + projectVersion: str, httpPrefix: str, + domain: str) -> {}: + """Returns a dictionary of posts for blocked domains + """ + if not outboxUrl: + return {} + profileStr = 'https://www.w3.org/ns/activitystreams' + asHeader = { + 'Accept': 'application/activity+json; profile="' + profileStr + '"' + } + if '/outbox/' in outboxUrl: + asHeader = { + 'Accept': 'application/ld+json; profile="' + profileStr + '"' + } + + blockedPosts = {} + + i = 0 + userFeed = parseUserFeed(session, outboxUrl, asHeader, + projectVersion, httpPrefix, domain) + for item in userFeed: + i += 1 + if i > maxPosts: + break + if not item.get('object'): + continue + if not isinstance(item['object'], dict): + continue + if item['object'].get('inReplyTo'): + if isinstance(item['object']['inReplyTo'], str): + postDomain, postPort = \ + getDomainFromActor(item['object']['inReplyTo']) + if isBlockedDomain(baseDir, postDomain): + if item['object'].get('url'): + url = item['object']['url'] + else: + url = item['object']['id'] + if not blockedPosts.get(postDomain): + blockedPosts[postDomain] = [url] + else: + if url not in blockedPosts[postDomain]: + blockedPosts[postDomain].append(url) + + if item['object'].get('tag'): + for tagItem in item['object']['tag']: + tagType = tagItem['type'].lower() + if tagType == 'mention': + if tagItem.get('href'): + postDomain, postPort = \ + getDomainFromActor(tagItem['href']) + if isBlockedDomain(baseDir, postDomain): + if item['object'].get('url'): + url = item['object']['url'] + else: + url = item['object']['id'] + if not blockedPosts.get(postDomain): + blockedPosts[postDomain] = [url] + else: + if url not in blockedPosts[postDomain]: + blockedPosts[postDomain].append(url) + return blockedPosts + + def deleteAllPosts(baseDir: str, nickname: str, domain: str, boxname: str) -> None: """Deletes all posts for a person from inbox or outbox @@ -740,10 +812,7 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int, tags = [] hashtagsDict = {} - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) # add tags if nickname != 'news': @@ -1070,10 +1139,7 @@ def outboxMessageCreateWrap(httpPrefix: str, https://www.w3.org/TR/activitypub/#object-without-create """ - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) statusNumber, published = getStatusNumber() if messageJson.get('published'): published = messageJson['published'] @@ -1108,10 +1174,7 @@ def postIsAddressedToFollowers(baseDir: str, postJsonObject: {}) -> bool: """Returns true if the given post is addressed to followers of the nickname """ - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) if not postJsonObject.get('object'): return False @@ -1174,11 +1237,7 @@ def createPublicPost(baseDir: str, eventDate=None, eventTime=None, location=None) -> {}: """Public post """ - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) return createPostBase(baseDir, nickname, domain, port, 'https://www.w3.org/ns/activitystreams#Public', httpPrefix + '://' + domainFull + '/users/' + @@ -1278,11 +1337,7 @@ def createQuestionPost(baseDir: str, subject: str, durationDays: int) -> {}: """Question post with multiple choice options """ - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) messageJson = \ createPostBase(baseDir, nickname, domain, port, 'https://www.w3.org/ns/activitystreams#Public', @@ -1328,11 +1383,7 @@ def createUnlistedPost(baseDir: str, eventDate=None, eventTime=None, location=None) -> {}: """Unlisted post. This has the #Public and followers links inverted. """ - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) return createPostBase(baseDir, nickname, domain, port, httpPrefix + '://' + domainFull + '/users/' + nickname + '/followers', @@ -1361,11 +1412,7 @@ def createFollowersOnlyPost(baseDir: str, location=None) -> {}: """Followers only post """ - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) return createPostBase(baseDir, nickname, domain, port, httpPrefix + '://' + domainFull + '/users/' + nickname + '/followers', @@ -1404,11 +1451,7 @@ def createEventPost(baseDir: str, if not category: print('Event has no category') return None - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) # create event uuid eventUUID = str(uuid.uuid1()) @@ -1524,11 +1567,7 @@ def createReportPost(baseDir: str, debug: bool, subject=None) -> {}: """Send a report to moderators """ - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) # add a title to distinguish moderation reports from other posts reportTitle = 'Moderation Report' @@ -1698,10 +1737,7 @@ def sendPost(projectVersion: str, # shared inbox actor on @domain@domain toNickname = toDomain - if toPort: - if toPort != 80 and toPort != 443: - if ':' not in toDomain: - toDomain = toDomain + ':' + str(toPort) + toDomain = getFullDomain(toDomain, toPort) handle = httpPrefix + '://' + toDomain + '/@' + toNickname @@ -1816,10 +1852,7 @@ def sendPostViaServer(projectVersion: str, print('WARN: No session for sendPostViaServer') return 6 - if toPort: - if toPort != 80 and toPort != 443: - if ':' not in fromDomain: - fromDomain = fromDomain + ':' + str(fromPort) + fromDomain = getFullDomain(fromDomain, fromPort) handle = httpPrefix + '://' + fromDomain + '/@' + fromNickname @@ -1863,11 +1896,7 @@ def sendPostViaServer(projectVersion: str, clientToServer = True if toDomain.lower().endswith('public'): toPersonId = 'https://www.w3.org/ns/activitystreams#Public' - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) cc = httpPrefix + '://' + fromDomainFull + '/users/' + \ fromNickname + '/followers' else: @@ -1877,11 +1906,7 @@ def sendPostViaServer(projectVersion: str, httpPrefix + '://' + \ fromDomainFull + '/users/' + fromNickname + '/followers' else: - toDomainFull = toDomain - if toPort: - if toPort != 80 and toPort != 443: - if ':' not in toDomain: - toDomainFull = toDomain + ':' + str(toPort) + toDomainFull = getFullDomain(toDomain, toPort) toPersonId = httpPrefix + '://' + toDomainFull + \ '/users/' + toNickname @@ -2010,10 +2035,7 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str, toNickname = toDomain # sharedInbox = True - if toPort: - if toPort != 80 and toPort != 443: - if ':' not in toDomain: - toDomain = toDomain + ':' + str(toPort) + toDomain = getFullDomain(toDomain, toPort) toDomainUrl = httpPrefix + '://' + toDomain if not siteIsActive(toDomainUrl): @@ -2290,16 +2312,8 @@ def sendToNamedAddresses(session, baseDir: str, if not toDomain: continue if debug: - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) - toDomainFull = toDomain - if toPort: - if toPort != 80 and toPort != 443: - if ':' not in toDomain: - toDomainFull = toDomain + ':' + str(toPort) + domainFull = getFullDomain(domain, port) + toDomainFull = getFullDomain(toDomain, toPort) print('DEBUG: Post sending s2s: ' + nickname + '@' + domainFull + ' to ' + toNickname + '@' + toDomainFull) @@ -2618,10 +2632,7 @@ def createModeration(baseDir: str, nickname: str, domain: str, port: int, boxDir = createPersonDir(nickname, domain, baseDir, 'inbox') boxname = 'moderation' - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) if not pageNumber: pageNumber = 1 @@ -2939,10 +2950,7 @@ def createBoxIndexed(recentPostsCache: {}, indexBoxName = boxname timelineNickname = 'news' - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) boxActor = httpPrefix + '://' + domain + '/users/' + nickname @@ -3332,11 +3340,7 @@ def getPublicPostsOfPerson(baseDir: str, nickname: str, domain: str, cachedWebfingers = {} federationList = [] - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) handle = httpPrefix + "://" + domainFull + "/@" + nickname wfRequest = \ webfingerHandle(session, handle, httpPrefix, cachedWebfingers, @@ -3377,11 +3381,7 @@ def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str, cachedWebfingers = {} federationList = [] - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) handle = httpPrefix + "://" + domainFull + "/@" + nickname wfRequest = \ webfingerHandle(session, handle, httpPrefix, cachedWebfingers, @@ -3411,6 +3411,67 @@ def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str, return postDomains +def getPublicPostInfo(session, baseDir: str, nickname: str, domain: str, + proxyType: str, port: int, httpPrefix: str, + debug: bool, projectVersion: str) -> []: + """ Returns a dict of domains referenced within public posts + """ + if not session: + session = createSession(proxyType) + if not session: + return {} + personCache = {} + cachedWebfingers = {} + federationList = [] + + domainFull = getFullDomain(domain, port) + handle = httpPrefix + "://" + domainFull + "/@" + nickname + wfRequest = \ + webfingerHandle(session, handle, httpPrefix, cachedWebfingers, + domain, projectVersion) + if not wfRequest: + return {} + if not isinstance(wfRequest, dict): + print('Webfinger for ' + handle + ' did not return a dict. ' + + str(wfRequest)) + return {} + + (personUrl, pubKeyId, pubKey, + personId, sharedInbox, + avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, + personCache, + projectVersion, httpPrefix, + nickname, domain, 'outbox') + maxMentions = 99 + maxEmoji = 99 + maxAttachments = 5 + maxPosts = 64 + postDomains = \ + getPostDomains(session, personUrl, maxPosts, maxMentions, maxEmoji, + maxAttachments, federationList, + personCache, debug, + projectVersion, httpPrefix, domain, []) + postDomains.sort() + domainsInfo = {} + for d in postDomains: + if not domainsInfo.get(d): + domainsInfo[d] = [] + + blockedPosts = \ + getPostsForBlockedDomains(baseDir, session, personUrl, maxPosts, + maxMentions, + maxEmoji, maxAttachments, + federationList, + personCache, + debug, + projectVersion, httpPrefix, + domain) + for blockedDomain, postUrlList in blockedPosts.items(): + domainsInfo[blockedDomain] += postUrlList + + return domainsInfo + + def getPublicPostDomainsBlocked(session, baseDir: str, nickname: str, domain: str, proxyType: str, port: int, httpPrefix: str, @@ -3740,10 +3801,7 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str, attributedDomain, attributedPort = \ getDomainFromActor(announcedJson['object']['id']) if attributedNickname and attributedDomain: - if attributedPort: - if attributedPort != 80 and attributedPort != 443: - attributedDomain = \ - attributedDomain + ':' + str(attributedPort) + attributedDomain = getFullDomain(attributedDomain, attributedPort) if isBlocked(baseDir, nickname, domain, attributedNickname, attributedDomain): rejectAnnounce(announceFilename) @@ -3859,11 +3917,7 @@ def sendBlockViaServer(baseDir: str, session, print('WARN: No session for sendBlockViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) toUrl = 'https://www.w3.org/ns/activitystreams#Public' ccUrl = httpPrefix + '://' + fromDomainFull + '/users/' + \ @@ -3942,11 +3996,7 @@ def sendUndoBlockViaServer(baseDir: str, session, print('WARN: No session for sendBlockViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) toUrl = 'https://www.w3.org/ns/activitystreams#Public' ccUrl = httpPrefix + '://' + fromDomainFull + '/users/' + \ diff --git a/roles.py b/roles.py index 22db327b3..ecbf237b8 100644 --- a/roles.py +++ b/roles.py @@ -11,6 +11,7 @@ from webfinger import webfingerHandle from auth import createBasicAuthHeader from posts import getPersonBox from session import postJson +from utils import getFullDomain from utils import getNicknameFromActor from utils import getDomainFromActor from utils import loadJson @@ -259,12 +260,7 @@ def sendRoleViaServer(baseDir: str, session, print('WARN: No session for sendRoleViaServer') return 6 - delegatorDomainFull = delegatorDomain - if delegatorPort: - if delegatorPort != 80 and delegatorPort != 443: - if ':' not in delegatorDomain: - delegatorDomainFull = \ - delegatorDomain + ':' + str(delegatorPort) + delegatorDomainFull = getFullDomain(delegatorDomain, delegatorPort) toUrl = \ httpPrefix + '://' + delegatorDomainFull + '/users/' + nickname diff --git a/shares.py b/shares.py index d4b19b36e..1926395a4 100644 --- a/shares.py +++ b/shares.py @@ -13,6 +13,7 @@ from auth import createBasicAuthHeader from posts import getPersonBox from session import postJson from session import postImage +from utils import getFullDomain from utils import validNickname from utils import loadJson from utils import saveJson @@ -115,11 +116,7 @@ def addShare(baseDir: str, imageFilename = sharesImageFilename + '.' + ext moveImage = True - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) # copy or move the image for the shared item to its destination if imageFilename: @@ -247,10 +244,7 @@ def getSharesFeedForPerson(baseDir: str, if not validNickname(domain, nickname): return None - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) handleDomain = domain if ':' in handleDomain: @@ -331,11 +325,7 @@ def sendShareViaServer(baseDir, session, print('WARN: No session for sendShareViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) toUrl = 'https://www.w3.org/ns/activitystreams#Public' ccUrl = httpPrefix + '://' + fromDomainFull + \ @@ -439,11 +429,7 @@ def sendUndoShareViaServer(baseDir: str, session, print('WARN: No session for sendUndoShareViaServer') return 6 - fromDomainFull = fromDomain - if fromPort: - if fromPort != 80 and fromPort != 443: - if ':' not in fromDomain: - fromDomainFull = fromDomain + ':' + str(fromPort) + fromDomainFull = getFullDomain(fromDomain, fromPort) toUrl = 'https://www.w3.org/ns/activitystreams#Public' ccUrl = httpPrefix + '://' + fromDomainFull + \ diff --git a/skills.py b/skills.py index 175e6ab03..2b4930ff2 100644 --- a/skills.py +++ b/skills.py @@ -11,6 +11,7 @@ from webfinger import webfingerHandle from auth import createBasicAuthHeader from posts import getPersonBox from session import postJson +from utils import getFullDomain from utils import getNicknameFromActor from utils import getDomainFromActor from utils import loadJson @@ -108,11 +109,7 @@ def sendSkillViaServer(baseDir: str, session, nickname: str, password: str, print('WARN: No session for sendSkillViaServer') return 6 - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) actor = httpPrefix + '://' + domainFull + '/users/' + nickname toUrl = actor diff --git a/socnet.py b/socnet.py index 6873d388a..31c59eb88 100644 --- a/socnet.py +++ b/socnet.py @@ -10,6 +10,7 @@ from session import createSession from webfinger import webfingerHandle from posts import getPersonBox from posts import getPostDomains +from utils import getFullDomain def instancesGraph(baseDir: str, handles: str, @@ -46,11 +47,7 @@ def instancesGraph(baseDir: str, handles: str, nickname = handle.split('@')[0] domain = handle.split('@')[1] - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) handle = httpPrefix + "://" + domainFull + "/@" + nickname wfRequest = \ webfingerHandle(session, handle, httpPrefix, diff --git a/tests.py b/tests.py index d23a0869f..654f977be 100644 --- a/tests.py +++ b/tests.py @@ -33,6 +33,7 @@ from follow import clearFollows from follow import clearFollowers from follow import sendFollowRequestViaServer from follow import sendUnfollowRequestViaServer +from utils import getFullDomain from utils import validNickname from utils import firstParagraphFromString from utils import removeIdEnding @@ -127,11 +128,7 @@ def testHttpsigBase(withDigest): } messageBodyJsonStr = json.dumps(messageBodyJson) - headersDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - headersDomain = domain + ':' + str(port) + headersDomain = getFullDomain(domain, port) dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime()) boxpath = '/inbox' diff --git a/theme/indymediamodern/banner.png b/theme/indymediamodern/banner.png index 5d1e78a25..d6f5e8a0a 100644 Binary files a/theme/indymediamodern/banner.png and b/theme/indymediamodern/banner.png differ diff --git a/theme/indymediamodern/left_col_image.png b/theme/indymediamodern/left_col_image.png index fd2241cd5..10896a20c 100644 Binary files a/theme/indymediamodern/left_col_image.png and b/theme/indymediamodern/left_col_image.png differ diff --git a/theme/indymediamodern/search_banner.png b/theme/indymediamodern/search_banner.png index 5d1e78a25..e8b0ef871 100644 Binary files a/theme/indymediamodern/search_banner.png and b/theme/indymediamodern/search_banner.png differ diff --git a/theme/solidaric/README.txt b/theme/solidaric/README.txt new file mode 100644 index 000000000..e661b8825 --- /dev/null +++ b/theme/solidaric/README.txt @@ -0,0 +1,2 @@ +Banner theme is Emma Goldman speaking in Paterson NJ to members of the IWW. 16th Dec 1913. +Font, post separator and globe image is from Mother Earth magazine. diff --git a/translations/ar.json b/translations/ar.json index 8ce52a2f5..1afa3ef36 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Hashtag Categories RSS Feed", "Ask about a shared item.": "اسأل عن عنصر مشترك.", "Account Information": "معلومات الحساب", - "This account interacts with the following instances": "يتفاعل هذا الحساب مع الحالات التالية" + "This account interacts with the following instances": "يتفاعل هذا الحساب مع الحالات التالية", + "News posts are moderated": "المشاركات الإخبارية خاضعة للإشراف" } diff --git a/translations/ca.json b/translations/ca.json index 7e9b2d8a7..257b46953 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Feed RSS de categories de hashtag", "Ask about a shared item.": "Pregunteu sobre un element compartit.", "Account Information": "Informació del compte", - "This account interacts with the following instances": "Aquest compte interactua amb les instàncies següents" + "This account interacts with the following instances": "Aquest compte interactua amb les instàncies següents", + "News posts are moderated": "Les publicacions de notícies es moderen" } diff --git a/translations/cy.json b/translations/cy.json index a0c996809..dd3f5b920 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Categorïau Hashtag RSS Feed", "Ask about a shared item.": "Gofynnwch am eitem a rennir.", "Account Information": "Gwybodaeth Gyfrif", - "This account interacts with the following instances": "Mae'r cyfrif hwn yn rhyngweithio â'r achosion canlynol" + "This account interacts with the following instances": "Mae'r cyfrif hwn yn rhyngweithio â'r achosion canlynol", + "News posts are moderated": "Mae swyddi newyddion yn cael eu cymedroli" } diff --git a/translations/de.json b/translations/de.json index f9eac6115..67d572256 100644 --- a/translations/de.json +++ b/translations/de.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Hashtag Kategorien RSS Feed", "Ask about a shared item.": "Fragen Sie nach einem gemeinsamen Artikel.", "Account Information": "Kontoinformationen", - "This account interacts with the following instances": "Dieses Konto interagiert mit den folgenden Instanzen" + "This account interacts with the following instances": "Dieses Konto interagiert mit den folgenden Instanzen", + "News posts are moderated": "Nachrichtenbeiträge werden moderiert" } diff --git a/translations/en.json b/translations/en.json index b17f8b92b..9453645d0 100644 --- a/translations/en.json +++ b/translations/en.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Hashtag Categories RSS Feed", "Ask about a shared item.": "Ask about a shared item.", "Account Information": "Account Information", - "This account interacts with the following instances": "This account interacts with the following instances" + "This account interacts with the following instances": "This account interacts with the following instances", + "News posts are moderated": "News posts are moderated" } diff --git a/translations/es.json b/translations/es.json index 4c970fe79..75c5f3e6a 100644 --- a/translations/es.json +++ b/translations/es.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Feed RSS de categorías de hashtags", "Ask about a shared item.": "Pregunte por un elemento compartido.", "Account Information": "Información de la cuenta", - "This account interacts with the following instances": "Esta cuenta interactúa con las siguientes instancias" + "This account interacts with the following instances": "Esta cuenta interactúa con las siguientes instancias", + "News posts are moderated": "Las publicaciones de noticias están moderadas" } diff --git a/translations/fr.json b/translations/fr.json index 167940b2a..8b37aa74c 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Flux RSS des catégories Hashtag", "Ask about a shared item.": "Renseignez-vous sur un élément partagé.", "Account Information": "Information sur le compte", - "This account interacts with the following instances": "Ce compte interagit avec les instances suivantes" + "This account interacts with the following instances": "Ce compte interagit avec les instances suivantes", + "News posts are moderated": "Les articles d'actualité sont modérés" } diff --git a/translations/ga.json b/translations/ga.json index 13e51eada..9f1825bf5 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Catagóirí Hashtag RSS Feed", "Ask about a shared item.": "Fiafraigh faoi earra roinnte.", "Account Information": "Faisnéis Chuntais", - "This account interacts with the following instances": "Idirghníomhaíonn an cuntas seo leis na cásanna seo a leanas" + "This account interacts with the following instances": "Idirghníomhaíonn an cuntas seo leis na cásanna seo a leanas", + "News posts are moderated": "Déantar poist nuachta a mhodhnú" } diff --git a/translations/hi.json b/translations/hi.json index 40ddfc5f6..feac20689 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "हैशटैग श्रेणियाँ आरएसएस फ़ीड", "Ask about a shared item.": "एक साझा आइटम के बारे में पूछें।", "Account Information": "खाते की जानकारी", - "This account interacts with the following instances": "यह खाता निम्नलिखित उदाहरणों के साथ सहभागिता करता है" + "This account interacts with the following instances": "यह खाता निम्नलिखित उदाहरणों के साथ सहभागिता करता है", + "News posts are moderated": "समाचार पोस्ट संचालित होते हैं" } diff --git a/translations/it.json b/translations/it.json index 5ab6e0dbc..735ecbdab 100644 --- a/translations/it.json +++ b/translations/it.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Feed RSS delle categorie hashtag", "Ask about a shared item.": "Chiedi informazioni su un elemento condiviso.", "Account Information": "Informazioni account", - "This account interacts with the following instances": "Questo account interagisce con le seguenti istanze" + "This account interacts with the following instances": "Questo account interagisce con le seguenti istanze", + "News posts are moderated": "I post di notizie sono moderati" } diff --git a/translations/ja.json b/translations/ja.json index 3afb8aff8..6cb030885 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "ハッシュタグカテゴリRSSフィード", "Ask about a shared item.": "共有アイテムについて質問します。", "Account Information": "口座情報", - "This account interacts with the following instances": "このアカウントは、次のインスタンスと相互作用します" + "This account interacts with the following instances": "このアカウントは、次のインスタンスと相互作用します", + "News posts are moderated": "ニュース投稿はモデレートされます" } diff --git a/translations/oc.json b/translations/oc.json index 9f8a92a0e..d8e91c995 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -337,5 +337,6 @@ "Hashtag Categories RSS Feed": "Hashtag Categories RSS Feed", "Ask about a shared item.": "Ask about a shared item.", "Account Information": "Account Information", - "This account interacts with the following instances": "This account interacts with the following instances" + "This account interacts with the following instances": "This account interacts with the following instances", + "News posts are moderated": "News posts are moderated" } diff --git a/translations/pt.json b/translations/pt.json index 53af4b8d6..93d13383e 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "Feed RSS das categorias de hashtag", "Ask about a shared item.": "Pergunte sobre um item compartilhado.", "Account Information": "Informação da conta", - "This account interacts with the following instances": "Esta conta interage com as seguintes instâncias" + "This account interacts with the following instances": "Esta conta interage com as seguintes instâncias", + "News posts are moderated": "Postagens de notícias são moderadas" } diff --git a/translations/ru.json b/translations/ru.json index e44e037f5..80c171d44 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "RSS-канал категорий хэштегов", "Ask about a shared item.": "Спросите об общем элементе.", "Account Information": "Информация об аккаунте", - "This account interacts with the following instances": "Этот аккаунт взаимодействует со следующими экземплярами" + "This account interacts with the following instances": "Этот аккаунт взаимодействует со следующими экземплярами", + "News posts are moderated": "Сообщения новостей модерируются" } diff --git a/translations/zh.json b/translations/zh.json index f12a444da..31c9e9954 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -341,5 +341,6 @@ "Hashtag Categories RSS Feed": "标签类别RSS提要", "Ask about a shared item.": "询问共享项目。", "Account Information": "帐户信息", - "This account interacts with the following instances": "此帐户与以下实例进行交互" + "This account interacts with the following instances": "此帐户与以下实例进行交互", + "News posts are moderated": "新闻发布被审核" } diff --git a/utils.py b/utils.py index 4fd05450d..8bebdddd2 100644 --- a/utils.py +++ b/utils.py @@ -19,6 +19,18 @@ from calendar import monthrange from followingCalendar import addPersonToCalendar +def getFullDomain(domain: str, port: int) -> str: + """Returns the full domain name, including port number + """ + if not port: + return domain + if ':' in domain: + return domain + if port == 80 or port == 443: + return domain + return domain + ':' + str(port) + + def isDormant(baseDir: str, nickname: str, domain: str, actor: str, dormantMonths=3) -> bool: """Is the given followed actor dormant, from the standpoint diff --git a/webapp_confirm.py b/webapp_confirm.py index a7396f9d4..a0f87f744 100644 --- a/webapp_confirm.py +++ b/webapp_confirm.py @@ -8,6 +8,7 @@ __status__ = "Production" import os from shutil import copyfile +from utils import getFullDomain from utils import getNicknameFromActor from utils import getDomainFromActor from utils import locatePost @@ -35,10 +36,7 @@ def htmlConfirmDelete(cssCache: {}, actor = messageId.split('/statuses/')[0] nickname = getNicknameFromActor(actor) domain, port = getDomainFromActor(actor) - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) postFilename = locatePost(baseDir, nickname, domain, messageId) if not postFilename: @@ -103,10 +101,7 @@ def htmlConfirmRemoveSharedItem(cssCache: {}, translate: {}, baseDir: str, itemID = getValidSharedItemID(shareName) nickname = getNicknameFromActor(actor) domain, port = getDomainFromActor(actor) - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) sharesFile = baseDir + '/accounts/' + \ nickname + '@' + domain + '/shares.json' if not os.path.isfile(sharesFile): diff --git a/webapp_moderation.py b/webapp_moderation.py index bb8859c11..63889536b 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -9,8 +9,9 @@ __status__ = "Production" import os from utils import getNicknameFromActor from utils import getDomainFromActor -from posts import getPublicPostDomains +from posts import getPublicPostInfo from webapp_timeline import htmlTimeline +from webapp_utils import getContentWarningButton from webapp_utils import htmlHeaderWithExternalStyle from webapp_utils import htmlFooter from blocking import isBlockedDomain @@ -78,29 +79,51 @@ def htmlAccountInfo(cssCache: {}, translate: {}, infoForm += translate[msgStr1] + '

' proxyType = 'tor' - domainList = [] - domainList = getPublicPostDomains(None, - baseDir, searchNickname, searchDomain, - proxyType, searchPort, - httpPrefix, debug, - __version__, domainList) + if not os.path.isfile('/usr/bin/tor'): + proxyType = None + if domain.endswith('.i2p'): + proxyType = None + domainDict = getPublicPostInfo(None, + baseDir, searchNickname, searchDomain, + proxyType, searchPort, + httpPrefix, debug, + __version__) infoForm += '
' usersPath = '/users/' + nickname + '/accountinfo' - for postDomain in domainList: + ctr = 1 + for postDomain, blockedPostUrls in domainDict.items(): infoForm += '' + postDomain + ' ' if isBlockedDomain(baseDir, postDomain): + blockedPostsLinks = '' + urlCtr = 0 + for url in blockedPostUrls: + if urlCtr > 0: + blockedPostsLinks += '
' + blockedPostsLinks += \ + '' + url + '' + urlCtr += 1 + blockedPostsHtml = '' + if blockedPostsLinks: + blockedPostsHtml = \ + getContentWarningButton('blockNumber' + str(ctr), + translate, blockedPostsLinks) + ctr += 1 + infoForm += \ '' infoForm += '' + translate['Unblock'] + ' ' + \ + blockedPostsHtml else: infoForm += \ '' - infoForm += '' + if postDomain != domain: + infoForm += '' + infoForm += '' infoForm += '
' infoForm += '
' diff --git a/webapp_person_options.py b/webapp_person_options.py index b18d5460a..4d845eb2d 100644 --- a/webapp_person_options.py +++ b/webapp_person_options.py @@ -11,6 +11,8 @@ from shutil import copyfile from petnames import getPetName from person import isPersonSnoozed from posts import isModerator +from utils import getFullDomain +from utils import getConfigParam from utils import isDormant from utils import removeHtml from utils import getDomainFromActor @@ -45,10 +47,7 @@ def htmlPersonOptions(defaultTimeline: str, """Show options for a person: view/follow/block/report """ optionsDomain, optionsPort = getDomainFromActor(optionsActor) - optionsDomainFull = optionsDomain - if optionsPort: - if optionsPort != 80 and optionsPort != 443: - optionsDomainFull = optionsDomain + ':' + str(optionsPort) + optionsDomainFull = getFullDomain(optionsDomain, optionsPort) if os.path.isfile(baseDir + '/accounts/options-background-custom.jpg'): if not os.path.isfile(baseDir + '/accounts/options-background.jpg'): @@ -74,10 +73,7 @@ def htmlPersonOptions(defaultTimeline: str, dormantMonths) optionsNickname = getNicknameFromActor(optionsActor) - optionsDomainFull = optionsDomain - if optionsPort: - if optionsPort != 80 and optionsPort != 443: - optionsDomainFull = optionsDomain + ':' + str(optionsPort) + optionsDomainFull = getFullDomain(optionsDomain, optionsPort) if isBlocked(baseDir, nickname, domain, optionsNickname, optionsDomainFull): blockStr = 'Block' @@ -187,9 +183,12 @@ def htmlPersonOptions(defaultTimeline: str, optionsStr += checkboxStr # checkbox for permission to post to newswire + newswirePostsPermitted = False if optionsDomainFull == domainFull: - if isModerator(baseDir, nickname) and \ - not isModerator(baseDir, optionsNickname): + adminNickname = getConfigParam(baseDir, 'admin') + if (nickname == adminNickname or + (isModerator(baseDir, nickname) and + not isModerator(baseDir, optionsNickname))): newswireBlockedFilename = \ baseDir + '/accounts/' + \ optionsNickname + '@' + optionsDomain + '/.nonewswire' @@ -202,8 +201,26 @@ def htmlPersonOptions(defaultTimeline: str, translate['Submit'] + '
\n' if os.path.isfile(newswireBlockedFilename): checkboxStr = checkboxStr.replace(' checked>', '>') + else: + newswirePostsPermitted = True optionsStr += checkboxStr + # whether blogs created by this account are moderated on the newswire + if newswirePostsPermitted: + moderatedFilename = \ + baseDir + '/accounts/' + \ + optionsNickname + '@' + optionsDomain + '/.newswiremoderated' + checkboxStr = \ + ' ' + \ + translate['News posts are moderated'] + \ + '\n
\n' + if not os.path.isfile(moderatedFilename): + checkboxStr = checkboxStr.replace(' checked>', '>') + optionsStr += checkboxStr + optionsStr += optionsLinkStr backPath = '/' if nickname: @@ -211,26 +228,32 @@ def htmlPersonOptions(defaultTimeline: str, optionsStr += \ ' ' + '\n' optionsStr += \ ' ' + translate['View'] + '\n' optionsStr += donateStr optionsStr += \ ' ' + followStr + '">' + translate[followStr] + '\n' optionsStr += \ ' ' + blockStr + '">' + translate[blockStr] + '\n' optionsStr += \ ' ' + translate['DM'] + '\n' optionsStr += \ ' ' + snoozeButtonStr + '">' + translate[snoozeButtonStr] + '\n' optionsStr += \ ' ' + translate['Report'] + '\n' + + if isModerator(baseDir, nickname): + optionsStr += \ + ' \n' personNotes = '' personNotesFilename = \ diff --git a/webapp_post.py b/webapp_post.py index e788ac6e4..5ad029320 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -22,6 +22,7 @@ from posts import getPersonBox from posts import isDM from posts import downloadAnnounce from posts import populateRepliesJson +from utils import getFullDomain from utils import isEditor from utils import locatePost from utils import loadJson @@ -1135,11 +1136,7 @@ def individualPostAsHtml(allowDownloads: bool, if messageId: messageIdStr = ';' + messageId - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) pageNumberParam = '' if pageNumber: @@ -1604,19 +1601,14 @@ def htmlIndividualPost(cssCache: {}, if likedBy: likedByNickname = getNicknameFromActor(likedBy) likedByDomain, likedByPort = getDomainFromActor(likedBy) - if likedByPort: - if likedByPort != 80 and likedByPort != 443: - likedByDomain += ':' + str(likedByPort) + likedByDomain = getFullDomain(likedByDomain, likedByPort) likedByHandle = likedByNickname + '@' + likedByDomain postStr += \ '

' + translate['Liked by'] + \ ' @' + \ likedByHandle + '\n' - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) actor = '/users/' + nickname followStr = '

\n' diff --git a/webapp_profile.py b/webapp_profile.py index 21fdbc4e1..c18c87945 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -8,6 +8,7 @@ __status__ = "Production" import os from pprint import pprint +from utils import getFullDomain from utils import isDormant from utils import getNicknameFromActor from utils import getDomainFromActor @@ -97,11 +98,7 @@ def htmlProfileAfterSearch(cssCache: {}, print('DEBUG: No domain found in ' + profileHandle) return None - searchDomainFull = searchDomain - if searchPort: - if searchPort != 80 and searchPort != 443: - if ':' not in searchDomain: - searchDomainFull = searchDomain + ':' + str(searchPort) + searchDomainFull = getFullDomain(searchDomain, searchPort) profileStr = '' cssFilename = baseDir + '/epicyon-profile.css' @@ -225,10 +222,7 @@ def htmlProfileAfterSearch(cssCache: {}, profileDescriptionShort, avatarUrl, imageUrl) - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) followIsPermitted = True if searchNickname == 'news' and searchDomainFull == domainFull: @@ -834,11 +828,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str, nickname = getNicknameFromActor(path) if not nickname: return '' - domainFull = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) actorFilename = \ baseDir + '/accounts/' + nickname + '@' + domain + '.json' diff --git a/webapp_search.py b/webapp_search.py index 13d8ea87a..05b2fc7f0 100644 --- a/webapp_search.py +++ b/webapp_search.py @@ -10,6 +10,7 @@ import os from shutil import copyfile import urllib.parse from datetime import datetime +from utils import getFullDomain from utils import isEditor from utils import loadJson from utils import getDomainFromActor @@ -544,10 +545,7 @@ def htmlHistorySearch(cssCache: {}, translate: {}, baseDir: str, htmlHeaderWithExternalStyle(cssFilename) # add the page title - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) actor = httpPrefix + '://' + domainFull + '/users/' + nickname historySearchForm += \ '

' + \ @@ -823,10 +821,7 @@ def rssHashtagSearch(nickname: str, domain: str, port: int, if not lines: return None - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) maxFeedLength = 10 hashtagFeed = \ diff --git a/webapp_timeline.py b/webapp_timeline.py index ca71c10d3..9ac94abd4 100644 --- a/webapp_timeline.py +++ b/webapp_timeline.py @@ -8,6 +8,7 @@ __status__ = "Production" import os import time +from utils import getFullDomain from utils import isEditor from utils import removeIdEnding from follow import followerApprovalActive @@ -191,10 +192,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str, eventsButton = 'buttonselected' # get the full domain, including any port number - fullDomain = domain - if port != 80 and port != 443: - if ':' not in domain: - fullDomain = domain + ':' + str(port) + fullDomain = getFullDomain(domain, port) usersPath = '/users/' + nickname actor = httpPrefix + '://' + fullDomain + usersPath @@ -399,10 +397,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str, tlStr += ' \n' tlStr += ' \n' - domainFull = domain - if port: - if port != 80 and port != 443: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) # left column leftColumnStr = \ @@ -449,6 +444,10 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str, else: tlStr += '
\n' + tlStr += \ + ' \n' tlStr += \ ' \n' - tlStr += \ - ' \n' tlStr += '\n\n' logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6') @@ -655,10 +650,7 @@ def htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int, sharesJson, lastPage = \ sharesTimelineJson(actor, pageNumber, itemsPerPage, baseDir, maxSharesPerAccount) - domainFull = domain - if port != 80 and port != 443: - if ':' not in domain: - domainFull = domain + ':' + str(port) + domainFull = getFullDomain(domain, port) actor = httpPrefix + '://' + domainFull + '/users/' + nickname timelineStr = '' diff --git a/webfinger.py b/webfinger.py index 65b5666fc..e95c8c7e1 100644 --- a/webfinger.py +++ b/webfinger.py @@ -18,6 +18,7 @@ import urllib.parse from session import getJson from cache import storeWebfingerInCache from cache import getWebfingerFromCache +from utils import getFullDomain from utils import loadJson from utils import loadJsonOnionify from utils import saveJson @@ -113,10 +114,7 @@ def storeWebfingerEndpoint(nickname: str, domain: str, port: int, """Stores webfinger endpoint for a user to a file """ originalDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) handle = nickname + '@' + domain wfSubdir = '/wfendpoints' if not os.path.isdir(baseDir + wfSubdir): @@ -135,10 +133,7 @@ def createWebfingerEndpoint(nickname: str, domain: str, port: int, """Creates a webfinger endpoint for a user """ originalDomain = domain - if port: - if port != 80 and port != 443: - if ':' not in domain: - domain = domain + ':' + str(port) + domain = getFullDomain(domain, port) personName = nickname personId = httpPrefix + "://" + domain + "/users/" + personName @@ -245,10 +240,7 @@ def webfingerLookup(path: str, baseDir: str, if debug: print('DEBUG: WEBFINGER no @ in handle ' + handle) return None - if port: - if port != 80 and port != 443: - if ':' not in handle: - handle = handle + ':' + str(port) + handle = getFullDomain(handle, port) # convert @domain@domain to inbox@domain if '@' in handle: handleDomain = handle.split('@')[1]