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