diff --git a/daemon.py b/daemon.py index d338be7d..dfef899c 100644 --- a/daemon.py +++ b/daemon.py @@ -19,6 +19,8 @@ from person import personLookup from person import personKeyLookup from person import personOutboxJson from posts import getPersonPubKey +from posts import outboxMessageCreateWrap +from posts import savePostToOutbox from inbox import inboxPermittedMessage from inbox import inboxMessageHasParams from follow import getFollowingFeed @@ -52,12 +54,12 @@ def readFollowList(filename: str): return followlist class PubServer(BaseHTTPRequestHandler): - def _set_headers(self,fileFormat): + def _set_headers(self,fileFormat: str) -> None: self.send_response(200) self.send_header('Content-type', fileFormat) self.end_headers() - def _404(self): + def _404(self) -> None: self.send_response(404) self.send_header('Content-Type', 'text/html; charset=utf-8') self.end_headers() @@ -90,13 +92,43 @@ class PubServer(BaseHTTPRequestHandler): self._404() return True - def _permittedDir(self,path): + def _permittedDir(self,path: str) -> bool: + """These are special paths which should not be accessible + directly via GET or POST + """ if path.startswith('/wfendpoints') or \ path.startswith('/keys') or \ path.startswith('/accounts'): return False return True + def _postToOutbox(messageJson: {}) -> 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('object'): + if messageJson.get('type'): + if messageJson['type']!='Create': + # https://www.w3.org/TR/activitypub/#object-without-create + messageJson= \ + outboxMessageCreateWrap(self.server.httpPrefix, \ + self.postToNickname, \ + self.server.domain,messageJson) + if not (messageJson.get('id') and \ + messageJson.get('type') and \ + messageJson.get('actor') and \ + messageJson.get('object') and \ + messageJson.get('atomUri') and \ + messageJson.get('to')): + return False + if messageJson['type']!='Create': + return False + # https://www.w3.org/TR/activitypub/#create-activity-outbox + messageJson['object']['attributedTo']=messageJson['actor'] + savePostToOutbox(self.server.baseDir,messageJson['id'],self.postToNickname,self.server.domain,messageJson) + return True + def do_GET(self): if self.server.debug: print('DEBUG: GET from '+self.server.baseDir+' path: '+self.path) @@ -282,15 +314,17 @@ class PubServer(BaseHTTPRequestHandler): # https://www.w3.org/TR/activitypub/#object-without-create if self.outboxAuthenticated: - if not messageJson.get('object'): - if messageJson.get('type'): - if messageJson['type']!='Create': - messageJson=outboxMessageCreateWrap(self.server.httpPrefix,self.postToNickname,self.server.domain,messageJson) - else: - self.send_response(403) - self.end_headers() - self.server.POSTbusy=False - return + if self._postToOutbox(messageJson): + self.send_header('Location',messageJson['object']['atomUri']) + self.send_response(201) + self.end_headers() + self.server.POSTbusy=False + return + else: + self.send_response(403) + self.end_headers() + self.server.POSTbusy=False + return # check the necessary properties are available if self.server.debug: diff --git a/posts.py b/posts.py index 6a53e1cf..a7e2ca3b 100644 --- a/posts.py +++ b/posts.py @@ -248,7 +248,17 @@ def deleteAllPosts(baseDir: str,nickname: str, domain: str) -> None: elif os.path.isdir(filePath): shutil.rmtree(filePath) except Exception as e: print(e) - + +def savePostToOutbox(baseDir: str,postId: str,nickname: str, domain: str,postJson: {}) -> None: + """Saves the give json to the outbox + """ + if ':' in domain: + domain=domain.split(':')[0] + outboxDir = createOutboxDir(nickname,domain,baseDir) + filename=outboxDir+'/'+postId.replace('/','#')+'.json' + with open(filename, 'w') as fp: + commentjson.dump(postJson, fp, indent=4, sort_keys=False) + def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \ toUrl: str, ccUrl: str, httpPrefix: str, content: str, \ followersOnly: bool, saveToFile: bool, clientToServer: bool, \ @@ -339,12 +349,7 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \ newPost['cc']=ccUrl newPost['object']['cc']=ccUrl if saveToFile: - if ':' in domain: - domain=domain.split(':')[0] - outboxDir = createOutboxDir(nickname,domain,baseDir) - filename=outboxDir+'/'+newPostId.replace('/','#')+'.json' - with open(filename, 'w') as fp: - commentjson.dump(newPost, fp, indent=4, sort_keys=False) + savePostToOutbox(baseDir,newPostId,nickname,domain,newPost) return newPost def outboxMessageCreateWrap(httpPrefix str,nickname: str,domain: str,messageJson: {}) -> {}: @@ -369,6 +374,8 @@ def outboxMessageCreateWrap(httpPrefix str,nickname: str,domain: str,messageJson 'object': messageJson } newPost['object']['id']=newPost['id'] + newPost['object']['url']=httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber + newPost['object']['atomUri']=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber return newPost def createPublicPost(baseDir: str,