Merge branch 'main' of gitlab.com:bashrc2/epicyon

main
Bob Mottram 2021-10-28 21:49:02 +01:00
commit 63e6dbc0db
6 changed files with 187 additions and 55 deletions

View File

@ -237,6 +237,7 @@ from categories import updateHashtagCategories
from languages import getActorLanguages from languages import getActorLanguages
from languages import setActorLanguages from languages import setActorLanguages
from like import updateLikesCollection from like import updateLikesCollection
from utils import malformedCiphertext
from utils import hasActor from utils import hasActor
from utils import setReplyIntervalHours from utils import setReplyIntervalHours
from utils import canReplyTo from utils import canReplyTo
@ -1490,10 +1491,15 @@ class PubServer(BaseHTTPRequestHandler):
# save the json for later queue processing # save the json for later queue processing
messageBytesDecoded = messageBytes.decode('utf-8') messageBytesDecoded = messageBytes.decode('utf-8')
if malformedCiphertext(messageBytesDecoded):
print('WARN: post contains malformed ciphertext ' +
str(originalMessageJson))
return 4
if containsInvalidLocalLinks(messageBytesDecoded): if containsInvalidLocalLinks(messageBytesDecoded):
print('WARN: post contains invalid local links ' + print('WARN: post contains invalid local links ' +
str(originalMessageJson)) str(originalMessageJson))
return 4 return 5
self.server.blockedCacheLastUpdated = \ self.server.blockedCacheLastUpdated = \
updateBlockedCache(self.server.baseDir, updateBlockedCache(self.server.baseDir,
@ -5868,6 +5874,14 @@ class PubServer(BaseHTTPRequestHandler):
actorJson['featuredTags'] = \ actorJson['featuredTags'] = \
actorJson['id'] + '/collections/tags' actorJson['id'] + '/collections/tags'
randomizeActorImages(actorJson) randomizeActorImages(actorJson)
# add an updated timestamp to the actor
updatedTime = datetime.datetime.utcnow()
actorJson['updated'] = \
updatedTime.strftime("%Y-%m-%dT%H:%M:%SZ")
# add updated timestamp to avatar and banner
actorJson['icon']['updated'] = actorJson['updated']
actorJson['image']['updated'] = actorJson['updated']
# save the actor
saveJson(actorJson, actorFilename) saveJson(actorJson, actorFilename)
webfingerUpdate(baseDir, webfingerUpdate(baseDir,
nickname, domain, nickname, domain,
@ -14402,13 +14416,13 @@ class PubServer(BaseHTTPRequestHandler):
if authorized and \ if authorized and \
'/users/' in self.path and \ '/users/' in self.path and \
'?editblogpost=' in self.path and \ '?editblogpost=' in self.path and \
'?actor=' in self.path: ';actor=' in self.path:
messageId = self.path.split('?editblogpost=')[1] messageId = self.path.split('?editblogpost=')[1]
if '?' in messageId: if ';' in messageId:
messageId = messageId.split('?')[0] messageId = messageId.split(';')[0]
actor = self.path.split('?actor=')[1] actor = self.path.split(';actor=')[1]
if '?' in actor: if ';' in actor:
actor = actor.split('?')[0] actor = actor.split(';')[0]
nickname = getNicknameFromActor(self.path.split('?')[0]) nickname = getNicknameFromActor(self.path.split('?')[0])
if nickname == actor: if nickname == actor:
postUrl = \ postUrl = \

View File

@ -3204,8 +3204,7 @@ def _checkJsonSignature(baseDir: str, queueJson: {}) -> (bool, bool):
baseDir + '/accounts/unknownContexts.txt' baseDir + '/accounts/unknownContexts.txt'
unknownContext = str(originalJson['@context']) unknownContext = str(originalJson['@context'])
print('unrecognized @context: ' + print('unrecognized @context: ' + unknownContext)
unknownContext)
alreadyUnknown = False alreadyUnknown = False
if os.path.isfile(unknownContextsFile): if os.path.isfile(unknownContextsFile):
@ -3217,8 +3216,7 @@ def _checkJsonSignature(baseDir: str, queueJson: {}) -> (bool, bool):
with open(unknownContextsFile, 'a+') as unknownFile: with open(unknownContextsFile, 'a+') as unknownFile:
unknownFile.write(unknownContext + '\n') unknownFile.write(unknownContext + '\n')
else: else:
print('Unrecognized jsonld signature type: ' + print('Unrecognized jsonld signature type: ' + jwebsigType)
jwebsigType)
unknownSignaturesFile = \ unknownSignaturesFile = \
baseDir + '/accounts/unknownJsonSignatures.txt' baseDir + '/accounts/unknownJsonSignatures.txt'

View File

@ -444,9 +444,11 @@ def _isPublicFeedPost(item: {}, personPosts: {}, debug: bool) -> bool:
if debug: if debug:
print('No type') print('No type')
return False return False
if item['type'] != 'Create' and item['type'] != 'Announce': if item['type'] != 'Create' and \
item['type'] != 'Announce' and \
item['type'] != 'Note':
if debug: if debug:
print('Not Create type') print('Not a Create/Note/Announce type')
return False return False
if item.get('object'): if item.get('object'):
if isinstance(item['object'], dict): if isinstance(item['object'], dict):
@ -463,19 +465,27 @@ def _isPublicFeedPost(item: {}, personPosts: {}, debug: bool) -> bool:
if debug: if debug:
print('object is not a dict or string') print('object is not a dict or string')
return False return False
elif item['type'] == 'Note':
if not item.get('published'):
if debug:
print('No published attribute')
return False
if not personPosts.get(item['id']): if not personPosts.get(item['id']):
thisItem = item
if item.get('object'):
thisItem = item['object']
# check that this is a public post # check that this is a public post
# #Public should appear in the "to" list # #Public should appear in the "to" list
if isinstance(item['object'], dict): if isinstance(thisItem, dict):
if item['object'].get('to'): if thisItem.get('to'):
isPublic = False isPublic = False
for recipient in item['object']['to']: for recipient in thisItem['to']:
if recipient.endswith('#Public'): if recipient.endswith('#Public'):
isPublic = True isPublic = True
break break
if not isPublic: if not isPublic:
return False return False
elif isinstance(item['object'], str): elif isinstance(thisItem, str) or item['type'] == 'Note':
if item.get('to'): if item.get('to'):
isPublic = False isPublic = False
for recipient in item['to']: for recipient in item['to']:
@ -570,6 +580,10 @@ def _getPosts(session, outboxUrl: str, maxPosts: int,
if not _isPublicFeedPost(item, personPosts, debug): if not _isPublicFeedPost(item, personPosts, debug):
continue continue
thisItem = item
if item['type'] != 'Note':
thisItem = item['object']
content = getBaseContentFromPost(item, systemLanguage) content = getBaseContentFromPost(item, systemLanguage)
content = content.replace(''', "'") content = content.replace(''', "'")
@ -579,9 +593,11 @@ def _getPosts(session, outboxUrl: str, maxPosts: int,
inReplyTo = '' inReplyTo = ''
attachment = [] attachment = []
sensitive = False sensitive = False
if isinstance(item['object'], dict): if isinstance(thisItem, dict):
if item['object'].get('tag'): if thisItem.get('tag'):
for tagItem in item['object']['tag']: for tagItem in thisItem['tag']:
if not tagItem.get('type'):
continue
tagType = tagItem['type'].lower() tagType = tagItem['type'].lower()
if tagType == 'emoji': if tagType == 'emoji':
if tagItem.get('name') and tagItem.get('icon'): if tagItem.get('name') and tagItem.get('icon'):
@ -609,25 +625,25 @@ def _getPosts(session, outboxUrl: str, maxPosts: int,
print('max emojis reached') print('max emojis reached')
continue continue
if item['object'].get('summary'): if thisItem.get('summary'):
if item['object']['summary']: if thisItem['summary']:
summary = item['object']['summary'] summary = thisItem['summary']
if item['object'].get('inReplyTo'): if thisItem.get('inReplyTo'):
if item['object']['inReplyTo']: if thisItem['inReplyTo']:
if isinstance(item['object']['inReplyTo'], str): if isinstance(thisItem['inReplyTo'], str):
# No replies to non-permitted domains # No replies to non-permitted domains
if not urlPermitted(item['object']['inReplyTo'], if not urlPermitted(thisItem['inReplyTo'],
federationList): federationList):
if debug: if debug:
print('url not permitted ' + print('url not permitted ' +
item['object']['inReplyTo']) thisItem['inReplyTo'])
continue continue
inReplyTo = item['object']['inReplyTo'] inReplyTo = thisItem['inReplyTo']
if item['object'].get('attachment'): if thisItem.get('attachment'):
if item['object']['attachment']: if thisItem['attachment']:
for attach in item['object']['attachment']: for attach in thisItem['attachment']:
if attach.get('name') and attach.get('url'): if attach.get('name') and attach.get('url'):
# no attachments from non-permitted domains # no attachments from non-permitted domains
if urlPermitted(attach['url'], if urlPermitted(attach['url'],
@ -640,8 +656,8 @@ def _getPosts(session, outboxUrl: str, maxPosts: int,
attach['url']) attach['url'])
sensitive = False sensitive = False
if item['object'].get('sensitive'): if thisItem.get('sensitive'):
sensitive = item['object']['sensitive'] sensitive = thisItem['sensitive']
if content: if content:
if simple: if simple:
@ -773,6 +789,8 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int,
if item['object'].get('tag'): if item['object'].get('tag'):
for tagItem in item['object']['tag']: for tagItem in item['object']['tag']:
if not tagItem.get('type'):
continue
tagType = tagItem['type'].lower() tagType = tagItem['type'].lower()
if tagType == 'mention': if tagType == 'mention':
if tagItem.get('href'): if tagItem.get('href'):
@ -841,9 +859,10 @@ def _getPostsForBlockedDomains(baseDir: str,
if item['object'].get('tag'): if item['object'].get('tag'):
for tagItem in item['object']['tag']: for tagItem in item['object']['tag']:
if not tagItem.get('type'):
continue
tagType = tagItem['type'].lower() tagType = tagItem['type'].lower()
if tagType == 'mention': if tagType == 'mention' and tagItem.get('href'):
if tagItem.get('href'):
postDomain, postPort = \ postDomain, postPort = \
getDomainFromActor(tagItem['href']) getDomainFromActor(tagItem['href'])
if isBlockedDomain(baseDir, postDomain): if isBlockedDomain(baseDir, postDomain):

View File

@ -2537,6 +2537,16 @@ def isPGPEncrypted(content: str) -> bool:
return False return False
def malformedCiphertext(content: str) -> bool:
"""Returns true if the given content contains a malformed key
"""
if '----BEGIN ' in content or '----END ' in content:
if not containsPGPPublicKey(content) and \
not isPGPEncrypted(content):
return True
return False
def loadTranslationsFromFile(baseDir: str, language: str) -> ({}, str): def loadTranslationsFromFile(baseDir: str, language: str) -> ({}, str):
"""Returns the translations dictionary """Returns the translations dictionary
""" """

View File

@ -283,16 +283,34 @@ def htmlProfileAfterSearch(cssCache: {},
if isCreateInsideAnnounce(item): if isCreateInsideAnnounce(item):
isAnnouncedFeedItem = True isAnnouncedFeedItem = True
item = item['object'] item = item['object']
if not item.get('actor'):
continue
if not isAnnouncedFeedItem and item['actor'] != personUrl:
continue
if not item.get('type'): if not item.get('type'):
continue continue
if item['type'] == 'Create': if item['type'] == 'Create':
if not hasObjectDict(item): if not hasObjectDict(item):
continue continue
if item['type'] != 'Create' and item['type'] != 'Announce': if item['type'] != 'Create' and item['type'] != 'Announce':
if item['type'] != 'Note':
continue
if not item.get('to'):
continue
if not item.get('id'):
continue
# wrap in create
cc = []
if item.get('cc'):
cc = item['cc']
newItem = {
'object': item,
'to': item['to'],
'cc': cc,
'id': item['id'],
'actor': personUrl,
'type': 'Create'
}
item = newItem
if not item.get('actor'):
continue
if not isAnnouncedFeedItem and item['actor'] != personUrl:
continue continue
profileStr += \ profileStr += \

View File

@ -159,12 +159,22 @@ def createWebfingerEndpoint(nickname: str, domain: str, port: int,
profilePageHref = httpPrefix + '://' + domain + \ profilePageHref = httpPrefix + '://' + domain + \
'/about/more?instance_actor=true' '/about/more?instance_actor=true'
personLink = httpPrefix + "://" + domain + "/@" + personName
account = { account = {
"aliases": [ "aliases": [
httpPrefix + "://" + domain + "/@" + personName, personLink,
personId personId
], ],
"links": [ "links": [
{
"href": personLink + "/avatar.png",
"rel": "http://webfinger.net/rel/avatar",
"type": "image/png"
},
{
"href": httpPrefix + "://" + domain + "/blog/" + personName,
"rel": "http://webfinger.net/rel/blog"
},
{ {
"href": profilePageHref, "href": profilePageHref,
"rel": "http://webfinger.net/rel/profile-page", "rel": "http://webfinger.net/rel/profile-page",
@ -242,7 +252,6 @@ def webfingerLookup(path: str, baseDir: str,
return None return None
if '&' in handle: if '&' in handle:
handle = handle.split('&')[0].strip() handle = handle.split('&')[0].strip()
if debug:
print('DEBUG: WEBFINGER handle with & removed ' + handle) print('DEBUG: WEBFINGER handle with & removed ' + handle)
if '@' not in handle: if '@' not in handle:
if debug: if debug:
@ -283,6 +292,64 @@ def webfingerLookup(path: str, baseDir: str,
return wfJson return wfJson
def _webfingerUpdateAvatar(wfJson: {}, actorJson: {}) -> bool:
"""Updates the avatar image link
"""
found = False
avatarUrl = actorJson['icon']['url']
mediaType = actorJson['icon']['mediaType']
for link in wfJson['links']:
if not link.get('rel'):
continue
if not link['rel'].endswith('://webfinger.net/rel/avatar'):
continue
found = True
if link['href'] != avatarUrl or link['type'] != mediaType:
link['href'] = avatarUrl
link['type'] = mediaType
return True
break
if found:
return False
wfJson['links'].append({
"href": avatarUrl,
"rel": "http://webfinger.net/rel/avatar",
"type": mediaType
})
return True
def _webfingerAddBlogLink(wfJson: {}, actorJson: {}) -> bool:
"""Adds a blog link to webfinger if needed
"""
found = False
if '/users/' in actorJson['id']:
blogUrl = \
actorJson['id'].split('/users/')[0] + '/blog/' + \
actorJson['id'].split('/users/')[1]
else:
blogUrl = \
actorJson['id'].split('/@')[0] + '/blog/' + \
actorJson['id'].split('/@')[1]
for link in wfJson['links']:
if not link.get('rel'):
continue
if not link['rel'].endswith('://webfinger.net/rel/blog'):
continue
found = True
if link['href'] != blogUrl:
link['href'] = blogUrl
return True
break
if found:
return False
wfJson['links'].append({
"href": blogUrl,
"rel": "http://webfinger.net/rel/blog"
})
return True
def _webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool: def _webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool:
"""Updates webfinger Email/blog/xmpp links from profile """Updates webfinger Email/blog/xmpp links from profile
Returns true if one or more tags has been changed Returns true if one or more tags has been changed
@ -357,6 +424,12 @@ def _webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool:
wfJson['aliases'].remove(fullAlias) wfJson['aliases'].remove(fullAlias)
changed = True changed = True
if _webfingerUpdateAvatar(wfJson, actorJson):
changed = True
if _webfingerAddBlogLink(wfJson, actorJson):
changed = True
return changed return changed