mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of gitlab.com:bashrc2/epicyon
commit
63e6dbc0db
28
daemon.py
28
daemon.py
|
|
@ -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 = \
|
||||||
|
|
|
||||||
6
inbox.py
6
inbox.py
|
|
@ -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'
|
||||||
|
|
|
||||||
93
posts.py
93
posts.py
|
|
@ -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,21 +859,22 @@ 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):
|
if item['object'].get('url'):
|
||||||
if item['object'].get('url'):
|
url = item['object']['url']
|
||||||
url = item['object']['url']
|
else:
|
||||||
else:
|
url = item['object']['id']
|
||||||
url = item['object']['id']
|
if not blockedPosts.get(postDomain):
|
||||||
if not blockedPosts.get(postDomain):
|
blockedPosts[postDomain] = [url]
|
||||||
blockedPosts[postDomain] = [url]
|
else:
|
||||||
else:
|
if url not in blockedPosts[postDomain]:
|
||||||
if url not in blockedPosts[postDomain]:
|
blockedPosts[postDomain].append(url)
|
||||||
blockedPosts[postDomain].append(url)
|
|
||||||
return blockedPosts
|
return blockedPosts
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
10
utils.py
10
utils.py
|
|
@ -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
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -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 += \
|
||||||
|
|
|
||||||
79
webfinger.py
79
webfinger.py
|
|
@ -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,8 +252,7 @@ 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:
|
||||||
print('DEBUG: WEBFINGER no @ in handle ' + handle)
|
print('DEBUG: WEBFINGER no @ in handle ' + handle)
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue