Connect new posts to web interface

master
Bob Mottram 2019-07-27 23:48:34 +01:00
parent 744b345b30
commit e6c246fc8e
7 changed files with 149 additions and 54 deletions

106
daemon.py
View File

@ -30,6 +30,9 @@ from posts import savePostToBox
from posts import sendToFollowers
from posts import postIsAddressedToPublic
from posts import sendToNamedAddresses
from posts import createPublicPost
from posts import createFollowersOnlyPost
from posts import createDirectMessagePost
from inbox import inboxPermittedMessage
from inbox import inboxMessageHasParams
from inbox import runInboxQueue
@ -1068,6 +1071,7 @@ class PubServer(BaseHTTPRequestHandler):
# email style encoding message/rfc822
messageFields=msg.get_payload(decode=False).split(boundary)
fields={}
filename=None
for f in messageFields:
if ' name="' in f:
postStr=f.split(' name="',1)[1]
@ -1089,7 +1093,6 @@ class PubServer(BaseHTTPRequestHandler):
# of an image
searchStr=b'Content-Type: image/png'
imageLocation=postBytes.find(searchStr)
filename=None
filenameBase=self.server.baseDir+'/accounts/'+nickname+'@'+self.server.domain+'/upload'
if imageLocation:
filename=filenameBase+'.png'
@ -1117,43 +1120,68 @@ class PubServer(BaseHTTPRequestHandler):
fd.write(postBytes[startPos:])
fd.close()
postSubject=None
postMessage=None
postImageDescription=None
postImage=None
postType=None
postCategory=None
postLocation=None
for postKey,postValue in fields.items():
if postKey=='subject':
postSubject=postValue
elif postKey=='message':
postMessage=postValue
elif postKey=='imageDescription':
postImageDescription=postValue
elif postKey=='postType':
postType=postValue
elif postKey=='category':
postCategory=postValue
elif postKey=='location':
postLocation=postValue
if self.server.debug:
if postSubject:
print('subject: '+postSubject)
if postMessage:
print('message: '+postMessage)
if postImageDescription:
print('image description: '+postImageDescription)
if postType:
print('type: '+postType)
if postCategory:
print('category: '+postCategory)
if postLocation:
print('location: '+postLocation)
if not postMessage:
return False
return True
return False
# send the post
if not fields.get('message'):
return False
if not fields.get('imageDescription'):
fields['imageDescription']=None
if not fields.get('subject'):
fields['subject']=None
if not fields.get('replyTo'):
fields['replyTo']=None
if postType=='newpost':
messageJson= \
createPublicPost(self.server.baseDir, \
nickname, \
self.server.domain,self.server.port, \
self.server.httpPrefix, \
fields['message'],False,False,False, \
filename,fields['imageDescription'],True, \
fields['replyTo'], fields['replyTo'],fields['subject'])
if messageJson:
queueStatus=self._updateInboxQueue(nickname,messageJson)
if queueStatus==0:
return True
if postType=='newfollowers':
messageJson= \
createFollowersOnlyPost(self.server.baseDir, \
nickname, \
self.server.domain,self.server.port, \
self.server.httpPrefix, \
fields['message'],True,False,False, \
filename,fields['imageDescription'],True, \
fields['replyTo'], fields['replyTo'],fields['subject'])
if messageJson:
queueStatus=self._updateInboxQueue(nickname,messageJson)
if queueStatus==0:
return True
if postType=='newdm':
messageJson= \
createDirectMessagePost(self.server.baseDir, \
nickname, \
self.server.domain,self.server.port, \
self.server.httpPrefix, \
fields['message'],True,False,False, \
filename,fields['imageDescription'],True, \
fields['replyTo'], fields['replyTo'],fields['subject'])
if messageJson:
queueStatus=self._updateInboxQueue(nickname,messageJson)
if queueStatus==0:
return True
if postType=='newunlisted':
# TODO
return True
if postType=='newshare':
# TODO
return True
return False
def do_POST(self):
@ -1449,7 +1477,7 @@ class PubServer(BaseHTTPRequestHandler):
else:
if self.path == '/sharedInbox' or self.path == '/inbox':
print('DEBUG: POST to shared inbox')
queueStatus-_updateInboxQueue('inbox',messageJson)
queueStatus=_updateInboxQueue('inbox',messageJson)
if queueStatus==0:
self.send_response(200)
self.end_headers()

View File

@ -11,7 +11,6 @@ from person import createSharedInbox
from person import createCapabilitiesInbox
from person import setPreferredNickname
from person import setBio
from person import validNickname
from person import setProfileImage
from skills import setSkillLevel
from roles import setRole
@ -44,7 +43,6 @@ from daemon import runDaemon
import socket
from follow import clearFollows
from follow import clearFollowers
from utils import followPerson
from follow import followerOfPerson
from follow import unfollowPerson
from follow import unfollowerOfPerson
@ -60,6 +58,8 @@ from auth import removePassword
from auth import createPassword
from utils import getDomainFromActor
from utils import getNicknameFromActor
from utils import followPerson
from utils import validNickname
from media import archiveMedia
from delete import sendDeleteViaServer
from like import sendLikeViaServer

View File

