Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon into main

main
Bob Mottram 2020-12-24 17:41:51 +00:00
commit b754b13fd8
42 changed files with 1043 additions and 483 deletions

View File

@ -7,6 +7,7 @@ __email__ = "bob@freedombone.net"
__status__ = "Production" __status__ = "Production"
import os import os
from utils import hasUsersPath
from utils import getFullDomain from utils import getFullDomain
from utils import urlPermitted from utils import urlPermitted
from utils import getDomainFromActor from utils import getDomainFromActor
@ -182,10 +183,7 @@ def receiveAcceptReject(session, baseDir: str,
if debug: if debug:
print('DEBUG: ' + messageJson['type'] + ' has no actor') print('DEBUG: ' + messageJson['type'] + ' has no actor')
return False return False
if '/users/' not in messageJson['actor'] and \ if not hasUsersPath(messageJson['actor']):
'/accounts/' not in messageJson['actor'] and \
'/channel/' not in messageJson['actor'] and \
'/profile/' not in messageJson['actor']:
if debug: if debug:
print('DEBUG: "users" or "profile" missing from actor in ' + print('DEBUG: "users" or "profile" missing from actor in ' +
messageJson['type'] + '. Assuming single user instance.') messageJson['type'] + '. Assuming single user instance.')

View File

@ -6,6 +6,7 @@ __maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net" __email__ = "bob@freedombone.net"
__status__ = "Production" __status__ = "Production"
from utils import hasUsersPath
from utils import getFullDomain from utils import getFullDomain
from utils import getStatusNumber from utils import getStatusNumber
from utils import createOutboxDir from utils import createOutboxDir
@ -143,10 +144,7 @@ def createAnnounce(session, baseDir: str, federationList: [],
announceNickname = None announceNickname = None
announceDomain = None announceDomain = None
announcePort = None announcePort = None
if '/users/' in objectUrl or \ if hasUsersPath(objectUrl):
'/accounts/' in objectUrl or \
'/channel/' in objectUrl or \
'/profile/' in objectUrl:
announceNickname = getNicknameFromActor(objectUrl) announceNickname = getNicknameFromActor(objectUrl)
announceDomain, announcePort = getDomainFromActor(objectUrl) announceDomain, announcePort = getDomainFromActor(objectUrl)

View File

@ -12,6 +12,7 @@ import binascii
import os import os
import secrets import secrets
from utils import isSystemAccount from utils import isSystemAccount
from utils import hasUsersPath
def _hashPassword(password: str) -> str: def _hashPassword(password: str) -> str:
@ -89,10 +90,7 @@ def authorizeBasic(baseDir: str, path: str, authHeader: str,
print('DEBUG: basic auth - Authorixation header does not ' + print('DEBUG: basic auth - Authorixation header does not ' +
'contain a space character') 'contain a space character')
return False return False
if '/users/' not in path and \ if not hasUsersPath(path):
'/accounts/' not in path and \
'/channel/' not in path and \
'/profile/' not in path:
if debug: if debug:
print('DEBUG: basic auth - ' + print('DEBUG: basic auth - ' +
'path for Authorization does not contain a user') 'path for Authorization does not contain a user')

View File

@ -7,6 +7,7 @@ __email__ = "bob@freedombone.net"
__status__ = "Production" __status__ = "Production"
import os import os
from utils import hasUsersPath
from utils import getFullDomain from utils import getFullDomain
from utils import removeIdEnding from utils import removeIdEnding
from utils import isEvil from utils import isEvil
@ -246,10 +247,7 @@ def outboxBlock(baseDir: str, httpPrefix: str,
if debug: if debug:
print('DEBUG: c2s block object is not a status') print('DEBUG: c2s block object is not a status')
return return
if '/users/' not in messageId and \ if not hasUsersPath(messageId):
'/accounts/' not in messageId and \
'/channel/' not in messageId and \
'/profile/' not in messageId:
if debug: if debug:
print('DEBUG: c2s block object has no nickname') print('DEBUG: c2s block object has no nickname')
return return
@ -321,10 +319,7 @@ def outboxUndoBlock(baseDir: str, httpPrefix: str,
if debug: if debug:
print('DEBUG: c2s undo block object is not a status') print('DEBUG: c2s undo block object is not a status')
return return
if '/users/' not in messageId and \ if not hasUsersPath(messageId):
'/accounts/' not in messageId and \
'/channel/' not in messageId and \
'/profile/' not in messageId:
if debug: if debug:
print('DEBUG: c2s undo block object has no nickname') print('DEBUG: c2s undo block object has no nickname')
return return

21
blog.py
View File

@ -158,6 +158,7 @@ def _htmlBlogPostContent(authorized: bool,
nickname: str, domain: str, domainFull: str, nickname: str, domain: str, domainFull: str,
postJsonObject: {}, postJsonObject: {},
handle: str, restrictToDomain: bool, handle: str, restrictToDomain: bool,
peertubeInstances: [],
blogSeparator='<hr>') -> str: blogSeparator='<hr>') -> str:
"""Returns the content for a single blog post """Returns the content for a single blog post
""" """
@ -231,7 +232,8 @@ def _htmlBlogPostContent(authorized: bool,
if postJsonObject['object'].get('content'): if postJsonObject['object'].get('content'):
contentStr = addEmbeddedElements(translate, contentStr = addEmbeddedElements(translate,
postJsonObject['object']['content']) postJsonObject['object']['content'],
peertubeInstances)
if postJsonObject['object'].get('tag'): if postJsonObject['object'].get('tag'):
contentStr = replaceEmojiFromTags(contentStr, contentStr = replaceEmojiFromTags(contentStr,
postJsonObject['object']['tag'], postJsonObject['object']['tag'],
@ -375,7 +377,8 @@ def _htmlBlogRemoveCwButton(blogStr: str, translate: {}) -> str:
def htmlBlogPost(authorized: bool, def htmlBlogPost(authorized: bool,
baseDir: str, httpPrefix: str, translate: {}, baseDir: str, httpPrefix: str, translate: {},
nickname: str, domain: str, domainFull: str, nickname: str, domain: str, domainFull: str,
postJsonObject: {}) -> str: postJsonObject: {},
peertubeInstances: []) -> str:
"""Returns a html blog post """Returns a html blog post
""" """
blogStr = '' blogStr = ''
@ -390,7 +393,8 @@ def htmlBlogPost(authorized: bool,
httpPrefix, translate, httpPrefix, translate,
nickname, domain, nickname, domain,
domainFull, postJsonObject, domainFull, postJsonObject,
None, False) None, False,
peertubeInstances)
# show rss links # show rss links
blogStr += '<p class="rssfeed">' blogStr += '<p class="rssfeed">'
@ -417,7 +421,8 @@ def htmlBlogPost(authorized: bool,
def htmlBlogPage(authorized: bool, session, def htmlBlogPage(authorized: bool, session,
baseDir: str, httpPrefix: str, translate: {}, baseDir: str, httpPrefix: str, translate: {},
nickname: str, domain: str, port: int, nickname: str, domain: str, port: int,
noOfItems: int, pageNumber: int) -> str: noOfItems: int, pageNumber: int,
peertubeInstances: []) -> str:
"""Returns a html blog page containing posts """Returns a html blog page containing posts
""" """
if ' ' in nickname or '@' in nickname or \ if ' ' in nickname or '@' in nickname or \
@ -477,7 +482,8 @@ def htmlBlogPage(authorized: bool, session,
httpPrefix, translate, httpPrefix, translate,
nickname, domain, nickname, domain,
domainFull, item, domainFull, item,
None, True) None, True,
peertubeInstances)
if len(timelineJson['orderedItems']) >= noOfItems: if len(timelineJson['orderedItems']) >= noOfItems:
blogStr += navigateStr blogStr += navigateStr
@ -638,7 +644,8 @@ def _singleBlogAccountNickname(baseDir: str) -> str:
def htmlBlogView(authorized: bool, def htmlBlogView(authorized: bool,
session, baseDir: str, httpPrefix: str, session, baseDir: str, httpPrefix: str,
translate: {}, domain: str, port: int, translate: {}, domain: str, port: int,
noOfItems: int) -> str: noOfItems: int,
peertubeInstances: []) -> str:
"""Show the blog main page """Show the blog main page
""" """
blogStr = '' blogStr = ''
@ -654,7 +661,7 @@ def htmlBlogView(authorized: bool,
return htmlBlogPage(authorized, session, return htmlBlogPage(authorized, session,
baseDir, httpPrefix, translate, baseDir, httpPrefix, translate,
nickname, domain, port, nickname, domain, port,
noOfItems, 1) noOfItems, 1, peertubeInstances)
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)

View File

@ -8,6 +8,7 @@ __status__ = "Production"
import os import os
from pprint import pprint from pprint import pprint
from utils import hasUsersPath
from utils import getFullDomain from utils import getFullDomain
from utils import removeIdEnding from utils import removeIdEnding
from utils import removePostFromCache from utils import removePostFromCache
@ -255,10 +256,7 @@ def bookmark(recentPostsCache: {},
bookmarkedPostNickname = getNicknameFromActor(acBm) bookmarkedPostNickname = getNicknameFromActor(acBm)
bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm) bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm)
else: else:
if '/users/' in objectUrl or \ if hasUsersPath(objectUrl):
'/accounts/' in objectUrl or \
'/channel/' in objectUrl or \
'/profile/' in objectUrl:
ou = objectUrl ou = objectUrl
bookmarkedPostNickname = getNicknameFromActor(ou) bookmarkedPostNickname = getNicknameFromActor(ou)
bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou) bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou)
@ -322,10 +320,7 @@ def undoBookmark(recentPostsCache: {},
bookmarkedPostNickname = getNicknameFromActor(acBm) bookmarkedPostNickname = getNicknameFromActor(acBm)
bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm) bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm)
else: else:
if '/users/' in objectUrl or \ if hasUsersPath(objectUrl):
'/accounts/' in objectUrl or \
'/channel/' in objectUrl or \
'/profile/' in objectUrl:
ou = objectUrl ou = objectUrl
bookmarkedPostNickname = getNicknameFromActor(ou) bookmarkedPostNickname = getNicknameFromActor(ou)
bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou) bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou)

