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 += '
' + 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 = '