@ -11,7 +11,7 @@ import commentjson
from pprint import pprint
import os
import sys
from person import validNickname
from utils import validNickname
from utils import domainPermitted
from utils import getDomainFromActor
from utils import getNicknameFromActor

View File

@ -22,6 +22,7 @@ from posts import createOutbox
from auth import storeBasicCredentials
from roles import setRole
from media import removeMetaData
from utils import validNickname
def generateRSAKey() -> (str,str):
key = RSA.generate(2048)
@ -259,16 +260,6 @@ def createCapabilitiesInbox(baseDir: str,nickname: str,domain: str,port: int, \
"""Generates the capabilities inbox to sign requests
"""
return createPersonBase(baseDir,nickname,domain,port,httpPrefix,True,None)
def validNickname(nickname: str) -> bool:
forbiddenChars=['.',' ','/','?',':',';','@']
for c in forbiddenChars:
if c in nickname:
return False
reservedNames=['inbox','outbox','following','followers','capabilities']
if nickname in reservedNames:
return False
return True
def personLookup(domain: str,path: str,baseDir: str) -> {}:
"""Lookup the person for an given nickname

View File

@ -35,6 +35,7 @@ from utils import urlPermitted
from utils import getNicknameFromActor
from utils import getDomainFromActor
from utils import deletePost
from utils import validNickname
from capabilities import getOcapFilename
from capabilities import capabilitiesUpdate
from media import attachImage
@ -591,7 +592,7 @@ def createPublicPost(baseDir: str,
clientToServer: bool,\
attachImageFilename: str,imageDescription: str,useBlurhash: bool, \
inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
"""Public post to the outbox
"""Public post
"""
return createPostBase(baseDir,nickname, domain, port, \
'https://www.w3.org/ns/activitystreams#Public', \
@ -601,6 +602,71 @@ def createPublicPost(baseDir: str,
attachImageFilename,imageDescription,useBlurhash, \
inReplyTo, inReplyToAtomUri, subject)
def createFollowersOnlyPost(baseDir: str,
nickname: str, domain: str, port: int,httpPrefix: str, \
content: str, followersOnly: bool, saveToFile: bool,
clientToServer: bool,\
attachImageFilename: str,imageDescription: str,useBlurhash: bool, \
inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
"""Followers only post
"""
return createPostBase(baseDir,nickname, domain, port, \
httpPrefix+'://'+domain+'/users/'+nickname+'/followers', \
None,
httpPrefix, content, followersOnly, saveToFile, \
clientToServer, \
attachImageFilename,imageDescription,useBlurhash, \
inReplyTo, inReplyToAtomUri, subject)
def getMentionedPeople(baseDir: str,httpPrefix: str,content: str,domain: str) -> []:
"""Extracts a list of mentioned actors from the given message content
"""
if '@' not in content:
return None
mentions=[]
words=content.split(' ')
for wrd in words:
if wrd.startswith('@'):
handle=wrd[1:]
if '@' not in handle:
handle=handle+'@'+domain
if not os.path.isdir(baseDir+'/accounts/'+handle):
continue
else:
externalDomain=handle.split('@')[1]
if not ('.' in externalDomain or externalDomain=='localhost'):
continue
mentionedNickname=handle.split('@')[0]
if not validNickname(mentionedNickname):
continue
actor=httpPrefix+'://'+handle.split('@')[1]+'/users/'+mentionedNickname
mentions.append(actor)
return actor
def createDirectMessagePost(baseDir: str,
nickname: str, domain: str, port: int,httpPrefix: str, \
content: str, followersOnly: bool, saveToFile: bool,
clientToServer: bool,\
attachImageFilename: str,imageDescription: str,useBlurhash: bool, \
inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
"""Direct Message post
"""
mentionedPeople=getMentionedPeople(baseDir,httpPrefix,content,domain)
postTo=None
postCc=None
if not mentionedPeople:
return None
if len(mentionedPeople)==1:
postTo=mentionedPeople[0]
if len(mentionedPeople)>1:
postCc=mentionedPeople[1]
return createPostBase(baseDir,nickname, domain, port, \
postTo,postCc, \
httpPrefix, content, followersOnly, saveToFile, \
clientToServer, \
attachImageFilename,imageDescription,useBlurhash, \
inReplyTo, inReplyToAtomUri, subject)
def threadSendPost(session,postJsonObject: {},federationList: [],\
inboxUrl: str, baseDir: str,signatureHeaderJson: {},postLog: [],
debug :bool) -> None:

View File

@ -11,11 +11,11 @@ import commentjson
import os
import time
from shutil import copyfile
from person import validNickname
from webfinger import webfingerHandle
from auth import createBasicAuthHeader
from posts import getPersonBox
from session import postJson
from utils import validNickname
from utils import getNicknameFromActor
from utils import getDomainFromActor
from media import removeMetaData

View File

@ -190,3 +190,13 @@ def deletePost(baseDir: str,httpPrefix: str,nickname: str,domain: str,postFilena
os.remove(repliesFilename)
# finally, remove the post itself
os.remove(postFilename)
def validNickname(nickname: str) -> bool:
forbiddenChars=['.',' ','/','?',':',';','@']
for c in forbiddenChars:
if c in nickname:
return False
reservedNames=['inbox','outbox','following','followers','capabilities']
if nickname in reservedNames:
return False
return True