103
briar.py 100644
View File

@ -0,0 +1,103 @@
__filename__ = "briar.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.1.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
def getBriarAddress(actorJson: {}) -> str:
"""Returns briar address for the given actor
"""
if not actorJson.get('attachment'):
return ''
for propertyValue in actorJson['attachment']:
if not propertyValue.get('name'):
continue
if not propertyValue['name'].lower().startswith('briar'):
continue
if not propertyValue.get('type'):
continue
if not propertyValue.get('value'):
continue
if propertyValue['type'] != 'PropertyValue':
continue
propertyValue['value'] = propertyValue['value'].strip()
if len(propertyValue['value']) < 50:
continue
if not propertyValue['value'].startswith('briar://'):
continue
if propertyValue['value'].lower() != propertyValue['value']:
continue
if '"' in propertyValue['value']:
continue
if ' ' in propertyValue['value']:
continue
if ',' in propertyValue['value']:
continue
if '.' in propertyValue['value']:
continue
return propertyValue['value']
return ''
def setBriarAddress(actorJson: {}, briarAddress: str) -> None:
"""Sets an briar address for the given actor
"""
notBriarAddress = False
if len(briarAddress) < 50:
notBriarAddress = True
if not briarAddress.startswith('briar://'):
notBriarAddress = True
if briarAddress.lower() != briarAddress:
notBriarAddress = True
if '"' in briarAddress:
notBriarAddress = True
if ' ' in briarAddress:
notBriarAddress = True
if '.' in briarAddress:
notBriarAddress = True
if ',' in briarAddress:
notBriarAddress = True
if '<' in briarAddress:
notBriarAddress = True
if not actorJson.get('attachment'):
actorJson['attachment'] = []
# remove any existing value
propertyFound = None
for propertyValue in actorJson['attachment']:
if not propertyValue.get('name'):
continue
if not propertyValue.get('type'):
continue
if not propertyValue['name'].lower().startswith('briar'):
continue
propertyFound = propertyValue
break
if propertyFound:
actorJson['attachment'].remove(propertyFound)
if notBriarAddress:
return
for propertyValue in actorJson['attachment']:
if not propertyValue.get('name'):
continue
if not propertyValue.get('type'):
continue
if not propertyValue['name'].lower().startswith('briar'):
continue
if propertyValue['type'] != 'PropertyValue':
continue
propertyValue['value'] = briarAddress
return
newBriarAddress = {
"name": "Briar",
"type": "PropertyValue",
"value": briarAddress
}
actorJson['attachment'].append(newBriarAddress)

690
daemon.py

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@ __status__ = "Production"
import os import os
from datetime import datetime from datetime import datetime
from utils import hasUsersPath
from utils import getFullDomain from utils import getFullDomain
from utils import removeIdEnding from utils import removeIdEnding
from utils import getNicknameFromActor from utils import getNicknameFromActor
@ -139,10 +140,7 @@ def outboxDelete(baseDir: str, httpPrefix: str,
if debug: if debug:
print('DEBUG: c2s delete object is not a status') print('DEBUG: c2s delete object is not a status')
return return
if '/users/' not in messageId and \ if not hasUsersPath(messageId):
'/accounts/' not in messageId and \
'/channel/' not in messageId and \
'/profile/' not in messageId:
if debug: if debug:
print('DEBUG: c2s delete object has no nickname') print('DEBUG: c2s delete object has no nickname')
return return

View File

@ -47,6 +47,7 @@ from tests import testClientToServer
from tests import runAllTests from tests import runAllTests
from auth import storeBasicCredentials from auth import storeBasicCredentials
from auth import createPassword from auth import createPassword
from utils import hasUsersPath
from utils import getFullDomain from utils import getFullDomain
from utils import setConfigParam from utils import setConfigParam
from utils import getConfigParam from utils import getConfigParam
@ -1318,10 +1319,7 @@ if args.actor:
for prefix in prefixes: for prefix in prefixes:
args.actor = args.actor.replace(prefix, '') args.actor = args.actor.replace(prefix, '')
args.actor = args.actor.replace('/@', '/users/') args.actor = args.actor.replace('/@', '/users/')
if '/users/' not in args.actor and \ if not hasUsersPath(args.actor):
'/accounts/' not in args.actor and \
'/channel/' not in args.actor and \
'/profile/' not in args.actor:
print('Expected actor format: ' + print('Expected actor format: ' +
'https://domain/@nick or https://domain/users/nick') 'https://domain/@nick or https://domain/users/nick')
sys.exit() sys.exit()
@ -1391,10 +1389,7 @@ if args.actor:
personUrl = None personUrl = None
if wfRequest.get('errors'): if wfRequest.get('errors'):
print('wfRequest error: ' + str(wfRequest['errors'])) print('wfRequest error: ' + str(wfRequest['errors']))
if '/users/' in args.actor or \ if hasUsersPath(args.actor):
'/accounts/' in args.actor or \
'/profile/' in args.actor or \
'/channel/' in args.actor:
personUrl = originalActor personUrl = originalActor
else: else:
sys.exit() sys.exit()

View File

@ -8,6 +8,7 @@ __status__ = "Production"
from pprint import pprint from pprint import pprint
import os import os
from utils import hasUsersPath
from utils import getFullDomain from utils import getFullDomain
from utils import isSystemAccount from utils import isSystemAccount
from utils import getFollowersList from utils import getFollowersList
@ -316,10 +317,7 @@ def _getNoOfFollows(baseDir: str, nickname: str, domain: str,
ctr += 1 ctr += 1
elif ((line.startswith('http') or elif ((line.startswith('http') or
line.startswith('dat')) and line.startswith('dat')) and
('/users/' in line or hasUsersPath(line)):
'/profile/' in line or
'/accounts/' in line or
'/channel/' in line)):
ctr += 1 ctr += 1
return ctr return ctr
@ -438,10 +436,7 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str,
following['orderedItems'].append(url) following['orderedItems'].append(url)
elif ((line.startswith('http') or elif ((line.startswith('http') or
line.startswith('dat')) and line.startswith('dat')) and
('/users/' in line or hasUsersPath(line)):
'/profile/' in line or
'/accounts/' in line or
'/channel/' in line)):
# https://domain/users/nickname # https://domain/users/nickname
pageCtr += 1 pageCtr += 1
totalCtr += 1 totalCtr += 1
@ -616,10 +611,7 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
if debug: if debug:
print('DEBUG: follow request has no actor') print('DEBUG: follow request has no actor')
return False return False
if '/users/' not in messageJson['actor'] and \ if not hasUsersPath(messageJson['actor']):
'/accounts/' not in messageJson['actor'] and \
'/channel/' not in messageJson['actor'] and \
'/profile/' not in messageJson['actor']:
if debug: if debug:
print('DEBUG: users/profile/accounts/channel missing from actor') print('DEBUG: users/profile/accounts/channel missing from actor')
return False return False
@ -641,10 +633,7 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
'nickname. Assuming single user instance.') 'nickname. Assuming single user instance.')
if not messageJson.get('to'): if not messageJson.get('to'):
messageJson['to'] = messageJson['object'] messageJson['to'] = messageJson['object']
if '/users/' not in messageJson['object'] and \ if not hasUsersPath(messageJson['object']):
'/accounts/' not in messageJson['object'] and \
'/channel/' not in messageJson['object'] and \
'/profile/' not in messageJson['object']:
if debug: if debug:
print('DEBUG: users/profile/channel/accounts ' + print('DEBUG: users/profile/channel/accounts ' +
'not found within object') 'not found within object')

View File

@ -10,6 +10,7 @@ import json
import os import os
import datetime import datetime
import time import time
from utils import hasUsersPath
from utils import validPostDate from utils import validPostDate
from utils import getFullDomain from utils import getFullDomain
from utils import isEventPost from utils import isEventPost
@ -145,7 +146,8 @@ def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
nickname: str, domain: str, port: int, nickname: str, domain: str, port: int,
postJsonObject: {}, postJsonObject: {},
allowDeletion: bool, boxname: str, allowDeletion: bool, boxname: str,
showPublishedDateOnly: bool) -> None: showPublishedDateOnly: bool,
peertubeInstances: []) -> 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
""" """
@ -170,6 +172,7 @@ def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
avatarUrl, True, allowDeletion, avatarUrl, True, allowDeletion,
httpPrefix, __version__, boxname, None, httpPrefix, __version__, boxname, None,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
not isDM(postJsonObject), not isDM(postJsonObject),
True, True, False, True) True, True, False, True)
@ -604,10 +607,7 @@ def _receiveUndoFollow(session, baseDir: str, httpPrefix: str,
if debug: if debug:
print('DEBUG: follow request has no actor within object') print('DEBUG: follow request has no actor within object')
return False return False
if '/users/' not in messageJson['object']['actor'] and \ if not hasUsersPath(messageJson['object']['actor']):
'/accounts/' not in messageJson['object']['actor'] and \
'/channel/' not in messageJson['object']['actor'] and \
'/profile/' not in messageJson['object']['actor']:
if debug: if debug:
print('DEBUG: "users" or "profile" missing ' + print('DEBUG: "users" or "profile" missing ' +
'from actor within object') 'from actor within object')
@ -668,10 +668,7 @@ def _receiveUndo(session, baseDir: str, httpPrefix: str,
if debug: if debug:
print('DEBUG: follow request has no actor') print('DEBUG: follow request has no actor')
return False return False
if '/users/' not in messageJson['actor'] and \ if not hasUsersPath(messageJson['actor']):
'/accounts/' not in messageJson['actor'] and \
'/channel/' not in messageJson['actor'] and \
'/profile/' not in messageJson['actor']:
if debug: if debug:
print('DEBUG: "users" or "profile" missing from actor') print('DEBUG: "users" or "profile" missing from actor')
return False return False
@ -735,19 +732,19 @@ def _personReceiveUpdate(baseDir: str,
' ' + str(personJson)) ' ' + str(personJson))
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
updateDomainFull = getFullDomain(updateDomain, updatePort) updateDomainFull = getFullDomain(updateDomain, updatePort)
actor = updateDomainFull + '/users/' + updateNickname usersPaths = ('users', 'profile', 'channel', 'accounts')
if actor not in personJson['id']: usersStrFound = False
actor = updateDomainFull + '/profile/' + updateNickname for usersStr in usersPaths:
if actor not in personJson['id']: actor = updateDomainFull + '/' + usersStr + '/' + updateNickname
actor = updateDomainFull + '/channel/' + updateNickname if actor in personJson['id']:
if actor not in personJson['id']: usersStrFound = True
actor = updateDomainFull + '/accounts/' + updateNickname break
if actor not in personJson['id']: if not usersStrFound:
if debug: if debug:
print('actor: ' + actor) print('actor: ' + actor)
print('id: ' + personJson['id']) print('id: ' + personJson['id'])
print('DEBUG: Actor does not match id') print('DEBUG: Actor does not match id')
return False return False
if updateDomainFull == domainFull: if updateDomainFull == domainFull:
if debug: if debug:
print('DEBUG: You can only receive actor updates ' + print('DEBUG: You can only receive actor updates ' +
@ -859,10 +856,7 @@ def _receiveUpdate(recentPostsCache: {}, session, baseDir: str,
if debug: if debug:
print('DEBUG: ' + messageJson['type'] + ' object has no type') print('DEBUG: ' + messageJson['type'] + ' object has no type')
return False return False
if '/users/' not in messageJson['actor'] and \ if not hasUsersPath(messageJson['actor']):
'/accounts/' not in messageJson['actor'] and \
'/channel/' not in messageJson['actor'] and \
'/profile/' not in messageJson['actor']:
if debug: if debug:
print('DEBUG: "users" or "profile" missing from actor in ' + print('DEBUG: "users" or "profile" missing from actor in ' +
messageJson['type']) messageJson['type'])
@ -943,10 +937,7 @@ def _receiveLike(recentPostsCache: {},
if debug: if debug:
print('DEBUG: ' + messageJson['type'] + ' has no "to" list') print('DEBUG: ' + messageJson['type'] + ' has no "to" list')
return False return False
if '/users/' not in messageJson['actor'] and \ if not hasUsersPath(messageJson['actor']):
'/accounts/' not in messageJson['actor'] and \
'/channel/' not in messageJson['actor'] and \
'/profile/' not in messageJson['actor']:
if debug: if debug:
print('DEBUG: "users" or "profile" missing from actor in ' + print('DEBUG: "users" or "profile" missing from actor in ' +
messageJson['type']) messageJson['type'])
@ -1014,10 +1005,7 @@ def _receiveUndoLike(recentPostsCache: {},
print('DEBUG: ' + messageJson['type'] + print('DEBUG: ' + messageJson['type'] +
' like object is not a string') ' like object is not a string')
return False return False
if '/users/' not in messageJson['actor'] and \ if not hasUsersPath(messageJson['actor']):
'/accounts/' not in messageJson['actor'] and \
'/channel/' not in messageJson['actor'] and \
'/profile/' not in messageJson['actor']:
if debug: if debug:
print('DEBUG: "users" or "profile" missing from actor in ' + print('DEBUG: "users" or "profile" missing from actor in ' +
messageJson['type'] + ' like') messageJson['type'] + ' like')
@ -1219,10 +1207,7 @@ def _receiveDelete(session, handle: str, isGroup: bool, baseDir: str,
if debug: if debug:
print('DEBUG: ' + messageJson['type'] + ' has no "to" list') print('DEBUG: ' + messageJson['type'] + ' has no "to" list')
return False return False
if '/users/' not in messageJson['actor'] and \ if not hasUsersPath(messageJson['actor']):
'/accounts/' not in messageJson['actor'] and \
'/channel/' not in messageJson['actor'] and \
'/profile/' not in messageJson['actor']:
if debug: if debug:
print('DEBUG: ' + print('DEBUG: ' +
'"users" or "profile" missing from actor in ' + '"users" or "profile" missing from actor in ' +
@ -1303,19 +1288,13 @@ def _receiveAnnounce(recentPostsCache: {},
if debug: if debug:
print('DEBUG: ' + messageJson['type'] + ' has no "to" list') print('DEBUG: ' + messageJson['type'] + ' has no "to" list')
return False return False
if '/users/' not in messageJson['actor'] and \ if not hasUsersPath(messageJson['actor']):
'/accounts/' not in messageJson['actor'] and \
'/channel/' not in messageJson['actor'] and \
'/profile/' not in messageJson['actor']:
if debug: if debug:
print('DEBUG: ' + print('DEBUG: ' +
'"users" or "profile" missing from actor in ' + '"users" or "profile" missing from actor in ' +
messageJson['type']) messageJson['type'])
return False return False
if '/users/' not in messageJson['object'] and \ if not hasUsersPath(messageJson['object']):
'/accounts/' not in messageJson['object'] and \
'/channel/' not in messageJson['object'] and \
'/profile/' not in messageJson['object']:
if debug: if debug:
print('DEBUG: ' + print('DEBUG: ' +
'"users", "channel" or "profile" missing in ' + '"users", "channel" or "profile" missing in ' +
@ -1387,10 +1366,7 @@ def _receiveAnnounce(recentPostsCache: {},
if isinstance(attrib, str): if isinstance(attrib, str):
lookupActor = attrib lookupActor = attrib
if lookupActor: if lookupActor:
if '/users/' in lookupActor or \ if hasUsersPath(lookupActor):
'/accounts/' in lookupActor or \
'/channel/' in lookupActor or \
'/profile/' in lookupActor:
if '/statuses/' in lookupActor: if '/statuses/' in lookupActor:
lookupActor = lookupActor.split('/statuses/')[0] lookupActor = lookupActor.split('/statuses/')[0]
@ -1439,10 +1415,7 @@ def _receiveUndoAnnounce(recentPostsCache: {},
return False return False
if messageJson['object']['type'] != 'Announce': if messageJson['object']['type'] != 'Announce':
return False return False
if '/users/' not in messageJson['actor'] and \ if not hasUsersPath(messageJson['actor']):
'/accounts/' not in messageJson['actor'] and \
'/channel/' not in messageJson['actor'] and \
'/profile/' not in messageJson['actor']:
if debug: if debug:
print('DEBUG: "users" or "profile" missing from actor in ' + print('DEBUG: "users" or "profile" missing from actor in ' +
messageJson['type'] + ' announce') messageJson['type'] + ' announce')
@ -1688,10 +1661,7 @@ def _obtainAvatarForReplyPost(session, baseDir: str, httpPrefix: str,
if not isinstance(lookupActor, str): if not isinstance(lookupActor, str):
return return
if not ('/users/' in lookupActor or if not hasUsersPath(lookupActor):
'/accounts/' in lookupActor or
'/channel/' in lookupActor or
'/profile/' in lookupActor):
return return
if '/statuses/' in lookupActor: if '/statuses/' in lookupActor:
@ -2071,7 +2041,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
maxMentions: int, maxEmoji: int, translate: {}, maxMentions: int, maxEmoji: int, translate: {},
unitTest: bool, YTReplacementDomain: str, unitTest: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool, showPublishedDateOnly: bool,
allowLocalNetworkAccess: bool) -> bool: allowLocalNetworkAccess: bool,
peertubeInstances: []) -> bool:
""" Anything which needs to be done after initial checks have passed """ Anything which needs to be done after initial checks have passed
""" """
actor = keyId actor = keyId
@ -2378,7 +2349,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
postJsonObject, postJsonObject,
allowDeletion, allowDeletion,
boxname, boxname,
showPublishedDateOnly) showPublishedDateOnly,
peertubeInstances)
if debug: if debug:
timeDiff = \ timeDiff = \
str(int((time.time() - htmlCacheStartTime) * str(int((time.time() - htmlCacheStartTime) *
@ -2478,7 +2450,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool, showPublishedDateOnly: bool,
allowNewsFollowers: bool, allowNewsFollowers: bool,
maxFollowers: int, allowLocalNetworkAccess: bool) -> None: maxFollowers: int, allowLocalNetworkAccess: bool,
peertubeInstances: []) -> None:
"""Processes received items and moves them to the appropriate """Processes received items and moves them to the appropriate
directories directories
""" """
@ -2895,7 +2868,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
translate, unitTest, translate, unitTest,
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
allowLocalNetworkAccess) allowLocalNetworkAccess,
peertubeInstances)
if debug: if debug:
pprint(queueJson['post']) pprint(queueJson['post'])

View File

@ -6,6 +6,7 @@ __maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net" __email__ = "bob@freedombone.net"
__status__ = "Production" __status__ = "Production"
from utils import hasUsersPath
from utils import getFullDomain from utils import getFullDomain
from utils import removeIdEnding from utils import removeIdEnding
from utils import urlPermitted from utils import urlPermitted
@ -87,10 +88,7 @@ def _like(recentPostsCache: {},
likedPostNickname = getNicknameFromActor(actorLiked) likedPostNickname = getNicknameFromActor(actorLiked)
likedPostDomain, likedPostPort = getDomainFromActor(actorLiked) likedPostDomain, likedPostPort = getDomainFromActor(actorLiked)
else: else:
if '/users/' in objectUrl or \ if hasUsersPath(objectUrl):
'/accounts/' in objectUrl or \
'/channel/' in objectUrl or \
'/profile/' in objectUrl:
likedPostNickname = getNicknameFromActor(objectUrl) likedPostNickname = getNicknameFromActor(objectUrl)
likedPostDomain, likedPostPort = getDomainFromActor(objectUrl) likedPostDomain, likedPostPort = getDomainFromActor(objectUrl)

View File

@ -30,6 +30,7 @@ from session import postJsonString
from session import postImage from session import postImage
from webfinger import webfingerHandle from webfinger import webfingerHandle
from httpsig import createSignedHeader from httpsig import createSignedHeader
from utils import hasUsersPath
from utils import validPostDate from utils import validPostDate
from utils import getFullDomain from utils import getFullDomain
from utils import getFollowersList from utils import getFollowersList
@ -155,10 +156,7 @@ def getUserUrl(wfRequest: {}, sourceId=0) -> str:
continue continue
if link['type'] != 'application/activity+json': if link['type'] != 'application/activity+json':
continue continue
if not ('/users/' in link['href'] or if not hasUsersPath(link['href']):
'/accounts/' in link['href'] or
'/profile/' in link['href'] or
'/channel/' in link['href']):
print('getUserUrl webfinger activity+json ' + print('getUserUrl webfinger activity+json ' +
'contains single user instance actor ' + 'contains single user instance actor ' +
str(sourceId) + ' ' + str(link)) str(sourceId) + ' ' + str(link))

154
tests.py
View File

@ -854,7 +854,7 @@ def testFollowBetweenServers():
True, __version__, False) True, __version__, False)
print('sendResult: ' + str(sendResult)) print('sendResult: ' + str(sendResult))
for t in range(10): for t in range(16):
if os.path.isfile(bobDir + '/accounts/bob@' + if os.path.isfile(bobDir + '/accounts/bob@' +
bobDomain + '/followers.txt'): bobDomain + '/followers.txt'):
if os.path.isfile(aliceDir + '/accounts/alice@' + if os.path.isfile(aliceDir + '/accounts/alice@' +
@ -2613,9 +2613,10 @@ def getFunctionCalls(name: str, lines: [], startLineCtr: int,
callsFunctions = [] callsFunctions = []
functionContentStr = '' functionContentStr = ''
for lineCtr in range(startLineCtr + 1, len(lines)): for lineCtr in range(startLineCtr + 1, len(lines)):
if lines[lineCtr].startswith('def '): lineStr = lines[lineCtr].strip()
if lineStr.startswith('def '):
break break
if lines[lineCtr].startswith('class '): if lineStr.startswith('class '):
break break
functionContentStr += lines[lineCtr] functionContentStr += lines[lineCtr]
for funcName, properties in functionProperties.items(): for funcName, properties in functionProperties.items():
@ -2635,14 +2636,14 @@ def functionArgsMatch(callArgs: [], funcArgs: []):
for a in callArgs: for a in callArgs:
if a == 'self': if a == 'self':
continue continue
if '=' not in a: if '=' not in a or a.startswith("'"):
callArgsCtr += 1 callArgsCtr += 1
funcArgsCtr = 0 funcArgsCtr = 0
for a in funcArgs: for a in funcArgs:
if a == 'self': if a == 'self':
continue continue
if '=' not in a: if '=' not in a or a.startswith("'"):
funcArgsCtr += 1 funcArgsCtr += 1
return callArgsCtr >= funcArgsCtr return callArgsCtr >= funcArgsCtr
@ -2670,7 +2671,7 @@ def testFunctions():
lines = f.readlines() lines = f.readlines()
modules[modName]['lines'] = lines modules[modName]['lines'] = lines
for line in lines: for line in lines:
if not line.startswith('def '): if not line.strip().startswith('def '):
continue continue
methodName = line.split('def ', 1)[1].split('(')[0] methodName = line.split('def ', 1)[1].split('(')[0]
methodArgs = \ methodArgs = \
@ -2694,7 +2695,9 @@ def testFunctions():
'pyjsonld' 'pyjsonld'
] ]
excludeFuncs = [ excludeFuncs = [
'link' 'link',
'set',
'get'
] ]
# which modules is each function used within? # which modules is each function used within?
for modName, modProperties in modules.items(): for modName, modProperties in modules.items():
@ -2702,7 +2705,11 @@ def testFunctions():
for name, properties in functionProperties.items(): for name, properties in functionProperties.items():
lineCtr = 0 lineCtr = 0
for line in modules[modName]['lines']: for line in modules[modName]['lines']:
if line.startswith('def '): lineStr = line.strip()
if lineStr.startswith('def '):
lineCtr += 1
continue
if lineStr.startswith('class '):
lineCtr += 1 lineCtr += 1
continue continue
if name + '(' in line: if name + '(' in line:
@ -2735,7 +2742,22 @@ def testFunctions():
# don't check these functions, because they are procedurally called # don't check these functions, because they are procedurally called
exclusions = [ exclusions = [
'do_GET',
'do_POST',
'do_HEAD',
'__run',
'globaltrace',
'localtrace',
'kill',
'clone',
'unregister_rdf_parser',
'set_document_loader', 'set_document_loader',
'has_property',
'has_value',
'add_value',
'get_values',
'remove_property',
'remove_value',
'normalize', 'normalize',
'get_document_loader', 'get_document_loader',
'runInboxQueueWatchdog', 'runInboxQueueWatchdog',
@ -2764,17 +2786,26 @@ def testFunctions():
'setOrganizationScheme' 'setOrganizationScheme'
] ]
excludeImports = [ excludeImports = [
'link' 'link',
'start'
] ]
excludeLocal = [ excludeLocal = [
'pyjsonld', 'pyjsonld',
'daemon', 'daemon',
'tests' 'tests'
] ]
excludeMods = [
'pyjsonld'
]
# check that functions are called somewhere # check that functions are called somewhere
for name, properties in functionProperties.items(): for name, properties in functionProperties.items():
if name.startswith('__'):
if name.endswith('__'):
continue
if name in exclusions: if name in exclusions:
continue continue
if properties['module'] in excludeMods:
continue
isLocalFunction = False isLocalFunction = False
if not properties['calledInModule']: if not properties['calledInModule']:
print('function ' + name + print('function ' + name +
@ -2815,18 +2846,80 @@ def testFunctions():
assert False assert False
print('Function: ' + name + '') print('Function: ' + name + '')
print('Constructing call graph') print('Constructing function call graph')
moduleColors = ('red', 'green', 'yellow', 'orange', 'purple', 'cyan',
'darkgoldenrod3', 'darkolivegreen1', 'darkorange1',
'darkorchid1', 'darkseagreen', 'darkslategray4',
'deeppink1', 'deepskyblue1', 'dimgrey', 'gold1',
'goldenrod', 'burlywood2', 'bisque1', 'brown1',
'chartreuse2', 'cornsilk', 'darksalmon')
maxModuleCalls = 1
maxFunctionCalls = 1
colorCtr = 0
for modName, modProperties in modules.items(): for modName, modProperties in modules.items():
lineCtr = 0 lineCtr = 0
modules[modName]['color'] = moduleColors[colorCtr]
colorCtr += 1
if colorCtr >= len(moduleColors):
colorCtr = 0
for line in modules[modName]['lines']: for line in modules[modName]['lines']:
if line.startswith('def '): if line.strip().startswith('def '):
name = line.split('def ')[1].split('(')[0] name = line.split('def ')[1].split('(')[0]
callsList = \ callsList = \
getFunctionCalls(name, modules[modName]['lines'], getFunctionCalls(name, modules[modName]['lines'],
lineCtr, functionProperties) lineCtr, functionProperties)
functionProperties[name]['calls'] = callsList.copy() functionProperties[name]['calls'] = callsList.copy()
if len(callsList) > maxFunctionCalls:
maxFunctionCalls = len(callsList)
# keep track of which module calls which other module
for fn in callsList:
modCall = functionProperties[fn]['module']
if modCall != modName:
if modules[modName].get('calls'):
if modCall not in modules[modName]['calls']:
modules[modName]['calls'].append(modCall)
if len(modules[modName]['calls']) > \
maxModuleCalls:
maxModuleCalls = \
len(modules[modName]['calls'])
else:
modules[modName]['calls'] = [modCall]
lineCtr += 1 lineCtr += 1
callGraphStr = 'digraph EpicyonModules {\n\n'
callGraphStr += ' graph [fontsize=10 fontname="Verdana" compound=true];\n'
callGraphStr += ' node [shape=record fontsize=10 fontname="Verdana"];\n\n'
# colors of modules nodes
for modName, modProperties in modules.items():
if not modProperties.get('calls'):
callGraphStr += ' "' + modName + \
'" [fillcolor=yellow style=filled];\n'
continue
if len(modProperties['calls']) <= int(maxModuleCalls / 8):
callGraphStr += ' "' + modName + \
'" [fillcolor=green style=filled];\n'
elif len(modProperties['calls']) < int(maxModuleCalls / 4):
callGraphStr += ' "' + modName + \
'" [fillcolor=orange style=filled];\n'
else:
callGraphStr += ' "' + modName + \
'" [fillcolor=red style=filled];\n'
callGraphStr += '\n'
# connections between modules
for modName, modProperties in modules.items():
if not modProperties.get('calls'):
continue
for modCall in modProperties['calls']:
callGraphStr += ' "' + modName + '" -> "' + modCall + '";\n'
callGraphStr += '\n}\n'
with open('epicyon_modules.dot', 'w+') as fp:
fp.write(callGraphStr)
print('Modules call graph saved to epicyon_modules.dot')
print('Plot using: ' +
'sfdp -x -Goverlap=false -Goverlap_scaling=2 ' +
'-Gsep=+100 -Tx11 epicyon_modules.dot')
callGraphStr = 'digraph Epicyon {\n\n' callGraphStr = 'digraph Epicyon {\n\n'
callGraphStr += ' size="8,6"; ratio=fill;\n'
callGraphStr += ' graph [fontsize=10 fontname="Verdana" compound=true];\n' callGraphStr += ' graph [fontsize=10 fontname="Verdana" compound=true];\n'
callGraphStr += ' node [shape=record fontsize=10 fontname="Verdana"];\n\n' callGraphStr += ' node [shape=record fontsize=10 fontname="Verdana"];\n\n'
@ -2834,25 +2927,52 @@ def testFunctions():
callGraphStr += ' subgraph cluster_' + modName + ' {\n' callGraphStr += ' subgraph cluster_' + modName + ' {\n'
callGraphStr += ' label = "' + modName + '";\n' callGraphStr += ' label = "' + modName + '";\n'
callGraphStr += ' node [style=filled];\n' callGraphStr += ' node [style=filled];\n'
callGraphStr += ' ' moduleFunctionsStr = ''
for name in modProperties['functions']: for name in modProperties['functions']:
callGraphStr += '"' + name + '" ' if name.startswith('test'):
callGraphStr += ';\n' continue
if name not in excludeFuncs:
if not functionProperties[name]['calls']:
moduleFunctionsStr += \
' "' + name + '" [fillcolor=yellow style=filled];\n'
continue
noOfCalls = len(functionProperties[name]['calls'])
if noOfCalls < int(maxFunctionCalls / 4):
moduleFunctionsStr += ' "' + name + \
'" [fillcolor=orange style=filled];\n'
else:
moduleFunctionsStr += ' "' + name + \
'" [fillcolor=red style=filled];\n'
if moduleFunctionsStr:
callGraphStr += moduleFunctionsStr + '\n'
callGraphStr += ' color=blue;\n' callGraphStr += ' color=blue;\n'
callGraphStr += ' }\n\n' callGraphStr += ' }\n\n'
for name, properties in functionProperties.items(): for name, properties in functionProperties.items():
if not properties['calls']: if not properties['calls']:
continue continue
noOfCalls = len(properties['calls'])
if noOfCalls <= int(maxFunctionCalls / 8):
modColor = 'blue'
elif noOfCalls < int(maxFunctionCalls / 4):
modColor = 'green'
else:
modColor = 'red'
for calledFunc in properties['calls']: for calledFunc in properties['calls']:
callGraphStr += ' "' + name + '" -> "' + calledFunc + '";\n' if calledFunc.startswith('test'):
continue
if calledFunc not in excludeFuncs:
callGraphStr += ' "' + name + '" -> "' + calledFunc + \
'" [color=' + modColor + '];\n'
callGraphStr += '\n}\n' callGraphStr += '\n}\n'
with open('epicyon.dot', 'w+') as fp: with open('epicyon.dot', 'w+') as fp:
fp.write(callGraphStr) fp.write(callGraphStr)
print('Call graph saved to epicyon.dot') print('Call graph saved to epicyon.dot')
print('Convert to image with: ' + print('Plot using: ' +
'dot -Tjpg epicyon.dot -o epicyon_diagram.jpg') 'sfdp -x -Goverlap=prism -Goverlap_scaling=8 ' +
'-Gsep=+120 -Tx11 epicyon.dot')
def runAllTests(): def runAllTests():

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,4 +1,6 @@
{ {
"post-separator-margin-top": "10px",
"post-separator-margin-bottom": "10px",
"calendar-header-font-style": "normal", "calendar-header-font-style": "normal",
"italic-font-style": "normal", "italic-font-style": "normal",
"calendar-header-font": "'Orbitron'", "calendar-header-font": "'Orbitron'",
@ -22,8 +24,6 @@
"publish-button-at-top": "False", "publish-button-at-top": "False",
"main-visited-color": "#46eed5", "main-visited-color": "#46eed5",
"options-main-visited-color": "#46eed5", "options-main-visited-color": "#46eed5",
"post-separator-margin-top": "9%",
"post-separator-margin-bottom": "9%",
"post-separator-width": "80%", "post-separator-width": "80%",
"post-separator-height": "10%", "post-separator-height": "10%",
"column-left-header-background": "#6800e7", "column-left-header-background": "#6800e7",

View File

@ -347,5 +347,7 @@
"Filter out words": "تصفية الكلمات", "Filter out words": "تصفية الكلمات",
"Unfilter": "غير مرشح", "Unfilter": "غير مرشح",
"Unfilter words": "الكلمات غير المصفاة", "Unfilter words": "الكلمات غير المصفاة",
"Show Accounts": "إظهار الحسابات" "Show Accounts": "إظهار الحسابات",
"Peertube Instances": "مثيلات Peertube",
"Show video previews for the following Peertube sites.": "إظهار معاينات الفيديو لمواقع Peertube التالية."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Filtra les paraules", "Filter out words": "Filtra les paraules",
"Unfilter": "Sense filtre", "Unfilter": "Sense filtre",
"Unfilter words": "Paraules sense filtre", "Unfilter words": "Paraules sense filtre",
"Show Accounts": "Mostra comptes" "Show Accounts": "Mostra comptes",
"Peertube Instances": "Instàncies de Peertube",
"Show video previews for the following Peertube sites.": "Mostra les previsualitzacions de vídeo dels següents llocs de Peertube."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Hidlo geiriau", "Filter out words": "Hidlo geiriau",
"Unfilter": "Di-hid", "Unfilter": "Di-hid",
"Unfilter words": "Geiriau di-hid", "Unfilter words": "Geiriau di-hid",
"Show Accounts": "Dangos Cyfrifon" "Show Accounts": "Dangos Cyfrifon",
"Peertube Instances": "Camau Peertube",
"Show video previews for the following Peertube sites.": "Dangos rhagolygon fideo ar gyfer y safleoedd Peertube canlynol."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Wörter herausfiltern", "Filter out words": "Wörter herausfiltern",
"Unfilter": "Filter entfernen", "Unfilter": "Filter entfernen",
"Unfilter words": "Wörter herausfiltern", "Unfilter words": "Wörter herausfiltern",
"Show Accounts": "Konten anzeigen" "Show Accounts": "Konten anzeigen",
"Peertube Instances": "Peertube-Instanzen",
"Show video previews for the following Peertube sites.": "Zeigen Sie eine Videovorschau für die folgenden Peertube-Websites an."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Filter out words", "Filter out words": "Filter out words",
"Unfilter": "Unfilter", "Unfilter": "Unfilter",
"Unfilter words": "Unfilter words", "Unfilter words": "Unfilter words",
"Show Accounts": "Show Accounts" "Show Accounts": "Show Accounts",
"Peertube Instances": "Peertube Instances",
"Show video previews for the following Peertube sites.": "Show video previews for the following Peertube sites."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Filtrar palabras", "Filter out words": "Filtrar palabras",
"Unfilter": "Unfilter", "Unfilter": "Unfilter",
"Unfilter words": "Palabras sin filtrar", "Unfilter words": "Palabras sin filtrar",
"Show Accounts": "Mostrar cuentas" "Show Accounts": "Mostrar cuentas",
"Peertube Instances": "Instancias de Peertube",
"Show video previews for the following Peertube sites.": "Muestre vistas previas de video para los siguientes sitios de Peertube."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Filtrer les mots", "Filter out words": "Filtrer les mots",
"Unfilter": "Non filtrer", "Unfilter": "Non filtrer",
"Unfilter words": "Mots non filtrés", "Unfilter words": "Mots non filtrés",
"Show Accounts": "Afficher les comptes" "Show Accounts": "Afficher les comptes",
"Peertube Instances": "Instances Peertube",
"Show video previews for the following Peertube sites.": "Afficher des aperçus vidéo pour les sites Peertube suivants."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Scag focail amach", "Filter out words": "Scag focail amach",
"Unfilter": "Neamhleithleach", "Unfilter": "Neamhleithleach",
"Unfilter words": "Focail neamhleithleacha", "Unfilter words": "Focail neamhleithleacha",
"Show Accounts": "Taispeáin Cuntais" "Show Accounts": "Taispeáin Cuntais",
"Peertube Instances": "Imeachtaí Peertube",
"Show video previews for the following Peertube sites.": "Taispeáin réamhamharcanna físe do na suíomhanna Peertube seo a leanas."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "शब्दों को फ़िल्टर करें", "Filter out words": "शब्दों को फ़िल्टर करें",
"Unfilter": "Unfilter", "Unfilter": "Unfilter",
"Unfilter words": "अनफ़िल्टर शब्द", "Unfilter words": "अनफ़िल्टर शब्द",
"Show Accounts": "खाते दिखाएं" "Show Accounts": "खाते दिखाएं",
"Peertube Instances": "Peertube उदाहरण",
"Show video previews for the following Peertube sites.": "निम्नलिखित Peertube साइटों के लिए वीडियो पूर्वावलोकन दिखाएं।"
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Filtra le parole", "Filter out words": "Filtra le parole",
"Unfilter": "Unfilter", "Unfilter": "Unfilter",
"Unfilter words": "Parole non filtrate", "Unfilter words": "Parole non filtrate",
"Show Accounts": "Mostra account" "Show Accounts": "Mostra account",
"Peertube Instances": "Istanze di Peertube",
"Show video previews for the following Peertube sites.": "Mostra le anteprime dei video per i seguenti siti Peertube."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "単語を除外する", "Filter out words": "単語を除外する",
"Unfilter": "フィルタリング解除", "Unfilter": "フィルタリング解除",
"Unfilter words": "単語のフィルタリングを解除する", "Unfilter words": "単語のフィルタリングを解除する",
"Show Accounts": "アカウントを表示する" "Show Accounts": "アカウントを表示する",
"Peertube Instances": "Peertubeインスタンス",
"Show video previews for the following Peertube sites.": "次のPeertubeサイトのビデオプレビューを表示します。"
} }

View File

@ -343,5 +343,7 @@
"Filter out words": "Filter out words", "Filter out words": "Filter out words",
"Unfilter": "Unfilter", "Unfilter": "Unfilter",
"Unfilter words": "Unfilter words", "Unfilter words": "Unfilter words",
"Show Accounts": "Show Accounts" "Show Accounts": "Show Accounts",
"Peertube Instances": "Peertube Instances",
"Show video previews for the following Peertube sites.": "Show video previews for the following Peertube sites."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Filtrar palavras", "Filter out words": "Filtrar palavras",
"Unfilter": "Unfilter", "Unfilter": "Unfilter",
"Unfilter words": "Palavras sem filtro", "Unfilter words": "Palavras sem filtro",
"Show Accounts": "Mostrar contas" "Show Accounts": "Mostrar contas",
"Peertube Instances": "Instâncias Peertube",
"Show video previews for the following Peertube sites.": "Mostrar visualizações de vídeo para os seguintes sites Peertube."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "Отфильтровать слова", "Filter out words": "Отфильтровать слова",
"Unfilter": "Нефильтровать", "Unfilter": "Нефильтровать",
"Unfilter words": "Не фильтровать слова", "Unfilter words": "Не фильтровать слова",
"Show Accounts": "Показать счета" "Show Accounts": "Показать счета",
"Peertube Instances": "Экземпляры Peertube",
"Show video previews for the following Peertube sites.": "Показать превью видео для следующих сайтов Peertube."
} }

View File

@ -347,5 +347,7 @@
"Filter out words": "过滤掉单词", "Filter out words": "过滤掉单词",
"Unfilter": "取消过滤", "Unfilter": "取消过滤",
"Unfilter words": "未过滤字词", "Unfilter words": "未过滤字词",
"Show Accounts": "显示帐户" "Show Accounts": "显示帐户",
"Peertube Instances": "Peertube实例",
"Show video previews for the following Peertube sites.": "显示以下Peertube网站的视频预览。"
} }

View File

@ -19,6 +19,16 @@ from calendar import monthrange
from followingCalendar import addPersonToCalendar from followingCalendar import addPersonToCalendar
def hasUsersPath(pathStr: str) -> bool:
"""Whether there is a /users/ path (or equivalent) in the given string
"""
usersList = ('users', 'accounts', 'channel', 'profile')
for usersStr in usersList:
if '/' + usersStr + '/' in pathStr:
return True
return False
def validPostDate(published: str, maxAgeDays=7) -> bool: def validPostDate(published: str, maxAgeDays=7) -> bool:
"""Returns true if the published date is recent and is not in the future """Returns true if the published date is recent and is not in the future
""" """

View File

@ -28,7 +28,8 @@ def htmlConfirmDelete(cssCache: {},
wfRequest: {}, personCache: {}, wfRequest: {}, personCache: {},
callingDomain: str, callingDomain: str,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool) -> str: showPublishedDateOnly: bool,
peertubeInstances: []) -> 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:
@ -66,6 +67,7 @@ def htmlConfirmDelete(cssCache: {},
httpPrefix, projectVersion, 'outbox', httpPrefix, projectVersion, 'outbox',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
False, False, False, False, False) False, False, False, False, False)
deletePostStr += '<center>' deletePostStr += '<center>'
deletePostStr += \ deletePostStr += \

View File

@ -27,7 +27,8 @@ def _htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
session, wfRequest: {}, personCache: {}, session, wfRequest: {}, personCache: {},
projectVersion: str, projectVersion: str,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool) -> str: showPublishedDateOnly: bool,
peertubeInstances: []) -> 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
@ -65,6 +66,7 @@ def _htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
httpPrefix, projectVersion, 'inbox', httpPrefix, projectVersion, 'inbox',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
False, False, False, True, False) False, False, False, True, False)
if postStr: if postStr:
profileStr += postStr + separatorStr profileStr += postStr + separatorStr
@ -85,7 +87,9 @@ def htmlFrontScreen(rssIconAtTop: bool,
session, wfRequest: {}, personCache: {}, session, wfRequest: {}, personCache: {},
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool, showPublishedDateOnly: bool,
newswire: {}, theme: str, extraJson=None, newswire: {}, theme: str,
peertubeInstances: [],
extraJson=None,
pageNumber=None, maxItemsPerPage=None) -> str: pageNumber=None, maxItemsPerPage=None) -> str:
"""Show the news instance front screen """Show the news instance front screen
""" """
@ -148,7 +152,8 @@ def htmlFrontScreen(rssIconAtTop: bool,
session, wfRequest, personCache, session, wfRequest, personCache,
projectVersion, projectVersion,
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly) + licenseStr showPublishedDateOnly,
peertubeInstances) + licenseStr
# Footer which is only used for system accounts # Footer which is only used for system accounts
profileFooterStr = ' </td>\n' profileFooterStr = ' </td>\n'

View File

@ -6,8 +6,30 @@ __maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net" __email__ = "bob@freedombone.net"
__status__ = "Production" __status__ = "Production"
import os
def loadPeertubeInstances(baseDir: str, peertubeInstances: []) -> None:
"""Loads peertube instances from file into the given list
"""
peertubeList = None
peertubeInstancesFilename = baseDir + '/accounts/peertube.txt'
if os.path.isfile(peertubeInstancesFilename):
with open(peertubeInstancesFilename, 'r') as fp:
peertubeStr = fp.read()
if peertubeStr:
peertubeStr = peertubeStr.replace('\r', '')
peertubeList = peertubeStr.split('\n')
if not peertubeList:
return
for url in peertubeList:
if url in peertubeInstances:
continue
peertubeInstances.append(url)
def _addEmbeddedVideoFromSites(translate: {}, content: str, def _addEmbeddedVideoFromSites(translate: {}, content: str,
peertubeInstances: [],
width=400, height=300) -> str: width=400, height=300) -> str:
"""Adds embedded videos """Adds embedded videos
""" """
@ -39,8 +61,14 @@ def _addEmbeddedVideoFromSites(translate: {}, content: str,
"allowfullscreen></iframe>\n</center>\n" "allowfullscreen></iframe>\n</center>\n"
return content return content
invidiousSites = ('https://invidio.us', invidiousSites = ('https://invidious.snopyta.org',
'https://invidious.snopyta.org', 'https://yewtu.be',
'https://tube.connect.cafe',
'https://invidious.kavin.rocks',
'https://invidiou.site',
'https://invidious.tube',
'https://invidious.xyz',
'https://invidious.zapashcanon.fr',
'http://c7hqkpkpemu6e7emz5b4vy' + 'http://c7hqkpkpemu6e7emz5b4vy' +
'z7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion', 'z7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion',
'http://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4' + 'http://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4' +
@ -76,38 +104,59 @@ def _addEmbeddedVideoFromSites(translate: {}, content: str,
return content return content
if '"https://' in content: if '"https://' in content:
# A selection of the current larger peertube sites, mostly if peertubeInstances:
# French and German language peerTubeSites = peertubeInstances
# These have been chosen based on reported numbers of users else:
# and the content of each has not been reviewed, so mileage could vary # A default selection of the current larger peertube sites,
peerTubeSites = ('peertube.mastodon.host', 'open.tube', 'share.tube', # mostly French and German language.
'tube.tr4sk.me', 'videos.elbinario.net', # These have only been semi-vetted, and so should be under
'hkvideo.live', # continuous review.
'peertube.snargol.com', 'tube.22decembre.eu', # Also see https://peertube_isolation.frama.io/list/ for
'tube.fabrigli.fr', 'libretube.net', 'libre.video', # adversarial instances. Nothing in that list should be
'peertube.linuxrocks.online', 'spacepub.space', # in the defaults below.
'video.ploud.jp', 'video.omniatv.com', peerTubeSites = ('share.tube',
'peertube.servebeer.com', 'tube.22decembre.eu',
'tube.tchncs.de', 'tubee.fr', 'video.alternanet.fr', 'libre.video',
'devtube.dev-wiki.de', 'video.samedi.pm', 'peertube.linuxrocks.online',
'video.irem.univ-paris-diderot.fr', 'spacepub.space',
'peertube.openstreetmap.fr', 'video.antopie.org', 'tube.tchncs.de',
'scitech.video', 'tube.4aem.com', 'video.ploud.fr', 'video.irem.univ-paris-diderot.fr',
'peervideo.net', 'video.valme.io', 'peertube.openstreetmap.fr',
'videos.pair2jeux.tube', 'video.antopie.org',
'vault.mle.party', 'hostyour.tv', 'scitech.video',
'diode.zone', 'visionon.tv', 'video.ploud.fr',
'artitube.artifaille.fr', 'peertube.fr', 'diode.zone',
'peertube.live', 'kolektiva.media', 'visionon.tv',
'tube.ac-lyon.fr', 'www.yiny.org', 'betamax.video', 'peertube.fr',
'tube.piweb.be', 'pe.ertu.be', 'peertube.social', 'peertube.live',
'videos.lescommuns.org', 'peertube.nogafa.org', 'kolektiva.media',
'skeptikon.fr', 'video.tedomum.net', 'betamax.video',
'tube.p2p.legal', 'tilvids.com', 'peertube.social',
'sikke.fi', 'exode.me', 'peertube.video') 'videos.lescommuns.org',
'video.tedomum.net',
'tilvids.com',
'exode.me',
'peertube.video')
for site in peerTubeSites: for site in peerTubeSites:
if '"https://' + site in content: site = site.strip()
url = content.split('"https://' + site)[1] if not site:
continue
if len(site) < 5:
continue
if '.' not in site:
continue
siteStr = site
if site.startswith('http://'):
site = site.replace('http://', '')
elif site.startswith('https://'):
site = site.replace('https://', '')
if site.endswith('.onion') or site.endswith('.i2p'):
siteStr = 'http://' + site
else:
siteStr = 'https://' + site
siteStr = '"' + siteStr
if siteStr in content:
url = content.split(siteStr)[1]
if '"' in url: if '"' in url:
url = url.split('"')[0].replace('/watch/', '/embed/') url = url.split('"')[0].replace('/watch/', '/embed/')
content = \ content = \
@ -216,9 +265,11 @@ def _addEmbeddedVideo(translate: {}, content: str,
return content return content
def addEmbeddedElements(translate: {}, content: str) -> str: def addEmbeddedElements(translate: {}, content: str,
peertubeInstances: []) -> str:
"""Adds embedded elements for various media types """Adds embedded elements for various media types
""" """
content = _addEmbeddedVideoFromSites(translate, content) content = _addEmbeddedVideoFromSites(translate, content,
peertubeInstances)
content = _addEmbeddedAudio(translate, content) content = _addEmbeddedAudio(translate, content)
return _addEmbeddedVideo(translate, content) return _addEmbeddedVideo(translate, content)

View File

@ -37,7 +37,7 @@ def htmlModeration(cssCache: {}, defaultTimeline: str,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, moderationActionStr: str, authorized: bool, moderationActionStr: str,
theme: str) -> str: theme: str, peertubeInstances: []) -> 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
""" """
@ -51,7 +51,8 @@ def htmlModeration(cssCache: {}, defaultTimeline: str,
newswire, False, False, positiveVoting, newswire, False, False, positiveVoting,
showPublishAsIcon, fullWidthTimelineButtonHeader, showPublishAsIcon, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, moderationActionStr, theme) authorized, moderationActionStr, theme,
peertubeInstances)
def htmlAccountInfo(cssCache: {}, translate: {}, def htmlAccountInfo(cssCache: {}, translate: {},

View File

@ -39,6 +39,7 @@ def htmlPersonOptions(defaultTimeline: str,
ssbAddress: str, ssbAddress: str,
blogAddress: str, blogAddress: str,
toxAddress: str, toxAddress: str,
briarAddress: str,
jamiAddress: str, jamiAddress: str,
PGPpubKey: str, PGPpubKey: str,
PGPfingerprint: str, PGPfingerprint: str,
@ -141,6 +142,15 @@ def htmlPersonOptions(defaultTimeline: str,
if toxAddress: if toxAddress:
optionsStr += \ optionsStr += \
'<p class="imText">Tox: ' + removeHtml(toxAddress) + '</p>\n' '<p class="imText">Tox: ' + removeHtml(toxAddress) + '</p>\n'
if briarAddress:
if briarAddress.startswith('briar://'):
optionsStr += \
'<p class="imText">' + \
removeHtml(briarAddress) + '</p>\n'
else:
optionsStr += \
'<p class="imText">briar://' + \
removeHtml(briarAddress) + '</p>\n'
if jamiAddress: if jamiAddress:
optionsStr += \ optionsStr += \
'<p class="imText">Jami: ' + removeHtml(jamiAddress) + '</p>\n' '<p class="imText">Jami: ' + removeHtml(jamiAddress) + '</p>\n'

View File

@ -1076,6 +1076,7 @@ def individualPostAsHtml(allowDownloads: bool,
httpPrefix: str, projectVersion: str, httpPrefix: str, projectVersion: str,
boxName: str, YTReplacementDomain: str, boxName: str, YTReplacementDomain: str,
showPublishedDateOnly: bool, showPublishedDateOnly: bool,
peertubeInstances: [],
showRepeats=True, showRepeats=True,
showIcons=False, showIcons=False,
manuallyApprovesFollowers=False, manuallyApprovesFollowers=False,
@ -1483,7 +1484,8 @@ def individualPostAsHtml(allowDownloads: bool,
if not postIsSensitive: if not postIsSensitive:
contentStr = objectContent + attachmentStr contentStr = objectContent + attachmentStr
contentStr = addEmbeddedElements(translate, contentStr) contentStr = addEmbeddedElements(translate, contentStr,
peertubeInstances)
contentStr = insertQuestion(baseDir, translate, contentStr = insertQuestion(baseDir, translate,
nickname, domain, port, nickname, domain, port,
contentStr, postJsonObject, contentStr, postJsonObject,
@ -1499,7 +1501,8 @@ def individualPostAsHtml(allowDownloads: bool,
# get the content warning text # get the content warning text
cwContentStr = objectContent + attachmentStr cwContentStr = objectContent + attachmentStr
if not isPatch: if not isPatch:
cwContentStr = addEmbeddedElements(translate, cwContentStr) cwContentStr = addEmbeddedElements(translate, cwContentStr,
peertubeInstances)
cwContentStr = \ cwContentStr = \
insertQuestion(baseDir, translate, nickname, domain, port, insertQuestion(baseDir, translate, nickname, domain, port,
cwContentStr, postJsonObject, pageNumber) cwContentStr, postJsonObject, pageNumber)
@ -1571,7 +1574,8 @@ def htmlIndividualPost(cssCache: {},
postJsonObject: {}, httpPrefix: str, postJsonObject: {}, httpPrefix: str,
projectVersion: str, likedBy: str, projectVersion: str, likedBy: str,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool) -> str: showPublishedDateOnly: bool,
peertubeInstances: []) -> str:
"""Show an individual post as html """Show an individual post as html
""" """
postStr = '' postStr = ''
@ -1611,6 +1615,7 @@ def htmlIndividualPost(cssCache: {},
httpPrefix, projectVersion, 'inbox', httpPrefix, projectVersion, 'inbox',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
False, authorized, False, False, False) False, authorized, False, False, False)
messageId = removeIdEnding(postJsonObject['id']) messageId = removeIdEnding(postJsonObject['id'])
@ -1636,6 +1641,7 @@ def htmlIndividualPost(cssCache: {},
httpPrefix, projectVersion, 'inbox', httpPrefix, projectVersion, 'inbox',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
False, authorized, False, authorized,
False, False, False) + postStr False, False, False) + postStr
@ -1664,6 +1670,7 @@ def htmlIndividualPost(cssCache: {},
httpPrefix, projectVersion, 'inbox', httpPrefix, projectVersion, 'inbox',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
False, authorized, False, authorized,
False, False, False) False, False, False)
cssFilename = baseDir + '/epicyon-profile.css' cssFilename = baseDir + '/epicyon-profile.css'
@ -1680,7 +1687,8 @@ def htmlPostReplies(cssCache: {},
nickname: str, domain: str, port: int, repliesJson: {}, nickname: str, domain: str, port: int, repliesJson: {},
httpPrefix: str, projectVersion: str, httpPrefix: str, projectVersion: str,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool) -> str: showPublishedDateOnly: bool,
peertubeInstances: []) -> str:
"""Show the replies to an individual post as html """Show the replies to an individual post as html
""" """
repliesStr = '' repliesStr = ''
@ -1696,6 +1704,7 @@ def htmlPostReplies(cssCache: {},
httpPrefix, projectVersion, 'inbox', httpPrefix, projectVersion, 'inbox',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
False, False, False, False, False) False, False, False, False, False)
cssFilename = baseDir + '/epicyon-profile.css' cssFilename = baseDir + '/epicyon-profile.css'

View File

@ -8,6 +8,7 @@ __status__ = "Production"
import os import os
from pprint import pprint from pprint import pprint
from utils import hasUsersPath
from utils import getFullDomain from utils import getFullDomain
from utils import isDormant from utils import isDormant
from utils import getNicknameFromActor from utils import getNicknameFromActor
@ -33,6 +34,7 @@ from pgp import getEmailAddress
from pgp import getPGPfingerprint from pgp import getPGPfingerprint
from pgp import getPGPpubKey from pgp import getPGPpubKey
from tox import getToxAddress from tox import getToxAddress
from briar import getBriarAddress
from jami import getJamiAddress from jami import getJamiAddress
from filters import isFiltered from filters import isFiltered
from webapp_frontscreen import htmlFrontScreen from webapp_frontscreen import htmlFrontScreen
@ -58,14 +60,11 @@ def htmlProfileAfterSearch(cssCache: {},
debug: bool, projectVersion: str, debug: bool, projectVersion: str,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool, showPublishedDateOnly: bool,
defaultTimeline: str) -> str: defaultTimeline: str,
peertubeInstances: []) -> str:
"""Show a profile page after a search for a fediverse address """Show a profile page after a search for a fediverse address
""" """
if '/users/' in profileHandle or \ if hasUsersPath(profileHandle) or '/@' in profileHandle:
'/accounts/' in profileHandle or \
'/channel/' in profileHandle or \
'/profile/' in profileHandle or \
'/@' in profileHandle:
searchNickname = getNicknameFromActor(profileHandle) searchNickname = getNicknameFromActor(profileHandle)
searchDomain, searchPort = getDomainFromActor(profileHandle) searchDomain, searchPort = getDomainFromActor(profileHandle)
else: else:
@ -279,6 +278,7 @@ def htmlProfileAfterSearch(cssCache: {},
httpPrefix, projectVersion, 'inbox', httpPrefix, projectVersion, 'inbox',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
False, False, False, False, False) False, False, False, False, False)
i += 1 i += 1
if i >= 20: if i >= 20:
@ -372,6 +372,7 @@ def htmlProfile(rssIconAtTop: bool,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool, showPublishedDateOnly: bool,
newswire: {}, theme: str, dormantMonths: int, newswire: {}, theme: str, dormantMonths: int,
peertubeInstances: [],
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
@ -443,9 +444,11 @@ def htmlProfile(rssIconAtTop: bool,
matrixAddress = getMatrixAddress(profileJson) matrixAddress = getMatrixAddress(profileJson)
ssbAddress = getSSBAddress(profileJson) ssbAddress = getSSBAddress(profileJson)
toxAddress = getToxAddress(profileJson) toxAddress = getToxAddress(profileJson)
briarAddress = getBriarAddress(profileJson)
jamiAddress = getJamiAddress(profileJson) jamiAddress = getJamiAddress(profileJson)
if donateUrl or xmppAddress or matrixAddress or \ if donateUrl or xmppAddress or matrixAddress or \
ssbAddress or toxAddress or jamiAddress or PGPpubKey or \ ssbAddress or toxAddress or briarAddress or \
jamiAddress or PGPpubKey or \
PGPfingerprint or emailAddress: PGPfingerprint or emailAddress:
donateSection = '<div class="container">\n' donateSection = '<div class="container">\n'
donateSection += ' <center>\n' donateSection += ' <center>\n'
@ -473,6 +476,15 @@ def htmlProfile(rssIconAtTop: bool,
donateSection += \ donateSection += \
'<p>Tox: <label class="toxaddr">' + \ '<p>Tox: <label class="toxaddr">' + \
toxAddress + '</label></p>\n' toxAddress + '</label></p>\n'
if briarAddress:
if briarAddress.startswith('briar://'):
donateSection += \
'<p><label class="toxaddr">' + \
briarAddress + '</label></p>\n'
else:
donateSection += \
'<p>briar://<label class="toxaddr">' + \
briarAddress + '</label></p>\n'
if jamiAddress: if jamiAddress:
donateSection += \ donateSection += \
'<p>Jami: <label class="toxaddr">' + \ '<p>Jami: <label class="toxaddr">' + \
@ -628,7 +640,8 @@ def htmlProfile(rssIconAtTop: bool,
session, wfRequest, personCache, session, wfRequest, personCache,
projectVersion, projectVersion,
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly) + licenseStr showPublishedDateOnly,
peertubeInstances) + licenseStr
elif selected == 'following': elif selected == 'following':
profileStr += \ profileStr += \
_htmlProfileFollowing(translate, baseDir, httpPrefix, _htmlProfileFollowing(translate, baseDir, httpPrefix,
@ -674,7 +687,8 @@ def _htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
session, wfRequest: {}, personCache: {}, session, wfRequest: {}, personCache: {},
projectVersion: str, projectVersion: str,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool) -> str: showPublishedDateOnly: bool,
peertubeInstances: []) -> 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
""" """
@ -712,6 +726,7 @@ def _htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
httpPrefix, projectVersion, 'inbox', httpPrefix, projectVersion, 'inbox',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
False, False, False, True, False) False, False, False, True, False)
if postStr: if postStr:
profileStr += postStr + separatorStr profileStr += postStr + separatorStr
@ -833,7 +848,8 @@ def _htmlProfileShares(actor: str, translate: {},
def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str, def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
domain: str, port: int, httpPrefix: str, domain: str, port: int, httpPrefix: str,
defaultTimeline: str, theme: str) -> str: defaultTimeline: str, theme: str,
peertubeInstances: []) -> str:
"""Shows the edit profile screen """Shows the edit profile screen
""" """
imageFormats = getImageFormats() imageFormats = getImageFormats()
@ -873,6 +889,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
ssbAddress = '' ssbAddress = ''
blogAddress = '' blogAddress = ''
toxAddress = '' toxAddress = ''
briarAddress = ''
manuallyApprovesFollowers = '' manuallyApprovesFollowers = ''
actorJson = loadJson(actorFilename) actorJson = loadJson(actorFilename)
if actorJson: if actorJson:
@ -882,6 +899,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
ssbAddress = getSSBAddress(actorJson) ssbAddress = getSSBAddress(actorJson)
blogAddress = getBlogAddress(actorJson) blogAddress = getBlogAddress(actorJson)
toxAddress = getToxAddress(actorJson) toxAddress = getToxAddress(actorJson)
briarAddress = getBriarAddress(actorJson)
jamiAddress = getJamiAddress(actorJson) jamiAddress = getJamiAddress(actorJson)
emailAddress = getEmailAddress(actorJson) emailAddress = getEmailAddress(actorJson)
PGPpubKey = getPGPpubKey(actorJson) PGPpubKey = getPGPpubKey(actorJson)
@ -1029,6 +1047,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
themesDropdown = '' themesDropdown = ''
instanceStr = '' instanceStr = ''
editorsStr = '' editorsStr = ''
peertubeStr = ''
adminNickname = getConfigParam(baseDir, 'admin') adminNickname = getConfigParam(baseDir, 'admin')
if adminNickname: if adminNickname:
@ -1145,6 +1164,21 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
'<option value="' + themeName + '<option value="' + themeName +
'" selected>') '" selected>')
peertubeStr = \
' <br><b><label class="labels">' + \
translate['Peertube Instances'] + '</label></b>\n'
idx = 'Show video previews for the following Peertube sites.'
peertubeStr += \
' <br><label class="labels">' + \
translate[idx] + '</label>\n'
peertubeInstancesStr = ''
for url in peertubeInstances:
peertubeInstancesStr += url + '\n'
peertubeStr += \
' <textarea id="message" name="ptInstances" ' + \
'style="height:200px">' + peertubeInstancesStr + \
'</textarea>\n'
editProfileForm = htmlHeaderWithExternalStyle(cssFilename) editProfileForm = htmlHeaderWithExternalStyle(cssFilename)
# top banner # top banner
@ -1220,6 +1254,11 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
' <input type="text" name="toxAddress" value="' + \ ' <input type="text" name="toxAddress" value="' + \
toxAddress + '">\n' toxAddress + '">\n'
editProfileForm += '<label class="labels">Briar</label><br>\n'
editProfileForm += \
' <input type="text" name="briarAddress" value="' + \
briarAddress + '">\n'
editProfileForm += '<label class="labels">Jami</label><br>\n' editProfileForm += '<label class="labels">Jami</label><br>\n'
editProfileForm += \ editProfileForm += \
' <input type="text" name="jamiAddress" value="' + \ ' <input type="text" name="jamiAddress" value="' + \
@ -1436,7 +1475,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
editProfileForm += ' <label class="labels">' + \ editProfileForm += ' <label class="labels">' + \
translate[idx] + '</label>\n' translate[idx] + '</label>\n'
editProfileForm += skillsStr + themesDropdown editProfileForm += skillsStr + themesDropdown
editProfileForm += moderatorsStr + editorsStr editProfileForm += moderatorsStr + editorsStr + peertubeStr
editProfileForm += ' </div>\n' + instanceStr editProfileForm += ' </div>\n' + instanceStr
editProfileForm += ' <div class="container">\n' editProfileForm += ' <div class="container">\n'
editProfileForm += ' <b><label class="labels">' + \ editProfileForm += ' <b><label class="labels">' + \

View File

@ -506,7 +506,8 @@ def htmlHistorySearch(cssCache: {}, translate: {}, baseDir: str,
personCache: {}, personCache: {},
port: int, port: int,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool) -> str: showPublishedDateOnly: bool,
peertubeInstances: []) -> 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('!'):
@ -579,6 +580,7 @@ def htmlHistorySearch(cssCache: {}, translate: {}, baseDir: str,
'search', 'search',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
showIndividualPostIcons, showIndividualPostIcons,
showIndividualPostIcons, showIndividualPostIcons,
False, False, False) False, False, False)
@ -599,7 +601,8 @@ def htmlHashtagSearch(cssCache: {},
session, wfRequest: {}, personCache: {}, session, wfRequest: {}, personCache: {},
httpPrefix: str, projectVersion: str, httpPrefix: str, projectVersion: str,
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool) -> str: showPublishedDateOnly: bool,
peertubeInstances: []) -> 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('#'):
@ -745,6 +748,7 @@ def htmlHashtagSearch(cssCache: {},
'search', 'search',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
showRepeats, showIcons, showRepeats, showIcons,
manuallyApprovesFollowers, manuallyApprovesFollowers,
showPublicOnly, showPublicOnly,

View File

@ -61,7 +61,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, authorized: bool,
moderationActionStr: str, moderationActionStr: str,
theme: str) -> str: theme: str,
peertubeInstances: []) -> str:
"""Show the timeline as html """Show the timeline as html
""" """
enableTimingLog = False enableTimingLog = False
@ -566,6 +567,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
boxName, boxName,
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
peertubeInstances,
boxName != 'dm', boxName != 'dm',
showIndividualPostIcons, showIndividualPostIcons,
manuallyApproveFollowers, manuallyApproveFollowers,
@ -720,7 +722,8 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the shares timeline as html """Show the shares timeline as html
""" """
manuallyApproveFollowers = \ manuallyApproveFollowers = \
@ -739,7 +742,7 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
positiveVoting, showPublishAsIcon, positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlInbox(cssCache: {}, defaultTimeline: str, def htmlInbox(cssCache: {}, defaultTimeline: str,
@ -757,7 +760,8 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the inbox as html """Show the inbox as html
""" """
manuallyApproveFollowers = \ manuallyApproveFollowers = \
@ -776,7 +780,7 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
positiveVoting, showPublishAsIcon, positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlBookmarks(cssCache: {}, defaultTimeline: str, def htmlBookmarks(cssCache: {}, defaultTimeline: str,
@ -794,7 +798,8 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the bookmarks as html """Show the bookmarks as html
""" """
manuallyApproveFollowers = \ manuallyApproveFollowers = \
@ -813,7 +818,7 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
positiveVoting, showPublishAsIcon, positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlEvents(cssCache: {}, defaultTimeline: str, def htmlEvents(cssCache: {}, defaultTimeline: str,
@ -831,7 +836,8 @@ def htmlEvents(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the events as html """Show the events as html
""" """
manuallyApproveFollowers = \ manuallyApproveFollowers = \
@ -850,7 +856,7 @@ def htmlEvents(cssCache: {}, defaultTimeline: str,
positiveVoting, showPublishAsIcon, positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlInboxDMs(cssCache: {}, defaultTimeline: str, def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
@ -868,7 +874,8 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the DM timeline as html """Show the DM timeline as html
""" """
return htmlTimeline(cssCache, defaultTimeline, return htmlTimeline(cssCache, defaultTimeline,
@ -882,7 +889,7 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
showPublishAsIcon, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlInboxReplies(cssCache: {}, defaultTimeline: str, def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
@ -900,7 +907,8 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the replies timeline as html """Show the replies timeline as html
""" """
return htmlTimeline(cssCache, defaultTimeline, return htmlTimeline(cssCache, defaultTimeline,
@ -915,7 +923,7 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
positiveVoting, showPublishAsIcon, positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlInboxMedia(cssCache: {}, defaultTimeline: str, def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
@ -933,7 +941,8 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the media timeline as html """Show the media timeline as html
""" """
return htmlTimeline(cssCache, defaultTimeline, return htmlTimeline(cssCache, defaultTimeline,
@ -948,7 +957,7 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
positiveVoting, showPublishAsIcon, positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlInboxBlogs(cssCache: {}, defaultTimeline: str, def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
@ -966,7 +975,8 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the blogs timeline as html """Show the blogs timeline as html
""" """
return htmlTimeline(cssCache, defaultTimeline, return htmlTimeline(cssCache, defaultTimeline,
@ -981,7 +991,7 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
positiveVoting, showPublishAsIcon, positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlInboxFeatures(cssCache: {}, defaultTimeline: str, def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
@ -1000,7 +1010,8 @@ def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, authorized: bool,
theme: str) -> str: theme: str,
peertubeInstances: []) -> str:
"""Show the features timeline as html """Show the features timeline as html
""" """
return htmlTimeline(cssCache, defaultTimeline, return htmlTimeline(cssCache, defaultTimeline,
@ -1015,7 +1026,7 @@ def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
positiveVoting, showPublishAsIcon, positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlInboxNews(cssCache: {}, defaultTimeline: str, def htmlInboxNews(cssCache: {}, defaultTimeline: str,
@ -1033,7 +1044,8 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the news timeline as html """Show the news timeline as html
""" """
return htmlTimeline(cssCache, defaultTimeline, return htmlTimeline(cssCache, defaultTimeline,
@ -1048,7 +1060,7 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
positiveVoting, showPublishAsIcon, positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop, iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme) authorized, None, theme, peertubeInstances)
def htmlOutbox(cssCache: {}, defaultTimeline: str, def htmlOutbox(cssCache: {}, defaultTimeline: str,
@ -1066,7 +1078,8 @@ def htmlOutbox(cssCache: {}, defaultTimeline: str,
iconsAsButtons: bool, iconsAsButtons: bool,
rssIconAtTop: bool, rssIconAtTop: bool,
publishButtonAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str) -> str: authorized: bool, theme: str,
peertubeInstances: []) -> str:
"""Show the Outbox as html """Show the Outbox as html
""" """
manuallyApproveFollowers = \ manuallyApproveFollowers = \
@ -1082,4 +1095,4 @@ 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) authorized, None, theme, peertubeInstances)