Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon
|
|
@ -0,0 +1,3 @@
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.egg-info/
|
||||||
79
content.py
|
|
@ -14,6 +14,8 @@ from utils import getImageExtensions
|
||||||
from utils import loadJson
|
from utils import loadJson
|
||||||
from utils import fileLastModified
|
from utils import fileLastModified
|
||||||
from utils import getLinkPrefixes
|
from utils import getLinkPrefixes
|
||||||
|
from utils import dangerousMarkup
|
||||||
|
from petnames import getPetName
|
||||||
|
|
||||||
|
|
||||||
def removeHtmlTag(htmlStr: str, tag: str) -> str:
|
def removeHtmlTag(htmlStr: str, tag: str) -> str:
|
||||||
|
|
@ -153,38 +155,6 @@ def htmlReplaceQuoteMarks(content: str) -> str:
|
||||||
return newContent
|
return newContent
|
||||||
|
|
||||||
|
|
||||||
def dangerousMarkup(content: str, allowLocalNetworkAccess: bool) -> bool:
|
|
||||||
"""Returns true if the given content contains dangerous html markup
|
|
||||||
"""
|
|
||||||
if '<' not in content:
|
|
||||||
return False
|
|
||||||
if '>' not in content:
|
|
||||||
return False
|
|
||||||
contentSections = content.split('<')
|
|
||||||
invalidPartials = ()
|
|
||||||
if not allowLocalNetworkAccess:
|
|
||||||
invalidPartials = ('localhost', '127.0.', '192.168', '10.0.')
|
|
||||||
invalidStrings = ('script', 'canvas', 'style', 'abbr',
|
|
||||||
'frame', 'iframe', 'html', 'body',
|
|
||||||
'hr', 'allow-popups', 'allow-scripts')
|
|
||||||
for markup in contentSections:
|
|
||||||
if '>' not in markup:
|
|
||||||
continue
|
|
||||||
markup = markup.split('>')[0].strip()
|
|
||||||
for partialMatch in invalidPartials:
|
|
||||||
if partialMatch in markup:
|
|
||||||
return True
|
|
||||||
if ' ' not in markup:
|
|
||||||
for badStr in invalidStrings:
|
|
||||||
if badStr in markup:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
for badStr in invalidStrings:
|
|
||||||
if badStr + ' ' in markup:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def dangerousCSS(filename: str, allowLocalNetworkAccess: bool) -> bool:
|
def dangerousCSS(filename: str, allowLocalNetworkAccess: bool) -> bool:
|
||||||
"""Returns true is the css file contains code which
|
"""Returns true is the css file contains code which
|
||||||
can create security problems
|
can create security problems
|
||||||
|
|
@ -489,7 +459,7 @@ def tagExists(tagType: str, tagName: str, tags: {}) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _addMention(wordStr: str, httpPrefix: str, following: str,
|
def _addMention(wordStr: str, httpPrefix: str, following: str, petnames: str,
|
||||||
replaceMentions: {}, recipients: [], tags: {}) -> bool:
|
replaceMentions: {}, recipients: [], tags: {}) -> bool:
|
||||||
"""Detects mentions and adds them to the replacements dict and
|
"""Detects mentions and adds them to the replacements dict and
|
||||||
recipients list
|
recipients list
|
||||||
|
|
@ -501,9 +471,12 @@ def _addMention(wordStr: str, httpPrefix: str, following: str,
|
||||||
# if no domain was specified. eg. @nick
|
# if no domain was specified. eg. @nick
|
||||||
possibleNickname = possibleHandle
|
possibleNickname = possibleHandle
|
||||||
for follow in following:
|
for follow in following:
|
||||||
if follow.startswith(possibleNickname + '@'):
|
if '@' not in follow:
|
||||||
replaceDomain = \
|
continue
|
||||||
follow.replace('\n', '').replace('\r', '').split('@')[1]
|
followNick = follow.split('@')[0]
|
||||||
|
if possibleNickname == followNick:
|
||||||
|
followStr = follow.replace('\n', '').replace('\r', '')
|
||||||
|
replaceDomain = followStr.split('@')[1]
|
||||||
recipientActor = httpPrefix + "://" + \
|
recipientActor = httpPrefix + "://" + \
|
||||||
replaceDomain + "/users/" + possibleNickname
|
replaceDomain + "/users/" + possibleNickname
|
||||||
if recipientActor not in recipients:
|
if recipientActor not in recipients:
|
||||||
|
|
@ -519,6 +492,34 @@ def _addMention(wordStr: str, httpPrefix: str, following: str,
|
||||||
"\" class=\"u-url mention\">@<span>" + possibleNickname + \
|
"\" class=\"u-url mention\">@<span>" + possibleNickname + \
|
||||||
"</span></a></span>"
|
"</span></a></span>"
|
||||||
return True
|
return True
|
||||||
|
# try replacing petnames with mentions
|
||||||
|
followCtr = 0
|
||||||
|
for follow in following:
|
||||||
|
if '@' not in follow:
|
||||||
|
followCtr += 1
|
||||||
|
continue
|
||||||
|
pet = petnames[followCtr].replace('\n', '')
|
||||||
|
if pet:
|
||||||
|
if possibleNickname == pet:
|
||||||
|
followStr = follow.replace('\n', '').replace('\r', '')
|
||||||
|
replaceNickname = followStr.split('@')[0]
|
||||||
|
replaceDomain = followStr.split('@')[1]
|
||||||
|
recipientActor = httpPrefix + "://" + \
|
||||||
|
replaceDomain + "/users/" + replaceNickname
|
||||||
|
if recipientActor not in recipients:
|
||||||
|
recipients.append(recipientActor)
|
||||||
|
tags[wordStr] = {
|
||||||
|
'href': recipientActor,
|
||||||
|
'name': wordStr,
|
||||||
|
'type': 'Mention'
|
||||||
|
}
|
||||||
|
replaceMentions[wordStr] = \
|
||||||
|
"<span class=\"h-card\"><a href=\"" + httpPrefix + \
|
||||||
|
"://" + replaceDomain + "/@" + replaceNickname + \
|
||||||
|
"\" class=\"u-url mention\">@<span>" + \
|
||||||
|
replaceNickname + "</span></a></span>"
|
||||||
|
return True
|
||||||
|
followCtr += 1
|
||||||
return False
|
return False
|
||||||
possibleNickname = None
|
possibleNickname = None
|
||||||
possibleDomain = None
|
possibleDomain = None
|
||||||
|
|
@ -752,10 +753,14 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
|
||||||
# read the following list so that we can detect just @nick
|
# read the following list so that we can detect just @nick
|
||||||
# in addition to @nick@domain
|
# in addition to @nick@domain
|
||||||
following = None
|
following = None
|
||||||
|
petnames = None
|
||||||
if '@' in words:
|
if '@' in words:
|
||||||
if os.path.isfile(followingFilename):
|
if os.path.isfile(followingFilename):
|
||||||
with open(followingFilename, "r") as f:
|
with open(followingFilename, "r") as f:
|
||||||
following = f.readlines()
|
following = f.readlines()
|
||||||
|
for handle in following:
|
||||||
|
pet = getPetName(baseDir, nickname, domain, handle)
|
||||||
|
petnames.append(pet + '\n')
|
||||||
|
|
||||||
# extract mentions and tags from words
|
# extract mentions and tags from words
|
||||||
longWordsList = []
|
longWordsList = []
|
||||||
|
|
@ -769,7 +774,7 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
|
||||||
longWordsList.append(wordStr)
|
longWordsList.append(wordStr)
|
||||||
firstChar = wordStr[0]
|
firstChar = wordStr[0]
|
||||||
if firstChar == '@':
|
if firstChar == '@':
|
||||||
if _addMention(wordStr, httpPrefix, following,
|
if _addMention(wordStr, httpPrefix, following, petnames,
|
||||||
replaceMentions, recipients, hashtags):
|
replaceMentions, recipients, hashtags):
|
||||||
prevWordStr = ''
|
prevWordStr = ''
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
81
daemon.py
|
|
@ -217,10 +217,10 @@ from utils import urlPermitted
|
||||||
from utils import loadJson
|
from utils import loadJson
|
||||||
from utils import saveJson
|
from utils import saveJson
|
||||||
from utils import isSuspended
|
from utils import isSuspended
|
||||||
|
from utils import dangerousMarkup
|
||||||
from manualapprove import manualDenyFollowRequest
|
from manualapprove import manualDenyFollowRequest
|
||||||
from manualapprove import manualApproveFollowRequest
|
from manualapprove import manualApproveFollowRequest
|
||||||
from announce import createAnnounce
|
from announce import createAnnounce
|
||||||
from content import dangerousMarkup
|
|
||||||
from content import replaceEmojiFromTags
|
from content import replaceEmojiFromTags
|
||||||
from content import addHtmlTags
|
from content import addHtmlTags
|
||||||
from content import extractMediaInFormPOST
|
from content import extractMediaInFormPOST
|
||||||
|
|
@ -1136,7 +1136,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
"""
|
"""
|
||||||
if self.server.restartInboxQueueInProgress:
|
if self.server.restartInboxQueueInProgress:
|
||||||
self._503()
|
self._503()
|
||||||
print('Message arrrived but currently restarting inbox queue')
|
print('Message arrived but currently restarting inbox queue')
|
||||||
self.server.POSTbusy = False
|
self.server.POSTbusy = False
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
|
@ -2614,7 +2614,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.projectVersion,
|
self.server.projectVersion,
|
||||||
self.server.YTReplacementDomain,
|
self.server.YTReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
if hashtagStr:
|
if hashtagStr:
|
||||||
msg = hashtagStr.encode('utf-8')
|
msg = hashtagStr.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
|
|
@ -2666,7 +2667,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
port,
|
port,
|
||||||
self.server.YTReplacementDomain,
|
self.server.YTReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
if historyStr:
|
if historyStr:
|
||||||
msg = historyStr.encode('utf-8')
|
msg = historyStr.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
|
|
@ -2733,6 +2735,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
showPublishedDateOnly = self.server.showPublishedDateOnly
|
showPublishedDateOnly = self.server.showPublishedDateOnly
|
||||||
|
allowLocalNetworkAccess = \
|
||||||
|
self.server.allowLocalNetworkAccess
|
||||||
profileStr = \
|
profileStr = \
|
||||||
htmlProfileAfterSearch(self.server.cssCache,
|
htmlProfileAfterSearch(self.server.cssCache,
|
||||||
self.server.recentPostsCache,
|
self.server.recentPostsCache,
|
||||||
|
|
@ -2753,7 +2757,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.YTReplacementDomain,
|
self.server.YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
self.server.defaultTimeline,
|
self.server.defaultTimeline,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
if profileStr:
|
if profileStr:
|
||||||
msg = profileStr.encode('utf-8')
|
msg = profileStr.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
|
|
@ -5674,7 +5679,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.projectVersion,
|
self.server.projectVersion,
|
||||||
self.server.YTReplacementDomain,
|
self.server.YTReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
if hashtagStr:
|
if hashtagStr:
|
||||||
msg = hashtagStr.encode('utf-8')
|
msg = hashtagStr.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
|
|
@ -6636,7 +6642,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.personCache, callingDomain,
|
self.server.personCache, callingDomain,
|
||||||
self.server.YTReplacementDomain,
|
self.server.YTReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
if deleteStr:
|
if deleteStr:
|
||||||
deleteStrLen = len(deleteStr)
|
deleteStrLen = len(deleteStr)
|
||||||
self._set_headers('text/html', deleteStrLen,
|
self._set_headers('text/html', deleteStrLen,
|
||||||
|
|
@ -6840,7 +6847,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
projectVersion,
|
projectVersion,
|
||||||
ytDomain,
|
ytDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
peertubeInstances)
|
peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -6926,7 +6934,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
projectVersion,
|
projectVersion,
|
||||||
ytDomain,
|
ytDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
peertubeInstances)
|
peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -7013,6 +7022,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
self.server.peertubeInstances,
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess,
|
||||||
actorJson['roles'],
|
actorJson['roles'],
|
||||||
None, None)
|
None, None)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
|
|
@ -7077,6 +7087,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.showPublishedDateOnly
|
self.server.showPublishedDateOnly
|
||||||
iconsAsButtons = \
|
iconsAsButtons = \
|
||||||
self.server.iconsAsButtons
|
self.server.iconsAsButtons
|
||||||
|
allowLocalNetworkAccess = \
|
||||||
|
self.server.allowLocalNetworkAccess
|
||||||
msg = \
|
msg = \
|
||||||
htmlProfile(self.server.rssIconAtTop,
|
htmlProfile(self.server.rssIconAtTop,
|
||||||
self.server.cssCache,
|
self.server.cssCache,
|
||||||
|
|
@ -7097,6 +7109,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
self.server.peertubeInstances,
|
self.server.peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
actorJson['skills'],
|
actorJson['skills'],
|
||||||
None, None)
|
None, None)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
|
|
@ -7208,6 +7221,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
peertubeInstances = \
|
peertubeInstances = \
|
||||||
self.server.peertubeInstances
|
self.server.peertubeInstances
|
||||||
cssCache = self.server.cssCache
|
cssCache = self.server.cssCache
|
||||||
|
allowLocalNetworkAccess = \
|
||||||
|
self.server.allowLocalNetworkAccess
|
||||||
msg = \
|
msg = \
|
||||||
htmlIndividualPost(cssCache,
|
htmlIndividualPost(cssCache,
|
||||||
recentPostsCache,
|
recentPostsCache,
|
||||||
|
|
@ -7227,7 +7242,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
likedBy,
|
likedBy,
|
||||||
ytDomain,
|
ytDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances)
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -7329,6 +7345,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.showPublishedDateOnly
|
self.server.showPublishedDateOnly
|
||||||
peertubeInstances = \
|
peertubeInstances = \
|
||||||
self.server.peertubeInstances
|
self.server.peertubeInstances
|
||||||
|
allowLocalNetworkAccess = \
|
||||||
|
self.server.allowLocalNetworkAccess
|
||||||
msg = \
|
msg = \
|
||||||
htmlIndividualPost(self.server.cssCache,
|
htmlIndividualPost(self.server.cssCache,
|
||||||
recentPostsCache,
|
recentPostsCache,
|
||||||
|
|
@ -7348,7 +7366,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
likedBy,
|
likedBy,
|
||||||
ytDomain,
|
ytDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances)
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -7481,7 +7500,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized,
|
authorized,
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
if GETstartTime:
|
if GETstartTime:
|
||||||
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
||||||
'show status done',
|
'show status done',
|
||||||
|
|
@ -7608,7 +7628,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized, self.server.themeName,
|
authorized, self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -7728,7 +7749,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized, self.server.themeName,
|
authorized, self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -7849,7 +7871,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized,
|
authorized,
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -7970,7 +7993,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized,
|
authorized,
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -8100,7 +8124,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized,
|
authorized,
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -8226,7 +8251,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized,
|
authorized,
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -8313,7 +8339,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized, self.server.themeName,
|
authorized, self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -8417,7 +8444,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized,
|
authorized,
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -8541,7 +8569,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized,
|
authorized,
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -8657,7 +8686,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized,
|
authorized,
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -8763,7 +8793,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized, moderationActionStr,
|
authorized, moderationActionStr,
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.peertubeInstances)
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
@ -8863,6 +8894,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
self.server.peertubeInstances,
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess,
|
||||||
shares,
|
shares,
|
||||||
pageNumber, sharesPerPage)
|
pageNumber, sharesPerPage)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
|
|
@ -8959,6 +8991,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
self.server.peertubeInstances,
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess,
|
||||||
following,
|
following,
|
||||||
pageNumber,
|
pageNumber,
|
||||||
followsPerPage).encode('utf-8')
|
followsPerPage).encode('utf-8')
|
||||||
|
|
@ -9055,6 +9088,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
self.server.peertubeInstances,
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess,
|
||||||
followers,
|
followers,
|
||||||
pageNumber,
|
pageNumber,
|
||||||
followsPerPage).encode('utf-8')
|
followsPerPage).encode('utf-8')
|
||||||
|
|
@ -9174,6 +9208,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.themeName,
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
self.server.peertubeInstances,
|
self.server.peertubeInstances,
|
||||||
|
self.server.allowLocalNetworkAccess,
|
||||||
None, None).encode('utf-8')
|
None, None).encode('utf-8')
|
||||||
msglen = len(msg)
|
msglen = len(msg)
|
||||||
self._set_headers('text/html', msglen,
|
self._set_headers('text/html', msglen,
|
||||||
|
|
|
||||||
85
deploy/onion
|
|
@ -16,10 +16,10 @@ if [[ "$1" == 'remove' ]]; then
|
||||||
rm "/etc/nginx/sites-availale/${username}"
|
rm "/etc/nginx/sites-availale/${username}"
|
||||||
rm -rf ${install_destination}
|
rm -rf ${install_destination}
|
||||||
if [ -d /var/www/cache ]; then
|
if [ -d /var/www/cache ]; then
|
||||||
rm -rf /var/www/cache
|
rm -rf /var/www/cache
|
||||||
fi
|
fi
|
||||||
if [ -d /srv/http/cache ]; then
|
if [ -d /srv/http/cache ]; then
|
||||||
rm -rf /srv/http/cache
|
rm -rf /srv/http/cache
|
||||||
fi
|
fi
|
||||||
userdel -r ${username}
|
userdel -r ${username}
|
||||||
echo 'Epicyon onion instance removed'
|
echo 'Epicyon onion instance removed'
|
||||||
|
|
@ -37,18 +37,36 @@ if [ -f /usr/bin/pacman ]; then
|
||||||
pacman -Syy
|
pacman -Syy
|
||||||
pacman -S --noconfirm tor python-pip python-pysocks python-pycryptodome \
|
pacman -S --noconfirm tor python-pip python-pysocks python-pycryptodome \
|
||||||
imagemagick python-pillow python-requests \
|
imagemagick python-pillow python-requests \
|
||||||
perl-image-exiftool python-numpy python-dateutil \
|
perl-image-exiftool python-numpy python-dateutil \
|
||||||
certbot flake8 git qrencode bandit
|
certbot flake8 git qrencode bandit
|
||||||
pip3 install pyLD pyqrcode pypng
|
pip3 install pyLD pyqrcode pypng
|
||||||
else
|
else
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get -y install imagemagick python3-crypto python3-pycryptodome \
|
apt-get -y install imagemagick python3-crypto python3-pycryptodome \
|
||||||
python3-dateutil python3-idna python3-requests \
|
python3-dateutil python3-idna python3-requests \
|
||||||
python3-numpy python3-pil.imagetk python3-pip \
|
python3-numpy python3-pil.imagetk python3-pip \
|
||||||
python3-setuptools python3-socks python3-idna \
|
python3-setuptools python3-socks python3-idna \
|
||||||
libimage-exiftool-perl python3-flake8 python3-pyld \
|
libimage-exiftool-perl python3-flake8 python3-pyld \
|
||||||
python3-django-timezone-field tor nginx git qrencode \
|
python3-django-timezone-field tor nginx git qrencode \
|
||||||
python3-pyqrcode python3-png python3-bandit
|
python3-pyqrcode python3-png python3-bandit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$(uname -a)" == *'Debian'* ]]; then
|
||||||
|
echo 'Fixing the tor daemon'
|
||||||
|
{ echo '[Unit]';
|
||||||
|
echo 'Description=Anonymizing overlay network for TCP (multi-instance-master)';
|
||||||
|
echo '';
|
||||||
|
echo '[Service]';
|
||||||
|
echo 'Type=simple';
|
||||||
|
echo 'User=root';
|
||||||
|
echo 'Group=debian-tor';
|
||||||
|
echo 'ExecStart=/usr/bin/tor --defaults-torrc /usr/share/tor/tor-service-defaults-torrc -f /etc/tor/torrc --RunAsDaemon 0';
|
||||||
|
echo '';
|
||||||
|
echo '[Install]';
|
||||||
|
echo 'WantedBy=multi-user.target'; } > /lib/systemd/system/tor.service
|
||||||
|
cp /lib/systemd/system/tor.service /root/tor.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl restart tor
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo 'Cloning the epicyon repo'
|
echo 'Cloning the epicyon repo'
|
||||||
|
|
@ -56,8 +74,8 @@ if [ ! -d ${install_destination} ]; then
|
||||||
git clone https://gitlab.com/bashrc2/epicyon ${install_destination}
|
git clone https://gitlab.com/bashrc2/epicyon ${install_destination}
|
||||||
|
|
||||||
if [ ! -d ${install_destination} ]; then
|
if [ ! -d ${install_destination} ]; then
|
||||||
echo 'Epicyon repo failed to clone'
|
echo 'Epicyon repo failed to clone'
|
||||||
exit 3
|
exit 3
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -79,6 +97,7 @@ if [ ! -d /etc/torrc.d ]; then
|
||||||
fi
|
fi
|
||||||
if ! grep -q '%include /etc/torrc.d' /etc/tor/torrc; then
|
if ! grep -q '%include /etc/torrc.d' /etc/tor/torrc; then
|
||||||
echo '%include /etc/torrc.d' >> /etc/tor/torrc
|
echo '%include /etc/torrc.d' >> /etc/tor/torrc
|
||||||
|
systemctl restart tor
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f /etc/torrc.d/epicyon ]; then
|
if [ ! -f /etc/torrc.d/epicyon ]; then
|
||||||
|
|
@ -185,7 +204,7 @@ if [ ! -f /etc/nginx/nginx.conf ]; then
|
||||||
echo '}'; } > /etc/nginx/nginx.conf
|
echo '}'; } > /etc/nginx/nginx.conf
|
||||||
else
|
else
|
||||||
if ! grep -q 'include /etc/nginx/sites-enabled' /etc/nginx/nginx.conf; then
|
if ! grep -q 'include /etc/nginx/sites-enabled' /etc/nginx/nginx.conf; then
|
||||||
echo 'include /etc/nginx/sites-enabled/*.conf;' >> /etc/nginx/nginx.conf
|
echo 'include /etc/nginx/sites-enabled/*.conf;' >> /etc/nginx/nginx.conf
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [ ! -d /etc/nginx/conf.d ]; then
|
if [ ! -d /etc/nginx/conf.d ]; then
|
||||||
|
|
@ -200,25 +219,25 @@ fi
|
||||||
|
|
||||||
if [ -f /usr/bin/pacman ]; then
|
if [ -f /usr/bin/pacman ]; then
|
||||||
if [ ! -f /lib/systemd/system/nginx.service ]; then
|
if [ ! -f /lib/systemd/system/nginx.service ]; then
|
||||||
echo 'Creating nginx daemon'
|
echo 'Creating nginx daemon'
|
||||||
{ echo '[Unit]';
|
{ echo '[Unit]';
|
||||||
echo 'Description=A high performance web server and a reverse proxy server';
|
echo 'Description=A high performance web server and a reverse proxy server';
|
||||||
echo 'Documentation=man:nginx(8)';
|
echo 'Documentation=man:nginx(8)';
|
||||||
echo 'After=network.target nss-lookup.target';
|
echo 'After=network.target nss-lookup.target';
|
||||||
echo ''
|
echo ''
|
||||||
echo '[Service]';
|
echo '[Service]';
|
||||||
echo 'Type=forking';
|
echo 'Type=forking';
|
||||||
echo 'PIDFile=/run/nginx.pid';
|
echo 'PIDFile=/run/nginx.pid';
|
||||||
echo "ExecStartPre=$(which nginx) -t -q -g 'daemon on; master_process on;'";
|
echo "ExecStartPre=$(which nginx) -t -q -g 'daemon on; master_process on;'";
|
||||||
echo "ExecStart=$(which nginx) -g 'daemon on; master_process on;'";
|
echo "ExecStart=$(which nginx) -g 'daemon on; master_process on;'";
|
||||||
echo "ExecReload=$(which nginx) -g 'daemon on; master_process on;' -s reload";
|
echo "ExecReload=$(which nginx) -g 'daemon on; master_process on;' -s reload";
|
||||||
echo 'ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid';
|
echo 'ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid';
|
||||||
echo 'TimeoutStopSec=5';
|
echo 'TimeoutStopSec=5';
|
||||||
echo 'KillMode=mixed';
|
echo 'KillMode=mixed';
|
||||||
echo '';
|
echo '';
|
||||||
echo '[Install]';
|
echo '[Install]';
|
||||||
echo 'WantedBy=multi-user.target'; } > /etc/systemd/system/nginx.service
|
echo 'WantedBy=multi-user.target'; } > /etc/systemd/system/nginx.service
|
||||||
systemctl enable nginx
|
systemctl enable nginx
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -257,7 +276,7 @@ echo "Creating nginx virtual host for ${ONION_DOMAIN}"
|
||||||
echo ' index index.html;';
|
echo ' index index.html;';
|
||||||
echo '';
|
echo '';
|
||||||
echo ' location /newsmirror {';
|
echo ' location /newsmirror {';
|
||||||
echo ' root /var/www/${ONION_DOMAIN}/htdocs;';
|
echo " root /var/www/${ONION_DOMAIN}/htdocs;";
|
||||||
echo ' try_files $uri =404;';
|
echo ' try_files $uri =404;';
|
||||||
echo ' }';
|
echo ' }';
|
||||||
echo '';
|
echo '';
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@
|
||||||
--font-size-tox: 16px;
|
--font-size-tox: 16px;
|
||||||
--font-size-tox2: 18px;
|
--font-size-tox2: 18px;
|
||||||
--time-color: #aaa;
|
--time-color: #aaa;
|
||||||
--time-vertical-align: 4px;
|
--time-vertical-align: 0%;
|
||||||
--time-vertical-align-mobile: 25px;
|
--time-vertical-align-mobile: 1.5%;
|
||||||
--publish-button-text: #FFFFFF;
|
--publish-button-text: #FFFFFF;
|
||||||
--button-margin: 5px;
|
--button-margin: 5px;
|
||||||
--button-left-margin: none;
|
--button-left-margin: none;
|
||||||
|
|
@ -96,6 +96,7 @@
|
||||||
--column-right-width: 10vw;
|
--column-right-width: 10vw;
|
||||||
--column-left-mobile-margin: 2%;
|
--column-left-mobile-margin: 2%;
|
||||||
--column-left-top-margin: 0;
|
--column-left-top-margin: 0;
|
||||||
|
--column-right-top-margin: 0;
|
||||||
--column-left-header-style: uppercase;
|
--column-left-header-style: uppercase;
|
||||||
--column-left-header-background: #555;
|
--column-left-header-background: #555;
|
||||||
--column-left-header-color: #fff;
|
--column-left-header-color: #fff;
|
||||||
|
|
@ -1156,7 +1157,7 @@ div.container {
|
||||||
.col-right img.rightColImg {
|
.col-right img.rightColImg {
|
||||||
background: var(--column-left-color);
|
background: var(--column-left-color);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 0;
|
margin-top: var(--column-right-top-margin);
|
||||||
padding: 0 0;
|
padding: 0 0;
|
||||||
}
|
}
|
||||||
.likesCount {
|
.likesCount {
|
||||||
|
|
|
||||||
10
epicyon.py
|
|
@ -868,7 +868,11 @@ configPort = getConfigParam(baseDir, 'port')
|
||||||
if configPort:
|
if configPort:
|
||||||
port = configPort
|
port = configPort
|
||||||
else:
|
else:
|
||||||
port = 8085
|
if domain.endswith('.onion') or \
|
||||||
|
domain.endswith('.i2p'):
|
||||||
|
port = 80
|
||||||
|
else:
|
||||||
|
port = 443
|
||||||
|
|
||||||
configProxyPort = getConfigParam(baseDir, 'proxyPort')
|
configProxyPort = getConfigParam(baseDir, 'proxyPort')
|
||||||
if configProxyPort:
|
if configProxyPort:
|
||||||
|
|
@ -1613,6 +1617,10 @@ if args.addaccount:
|
||||||
if os.path.isdir(baseDir + '/deactivated/' + nickname + '@' + domain):
|
if os.path.isdir(baseDir + '/deactivated/' + nickname + '@' + domain):
|
||||||
print('Account is deactivated')
|
print('Account is deactivated')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
if domain.endswith('.onion') or \
|
||||||
|
domain.endswith('.i2p'):
|
||||||
|
port = 80
|
||||||
|
httpPrefix = 'http'
|
||||||
createPerson(baseDir, nickname, domain, port, httpPrefix,
|
createPerson(baseDir, nickname, domain, port, httpPrefix,
|
||||||
True, not args.noapproval, args.password.strip())
|
True, not args.noapproval, args.password.strip())
|
||||||
if os.path.isdir(baseDir + '/accounts/' + nickname + '@' + domain):
|
if os.path.isdir(baseDir + '/accounts/' + nickname + '@' + domain):
|
||||||
|
|
|
||||||
22
inbox.py
|
|
@ -54,6 +54,7 @@ from blocking import isBlockedDomain
|
||||||
from filters import isFiltered
|
from filters import isFiltered
|
||||||
from utils import updateAnnounceCollection
|
from utils import updateAnnounceCollection
|
||||||
from utils import undoAnnounceCollectionEntry
|
from utils import undoAnnounceCollectionEntry
|
||||||
|
from utils import dangerousMarkup
|
||||||
from httpsig import messageContentDigest
|
from httpsig import messageContentDigest
|
||||||
from posts import validContentWarning
|
from posts import validContentWarning
|
||||||
from posts import downloadAnnounce
|
from posts import downloadAnnounce
|
||||||
|
|
@ -69,7 +70,6 @@ from media import replaceYouTube
|
||||||
from git import isGitPatch
|
from git import isGitPatch
|
||||||
from git import receiveGitPatch
|
from git import receiveGitPatch
|
||||||
from followingCalendar import receivingCalendarEvents
|
from followingCalendar import receivingCalendarEvents
|
||||||
from content import dangerousMarkup
|
|
||||||
from happening import saveEventPost
|
from happening import saveEventPost
|
||||||
from delete import removeOldHashtags
|
from delete import removeOldHashtags
|
||||||
from follow import isFollowingActor
|
from follow import isFollowingActor
|
||||||
|
|
@ -151,7 +151,8 @@ def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
postJsonObject: {},
|
postJsonObject: {},
|
||||||
allowDeletion: bool, boxname: str,
|
allowDeletion: bool, boxname: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
peertubeInstances: []) -> None:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> None:
|
||||||
"""Converts the json post into html and stores it in a cache
|
"""Converts the json post into html and stores it in a cache
|
||||||
This enables the post to be quickly displayed later
|
This enables the post to be quickly displayed later
|
||||||
"""
|
"""
|
||||||
|
|
@ -168,7 +169,7 @@ def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
avatarUrl, True, allowDeletion,
|
avatarUrl, True, allowDeletion,
|
||||||
httpPrefix, __version__, boxname, None,
|
httpPrefix, __version__, boxname, None,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances, allowLocalNetworkAccess,
|
||||||
not isDM(postJsonObject),
|
not isDM(postJsonObject),
|
||||||
True, True, False, True)
|
True, True, False, True)
|
||||||
|
|
||||||
|
|
@ -1259,7 +1260,8 @@ def _receiveAnnounce(recentPostsCache: {},
|
||||||
sendThreads: [], postLog: [], cachedWebfingers: {},
|
sendThreads: [], postLog: [], cachedWebfingers: {},
|
||||||
personCache: {}, messageJson: {}, federationList: [],
|
personCache: {}, messageJson: {}, federationList: [],
|
||||||
debug: bool, translate: {},
|
debug: bool, translate: {},
|
||||||
YTReplacementDomain: str) -> bool:
|
YTReplacementDomain: str,
|
||||||
|
allowLocalNetworkAccess: bool) -> bool:
|
||||||
"""Receives an announce activity within the POST section of HTTPServer
|
"""Receives an announce activity within the POST section of HTTPServer
|
||||||
"""
|
"""
|
||||||
if messageJson['type'] != 'Announce':
|
if messageJson['type'] != 'Announce':
|
||||||
|
|
@ -1338,7 +1340,8 @@ def _receiveAnnounce(recentPostsCache: {},
|
||||||
postJsonObject = downloadAnnounce(session, baseDir, httpPrefix,
|
postJsonObject = downloadAnnounce(session, baseDir, httpPrefix,
|
||||||
nickname, domain, messageJson,
|
nickname, domain, messageJson,
|
||||||
__version__, translate,
|
__version__, translate,
|
||||||
YTReplacementDomain)
|
YTReplacementDomain,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
if not postJsonObject:
|
if not postJsonObject:
|
||||||
if domain not in messageJson['object'] and \
|
if domain not in messageJson['object'] and \
|
||||||
onionDomain not in messageJson['object']:
|
onionDomain not in messageJson['object']:
|
||||||
|
|
@ -2119,7 +2122,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
messageJson,
|
messageJson,
|
||||||
federationList,
|
federationList,
|
||||||
debug, translate,
|
debug, translate,
|
||||||
YTReplacementDomain):
|
YTReplacementDomain,
|
||||||
|
allowLocalNetworkAccess):
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: Announce accepted from ' + actor)
|
print('DEBUG: Announce accepted from ' + actor)
|
||||||
|
|
||||||
|
|
@ -2299,7 +2303,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
|
|
||||||
if isImageMedia(session, baseDir, httpPrefix,
|
if isImageMedia(session, baseDir, httpPrefix,
|
||||||
nickname, domain, postJsonObject,
|
nickname, domain, postJsonObject,
|
||||||
translate, YTReplacementDomain):
|
translate, YTReplacementDomain,
|
||||||
|
allowLocalNetworkAccess):
|
||||||
# media index will be updated
|
# media index will be updated
|
||||||
updateIndexList.append('tlmedia')
|
updateIndexList.append('tlmedia')
|
||||||
if isBlogPost(postJsonObject):
|
if isBlogPost(postJsonObject):
|
||||||
|
|
@ -2349,7 +2354,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
allowDeletion,
|
allowDeletion,
|
||||||
boxname,
|
boxname,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances)
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
if debug:
|
if debug:
|
||||||
timeDiff = \
|
timeDiff = \
|
||||||
str(int((time.time() - htmlCacheStartTime) *
|
str(int((time.time() - htmlCacheStartTime) *
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ from newswire import getDictFromNewswire
|
||||||
# from posts import sendSignedJson
|
# from posts import sendSignedJson
|
||||||
from posts import createNewsPost
|
from posts import createNewsPost
|
||||||
from posts import archivePostsForPerson
|
from posts import archivePostsForPerson
|
||||||
from content import dangerousMarkup
|
|
||||||
from content import validHashTag
|
from content import validHashTag
|
||||||
from utils import removeHtml
|
from utils import removeHtml
|
||||||
from utils import getFullDomain
|
from utils import getFullDomain
|
||||||
|
|
@ -31,6 +30,7 @@ from utils import loadJson
|
||||||
from utils import saveJson
|
from utils import saveJson
|
||||||
from utils import getStatusNumber
|
from utils import getStatusNumber
|
||||||
from utils import clearFromPostCaches
|
from utils import clearFromPostCaches
|
||||||
|
from utils import dangerousMarkup
|
||||||
from inbox import storeHashTags
|
from inbox import storeHashTags
|
||||||
from session import createSession
|
from session import createSession
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ from posts import sendToNamedAddresses
|
||||||
from utils import getFullDomain
|
from utils import getFullDomain
|
||||||
from utils import removeIdEnding
|
from utils import removeIdEnding
|
||||||
from utils import getDomainFromActor
|
from utils import getDomainFromActor
|
||||||
|
from utils import dangerousMarkup
|
||||||
from blocking import isBlockedDomain
|
from blocking import isBlockedDomain
|
||||||
from blocking import outboxBlock
|
from blocking import outboxBlock
|
||||||
from blocking import outboxUndoBlock
|
from blocking import outboxUndoBlock
|
||||||
|
|
@ -36,7 +37,6 @@ from bookmarks import outboxUndoBookmark
|
||||||
from delete import outboxDelete
|
from delete import outboxDelete
|
||||||
from shares import outboxShareUpload
|
from shares import outboxShareUpload
|
||||||
from shares import outboxUndoShareUpload
|
from shares import outboxUndoShareUpload
|
||||||
from content import dangerousMarkup
|
|
||||||
|
|
||||||
|
|
||||||
def postMessageToOutbox(messageJson: {}, postToNickname: str,
|
def postMessageToOutbox(messageJson: {}, postToNickname: str,
|
||||||
|
|
|
||||||
52
posts.py
|
|
@ -55,6 +55,7 @@ from utils import locateNewsVotes
|
||||||
from utils import locateNewsArrival
|
from utils import locateNewsArrival
|
||||||
from utils import votesOnNewswireItem
|
from utils import votesOnNewswireItem
|
||||||
from utils import removeHtml
|
from utils import removeHtml
|
||||||
|
from utils import dangerousMarkup
|
||||||
from media import attachMedia
|
from media import attachMedia
|
||||||
from media import replaceYouTube
|
from media import replaceYouTube
|
||||||
from content import tagExists
|
from content import tagExists
|
||||||
|
|
@ -291,7 +292,13 @@ def getPersonBox(baseDir: str, session, wfRequest: {},
|
||||||
avatarUrl = personJson['icon']['url']
|
avatarUrl = personJson['icon']['url']
|
||||||
displayName = None
|
displayName = None
|
||||||
if personJson.get('name'):
|
if personJson.get('name'):
|
||||||
displayName = removeHtml(personJson['name'])
|
displayName = personJson['name']
|
||||||
|
if dangerousMarkup(personJson['name'], False):
|
||||||
|
displayName = '*ADVERSARY*'
|
||||||
|
elif isFiltered(baseDir,
|
||||||
|
nickname, domain,
|
||||||
|
displayName):
|
||||||
|
displayName = '*FILTERED*'
|
||||||
# have they moved?
|
# have they moved?
|
||||||
if personJson.get('movedTo'):
|
if personJson.get('movedTo'):
|
||||||
displayName += ' ⌂'
|
displayName += ' ⌂'
|
||||||
|
|
@ -1824,11 +1831,16 @@ def threadSendPost(session, postJsonStr: str, federationList: [],
|
||||||
for attempt in range(20):
|
for attempt in range(20):
|
||||||
postResult = None
|
postResult = None
|
||||||
unauthorized = False
|
unauthorized = False
|
||||||
|
if debug:
|
||||||
|
print('Getting postJsonString for ' + inboxUrl)
|
||||||
try:
|
try:
|
||||||
postResult, unauthorized = \
|
postResult, unauthorized = \
|
||||||
postJsonString(session, postJsonStr, federationList,
|
postJsonString(session, postJsonStr, federationList,
|
||||||
inboxUrl, signatureHeaderJson,
|
inboxUrl, signatureHeaderJson,
|
||||||
debug)
|
debug)
|
||||||
|
if debug:
|
||||||
|
print('Obtained postJsonString for ' + inboxUrl +
|
||||||
|
' unauthorized: ' + str(unauthorized))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('ERROR: postJsonString failed ' + str(e))
|
print('ERROR: postJsonString failed ' + str(e))
|
||||||
if unauthorized:
|
if unauthorized:
|
||||||
|
|
@ -2908,7 +2920,8 @@ def isDM(postJsonObject: {}) -> bool:
|
||||||
def isImageMedia(session, baseDir: str, httpPrefix: str,
|
def isImageMedia(session, baseDir: str, httpPrefix: str,
|
||||||
nickname: str, domain: str,
|
nickname: str, domain: str,
|
||||||
postJsonObject: {}, translate: {},
|
postJsonObject: {}, translate: {},
|
||||||
YTReplacementDomain: str) -> bool:
|
YTReplacementDomain: str,
|
||||||
|
allowLocalNetworkAccess: bool) -> bool:
|
||||||
"""Returns true if the given post has attached image media
|
"""Returns true if the given post has attached image media
|
||||||
"""
|
"""
|
||||||
if postJsonObject['type'] == 'Announce':
|
if postJsonObject['type'] == 'Announce':
|
||||||
|
|
@ -2916,7 +2929,8 @@ def isImageMedia(session, baseDir: str, httpPrefix: str,
|
||||||
downloadAnnounce(session, baseDir, httpPrefix,
|
downloadAnnounce(session, baseDir, httpPrefix,
|
||||||
nickname, domain, postJsonObject,
|
nickname, domain, postJsonObject,
|
||||||
__version__, translate,
|
__version__, translate,
|
||||||
YTReplacementDomain)
|
YTReplacementDomain,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
if postJsonAnnounce:
|
if postJsonAnnounce:
|
||||||
postJsonObject = postJsonAnnounce
|
postJsonObject = postJsonAnnounce
|
||||||
if postJsonObject['type'] != 'Create':
|
if postJsonObject['type'] != 'Create':
|
||||||
|
|
@ -3831,7 +3845,8 @@ def _rejectAnnounce(announceFilename: str):
|
||||||
def downloadAnnounce(session, baseDir: str, httpPrefix: str,
|
def downloadAnnounce(session, baseDir: str, httpPrefix: str,
|
||||||
nickname: str, domain: str,
|
nickname: str, domain: str,
|
||||||
postJsonObject: {}, projectVersion: str,
|
postJsonObject: {}, projectVersion: str,
|
||||||
translate: {}, YTReplacementDomain: str) -> {}:
|
translate: {}, YTReplacementDomain: str,
|
||||||
|
allowLocalNetworkAccess: bool) -> {}:
|
||||||
"""Download the post referenced by an announce
|
"""Download the post referenced by an announce
|
||||||
"""
|
"""
|
||||||
if not postJsonObject.get('object'):
|
if not postJsonObject.get('object'):
|
||||||
|
|
@ -3911,20 +3926,16 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str,
|
||||||
if '/statuses/' not in announcedJson['id']:
|
if '/statuses/' not in announcedJson['id']:
|
||||||
_rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if '/users/' not in announcedJson['id'] and \
|
if not hasUsersPath(announcedJson['id']):
|
||||||
'/accounts/' not in announcedJson['id'] and \
|
|
||||||
'/channel/' not in announcedJson['id'] and \
|
|
||||||
'/profile/' not in announcedJson['id']:
|
|
||||||
_rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if not announcedJson.get('type'):
|
if not announcedJson.get('type'):
|
||||||
_rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
# pprint(announcedJson)
|
|
||||||
return None
|
return None
|
||||||
if announcedJson['type'] != 'Note' and \
|
if announcedJson['type'] != 'Note' and \
|
||||||
announcedJson['type'] != 'Article':
|
announcedJson['type'] != 'Article':
|
||||||
|
# You can only announce Note or Article types
|
||||||
_rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
# pprint(announcedJson)
|
|
||||||
return None
|
return None
|
||||||
if not announcedJson.get('content'):
|
if not announcedJson.get('content'):
|
||||||
_rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
|
|
@ -3935,16 +3946,25 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str,
|
||||||
if not validPostDate(announcedJson['published']):
|
if not validPostDate(announcedJson['published']):
|
||||||
_rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if isFiltered(baseDir, nickname, domain, announcedJson['content']):
|
|
||||||
|
# Check the content of the announce
|
||||||
|
contentStr = announcedJson['content']
|
||||||
|
if dangerousMarkup(contentStr, allowLocalNetworkAccess):
|
||||||
_rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if isFiltered(baseDir, nickname, domain, contentStr):
|
||||||
|
_rejectAnnounce(announceFilename)
|
||||||
|
return None
|
||||||
|
|
||||||
# remove any long words
|
# remove any long words
|
||||||
announcedJson['content'] = \
|
contentStr = removeLongWords(contentStr, 40, [])
|
||||||
removeLongWords(announcedJson['content'], 40, [])
|
|
||||||
|
|
||||||
# remove text formatting, such as bold/italics
|
# remove text formatting, such as bold/italics
|
||||||
announcedJson['content'] = \
|
contentStr = removeTextFormatting(contentStr)
|
||||||
removeTextFormatting(announcedJson['content'])
|
|
||||||
|
# set the content after santitization
|
||||||
|
announcedJson['content'] = contentStr
|
||||||
|
|
||||||
# wrap in create to be consistent with other posts
|
# wrap in create to be consistent with other posts
|
||||||
announcedJson = \
|
announcedJson = \
|
||||||
|
|
@ -3952,8 +3972,8 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str,
|
||||||
actorNickname, actorDomain, actorPort,
|
actorNickname, actorDomain, actorPort,
|
||||||
announcedJson)
|
announcedJson)
|
||||||
if announcedJson['type'] != 'Create':
|
if announcedJson['type'] != 'Create':
|
||||||
|
# Create wrap failed
|
||||||
_rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
# pprint(announcedJson)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# labelAccusatoryPost(postJsonObject, translate)
|
# labelAccusatoryPost(postJsonObject, translate)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
[metadata]
|
||||||
|
name = epicyon
|
||||||
|
version = 1.2.0
|
||||||
|
|
||||||
|
[options]
|
||||||
|
packages = .
|
||||||
|
install_requires =
|
||||||
|
crypto
|
||||||
|
idna<3,>=2.5
|
||||||
|
numpy
|
||||||
|
pillow
|
||||||
|
pycryptodome
|
||||||
|
pyqrcode
|
||||||
|
python-dateutil
|
||||||
|
requests
|
||||||
|
socks
|
||||||
19
tests.py
|
|
@ -49,6 +49,7 @@ from utils import saveJson
|
||||||
from utils import getStatusNumber
|
from utils import getStatusNumber
|
||||||
from utils import getFollowersOfPerson
|
from utils import getFollowersOfPerson
|
||||||
from utils import removeHtml
|
from utils import removeHtml
|
||||||
|
from utils import dangerousMarkup
|
||||||
from follow import followerOfPerson
|
from follow import followerOfPerson
|
||||||
from follow import unfollowAccount
|
from follow import unfollowAccount
|
||||||
from follow import unfollowerOfAccount
|
from follow import unfollowerOfAccount
|
||||||
|
|
@ -77,7 +78,6 @@ from inbox import validInboxFilenames
|
||||||
from categories import guessHashtagCategory
|
from categories import guessHashtagCategory
|
||||||
from content import htmlReplaceEmailQuote
|
from content import htmlReplaceEmailQuote
|
||||||
from content import htmlReplaceQuoteMarks
|
from content import htmlReplaceQuoteMarks
|
||||||
from content import dangerousMarkup
|
|
||||||
from content import dangerousCSS
|
from content import dangerousCSS
|
||||||
from content import addWebLinks
|
from content import addWebLinks
|
||||||
from content import replaceEmojiFromTags
|
from content import replaceEmojiFromTags
|
||||||
|
|
@ -95,6 +95,7 @@ from newswire import getNewswireTags
|
||||||
from newswire import parseFeedDate
|
from newswire import parseFeedDate
|
||||||
from mastoapiv1 import getMastoApiV1IdFromNickname
|
from mastoapiv1 import getMastoApiV1IdFromNickname
|
||||||
from mastoapiv1 import getNicknameFromMastoApiV1Id
|
from mastoapiv1 import getNicknameFromMastoApiV1Id
|
||||||
|
from webapp_post import prepareHtmlPostNickname
|
||||||
|
|
||||||
testServerAliceRunning = False
|
testServerAliceRunning = False
|
||||||
testServerBobRunning = False
|
testServerBobRunning = False
|
||||||
|
|
@ -3072,9 +3073,25 @@ def testDomainHandling():
|
||||||
assert decodedHost(testDomain) == "españa.icom.museum"
|
assert decodedHost(testDomain) == "españa.icom.museum"
|
||||||
|
|
||||||
|
|
||||||
|
def testPrepareHtmlPostNickname():
|
||||||
|
print('testPrepareHtmlPostNickname')
|
||||||
|
postHtml = '<a class="imageAnchor" href="/users/bob?replyfollowers='
|
||||||
|
postHtml += '<a class="imageAnchor" href="/users/bob?repeatprivate='
|
||||||
|
result = prepareHtmlPostNickname('alice', postHtml)
|
||||||
|
assert result == postHtml.replace('/bob?', '/alice?')
|
||||||
|
|
||||||
|
postHtml = '<a class="imageAnchor" href="/users/bob?replyfollowers='
|
||||||
|
postHtml += '<a class="imageAnchor" href="/users/bob;repeatprivate='
|
||||||
|
expectedHtml = '<a class="imageAnchor" href="/users/alice?replyfollowers='
|
||||||
|
expectedHtml += '<a class="imageAnchor" href="/users/bob;repeatprivate='
|
||||||
|
result = prepareHtmlPostNickname('alice', postHtml)
|
||||||
|
assert result == expectedHtml
|
||||||
|
|
||||||
|
|
||||||
def runAllTests():
|
def runAllTests():
|
||||||
print('Running tests...')
|
print('Running tests...')
|
||||||
testFunctions()
|
testFunctions()
|
||||||
|
testPrepareHtmlPostNickname()
|
||||||
testDomainHandling()
|
testDomainHandling()
|
||||||
testMastoApi()
|
testMastoApi()
|
||||||
testLinksWithinPost()
|
testLinksWithinPost()
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 449 KiB After Width: | Height: | Size: 289 KiB |
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -1,4 +1,10 @@
|
||||||
{
|
{
|
||||||
|
"column-left-top-margin": "0.4cm",
|
||||||
|
"column-right-top-margin": "0.8cm",
|
||||||
|
"time-vertical-align": "0%",
|
||||||
|
"time-vertical-align-mobile": "1.5%",
|
||||||
|
"post-separator-margin-top": "10px",
|
||||||
|
"post-separator-margin-bottom": "10px",
|
||||||
"column-left-header-background": "#35244d",
|
"column-left-header-background": "#35244d",
|
||||||
"newswire-publish-icon": "True",
|
"newswire-publish-icon": "True",
|
||||||
"full-width-timeline-buttons": "False",
|
"full-width-timeline-buttons": "False",
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "حسابات أخرى",
|
"Other accounts": "حسابات أخرى",
|
||||||
"Pin this post to your profile.": "تثبيت هذه الوظيفة في ملف التعريف الخاص بك.",
|
"Pin this post to your profile.": "تثبيت هذه الوظيفة في ملف التعريف الخاص بك.",
|
||||||
"Administered by": "تدار من قبل",
|
"Administered by": "تدار من قبل",
|
||||||
"Version": "الإصدار"
|
"Version": "الإصدار",
|
||||||
|
"Skip to timeline": "تخطي إلى الجدول الزمني",
|
||||||
|
"Skip to Newswire": "انتقل إلى Newswire",
|
||||||
|
"Skip to Links": "تخطي إلى روابط الويب"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Altres comptes",
|
"Other accounts": "Altres comptes",
|
||||||
"Pin this post to your profile.": "Fixa aquesta publicació al teu perfil.",
|
"Pin this post to your profile.": "Fixa aquesta publicació al teu perfil.",
|
||||||
"Administered by": "Administrat per",
|
"Administered by": "Administrat per",
|
||||||
"Version": "Versió"
|
"Version": "Versió",
|
||||||
|
"Skip to timeline": "Ves a la cronologia",
|
||||||
|
"Skip to Newswire": "Vés a Newswire",
|
||||||
|
"Skip to Links": "Vés als enllaços web"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Cyfrifon eraill",
|
"Other accounts": "Cyfrifon eraill",
|
||||||
"Pin this post to your profile.": "Piniwch y post hwn i'ch proffil.",
|
"Pin this post to your profile.": "Piniwch y post hwn i'ch proffil.",
|
||||||
"Administered by": "Gweinyddir gan",
|
"Administered by": "Gweinyddir gan",
|
||||||
"Version": "Fersiwn"
|
"Version": "Fersiwn",
|
||||||
|
"Skip to timeline": "Neidio i'r llinell amser",
|
||||||
|
"Skip to Newswire": "Neidio i Newswire",
|
||||||
|
"Skip to Links": "Neidio i Dolenni Gwe"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Andere Konten",
|
"Other accounts": "Andere Konten",
|
||||||
"Pin this post to your profile.": "Pin diesen Beitrag zu Ihrem Profil.",
|
"Pin this post to your profile.": "Pin diesen Beitrag zu Ihrem Profil.",
|
||||||
"Administered by": "Verwaltet von",
|
"Administered by": "Verwaltet von",
|
||||||
"Version": "Ausführung"
|
"Version": "Ausführung",
|
||||||
|
"Skip to timeline": "Zur Zeitleiste springen",
|
||||||
|
"Skip to Newswire": "Springe zu Newswire",
|
||||||
|
"Skip to Links": "Springe zu Weblinks"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
"Location": "Location",
|
"Location": "Location",
|
||||||
"Login": "Login",
|
"Login": "Login",
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
"Switch to timeline view": "Switch to timeline view",
|
"Switch to timeline view": "Timeline view",
|
||||||
"Approve": "Approve",
|
"Approve": "Approve",
|
||||||
"Deny": "Deny",
|
"Deny": "Deny",
|
||||||
"Posts": "Posts",
|
"Posts": "Posts",
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
"Your browser does not support the video element.": "Your browser does not support the video element.",
|
"Your browser does not support the video element.": "Your browser does not support the video element.",
|
||||||
"Create a new post": "New post",
|
"Create a new post": "New post",
|
||||||
"Create a new DM": "Create a new DM",
|
"Create a new DM": "Create a new DM",
|
||||||
"Switch to profile view": "Switch to profile view",
|
"Switch to profile view": "Profile view",
|
||||||
"Inbox": "Inbox",
|
"Inbox": "Inbox",
|
||||||
"Outbox": "Outbox",
|
"Outbox": "Outbox",
|
||||||
"Search and follow": "Search/follow",
|
"Search and follow": "Search/follow",
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Other accounts",
|
"Other accounts": "Other accounts",
|
||||||
"Pin this post to your profile.": "Pin this post to your profile.",
|
"Pin this post to your profile.": "Pin this post to your profile.",
|
||||||
"Administered by": "Administered by",
|
"Administered by": "Administered by",
|
||||||
"Version": "Version"
|
"Version": "Version",
|
||||||
|
"Skip to timeline": "Skip to timeline",
|
||||||
|
"Skip to Newswire": "Skip to Newswire",
|
||||||
|
"Skip to Links": "Skip to Links"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Otras cuentas",
|
"Other accounts": "Otras cuentas",
|
||||||
"Pin this post to your profile.": "Fija esta publicación a tu perfil.",
|
"Pin this post to your profile.": "Fija esta publicación a tu perfil.",
|
||||||
"Administered by": "Administrado por",
|
"Administered by": "Administrado por",
|
||||||
"Version": "Versión"
|
"Version": "Versión",
|
||||||
|
"Skip to timeline": "Saltar a la línea de tiempo",
|
||||||
|
"Skip to Newswire": "Saltar a Newswire",
|
||||||
|
"Skip to Links": "Saltar a enlaces web"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Autres comptes",
|
"Other accounts": "Autres comptes",
|
||||||
"Pin this post to your profile.": "Épinglez ce message à votre profil.",
|
"Pin this post to your profile.": "Épinglez ce message à votre profil.",
|
||||||
"Administered by": "Administré par",
|
"Administered by": "Administré par",
|
||||||
"Version": "Version"
|
"Version": "Version",
|
||||||
|
"Skip to timeline": "Passer à la chronologie",
|
||||||
|
"Skip to Newswire": "Passer à Newswire",
|
||||||
|
"Skip to Links": "Passer aux liens Web"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Cuntais eile",
|
"Other accounts": "Cuntais eile",
|
||||||
"Pin this post to your profile.": "Bioráin an post seo le do phróifíl.",
|
"Pin this post to your profile.": "Bioráin an post seo le do phróifíl.",
|
||||||
"Administered by": "Riartha ag",
|
"Administered by": "Riartha ag",
|
||||||
"Version": "Leagan"
|
"Version": "Leagan",
|
||||||
|
"Skip to timeline": "Scipeáil chuig an amlíne",
|
||||||
|
"Skip to Newswire": "Scipeáil chuig Newswire",
|
||||||
|
"Skip to Links": "Scipeáil chuig Naisc Ghréasáin"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "अन्य खाते",
|
"Other accounts": "अन्य खाते",
|
||||||
"Pin this post to your profile.": "इस पोस्ट को अपनी प्रोफाइल पर पिन करें।",
|
"Pin this post to your profile.": "इस पोस्ट को अपनी प्रोफाइल पर पिन करें।",
|
||||||
"Administered by": "द्वारा प्रशासित",
|
"Administered by": "द्वारा प्रशासित",
|
||||||
"Version": "संस्करण"
|
"Version": "संस्करण",
|
||||||
|
"Skip to timeline": "टाइमलाइन पर जाएं",
|
||||||
|
"Skip to Newswire": "Newswire पर जाएं",
|
||||||
|
"Skip to Links": "वेब लिंक पर जाएं"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Altri account",
|
"Other accounts": "Altri account",
|
||||||
"Pin this post to your profile.": "Metti questo post sul tuo profilo.",
|
"Pin this post to your profile.": "Metti questo post sul tuo profilo.",
|
||||||
"Administered by": "Amministrato da",
|
"Administered by": "Amministrato da",
|
||||||
"Version": "Versione"
|
"Version": "Versione",
|
||||||
|
"Skip to timeline": "Passa alla sequenza temporale",
|
||||||
|
"Skip to Newswire": "Passa a Newswire",
|
||||||
|
"Skip to Links": "Passa a collegamenti Web"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "その他のアカウント",
|
"Other accounts": "その他のアカウント",
|
||||||
"Pin this post to your profile.": "この投稿をプロフィールに固定します。",
|
"Pin this post to your profile.": "この投稿をプロフィールに固定します。",
|
||||||
"Administered by": "管理者",
|
"Administered by": "管理者",
|
||||||
"Version": "バージョン"
|
"Version": "バージョン",
|
||||||
|
"Skip to timeline": "タイムラインにスキップ",
|
||||||
|
"Skip to Newswire": "Newswireにスキップ",
|
||||||
|
"Skip to Links": "Webリンクにスキップ"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -359,5 +359,8 @@
|
||||||
"Other accounts": "Other accounts",
|
"Other accounts": "Other accounts",
|
||||||
"Pin this post to your profile.": "Pin this post to your profile.",
|
"Pin this post to your profile.": "Pin this post to your profile.",
|
||||||
"Administered by": "Administered by",
|
"Administered by": "Administered by",
|
||||||
"Version": "Version"
|
"Version": "Version",
|
||||||
|
"Skip to timeline": "Skip to timeline",
|
||||||
|
"Skip to Newswire": "Skip to Newswire",
|
||||||
|
"Skip to Links": "Skip to Links"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Outras contas",
|
"Other accounts": "Outras contas",
|
||||||
"Pin this post to your profile.": "Fixar esta postagem em seu perfil.",
|
"Pin this post to your profile.": "Fixar esta postagem em seu perfil.",
|
||||||
"Administered by": "Administrado por",
|
"Administered by": "Administrado por",
|
||||||
"Version": "Versão"
|
"Version": "Versão",
|
||||||
|
"Skip to timeline": "Pular para a linha do tempo",
|
||||||
|
"Skip to Newswire": "Pular para Newswire",
|
||||||
|
"Skip to Links": "Pular para links da web"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "Другие аккаунты",
|
"Other accounts": "Другие аккаунты",
|
||||||
"Pin this post to your profile.": "Закрепите это сообщение в своем профиле.",
|
"Pin this post to your profile.": "Закрепите это сообщение в своем профиле.",
|
||||||
"Administered by": "Под управлением",
|
"Administered by": "Под управлением",
|
||||||
"Version": "Версия"
|
"Version": "Версия",
|
||||||
|
"Skip to timeline": "Перейти к временной шкале",
|
||||||
|
"Skip to Newswire": "Перейти к ленте новостей",
|
||||||
|
"Skip to Links": "Перейти к веб-ссылкам"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,5 +363,8 @@
|
||||||
"Other accounts": "其他账户",
|
"Other accounts": "其他账户",
|
||||||
"Pin this post to your profile.": "将此帖子固定到您的个人资料。",
|
"Pin this post to your profile.": "将此帖子固定到您的个人资料。",
|
||||||
"Administered by": "由...管理",
|
"Administered by": "由...管理",
|
||||||
"Version": "版"
|
"Version": "版",
|
||||||
|
"Skip to timeline": "跳到时间线",
|
||||||
|
"Skip to Newswire": "跳到新闻专线",
|
||||||
|
"Skip to Links": "跳到网页链接"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
47
utils.py
|
|
@ -554,6 +554,38 @@ def urlPermitted(url: str, federationList: []):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def dangerousMarkup(content: str, allowLocalNetworkAccess: bool) -> bool:
|
||||||
|
"""Returns true if the given content contains dangerous html markup
|
||||||
|
"""
|
||||||
|
if '<' not in content:
|
||||||
|
return False
|
||||||
|
if '>' not in content:
|
||||||
|
return False
|
||||||
|
contentSections = content.split('<')
|
||||||
|
invalidPartials = ()
|
||||||
|
if not allowLocalNetworkAccess:
|
||||||
|
invalidPartials = ('localhost', '127.0.', '192.168', '10.0.')
|
||||||
|
invalidStrings = ('script', 'canvas', 'style', 'abbr',
|
||||||
|
'frame', 'iframe', 'html', 'body',
|
||||||
|
'hr', 'allow-popups', 'allow-scripts')
|
||||||
|
for markup in contentSections:
|
||||||
|
if '>' not in markup:
|
||||||
|
continue
|
||||||
|
markup = markup.split('>')[0].strip()
|
||||||
|
for partialMatch in invalidPartials:
|
||||||
|
if partialMatch in markup:
|
||||||
|
return True
|
||||||
|
if ' ' not in markup:
|
||||||
|
for badStr in invalidStrings:
|
||||||
|
if badStr in markup:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
for badStr in invalidStrings:
|
||||||
|
if badStr + ' ' in markup:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def getDisplayName(baseDir: str, actor: str, personCache: {}) -> str:
|
def getDisplayName(baseDir: str, actor: str, personCache: {}) -> str:
|
||||||
"""Returns the display name for the given actor
|
"""Returns the display name for the given actor
|
||||||
"""
|
"""
|
||||||
|
|
@ -561,9 +593,10 @@ def getDisplayName(baseDir: str, actor: str, personCache: {}) -> str:
|
||||||
actor = actor.split('/statuses/')[0]
|
actor = actor.split('/statuses/')[0]
|
||||||
if not personCache.get(actor):
|
if not personCache.get(actor):
|
||||||
return None
|
return None
|
||||||
|
nameFound = None
|
||||||
if personCache[actor].get('actor'):
|
if personCache[actor].get('actor'):
|
||||||
if personCache[actor]['actor'].get('name'):
|
if personCache[actor]['actor'].get('name'):
|
||||||
return personCache[actor]['actor']['name']
|
nameFound = personCache[actor]['actor']['name']
|
||||||
else:
|
else:
|
||||||
# Try to obtain from the cached actors
|
# Try to obtain from the cached actors
|
||||||
cachedActorFilename = \
|
cachedActorFilename = \
|
||||||
|
|
@ -572,8 +605,11 @@ def getDisplayName(baseDir: str, actor: str, personCache: {}) -> str:
|
||||||
actorJson = loadJson(cachedActorFilename, 1)
|
actorJson = loadJson(cachedActorFilename, 1)
|
||||||
if actorJson:
|
if actorJson:
|
||||||
if actorJson.get('name'):
|
if actorJson.get('name'):
|
||||||
return(actorJson['name'])
|
nameFound = actorJson['name']
|
||||||
return None
|
if nameFound:
|
||||||
|
if dangerousMarkup(nameFound, False):
|
||||||
|
nameFound = "*ADVERSARY*"
|
||||||
|
return nameFound
|
||||||
|
|
||||||
|
|
||||||
def getNicknameFromActor(actor: str) -> str:
|
def getNicknameFromActor(actor: str) -> str:
|
||||||
|
|
@ -1721,6 +1757,11 @@ def siteIsActive(url: str) -> bool:
|
||||||
"""
|
"""
|
||||||
if not url.startswith('http'):
|
if not url.startswith('http'):
|
||||||
return False
|
return False
|
||||||
|
if '.onion/' in url or '.i2p/' in url or \
|
||||||
|
url.endswith('.onion') or \
|
||||||
|
url.endswith('.i2p'):
|
||||||
|
# skip this check for onion and i2p
|
||||||
|
return True
|
||||||
try:
|
try:
|
||||||
req = urllib.request.Request(url)
|
req = urllib.request.Request(url)
|
||||||
urllib.request.urlopen(req, timeout=10) # nosec
|
urllib.request.urlopen(req, timeout=10) # nosec
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
'\n <center>\n' + \
|
'\n <center>\n' + \
|
||||||
' <img class="leftColImg" ' + \
|
' <img class="leftColImg" ' + \
|
||||||
'loading="lazy" src="/users/' + \
|
'alt="" loading="lazy" src="/users/' + \
|
||||||
nickname + '/' + leftImageFile + '" />\n' + \
|
nickname + '/' + leftImageFile + '" />\n' + \
|
||||||
' </center>\n'
|
' </center>\n'
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
'/users/' + nickname + '/editlinks">' + \
|
'/users/' + nickname + '/editlinks">' + \
|
||||||
'<img class="' + editImageClass + \
|
'<img class="' + editImageClass + \
|
||||||
'" loading="lazy" alt="' + \
|
'" loading="lazy" alt="' + \
|
||||||
translate['Edit Links'] + '" title="' + \
|
translate['Edit Links'] + ' | " title="' + \
|
||||||
translate['Edit Links'] + '" src="/' + \
|
translate['Edit Links'] + '" src="/' + \
|
||||||
'icons/edit.png" /></a>\n'
|
'icons/edit.png" /></a>\n'
|
||||||
|
|
||||||
|
|
@ -268,6 +268,7 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
||||||
'<img loading="lazy" class="timeline-banner" ' + \
|
'<img loading="lazy" class="timeline-banner" ' + \
|
||||||
|
'alt="' + translate['Switch to timeline view'] + '" ' + \
|
||||||
'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n'
|
'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n'
|
||||||
|
|
||||||
htmlStr += '<div class="col-left-mobile">\n'
|
htmlStr += '<div class="col-left-mobile">\n'
|
||||||
|
|
@ -333,7 +334,8 @@ def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
'<a href="/users/' + nickname + '/' + defaultTimeline + '" title="' + \
|
'<a href="/users/' + nickname + '/' + defaultTimeline + '" title="' + \
|
||||||
translate['Switch to timeline view'] + '" alt="' + \
|
translate['Switch to timeline view'] + '" alt="' + \
|
||||||
translate['Switch to timeline view'] + '">\n'
|
translate['Switch to timeline view'] + '">\n'
|
||||||
editLinksForm += '<img loading="lazy" class="timeline-banner" src="' + \
|
editLinksForm += '<img loading="lazy" class="timeline-banner" ' + \
|
||||||
|
'alt = "" src="' + \
|
||||||
'/users/' + nickname + '/' + bannerFile + '" /></a>\n' + \
|
'/users/' + nickname + '/' + bannerFile + '" /></a>\n' + \
|
||||||
'</header>\n'
|
'</header>\n'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
'\n <center>\n' + \
|
'\n <center>\n' + \
|
||||||
' <img class="rightColImg" ' + \
|
' <img class="rightColImg" ' + \
|
||||||
'loading="lazy" src="/users/' + \
|
'alt="" loading="lazy" src="/users/' + \
|
||||||
nickname + '/' + rightImageFile + '" />\n' + \
|
nickname + '/' + rightImageFile + '" />\n' + \
|
||||||
' </center>\n'
|
' </center>\n'
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
'/users/' + nickname + '/editnewswire">' + \
|
'/users/' + nickname + '/editnewswire">' + \
|
||||||
'<img class="' + editImageClass + \
|
'<img class="' + editImageClass + \
|
||||||
'" loading="lazy" alt="' + \
|
'" loading="lazy" alt="' + \
|
||||||
translate['Edit newswire'] + '" title="' + \
|
translate['Edit newswire'] + ' | " title="' + \
|
||||||
translate['Edit newswire'] + '" src="/' + \
|
translate['Edit newswire'] + '" src="/' + \
|
||||||
'icons/edit_notify.png" /></a>\n'
|
'icons/edit_notify.png" /></a>\n'
|
||||||
else:
|
else:
|
||||||
|
|
@ -133,7 +133,7 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
'/users/' + nickname + '/editnewswire">' + \
|
'/users/' + nickname + '/editnewswire">' + \
|
||||||
'<img class="' + editImageClass + \
|
'<img class="' + editImageClass + \
|
||||||
'" loading="lazy" alt="' + \
|
'" loading="lazy" alt="' + \
|
||||||
translate['Edit newswire'] + '" title="' + \
|
translate['Edit newswire'] + ' | " title="' + \
|
||||||
translate['Edit newswire'] + '" src="/' + \
|
translate['Edit newswire'] + '" src="/' + \
|
||||||
'icons/edit.png" /></a>\n'
|
'icons/edit.png" /></a>\n'
|
||||||
|
|
||||||
|
|
@ -142,14 +142,14 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
' <a href="/categories.xml">' + \
|
' <a href="/categories.xml">' + \
|
||||||
'<img class="' + editImageClass + \
|
'<img class="' + editImageClass + \
|
||||||
'" loading="lazy" alt="' + \
|
'" loading="lazy" alt="' + \
|
||||||
translate['Hashtag Categories RSS Feed'] + '" title="' + \
|
translate['Hashtag Categories RSS Feed'] + ' | " title="' + \
|
||||||
translate['Hashtag Categories RSS Feed'] + '" src="/' + \
|
translate['Hashtag Categories RSS Feed'] + '" src="/' + \
|
||||||
'icons/categoriesrss.png" /></a>\n'
|
'icons/categoriesrss.png" /></a>\n'
|
||||||
rssIconStr += \
|
rssIconStr += \
|
||||||
' <a href="/newswire.xml">' + \
|
' <a href="/newswire.xml">' + \
|
||||||
'<img class="' + editImageClass + \
|
'<img class="' + editImageClass + \
|
||||||
'" loading="lazy" alt="' + \
|
'" loading="lazy" alt="' + \
|
||||||
translate['Newswire RSS Feed'] + '" title="' + \
|
translate['Newswire RSS Feed'] + ' | " title="' + \
|
||||||
translate['Newswire RSS Feed'] + '" src="/' + \
|
translate['Newswire RSS Feed'] + '" src="/' + \
|
||||||
'icons/logorss.png" /></a>\n'
|
'icons/logorss.png" /></a>\n'
|
||||||
if rssIconAtTop:
|
if rssIconAtTop:
|
||||||
|
|
@ -241,6 +241,7 @@ def _htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
|
||||||
if faviconUrl:
|
if faviconUrl:
|
||||||
faviconLink = \
|
faviconLink = \
|
||||||
'<img loading="lazy" src="' + faviconUrl + '" ' + \
|
'<img loading="lazy" src="' + faviconUrl + '" ' + \
|
||||||
|
'alt="" ' + \
|
||||||
_getBrokenFavSubstitute() + '/>'
|
_getBrokenFavSubstitute() + '/>'
|
||||||
moderatedItem = item[5]
|
moderatedItem = item[5]
|
||||||
htmlStr += separatorStr
|
htmlStr += separatorStr
|
||||||
|
|
@ -265,6 +266,7 @@ def _htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
|
||||||
'/newswireunvote=' + dateStrLink + '" ' + \
|
'/newswireunvote=' + dateStrLink + '" ' + \
|
||||||
'title="' + translate['Remove Vote'] + '">'
|
'title="' + translate['Remove Vote'] + '">'
|
||||||
htmlStr += '<img loading="lazy" class="voteicon" src="/' + \
|
htmlStr += '<img loading="lazy" class="voteicon" src="/' + \
|
||||||
|
'alt="' + translate['Remove Vote'] + '" ' + \
|
||||||
'icons/vote.png" /></a></p>\n'
|
'icons/vote.png" /></a></p>\n'
|
||||||
else:
|
else:
|
||||||
htmlStr += ' <span class="newswireDateVotedOn">'
|
htmlStr += ' <span class="newswireDateVotedOn">'
|
||||||
|
|
@ -290,8 +292,9 @@ def _htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
|
||||||
htmlStr += '<a href="/users/' + nickname + \
|
htmlStr += '<a href="/users/' + nickname + \
|
||||||
'/newswirevote=' + dateStrLink + '" ' + \
|
'/newswirevote=' + dateStrLink + '" ' + \
|
||||||
'title="' + translate['Vote'] + '">'
|
'title="' + translate['Vote'] + '">'
|
||||||
htmlStr += '<img class="voteicon" src="/' + \
|
htmlStr += '<img class="voteicon" ' + \
|
||||||
'icons/vote.png" /></a>'
|
'alt="' + translate['Vote'] + '" ' + \
|
||||||
|
'src="/icons/vote.png" /></a>'
|
||||||
htmlStr += '</p>\n'
|
htmlStr += '</p>\n'
|
||||||
else:
|
else:
|
||||||
htmlStr += '<p class="newswireItem">' + \
|
htmlStr += '<p class="newswireItem">' + \
|
||||||
|
|
@ -354,7 +357,8 @@ def htmlCitations(baseDir: str, nickname: str, domain: str,
|
||||||
'<a href="/users/' + nickname + '/newblog" title="' + \
|
'<a href="/users/' + nickname + '/newblog" title="' + \
|
||||||
translate['Go Back'] + '" alt="' + \
|
translate['Go Back'] + '" alt="' + \
|
||||||
translate['Go Back'] + '">\n'
|
translate['Go Back'] + '">\n'
|
||||||
htmlStr += '<img loading="lazy" class="timeline-banner" src="' + \
|
htmlStr += '<img loading="lazy" class="timeline-banner" ' + \
|
||||||
|
'alt="" src="' + \
|
||||||
'/users/' + nickname + '/' + bannerFile + '" /></a>\n'
|
'/users/' + nickname + '/' + bannerFile + '" /></a>\n'
|
||||||
|
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
|
|
@ -464,6 +468,7 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
||||||
'<img loading="lazy" class="timeline-banner" ' + \
|
'<img loading="lazy" class="timeline-banner" ' + \
|
||||||
|
'alt="' + translate['Timeline banner image'] + '" ' + \
|
||||||
'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n'
|
'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n'
|
||||||
|
|
||||||
htmlStr += '<div class="col-right-mobile">\n'
|
htmlStr += '<div class="col-right-mobile">\n'
|
||||||
|
|
@ -531,8 +536,8 @@ def htmlEditNewswire(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
translate['Switch to timeline view'] + '" alt="' + \
|
translate['Switch to timeline view'] + '" alt="' + \
|
||||||
translate['Switch to timeline view'] + '">\n'
|
translate['Switch to timeline view'] + '">\n'
|
||||||
editNewswireForm += '<img loading="lazy" class="timeline-banner" src="' + \
|
editNewswireForm += '<img loading="lazy" class="timeline-banner" src="' + \
|
||||||
'/users/' + nickname + '/' + bannerFile + '" /></a>\n' + \
|
'/users/' + nickname + '/' + bannerFile + '" ' + \
|
||||||
'</header>'
|
'alt="" /></a>\n</header>'
|
||||||
|
|
||||||
editNewswireForm += \
|
editNewswireForm += \
|
||||||
'<form enctype="multipart/form-data" method="POST" ' + \
|
'<form enctype="multipart/form-data" method="POST" ' + \
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ def htmlConfirmDelete(cssCache: {},
|
||||||
callingDomain: str,
|
callingDomain: str,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Shows a screen asking to confirm the deletion of a post
|
"""Shows a screen asking to confirm the deletion of a post
|
||||||
"""
|
"""
|
||||||
if '/statuses/' not in messageId:
|
if '/statuses/' not in messageId:
|
||||||
|
|
@ -70,7 +71,7 @@ def htmlConfirmDelete(cssCache: {},
|
||||||
httpPrefix, projectVersion, 'outbox',
|
httpPrefix, projectVersion, 'outbox',
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances, allowLocalNetworkAccess,
|
||||||
False, False, False, False, False)
|
False, False, False, False, False)
|
||||||
deletePostStr += '<center>'
|
deletePostStr += '<center>'
|
||||||
deletePostStr += \
|
deletePostStr += \
|
||||||
|
|
|
||||||
|
|
@ -572,7 +572,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
|
||||||
translate['Switch to timeline view'] + '" alt="' + \
|
translate['Switch to timeline view'] + '" alt="' + \
|
||||||
translate['Switch to timeline view'] + '">\n'
|
translate['Switch to timeline view'] + '">\n'
|
||||||
newPostForm += '<img loading="lazy" class="timeline-banner" src="' + \
|
newPostForm += '<img loading="lazy" class="timeline-banner" src="' + \
|
||||||
'/users/' + nickname + '/' + bannerFile + '" /></a>\n' + \
|
'/users/' + nickname + '/' + bannerFile + '" alt="" /></a>\n' + \
|
||||||
'</header>\n'
|
'</header>\n'
|
||||||
|
|
||||||
mentionsStr = ''
|
mentionsStr = ''
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,8 @@ def _htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
projectVersion: str,
|
projectVersion: str,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Shows posts on the front screen of a news instance
|
"""Shows posts on the front screen of a news instance
|
||||||
These should only be public blog posts from the features timeline
|
These should only be public blog posts from the features timeline
|
||||||
which is the blog timeline of the news actor
|
which is the blog timeline of the news actor
|
||||||
|
|
@ -69,6 +70,7 @@ def _htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
False, False, False, True, False)
|
False, False, False, True, False)
|
||||||
if postStr:
|
if postStr:
|
||||||
profileStr += postStr + separatorStr
|
profileStr += postStr + separatorStr
|
||||||
|
|
@ -91,6 +93,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
newswire: {}, theme: str,
|
newswire: {}, theme: str,
|
||||||
peertubeInstances: [],
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool,
|
||||||
extraJson=None,
|
extraJson=None,
|
||||||
pageNumber=None, maxItemsPerPage=None) -> str:
|
pageNumber=None, maxItemsPerPage=None) -> str:
|
||||||
"""Show the news instance front screen
|
"""Show the news instance front screen
|
||||||
|
|
@ -155,7 +158,8 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
||||||
projectVersion,
|
projectVersion,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances) + licenseStr
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess) + licenseStr
|
||||||
|
|
||||||
# Footer which is only used for system accounts
|
# Footer which is only used for system accounts
|
||||||
profileFooterStr = ' </td>\n'
|
profileFooterStr = ' </td>\n'
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ def htmlSearchHashtagCategory(cssCache: {}, translate: {},
|
||||||
if os.path.isfile(searchBannerFilename):
|
if os.path.isfile(searchBannerFilename):
|
||||||
htmlStr += '<a href="' + actor + '/search">\n'
|
htmlStr += '<a href="' + actor + '/search">\n'
|
||||||
htmlStr += '<img loading="lazy" class="timeline-banner" src="' + \
|
htmlStr += '<img loading="lazy" class="timeline-banner" src="' + \
|
||||||
actor + '/' + searchBannerFile + '" /></a>\n'
|
actor + '/' + searchBannerFile + '" alt="" /></a>\n'
|
||||||
|
|
||||||
htmlStr += '<div class="follow">'
|
htmlStr += '<div class="follow">'
|
||||||
htmlStr += '<center><br><br><br>'
|
htmlStr += '<center><br><br><br>'
|
||||||
|
|
|
||||||
|
|
@ -138,9 +138,12 @@ def htmlLogin(cssCache: {}, translate: {},
|
||||||
loginForm += '<br>\n'
|
loginForm += '<br>\n'
|
||||||
loginForm += '<form method="POST" action="/login">\n'
|
loginForm += '<form method="POST" action="/login">\n'
|
||||||
loginForm += ' <div class="imgcontainer">\n'
|
loginForm += ' <div class="imgcontainer">\n'
|
||||||
|
instanceTitle = getConfigParam(baseDir, 'instanceTitle')
|
||||||
|
if not instanceTitle:
|
||||||
|
instanceTitle = "Epicyon"
|
||||||
loginForm += \
|
loginForm += \
|
||||||
' <img loading="lazy" src="' + loginImage + \
|
' <img loading="lazy" src="' + loginImage + \
|
||||||
'" alt="login image" class="loginimage">\n'
|
'" alt="' + instanceTitle + '" class="loginimage">\n'
|
||||||
loginForm += loginText + TOSstr + '\n'
|
loginForm += loginText + TOSstr + '\n'
|
||||||
loginForm += ' </div>\n'
|
loginForm += ' </div>\n'
|
||||||
loginForm += '\n'
|
loginForm += '\n'
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@ def htmlModeration(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, moderationActionStr: str,
|
authorized: bool, moderationActionStr: str,
|
||||||
theme: str, peertubeInstances: []) -> str:
|
theme: str, peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the moderation feed as html
|
"""Show the moderation feed as html
|
||||||
This is what you see when selecting the "mod" timeline
|
This is what you see when selecting the "mod" timeline
|
||||||
"""
|
"""
|
||||||
|
|
@ -57,7 +58,7 @@ def htmlModeration(cssCache: {}, defaultTimeline: str,
|
||||||
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, moderationActionStr, theme,
|
authorized, moderationActionStr, theme,
|
||||||
peertubeInstances)
|
peertubeInstances, allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlAccountInfo(cssCache: {}, translate: {},
|
def htmlAccountInfo(cssCache: {}, translate: {},
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ def htmlPersonOptions(defaultTimeline: str,
|
||||||
optionsStr += ' <center>\n'
|
optionsStr += ' <center>\n'
|
||||||
optionsStr += ' <a href="' + optionsActor + '">\n'
|
optionsStr += ' <a href="' + optionsActor + '">\n'
|
||||||
optionsStr += ' <img loading="lazy" src="' + optionsProfileUrl + \
|
optionsStr += ' <img loading="lazy" src="' + optionsProfileUrl + \
|
||||||
'" ' + getBrokenLinkSubstitute() + '/></a>\n'
|
'" alt="" ' + getBrokenLinkSubstitute() + '/></a>\n'
|
||||||
handle = getNicknameFromActor(optionsActor) + '@' + optionsDomain
|
handle = getNicknameFromActor(optionsActor) + '@' + optionsDomain
|
||||||
handleShown = handle
|
handleShown = handle
|
||||||
if lockedAccount:
|
if lockedAccount:
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,46 @@ def _logPostTiming(enableTimingLog: bool, postStartTime, debugId: str) -> None:
|
||||||
print('TIMING INDIV ' + debugId + ' = ' + str(timeDiff))
|
print('TIMING INDIV ' + debugId + ' = ' + str(timeDiff))
|
||||||
|
|
||||||
|
|
||||||
def preparePostFromHtmlCache(postHtml: str, boxName: str,
|
def prepareHtmlPostNickname(nickname: str, postHtml: str) -> str:
|
||||||
|
"""html posts stored in memory are for all accounts on the instance
|
||||||
|
and they're indexed by id. However, some incoming posts may be
|
||||||
|
destined for multiple accounts (followers). This creates a problem
|
||||||
|
where the icon links whose urls begin with href="/users/nickname?
|
||||||
|
need to be changed for different nicknames to display correctly
|
||||||
|
within their timelines.
|
||||||
|
This function changes the nicknames for the icon links.
|
||||||
|
"""
|
||||||
|
# replace the nickname
|
||||||
|
usersStr = ' href="/users/'
|
||||||
|
if usersStr not in postHtml:
|
||||||
|
return postHtml
|
||||||
|
|
||||||
|
userFound = True
|
||||||
|
postStr = postHtml
|
||||||
|
newPostStr = ''
|
||||||
|
while userFound:
|
||||||
|
if usersStr not in postStr:
|
||||||
|
newPostStr += postStr
|
||||||
|
break
|
||||||
|
|
||||||
|
# the next part, after href="/users/nickname?
|
||||||
|
nextStr = postStr.split(usersStr, 1)[1]
|
||||||
|
if '?' in nextStr:
|
||||||
|
nextStr = nextStr.split('?', 1)[1]
|
||||||
|
else:
|
||||||
|
newPostStr += postStr
|
||||||
|
break
|
||||||
|
|
||||||
|
# append the previous text to the result
|
||||||
|
newPostStr += postStr.split(usersStr)[0]
|
||||||
|
newPostStr += usersStr + nickname + '?'
|
||||||
|
|
||||||
|
# post is now the next part
|
||||||
|
postStr = nextStr
|
||||||
|
return newPostStr
|
||||||
|
|
||||||
|
|
||||||
|
def preparePostFromHtmlCache(nickname: str, postHtml: str, boxName: str,
|
||||||
pageNumber: int) -> str:
|
pageNumber: int) -> str:
|
||||||
"""Sets the page number on a cached html post
|
"""Sets the page number on a cached html post
|
||||||
"""
|
"""
|
||||||
|
|
@ -91,7 +130,7 @@ def preparePostFromHtmlCache(postHtml: str, boxName: str,
|
||||||
withPageNumber = postHtml.replace(';-999;', ';' + str(pageNumber) + ';')
|
withPageNumber = postHtml.replace(';-999;', ';' + str(pageNumber) + ';')
|
||||||
withPageNumber = withPageNumber.replace('?page=-999',
|
withPageNumber = withPageNumber.replace('?page=-999',
|
||||||
'?page=' + str(pageNumber))
|
'?page=' + str(pageNumber))
|
||||||
return withPageNumber
|
return prepareHtmlPostNickname(nickname, withPageNumber)
|
||||||
|
|
||||||
|
|
||||||
def _saveIndividualPostAsHtmlToCache(baseDir: str,
|
def _saveIndividualPostAsHtmlToCache(baseDir: str,
|
||||||
|
|
@ -173,7 +212,8 @@ def _getPostFromRecentCache(session,
|
||||||
if not postHtml:
|
if not postHtml:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
postHtml = preparePostFromHtmlCache(postHtml, boxName, pageNumber)
|
postHtml = \
|
||||||
|
preparePostFromHtmlCache(nickname, postHtml, boxName, pageNumber)
|
||||||
updateRecentPostsCache(recentPostsCache, maxRecentPosts,
|
updateRecentPostsCache(recentPostsCache, maxRecentPosts,
|
||||||
postJsonObject, postHtml)
|
postJsonObject, postHtml)
|
||||||
_logPostTiming(enableTimingLog, postStartTime, '3')
|
_logPostTiming(enableTimingLog, postStartTime, '3')
|
||||||
|
|
@ -1081,6 +1121,7 @@ def individualPostAsHtml(allowDownloads: bool,
|
||||||
boxName: str, YTReplacementDomain: str,
|
boxName: str, YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
peertubeInstances: [],
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool,
|
||||||
showRepeats=True,
|
showRepeats=True,
|
||||||
showIcons=False,
|
showIcons=False,
|
||||||
manuallyApprovesFollowers=False,
|
manuallyApprovesFollowers=False,
|
||||||
|
|
@ -1231,7 +1272,8 @@ def individualPostAsHtml(allowDownloads: bool,
|
||||||
downloadAnnounce(session, baseDir, httpPrefix,
|
downloadAnnounce(session, baseDir, httpPrefix,
|
||||||
nickname, domain, postJsonObject,
|
nickname, domain, postJsonObject,
|
||||||
projectVersion, translate,
|
projectVersion, translate,
|
||||||
YTReplacementDomain)
|
YTReplacementDomain,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
if not postJsonAnnounce:
|
if not postJsonAnnounce:
|
||||||
return ''
|
return ''
|
||||||
postJsonObject = postJsonAnnounce
|
postJsonObject = postJsonAnnounce
|
||||||
|
|
@ -1605,7 +1647,8 @@ def htmlIndividualPost(cssCache: {},
|
||||||
projectVersion: str, likedBy: str,
|
projectVersion: str, likedBy: str,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show an individual post as html
|
"""Show an individual post as html
|
||||||
"""
|
"""
|
||||||
postStr = ''
|
postStr = ''
|
||||||
|
|
@ -1646,6 +1689,7 @@ def htmlIndividualPost(cssCache: {},
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
False, authorized, False, False, False)
|
False, authorized, False, False, False)
|
||||||
messageId = removeIdEnding(postJsonObject['id'])
|
messageId = removeIdEnding(postJsonObject['id'])
|
||||||
|
|
||||||
|
|
@ -1672,6 +1716,7 @@ def htmlIndividualPost(cssCache: {},
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
False, authorized,
|
False, authorized,
|
||||||
False, False, False) + postStr
|
False, False, False) + postStr
|
||||||
|
|
||||||
|
|
@ -1701,6 +1746,7 @@ def htmlIndividualPost(cssCache: {},
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
False, authorized,
|
False, authorized,
|
||||||
False, False, False)
|
False, False, False)
|
||||||
cssFilename = baseDir + '/epicyon-profile.css'
|
cssFilename = baseDir + '/epicyon-profile.css'
|
||||||
|
|
@ -1721,7 +1767,8 @@ def htmlPostReplies(cssCache: {},
|
||||||
httpPrefix: str, projectVersion: str,
|
httpPrefix: str, projectVersion: str,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the replies to an individual post as html
|
"""Show the replies to an individual post as html
|
||||||
"""
|
"""
|
||||||
repliesStr = ''
|
repliesStr = ''
|
||||||
|
|
@ -1739,6 +1786,7 @@ def htmlPostReplies(cssCache: {},
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
False, False, False, False, False)
|
False, False, False, False, False)
|
||||||
|
|
||||||
cssFilename = baseDir + '/epicyon-profile.css'
|
cssFilename = baseDir + '/epicyon-profile.css'
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ def htmlProfileAfterSearch(cssCache: {},
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
defaultTimeline: str,
|
defaultTimeline: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show a profile page after a search for a fediverse address
|
"""Show a profile page after a search for a fediverse address
|
||||||
"""
|
"""
|
||||||
if hasUsersPath(profileHandle) or '/@' in profileHandle:
|
if hasUsersPath(profileHandle) or '/@' in profileHandle:
|
||||||
|
|
@ -292,7 +293,7 @@ def htmlProfileAfterSearch(cssCache: {},
|
||||||
httpPrefix, projectVersion, 'inbox',
|
httpPrefix, projectVersion, 'inbox',
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances, allowLocalNetworkAccess,
|
||||||
False, False, False, False, False)
|
False, False, False, False, False)
|
||||||
i += 1
|
i += 1
|
||||||
if i >= 20:
|
if i >= 20:
|
||||||
|
|
@ -323,6 +324,7 @@ def _getProfileHeader(baseDir: str, httpPrefix: str,
|
||||||
nickname + '/' + defaultTimeline + '" title="' + \
|
nickname + '/' + defaultTimeline + '" title="' + \
|
||||||
translate['Switch to timeline view'] + '">\n'
|
translate['Switch to timeline view'] + '">\n'
|
||||||
htmlStr += ' <img class="profileBackground" ' + \
|
htmlStr += ' <img class="profileBackground" ' + \
|
||||||
|
'alt="" ' + \
|
||||||
'src="/users/' + nickname + '/image_' + theme + '.png" /></a>\n'
|
'src="/users/' + nickname + '/image_' + theme + '.png" /></a>\n'
|
||||||
htmlStr += ' <figcaption>\n'
|
htmlStr += ' <figcaption>\n'
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
|
|
@ -330,7 +332,7 @@ def _getProfileHeader(baseDir: str, httpPrefix: str,
|
||||||
nickname + '/' + defaultTimeline + '" title="' + \
|
nickname + '/' + defaultTimeline + '" title="' + \
|
||||||
translate['Switch to timeline view'] + '">\n' + \
|
translate['Switch to timeline view'] + '">\n' + \
|
||||||
' <img loading="lazy" src="' + avatarUrl + '" ' + \
|
' <img loading="lazy" src="' + avatarUrl + '" ' + \
|
||||||
' class="title"></a>\n'
|
'alt="" class="title"></a>\n'
|
||||||
htmlStr += ' <h1>' + displayName + '</h1>\n'
|
htmlStr += ' <h1>' + displayName + '</h1>\n'
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
' <p><b>@' + nickname + '@' + domainFull + '</b><br>\n'
|
' <p><b>@' + nickname + '@' + domainFull + '</b><br>\n'
|
||||||
|
|
@ -372,8 +374,8 @@ def _getProfileHeader(baseDir: str, httpPrefix: str,
|
||||||
' <a href="/users/' + nickname + \
|
' <a href="/users/' + nickname + \
|
||||||
'/qrcode.png" alt="' + translate['QR Code'] + '" title="' + \
|
'/qrcode.png" alt="' + translate['QR Code'] + '" title="' + \
|
||||||
translate['QR Code'] + '">' + \
|
translate['QR Code'] + '">' + \
|
||||||
'<img class="qrcode" src="/icons' + \
|
'<img class="qrcode" alt="' + translate['QR Code'] + \
|
||||||
'/qrcode.png" /></a></p>\n'
|
'" src="/icons/qrcode.png" /></a></p>\n'
|
||||||
htmlStr += ' <p>' + profileDescriptionShort + '</p>\n'
|
htmlStr += ' <p>' + profileDescriptionShort + '</p>\n'
|
||||||
htmlStr += loginButton
|
htmlStr += loginButton
|
||||||
if pinnedContent:
|
if pinnedContent:
|
||||||
|
|
@ -402,6 +404,7 @@ def _getProfileHeaderAfterSearch(baseDir: str,
|
||||||
nickname + '/' + defaultTimeline + '" title="' + \
|
nickname + '/' + defaultTimeline + '" title="' + \
|
||||||
translate['Switch to timeline view'] + '">\n'
|
translate['Switch to timeline view'] + '">\n'
|
||||||
htmlStr += ' <img class="profileBackground" ' + \
|
htmlStr += ' <img class="profileBackground" ' + \
|
||||||
|
'alt="" ' + \
|
||||||
'src="' + imageUrl + '" /></a>\n'
|
'src="' + imageUrl + '" /></a>\n'
|
||||||
htmlStr += ' <figcaption>\n'
|
htmlStr += ' <figcaption>\n'
|
||||||
if avatarUrl:
|
if avatarUrl:
|
||||||
|
|
@ -410,7 +413,7 @@ def _getProfileHeaderAfterSearch(baseDir: str,
|
||||||
translate['Switch to timeline view'] + '">\n'
|
translate['Switch to timeline view'] + '">\n'
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
' <img loading="lazy" src="' + avatarUrl + '" ' + \
|
' <img loading="lazy" src="' + avatarUrl + '" ' + \
|
||||||
' class="title"></a>\n'
|
'alt="" class="title"></a>\n'
|
||||||
htmlStr += ' <h1>' + displayName + '</h1>\n'
|
htmlStr += ' <h1>' + displayName + '</h1>\n'
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
' <p><b>@' + searchNickname + '@' + searchDomainFull + '</b><br>\n'
|
' <p><b>@' + searchNickname + '@' + searchDomainFull + '</b><br>\n'
|
||||||
|
|
@ -468,6 +471,7 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
newswire: {}, theme: str, dormantMonths: int,
|
newswire: {}, theme: str, dormantMonths: int,
|
||||||
peertubeInstances: [],
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool,
|
||||||
extraJson=None, pageNumber=None,
|
extraJson=None, pageNumber=None,
|
||||||
maxItemsPerPage=None) -> str:
|
maxItemsPerPage=None) -> str:
|
||||||
"""Show the profile page as html
|
"""Show the profile page as html
|
||||||
|
|
@ -487,6 +491,7 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, theme, extraJson,
|
newswire, theme, extraJson,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
pageNumber, maxItemsPerPage)
|
pageNumber, maxItemsPerPage)
|
||||||
|
|
||||||
domain, port = getDomainFromActor(profileJson['id'])
|
domain, port = getDomainFromActor(profileJson['id'])
|
||||||
|
|
@ -702,7 +707,18 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
movedTo, alsoKnownAs,
|
movedTo, alsoKnownAs,
|
||||||
pinnedContent)
|
pinnedContent)
|
||||||
|
|
||||||
profileStr = profileHeaderStr + donateSection
|
# Links for keyboard navigation
|
||||||
|
profileStr = \
|
||||||
|
'<div class="transparent">' + \
|
||||||
|
'<label class="transparent">' + \
|
||||||
|
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
||||||
|
translate['Switch to timeline view'] + '</a></label> | ' + \
|
||||||
|
'<label class="transparent">' + \
|
||||||
|
'<a class="skip-main" href="#buttonheader">' + \
|
||||||
|
translate['Skip to timeline'] + '</a></label>' + \
|
||||||
|
'</div>\n'
|
||||||
|
|
||||||
|
profileStr += profileHeaderStr + donateSection
|
||||||
profileStr += '<div class="container" id="buttonheader">\n'
|
profileStr += '<div class="container" id="buttonheader">\n'
|
||||||
profileStr += ' <center>'
|
profileStr += ' <center>'
|
||||||
profileStr += \
|
profileStr += \
|
||||||
|
|
@ -756,7 +772,8 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
projectVersion,
|
projectVersion,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances) + licenseStr
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess) + licenseStr
|
||||||
elif selected == 'following':
|
elif selected == 'following':
|
||||||
profileStr += \
|
profileStr += \
|
||||||
_htmlProfileFollowing(translate, baseDir, httpPrefix,
|
_htmlProfileFollowing(translate, baseDir, httpPrefix,
|
||||||
|
|
@ -805,7 +822,8 @@ def _htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
projectVersion: str,
|
projectVersion: str,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Shows posts on the profile screen
|
"""Shows posts on the profile screen
|
||||||
These should only be public posts
|
These should only be public posts
|
||||||
"""
|
"""
|
||||||
|
|
@ -844,6 +862,7 @@ def _htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
False, False, False, True, False)
|
False, False, False, True, False)
|
||||||
if postStr:
|
if postStr:
|
||||||
profileStr += postStr + separatorStr
|
profileStr += postStr + separatorStr
|
||||||
|
|
|
||||||
|
|
@ -348,7 +348,7 @@ def htmlSearch(cssCache: {}, translate: {},
|
||||||
translate['Switch to timeline view'] + '" alt="' + \
|
translate['Switch to timeline view'] + '" alt="' + \
|
||||||
translate['Switch to timeline view'] + '">\n'
|
translate['Switch to timeline view'] + '">\n'
|
||||||
followStr += '<img loading="lazy" class="timeline-banner" src="' + \
|
followStr += '<img loading="lazy" class="timeline-banner" src="' + \
|
||||||
usersPath + '/' + searchBannerFile + '" /></a>\n' + \
|
usersPath + '/' + searchBannerFile + '" alt="" /></a>\n' + \
|
||||||
'</header>\n'
|
'</header>\n'
|
||||||
|
|
||||||
# show the search box
|
# show the search box
|
||||||
|
|
@ -496,7 +496,7 @@ def htmlSkillsSearch(actor: str,
|
||||||
actor + '/skills">'
|
actor + '/skills">'
|
||||||
skillSearchForm += \
|
skillSearchForm += \
|
||||||
'<img loading="lazy" src="' + avatarUrl + \
|
'<img loading="lazy" src="' + avatarUrl + \
|
||||||
'"/><span class="search-result-text">' + actorName + \
|
'" alt="" /><span class="search-result-text">' + actorName + \
|
||||||
'</span></a></div>'
|
'</span></a></div>'
|
||||||
ctr += 1
|
ctr += 1
|
||||||
if ctr >= postsPerPage:
|
if ctr >= postsPerPage:
|
||||||
|
|
@ -520,7 +520,8 @@ def htmlHistorySearch(cssCache: {}, translate: {}, baseDir: str,
|
||||||
port: int,
|
port: int,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show a page containing search results for your post history
|
"""Show a page containing search results for your post history
|
||||||
"""
|
"""
|
||||||
if historysearch.startswith('!'):
|
if historysearch.startswith('!'):
|
||||||
|
|
@ -596,6 +597,7 @@ def htmlHistorySearch(cssCache: {}, translate: {}, baseDir: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
showIndividualPostIcons,
|
showIndividualPostIcons,
|
||||||
showIndividualPostIcons,
|
showIndividualPostIcons,
|
||||||
False, False, False)
|
False, False, False)
|
||||||
|
|
@ -617,7 +619,8 @@ def htmlHashtagSearch(cssCache: {},
|
||||||
httpPrefix: str, projectVersion: str,
|
httpPrefix: str, projectVersion: str,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show a page containing search results for a hashtag
|
"""Show a page containing search results for a hashtag
|
||||||
"""
|
"""
|
||||||
if hashtag.startswith('#'):
|
if hashtag.startswith('#'):
|
||||||
|
|
@ -766,6 +769,7 @@ def htmlHashtagSearch(cssCache: {},
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
showRepeats, showIcons,
|
showRepeats, showIcons,
|
||||||
manuallyApprovesFollowers,
|
manuallyApprovesFollowers,
|
||||||
showPublicOnly,
|
showPublicOnly,
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
moderationActionStr: str,
|
moderationActionStr: str,
|
||||||
theme: str,
|
theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the timeline as html
|
"""Show the timeline as html
|
||||||
"""
|
"""
|
||||||
enableTimingLog = False
|
enableTimingLog = False
|
||||||
|
|
@ -362,12 +363,25 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
'<button class="button"><span>' + \
|
'<button class="button"><span>' + \
|
||||||
translate['Post'] + '</span></button></a>'
|
translate['Post'] + '</span></button></a>'
|
||||||
|
|
||||||
# This creates a link to the profile page when viewed
|
# This creates a link to skip to the timeline and change to
|
||||||
# in lynx, but should be invisible in a graphical web browser
|
# profile view when accessed within lynx, but should be
|
||||||
|
# invisible in a graphical web browser
|
||||||
tlStr += \
|
tlStr += \
|
||||||
'<div class="transparent"><label class="transparent">' + \
|
'<div class="transparent">' + \
|
||||||
|
'<label class="transparent">' + \
|
||||||
'<a href="/users/' + nickname + '">' + \
|
'<a href="/users/' + nickname + '">' + \
|
||||||
translate['Switch to profile view'] + '</a></label></div>\n'
|
translate['Switch to profile view'] + '</a></label> | ' + \
|
||||||
|
'<label class="transparent">' + \
|
||||||
|
'<a class="skip-main" href="' + usersPath + '/' + boxName + \
|
||||||
|
'#timeline">' + \
|
||||||
|
translate['Skip to timeline'] + '</a></label> | ' + \
|
||||||
|
'<label class="transparent">' + \
|
||||||
|
'<a class="skip-newswire" href="#newswire">' + \
|
||||||
|
translate['Skip to Newswire'] + '</a></label> | ' + \
|
||||||
|
'<label class="transparent">' + \
|
||||||
|
'<a class="skip-links" href="#links">' + \
|
||||||
|
translate['Skip to Links'] + '</a></label>' + \
|
||||||
|
'</div>\n'
|
||||||
|
|
||||||
# banner and row of buttons
|
# banner and row of buttons
|
||||||
tlStr += \
|
tlStr += \
|
||||||
|
|
@ -375,8 +389,9 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
'<a href="/users/' + nickname + '" title="' + \
|
'<a href="/users/' + nickname + '" title="' + \
|
||||||
translate['Switch to profile view'] + '" alt="' + \
|
translate['Switch to profile view'] + '" alt="' + \
|
||||||
translate['Switch to profile view'] + '">\n'
|
translate['Switch to profile view'] + '">\n'
|
||||||
tlStr += '<img loading="lazy" class="timeline-banner" src="' + \
|
tlStr += '<img loading="lazy" class="timeline-banner" ' + \
|
||||||
usersPath + '/' + bannerFile + '" /></a>\n' + \
|
'alt="" ' + \
|
||||||
|
'src="' + usersPath + '/' + bannerFile + '" /></a>\n' + \
|
||||||
'</header>\n'
|
'</header>\n'
|
||||||
|
|
||||||
if fullWidthTimelineButtonHeader:
|
if fullWidthTimelineButtonHeader:
|
||||||
|
|
@ -413,10 +428,12 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
editor, False, None, rssIconAtTop,
|
editor, False, None, rssIconAtTop,
|
||||||
True, False, theme)
|
True, False, theme)
|
||||||
tlStr += ' <td valign="top" class="col-left">' + \
|
tlStr += ' <td valign="top" class="col-left" ' + \
|
||||||
|
'id="links" tabindex="-1">' + \
|
||||||
leftColumnStr + ' </td>\n'
|
leftColumnStr + ' </td>\n'
|
||||||
# center column containing posts
|
# center column containing posts
|
||||||
tlStr += ' <td valign="top" class="col-center">\n'
|
tlStr += ' <td valign="top" class="col-center">\n'
|
||||||
|
tlStr += ' <main id="timeline" tabindex="-1">\n'
|
||||||
|
|
||||||
if not fullWidthTimelineButtonHeader:
|
if not fullWidthTimelineButtonHeader:
|
||||||
tlStr += \
|
tlStr += \
|
||||||
|
|
@ -546,7 +563,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
if recentPostsCache['html'].get(postId):
|
if recentPostsCache['html'].get(postId):
|
||||||
currTlStr = recentPostsCache['html'][postId]
|
currTlStr = recentPostsCache['html'][postId]
|
||||||
currTlStr = \
|
currTlStr = \
|
||||||
preparePostFromHtmlCache(currTlStr,
|
preparePostFromHtmlCache(nickname,
|
||||||
|
currTlStr,
|
||||||
boxName,
|
boxName,
|
||||||
pageNumber)
|
pageNumber)
|
||||||
_logTimelineTiming(enableTimingLog,
|
_logTimelineTiming(enableTimingLog,
|
||||||
|
|
@ -574,6 +592,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
peertubeInstances,
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
boxName != 'dm',
|
boxName != 'dm',
|
||||||
showIndividualPostIcons,
|
showIndividualPostIcons,
|
||||||
manuallyApproveFollowers,
|
manuallyApproveFollowers,
|
||||||
|
|
@ -616,7 +635,9 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
showPublishAsIcon,
|
showPublishAsIcon,
|
||||||
rssIconAtTop, publishButtonAtTop,
|
rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, True, theme)
|
authorized, True, theme)
|
||||||
tlStr += ' <td valign="top" class="col-right">' + \
|
tlStr += ' </main>\n'
|
||||||
|
tlStr += ' <td valign="top" class="col-right" ' + \
|
||||||
|
'id="newswire" tabindex="-1">' + \
|
||||||
rightColumnStr + ' </td>\n'
|
rightColumnStr + ' </td>\n'
|
||||||
tlStr += ' </tr>\n'
|
tlStr += ' </tr>\n'
|
||||||
|
|
||||||
|
|
@ -730,7 +751,8 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the shares timeline as html
|
"""Show the shares timeline as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -750,7 +772,8 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlInbox(cssCache: {}, defaultTimeline: str,
|
def htmlInbox(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -770,7 +793,8 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the inbox as html
|
"""Show the inbox as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -790,7 +814,8 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -810,7 +835,8 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the bookmarks as html
|
"""Show the bookmarks as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -830,7 +856,8 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlEvents(cssCache: {}, defaultTimeline: str,
|
def htmlEvents(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -850,7 +877,8 @@ def htmlEvents(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the events as html
|
"""Show the events as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -870,7 +898,8 @@ def htmlEvents(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -890,7 +919,8 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the DM timeline as html
|
"""Show the DM timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -905,7 +935,8 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
||||||
showPublishAsIcon,
|
showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -925,7 +956,8 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the replies timeline as html
|
"""Show the replies timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -941,7 +973,8 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -961,7 +994,8 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the media timeline as html
|
"""Show the media timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -977,7 +1011,8 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -997,7 +1032,8 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the blogs timeline as html
|
"""Show the blogs timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -1013,7 +1049,8 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -1034,7 +1071,8 @@ def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
theme: str,
|
theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the features timeline as html
|
"""Show the features timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -1050,7 +1088,8 @@ def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -1070,7 +1109,8 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the news timeline as html
|
"""Show the news timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -1086,7 +1126,8 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -1106,7 +1147,8 @@ def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool, theme: str,
|
authorized: bool, theme: str,
|
||||||
peertubeInstances: []) -> str:
|
peertubeInstances: [],
|
||||||
|
allowLocalNetworkAccess: bool) -> str:
|
||||||
"""Show the Outbox as html
|
"""Show the Outbox as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -1123,4 +1165,5 @@ def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
||||||
newswire, False, False, positiveVoting,
|
newswire, False, False, positiveVoting,
|
||||||
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances)
|
authorized, None, theme, peertubeInstances,
|
||||||
|
allowLocalNetworkAccess)
|
||||||
|
|
|
||||||
|
|
@ -591,24 +591,24 @@ def addEmojiToDisplayName(baseDir: str, httpPrefix: str,
|
||||||
|
|
||||||
displayName = displayName.replace('<p>', '').replace('</p>', '')
|
displayName = displayName.replace('<p>', '').replace('</p>', '')
|
||||||
emojiTags = {}
|
emojiTags = {}
|
||||||
print('TAG: displayName before tags: ' + displayName)
|
# print('TAG: displayName before tags: ' + displayName)
|
||||||
displayName = \
|
displayName = \
|
||||||
addHtmlTags(baseDir, httpPrefix,
|
addHtmlTags(baseDir, httpPrefix,
|
||||||
nickname, domain, displayName, [], emojiTags)
|
nickname, domain, displayName, [], emojiTags)
|
||||||
displayName = displayName.replace('<p>', '').replace('</p>', '')
|
displayName = displayName.replace('<p>', '').replace('</p>', '')
|
||||||
print('TAG: displayName after tags: ' + displayName)
|
# print('TAG: displayName after tags: ' + displayName)
|
||||||
# convert the emoji dictionary to a list
|
# convert the emoji dictionary to a list
|
||||||
emojiTagsList = []
|
emojiTagsList = []
|
||||||
for tagName, tag in emojiTags.items():
|
for tagName, tag in emojiTags.items():
|
||||||
emojiTagsList.append(tag)
|
emojiTagsList.append(tag)
|
||||||
print('TAG: emoji tags list: ' + str(emojiTagsList))
|
# print('TAG: emoji tags list: ' + str(emojiTagsList))
|
||||||
if not inProfileName:
|
if not inProfileName:
|
||||||
displayName = \
|
displayName = \
|
||||||
replaceEmojiFromTags(displayName, emojiTagsList, 'post header')
|
replaceEmojiFromTags(displayName, emojiTagsList, 'post header')
|
||||||
else:
|
else:
|
||||||
displayName = \
|
displayName = \
|
||||||
replaceEmojiFromTags(displayName, emojiTagsList, 'profile')
|
replaceEmojiFromTags(displayName, emojiTagsList, 'profile')
|
||||||
print('TAG: displayName after tags 2: ' + displayName)
|
# print('TAG: displayName after tags 2: ' + displayName)
|
||||||
|
|
||||||
# remove any stray emoji
|
# remove any stray emoji
|
||||||
while ':' in displayName:
|
while ':' in displayName:
|
||||||
|
|
@ -619,8 +619,8 @@ def addEmojiToDisplayName(baseDir: str, httpPrefix: str,
|
||||||
displayName = displayName.replace(':' + emojiStr + ':', '').strip()
|
displayName = displayName.replace(':' + emojiStr + ':', '').strip()
|
||||||
if prevDisplayName == displayName:
|
if prevDisplayName == displayName:
|
||||||
break
|
break
|
||||||
print('TAG: displayName after tags 3: ' + displayName)
|
# print('TAG: displayName after tags 3: ' + displayName)
|
||||||
print('TAG: displayName after tag replacements: ' + displayName)
|
# print('TAG: displayName after tag replacements: ' + displayName)
|
||||||
|
|
||||||
return displayName
|
return displayName
|
||||||
|
|
||||||
|
|
@ -838,8 +838,8 @@ def htmlPostSeparator(baseDir: str, column: str) -> str:
|
||||||
if os.path.isfile(separatorImageFilename):
|
if os.path.isfile(separatorImageFilename):
|
||||||
separatorStr = \
|
separatorStr = \
|
||||||
'<div class="' + separatorClass + '"><center>' + \
|
'<div class="' + separatorClass + '"><center>' + \
|
||||||
'<img src="/icons/' + filename + '"/>' + \
|
'<img src="/icons/' + filename + '" ' + \
|
||||||
'</center></div>\n'
|
'alt="" /></center></div>\n'
|
||||||
return separatorStr
|
return separatorStr
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,7 @@ def webfingerLookup(path: str, baseDir: str,
|
||||||
handle = None
|
handle = None
|
||||||
if 'resource=acct:' in path:
|
if 'resource=acct:' in path:
|
||||||
handle = path.split('resource=acct:')[1].strip()
|
handle = path.split('resource=acct:')[1].strip()
|
||||||
|
handle = urllib.parse.unquote(handle)
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: WEBFINGER handle ' + handle)
|
print('DEBUG: WEBFINGER handle ' + handle)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||