Move outbox function to its own module

merge-requests/6/head
Bob Mottram 2020-01-13 10:35:17 +00:00
parent 3abac14512
commit 8cf1a6266a
2 changed files with 282 additions and 248 deletions

249
daemon.py
View File

@ -169,6 +169,7 @@ from httpsig import verifyPostHeaders
from theme import setTheme
from schedule import runPostSchedule
from schedule import runPostScheduleWatchdog
from outbox import postMessageToOutbox
import os
import sys
@ -184,254 +185,6 @@ followsPerPage=12
# number of item shares per page
sharesPerPage=12
def postMessageToOutbox(messageJson: {},postToNickname: str, \
server,baseDir: str,httpPrefix: str, \
domain: str,domainFull: str,port: int, \
recentPostsCache: {},followersThreads: [], \
federationList: [],sendThreads: [], \
postLog: [],cachedWebfingers: {}, \
personCache: {},allowDeletion: bool, \
useTor: bool,version: str,debug: bool) -> bool:
"""post is received by the outbox
Client to server message post
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
"""
if not messageJson.get('type'):
if debug:
print('DEBUG: POST to outbox has no "type" parameter')
return False
if not messageJson.get('object') and messageJson.get('content'):
if messageJson['type']!='Create':
# https://www.w3.org/TR/activitypub/#object-without-create
if debug:
print('DEBUG: POST to outbox - adding Create wrapper')
messageJson= \
outboxMessageCreateWrap(httpPrefix, \
postToNickname, \
domain,port, \
messageJson)
if messageJson['type']=='Create':
if not (messageJson.get('id') and \
messageJson.get('type') and \
messageJson.get('actor') and \
messageJson.get('object') and \
messageJson.get('to')):
if debug:
print('DEBUG: POST to outbox - Create does not have the required parameters')
return False
testDomain,testPort=getDomainFromActor(messageJson['actor'])
if testPort:
if testPort!=80 and testPort!=443:
testDomain=testDomain+':'+str(testPort)
if isBlockedDomain(baseDir,testDomain):
if debug:
print('DEBUG: domain is blocked: '+messageJson['actor'])
return False
# https://www.w3.org/TR/activitypub/#create-activity-outbox
messageJson['object']['attributedTo']=messageJson['actor']
if messageJson['object'].get('attachment'):
attachmentIndex=0
if messageJson['object']['attachment'][attachmentIndex].get('mediaType'):
fileExtension='png'
mediaTypeStr= \
messageJson['object']['attachment'][attachmentIndex]['mediaType']
if mediaTypeStr.endswith('jpeg'):
fileExtension='jpg'
elif mediaTypeStr.endswith('gif'):
fileExtension='gif'
elif mediaTypeStr.endswith('webp'):
fileExtension='webp'
elif mediaTypeStr.endswith('audio/mpeg'):
fileExtension='mp3'
elif mediaTypeStr.endswith('ogg'):
fileExtension='ogg'
elif mediaTypeStr.endswith('mp4'):
fileExtension='mp4'
elif mediaTypeStr.endswith('webm'):
fileExtension='webm'
elif mediaTypeStr.endswith('ogv'):
fileExtension='ogv'
mediaDir= \
baseDir+'/accounts/'+ \
postToNickname+'@'+domain
uploadMediaFilename=mediaDir+'/upload.'+fileExtension
if not os.path.isfile(uploadMediaFilename):
del messageJson['object']['attachment']
else:
# generate a path for the uploaded image
mPath=getMediaPath()
mediaPath=mPath+'/'+createPassword(32)+'.'+fileExtension
createMediaDirs(baseDir,mPath)
mediaFilename=baseDir+'/'+mediaPath
# move the uploaded image to its new path
os.rename(uploadMediaFilename,mediaFilename)
# change the url of the attachment
messageJson['object']['attachment'][attachmentIndex]['url']= \
httpPrefix+'://'+domainFull+ \
'/'+mediaPath
permittedOutboxTypes=[
'Create','Announce','Like','Follow','Undo', \
'Update','Add','Remove','Block','Delete', \
'Delegate','Skill','Bookmark'
]
if messageJson['type'] not in permittedOutboxTypes:
if debug:
print('DEBUG: POST to outbox - '+messageJson['type']+ \
' is not a permitted activity type')
return False
if messageJson.get('id'):
postId=messageJson['id'].replace('/activity','').replace('/undo','')
if debug:
print('DEBUG: id attribute exists within POST to outbox')
else:
if debug:
print('DEBUG: No id attribute within POST to outbox')
postId=None
if debug:
print('DEBUG: savePostToBox')
if messageJson['type']!='Upgrade':
savedFilename= \
savePostToBox(baseDir, \
httpPrefix, \
postId, \
postToNickname, \
domainFull,messageJson,'outbox')
if messageJson['type']=='Create' or \
messageJson['type']=='Question' or \
messageJson['type']=='Note' or \
messageJson['type']=='Announce':
inboxUpdateIndex('outbox',baseDir, \
postToNickname+'@'+domain, \
savedFilename,debug)
if outboxAnnounce(recentPostsCache, \
baseDir,messageJson,debug):
if debug:
print('DEBUG: Updated announcements (shares) collection for the post associated with the Announce activity')
if not server.session:
if debug:
print('DEBUG: creating new session for c2s')
server.session= \
createSession(useTor)
if debug:
print('DEBUG: sending c2s post to followers')
# remove inactive threads
inactiveFollowerThreads=[]
for th in followersThreads:
if not th.is_alive():
inactiveFollowerThreads.append(th)
for th in inactiveFollowerThreads:
followersThreads.remove(th)
if debug:
print('DEBUG: '+str(len(followersThreads))+' followers threads active')
# retain up to 20 threads
if len(followersThreads)>20:
# kill the thread if it is still alive
if followersThreads[0].is_alive():
followersThreads[0].kill()
# remove it from the list
followersThreads.pop(0)
# create a thread to send the post to followers
followersThread= \
sendToFollowersThread(server.session, \
baseDir, \
postToNickname, \
domain, \
port, \
httpPrefix, \
federationList, \
sendThreads, \
postLog, \
cachedWebfingers, \
personCache, \
messageJson,debug, \
version)
followersThreads.append(followersThread)
if debug:
print('DEBUG: handle any unfollow requests')
outboxUndoFollow(baseDir,messageJson,debug)
if debug:
print('DEBUG: handle delegation requests')
outboxDelegate(baseDir,postToNickname,messageJson,debug)
if debug:
print('DEBUG: handle skills changes requests')
outboxSkills(baseDir,postToNickname,messageJson,debug)
if debug:
print('DEBUG: handle availability changes requests')
outboxAvailability(baseDir,postToNickname,messageJson,debug)
if debug:
print('DEBUG: handle any like requests')
outboxLike(recentPostsCache, \
baseDir,httpPrefix, \
postToNickname,domain,port, \
messageJson,debug)
if debug:
print('DEBUG: handle any undo like requests')
outboxUndoLike(baseDir,httpPrefix, \
postToNickname,domain,port, \
messageJson,debug)
if debug:
print('DEBUG: handle any bookmark requests')
outboxBookmark(recentPostsCache, \
baseDir,httpPrefix, \
postToNickname,domain,port, \
messageJson,debug)
if debug:
print('DEBUG: handle any undo bookmark requests')
outboxUndoBookmark(recentPostsCache, \
baseDir,httpPrefix, \
postToNickname,domain,port, \
messageJson,debug)
if debug:
print('DEBUG: handle delete requests')
outboxDelete(baseDir,httpPrefix, \
postToNickname,domain, \
messageJson,debug, \
allowDeletion)
if debug:
print('DEBUG: handle block requests')
outboxBlock(baseDir,httpPrefix, \
postToNickname,domain, \
port,
messageJson,debug)
if debug:
print('DEBUG: handle undo block requests')
outboxUndoBlock(baseDir,httpPrefix, \
postToNickname,domain, \
port,
messageJson,debug)
if debug:
print('DEBUG: handle share uploads')
outboxShareUpload(baseDir,httpPrefix, \
postToNickname,domain, \
port,
messageJson,debug)
if debug:
print('DEBUG: handle undo share uploads')
outboxUndoShareUpload(baseDir,httpPrefix, \
postToNickname,domain, \
port,
messageJson,debug)
if debug:
print('DEBUG: sending c2s post to named addresses')
print('c2s sender: '+postToNickname+'@'+ \
domain+':'+str(port))
sendToNamedAddresses(server.session,baseDir, \
postToNickname,domain, \
port, \
httpPrefix, \
federationList, \
sendThreads, \
postLog, \
cachedWebfingers, \
personCache, \
messageJson,debug, \
version)
return True
def readFollowList(filename: str) -> None:
"""Returns a list of ActivityPub addresses to follow
"""

