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

View File

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

View File

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

View File

@ -22,6 +22,7 @@ from posts import createOutbox
from auth import storeBasicCredentials from auth import storeBasicCredentials
from roles import setRole from roles import setRole
from media import removeMetaData from media import removeMetaData
from utils import validNickname
def generateRSAKey() -> (str,str): def generateRSAKey() -> (str,str):
key = RSA.generate(2048) 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 """Generates the capabilities inbox to sign requests
""" """
return createPersonBase(baseDir,nickname,domain,port,httpPrefix,True,None) 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) -> {}: def personLookup(domain: str,path: str,baseDir: str) -> {}:
"""Lookup the person for an given nickname """Lookup the person for an given nickname

View File

@ -35,6 +35,7 @@ from utils import urlPermitted
from utils import getNicknameFromActor from utils import getNicknameFromActor
from utils import getDomainFromActor from utils import getDomainFromActor
from utils import deletePost from utils import deletePost
from utils import validNickname
from capabilities import getOcapFilename from capabilities import getOcapFilename
from capabilities import capabilitiesUpdate from capabilities import capabilitiesUpdate
from media import attachImage from media import attachImage
@ -591,7 +592,7 @@ def createPublicPost(baseDir: str,
clientToServer: bool,\ clientToServer: bool,\
attachImageFilename: str,imageDescription: str,useBlurhash: bool, \ attachImageFilename: str,imageDescription: str,useBlurhash: bool, \
inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}: inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
"""Public post to the outbox """Public post
""" """
return createPostBase(baseDir,nickname, domain, port, \ return createPostBase(baseDir,nickname, domain, port, \
'https://www.w3.org/ns/activitystreams#Public', \ 'https://www.w3.org/ns/activitystreams#Public', \
@ -601,6 +602,71 @@ def createPublicPost(baseDir: str,
attachImageFilename,imageDescription,useBlurhash, \ attachImageFilename,imageDescription,useBlurhash, \
inReplyTo, inReplyToAtomUri, subject) 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: [],\ def threadSendPost(session,postJsonObject: {},federationList: [],\
inboxUrl: str, baseDir: str,signatureHeaderJson: {},postLog: [], inboxUrl: str, baseDir: str,signatureHeaderJson: {},postLog: [],
debug :bool) -> None: debug :bool) -> None:

View File

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

View File

@ -190,3 +190,13 @@ def deletePost(baseDir: str,httpPrefix: str,nickname: str,domain: str,postFilena
os.remove(repliesFilename) os.remove(repliesFilename)
# finally, remove the post itself # finally, remove the post itself
os.remove(postFilename) 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