281
outbox.py 100644
View File

@ -0,0 +1,281 @@
__filename__ = "outbox.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.1.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
import os
import json
from session import createSession
from posts import outboxMessageCreateWrap
from posts import savePostToBox
from posts import sendToFollowersThread
from posts import sendToNamedAddresses
from utils import getDomainFromActor
from blocking import isBlockedDomain
from blocking import outboxBlock
from blocking import outboxUndoBlock
from media import getMediaPath
from media import createMediaDirs
from inbox import inboxUpdateIndex
from announce import outboxAnnounce
from follow import outboxUndoFollow
from roles import outboxDelegate
from skills import outboxSkills
from availability import outboxAvailability
from like import outboxLike
from like import outboxUndoLike
from bookmarks import outboxBookmark
from bookmarks import outboxUndoBookmark
from delete import outboxDelete
from shares import outboxShareUpload
from shares import outboxUndoShareUpload
def postMessageToOutbox(messageJson: {},postToNickname: str, \
server,baseDir: str,httpPrefix: str, \
domain: str,domainFull: str,port: int, \
recentPostsCache: {},followersThreads: [], \
federationList: [],sendThreads: [], \
postLog: [],cachedWebfingers: {}, \
personCache: {},allowDeletion: bool, \
useTor: bool,version: str,debug: bool) -> bool:
"""post is received by the outbox
Client to server message post
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
"""
if not messageJson.get('type'):
if debug:
print('DEBUG: POST to outbox has no "type" parameter')
return False
if not messageJson.get('object') and messageJson.get('content'):
if messageJson['type']!='Create':
# https://www.w3.org/TR/activitypub/#object-without-create
if debug:
print('DEBUG: POST to outbox - adding Create wrapper')
messageJson= \
outboxMessageCreateWrap(httpPrefix, \
postToNickname, \
domain,port, \
messageJson)
if messageJson['type']=='Create':
if not (messageJson.get('id') and \
messageJson.get('type') and \
messageJson.get('actor') and \
messageJson.get('object') and \
messageJson.get('to')):
if debug:
print('DEBUG: POST to outbox - Create does not have the required parameters')
return False
testDomain,testPort=getDomainFromActor(messageJson['actor'])
if testPort:
if testPort!=80 and testPort!=443:
testDomain=testDomain+':'+str(testPort)
if isBlockedDomain(baseDir,testDomain):
if debug:
print('DEBUG: domain is blocked: '+messageJson['actor'])
return False
# https://www.w3.org/TR/activitypub/#create-activity-outbox
messageJson['object']['attributedTo']=messageJson['actor']
if messageJson['object'].get('attachment'):
attachmentIndex=0
if messageJson['object']['attachment'][attachmentIndex].get('mediaType'):
fileExtension='png'
mediaTypeStr= \
messageJson['object']['attachment'][attachmentIndex]['mediaType']
if mediaTypeStr.endswith('jpeg'):
fileExtension='jpg'
elif mediaTypeStr.endswith('gif'):
fileExtension='gif'
elif mediaTypeStr.endswith('webp'):
fileExtension='webp'
elif mediaTypeStr.endswith('audio/mpeg'):
fileExtension='mp3'
elif mediaTypeStr.endswith('ogg'):
fileExtension='ogg'
elif mediaTypeStr.endswith('mp4'):
fileExtension='mp4'
elif mediaTypeStr.endswith('webm'):
fileExtension='webm'
elif mediaTypeStr.endswith('ogv'):
fileExtension='ogv'
mediaDir= \
baseDir+'/accounts/'+ \
postToNickname+'@'+domain
uploadMediaFilename=mediaDir+'/upload.'+fileExtension
if not os.path.isfile(uploadMediaFilename):
del messageJson['object']['attachment']
else:
# generate a path for the uploaded image
mPath=getMediaPath()
mediaPath=mPath+'/'+createPassword(32)+'.'+fileExtension
createMediaDirs(baseDir,mPath)
mediaFilename=baseDir+'/'+mediaPath
# move the uploaded image to its new path
os.rename(uploadMediaFilename,mediaFilename)
# change the url of the attachment
messageJson['object']['attachment'][attachmentIndex]['url']= \
httpPrefix+'://'+domainFull+'/'+mediaPath
permittedOutboxTypes=[
'Create','Announce','Like','Follow','Undo', \
'Update','Add','Remove','Block','Delete', \
'Delegate','Skill','Bookmark'
]
if messageJson['type'] not in permittedOutboxTypes:
if debug:
print('DEBUG: POST to outbox - '+messageJson['type']+ \
' is not a permitted activity type')
return False
if messageJson.get('id'):
postId=messageJson['id'].replace('/activity','').replace('/undo','')
if debug:
print('DEBUG: id attribute exists within POST to outbox')
else:
if debug:
print('DEBUG: No id attribute within POST to outbox')
postId=None
if debug:
print('DEBUG: savePostToBox')
if messageJson['type']!='Upgrade':
savedFilename= \
savePostToBox(baseDir, \
httpPrefix, \
postId, \
postToNickname, \
domainFull,messageJson,'outbox')
if messageJson['type']=='Create' or \
messageJson['type']=='Question' or \
messageJson['type']=='Note' or \
messageJson['type']=='Announce':
inboxUpdateIndex('outbox',baseDir, \
postToNickname+'@'+domain, \
savedFilename,debug)
if outboxAnnounce(recentPostsCache, \
baseDir,messageJson,debug):
if debug:
print('DEBUG: Updated announcements (shares) collection for the post associated with the Announce activity')
if not server.session:
if debug:
print('DEBUG: creating new session for c2s')
server.session= \
createSession(useTor)
if debug:
print('DEBUG: sending c2s post to followers')
# remove inactive threads
inactiveFollowerThreads=[]
for th in followersThreads:
if not th.is_alive():
inactiveFollowerThreads.append(th)
for th in inactiveFollowerThreads:
followersThreads.remove(th)
if debug:
print('DEBUG: '+str(len(followersThreads))+' followers threads active')
# retain up to 20 threads
if len(followersThreads)>20:
# kill the thread if it is still alive
if followersThreads[0].is_alive():
followersThreads[0].kill()
# remove it from the list
followersThreads.pop(0)
# create a thread to send the post to followers
followersThread= \
sendToFollowersThread(server.session, \
baseDir, \
postToNickname, \
domain, \
port, \
httpPrefix, \
federationList, \
sendThreads, \
postLog, \
cachedWebfingers, \
personCache, \
messageJson,debug, \
version)
followersThreads.append(followersThread)
if debug:
print('DEBUG: handle any unfollow requests')
outboxUndoFollow(baseDir,messageJson,debug)
if debug:
print('DEBUG: handle delegation requests')
outboxDelegate(baseDir,postToNickname,messageJson,debug)
if debug:
print('DEBUG: handle skills changes requests')
outboxSkills(baseDir,postToNickname,messageJson,debug)
if debug:
print('DEBUG: handle availability changes requests')
outboxAvailability(baseDir,postToNickname,messageJson,debug)
if debug:
print('DEBUG: handle any like requests')
outboxLike(recentPostsCache, \
baseDir,httpPrefix, \
postToNickname,domain,port, \
messageJson,debug)
if debug:
print('DEBUG: handle any undo like requests')
outboxUndoLike(baseDir,httpPrefix, \
postToNickname,domain,port, \
messageJson,debug)
if debug:
print('DEBUG: handle any bookmark requests')
outboxBookmark(recentPostsCache, \
baseDir,httpPrefix, \
postToNickname,domain,port, \
messageJson,debug)
if debug:
print('DEBUG: handle any undo bookmark requests')
outboxUndoBookmark(recentPostsCache, \
baseDir,httpPrefix, \
postToNickname,domain,port, \
messageJson,debug)
if debug:
print('DEBUG: handle delete requests')
outboxDelete(baseDir,httpPrefix, \
postToNickname,domain, \
messageJson,debug, \
allowDeletion)
if debug:
print('DEBUG: handle block requests')
outboxBlock(baseDir,httpPrefix, \
postToNickname,domain, \
port,
messageJson,debug)
if debug:
print('DEBUG: handle undo block requests')
outboxUndoBlock(baseDir,httpPrefix, \
postToNickname,domain, \
port,
messageJson,debug)
if debug:
print('DEBUG: handle share uploads')
outboxShareUpload(baseDir,httpPrefix, \
postToNickname,domain, \
port,
messageJson,debug)
if debug:
print('DEBUG: handle undo share uploads')
outboxUndoShareUpload(baseDir,httpPrefix, \
postToNickname,domain, \
port,
messageJson,debug)
if debug:
print('DEBUG: sending c2s post to named addresses')
print('c2s sender: '+postToNickname+'@'+ \
domain+':'+str(port))
sendToNamedAddresses(server.session,baseDir, \
postToNickname,domain, \
port, \
httpPrefix, \
federationList, \
sendThreads, \
postLog, \
cachedWebfingers, \
personCache, \
messageJson,debug, \
version)
return True