diff --git a/daemon.py b/daemon.py index 0be1c1f4..c9c9e322 100644 --- a/daemon.py +++ b/daemon.py @@ -312,12 +312,12 @@ class PubServer(BaseHTTPRequestHandler): outboxUndoLike(self.server.baseDir,self.server.httpPrefix, \ self.postToNickname,self.server.domain,self.server.port, \ messageJson,self.server.debug) - if self.server.allowDeletion: - if self.server.debug: - print('DEBUG: handle delete requests') - outboxDelete(self.server.baseDir,self.server.httpPrefix, \ - self.postToNickname,self.server.domain, \ - messageJson,self.server.debug) + if self.server.debug: + print('DEBUG: handle delete requests') + outboxDelete(self.server.baseDir,self.server.httpPrefix, \ + self.postToNickname,self.server.domain, \ + messageJson,self.server.debug, \ + self.server.allowDeletion) if self.server.debug: print('DEBUG: handle block requests') outboxBlock(self.server.baseDir,self.server.httpPrefix, \ @@ -894,32 +894,34 @@ class PubServer(BaseHTTPRequestHandler): return # delete a post from the web interface icon - if authorized and self.server.allowDeletion and '?delete=' in self.path: + if authorized and '?delete=' in self.path: deleteUrl=self.path.split('?delete=')[1] actor=self.server.httpPrefix+'://'+self.server.domainFull+self.path.split('?delete=')[0] - if self.server.debug: - print('DEBUG: deleteUrl='+deleteUrl) - print('DEBUG: actor='+actor) - if actor not in deleteUrl: - # You can only delete your own posts - self.server.GETbusy=False - self._redirect_headers(actor+'/inbox',cookie) - return - self.postToNickname=getNicknameFromActor(actor) - if not self.server.session: - self.server.session= \ - createSession(self.server.domain,self.server.port,self.server.useTor) - deleteActor=self.server.httpPrefix+'://'+self.server.domainFull+'/users/'+self.postToNickname - deleteJson= { - 'actor': actor, - 'object': deleteUrl, - 'to': ['https://www.w3.org/ns/activitystreams#Public',actor], - 'cc': [actor+'/followers'], - 'type': 'Delete' - } - if self.server.debug: - pprint(deleteJson) - self._postToOutbox(deleteJson) + if self.server.allowDeletion or \ + deleteUrl.startswith(actor): + if self.server.debug: + print('DEBUG: deleteUrl='+deleteUrl) + print('DEBUG: actor='+actor) + if actor not in deleteUrl: + # You can only delete your own posts + self.server.GETbusy=False + self._redirect_headers(actor+'/inbox',cookie) + return + self.postToNickname=getNicknameFromActor(actor) + if not self.server.session: + self.server.session= \ + createSession(self.server.domain,self.server.port,self.server.useTor) + deleteActor=self.server.httpPrefix+'://'+self.server.domainFull+'/users/'+self.postToNickname + deleteJson= { + 'actor': actor, + 'object': deleteUrl, + 'to': ['https://www.w3.org/ns/activitystreams#Public',actor], + 'cc': [actor+'/followers'], + 'type': 'Delete' + } + if self.server.debug: + pprint(deleteJson) + self._postToOutbox(deleteJson) self.server.GETbusy=False self._redirect_headers(actor+'/inbox',cookie) return diff --git a/delete.py b/delete.py index 2f55a2ea..48cdb123 100644 --- a/delete.py +++ b/delete.py @@ -16,6 +16,7 @@ from utils import getNicknameFromActor from utils import getDomainFromActor from utils import locatePost from utils import deletePost +from utils import removeModerationPostFromIndex from posts import sendSignedJson from session import postJson from webfinger import webfingerHandle @@ -195,7 +196,8 @@ def deletePostPub(session,baseDir: str,federationList: [], \ def outboxDelete(baseDir: str,httpPrefix: str, \ nickname: str,domain: str, \ - messageJson: {},debug: bool) -> None: + messageJson: {},debug: bool, + allowDeletion: bool) -> None: """ When a delete request is received by the outbox from c2s """ if not messageJson.get('type'): @@ -216,7 +218,13 @@ def outboxDelete(baseDir: str,httpPrefix: str, \ return if debug: print('DEBUG: c2s delete request arrived in outbox') - + deletePrefix=httpPrefix+'://'+domain + if not allowDeletion and \ + (not messageJson['object'].startswith(deletePrefix) or \ + not messageJson['actor'].startswith(deletePrefix)): + if debug: + print('DEBUG: delete not permitted from other instances') + return messageId=messageJson['object'].replace('/activity','') if '/statuses/' not in messageId: if debug: @@ -238,6 +246,7 @@ def outboxDelete(baseDir: str,httpPrefix: str, \ if debug: print("DEBUG: you can't delete a post which wasn't created by you (domain does not match)") return + removeModerationPostFromIndex(baseDir,messageId,debug) postFilename=locatePost(baseDir,deleteNickname,deleteDomain,messageId) if not postFilename: if debug: diff --git a/inbox.py b/inbox.py index c5b80e38..f981f624 100644 --- a/inbox.py +++ b/inbox.py @@ -22,6 +22,7 @@ from utils import domainPermitted from utils import locatePost from utils import deletePost from utils import removeAttachment +from utils import removeModerationPostFromIndex from httpsig import verifyPostHeaders from session import createSession from session import getJson @@ -661,7 +662,7 @@ def receiveDelete(session,handle: str,baseDir: str, \ httpPrefix: str,domain :str,port: int, \ sendThreads: [],postLog: [],cachedWebfingers: {}, \ personCache: {},messageJson: {},federationList: [], \ - debug : bool) -> bool: + debug : bool,allowDeletion: bool) -> bool: """Receives a Delete activity within the POST section of HTTPServer """ if messageJson['type']!='Delete': @@ -680,6 +681,17 @@ def receiveDelete(session,handle: str,baseDir: str, \ if debug: print('DEBUG: '+messageJson['type']+' object is not a string') return False + domainFull=domain + if port: + if port!=80 and port!=443: + domainFull=domain+':'+str(port) + deletePrefix=httpPrefix+'://'+domainFull+'/' + if not allowDeletion and \ + (not messageJson['object'].startswith(deletePrefix) or \ + not messageJson['actor'].startswith(deletePrefix)): + if debug: + print('DEBUG: delete not permitted from other instances') + return False if not messageJson.get('to'): if debug: print('DEBUG: '+messageJson['type']+' has no "to" list') @@ -696,9 +708,10 @@ def receiveDelete(session,handle: str,baseDir: str, \ if debug: print('DEBUG: actor is not the owner of the post to be deleted') if not os.path.isdir(baseDir+'/accounts/'+handle): - print('DEBUG: unknown recipient of like - '+handle) + print('DEBUG: unknown recipient of like - '+handle) # if this post in the outbox of the person? messageId=messageJson['object'].replace('/activity','') + removeModerationPostFromIndex(baseDir,messageId,debug) postFilename=locatePost(baseDir,handle.split('@')[0],handle.split('@')[1],messageId) if not postFilename: if debug: @@ -928,22 +941,21 @@ def inboxAfterCapabilities(session,keyId: str,handle: str,messageJson: {}, \ print('DEBUG: Undo announce accepted from '+keyId) return False - if allowDeletion: - if receiveDelete(session,handle, \ - baseDir,httpPrefix, \ - domain,port, \ - sendThreads,postLog, \ - cachedWebfingers, \ - personCache, \ - messageJson, \ - federationList, \ - debug): - if debug: - print('DEBUG: Delete accepted from '+keyId) - return False - + if receiveDelete(session,handle, \ + baseDir,httpPrefix, \ + domain,port, \ + sendThreads,postLog, \ + cachedWebfingers, \ + personCache, \ + messageJson, \ + federationList, \ + debug,allowDeletion): + if debug: + print('DEBUG: Delete accepted from '+keyId) + return False + populateReplies(baseDir,httpPrefix,domain,messageJson,maxReplies,debug) - + if debug: print('DEBUG: object capabilities passed') print('copy from '+queueFilename+' to '+destinationFilename) diff --git a/utils.py b/utils.py index 922330c8..8d763853 100644 --- a/utils.py +++ b/utils.py @@ -167,6 +167,24 @@ def removeAttachment(baseDir: str,httpPrefix: str,domain: str,postJson: {}): os.remove(mediaFilename) postJson['attachment']=[] +def removeModerationPostFromIndex(baseDir: str,postUrl: str,debug: bool) -> None: + """Removes a url from the moderation index + """ + moderationIndexFile=baseDir+'/accounts/moderation.txt' + if not os.path.isfile(moderationIndexFile): + return + postId=postUrl.replace('/activity','') + if postId in open(moderationIndexFile).read(): + with open(moderationIndexFile, "r") as f: + lines = f.readlines() + with open(moderationIndexFile, "w+") as f: + for line in lines: + if line.strip("\n") != postId: + f.write(line) + else: + if debug: + print('DEBUG: removed '+postId+' from moderation index') + def deletePost(baseDir: str,httpPrefix: str,nickname: str,domain: str,postFilename: str,debug: bool): """Recursively deletes a post and its replies and attachments """ @@ -178,20 +196,11 @@ def deletePost(baseDir: str,httpPrefix: str,nickname: str,domain: str,postFilena # remove from moderation index file if postJsonObject.get('moderationStatus'): - moderationIndexFile=baseDir+'/accounts/moderation.txt' - if os.path.isfile(moderationIndexFile): - if postJsonObject.get('object'): - if isinstance(postJsonObject['object'], dict): - if postJsonObject['object'].get('id'): - # get the id of the post - postId=postJsonObject['object']['id'].replace('/activity','') - if postId in open(moderationIndexFile).read(): - with open(moderationIndexFile, "r") as f: - lines = f.readlines() - with open(moderationIndexFile, "w+") as f: - for line in lines: - if line.strip("\n") != postId: - f.write(line) + if postJsonObject.get('object'): + if isinstance(postJsonObject['object'], dict): + if postJsonObject['object'].get('id'): + postId=postJsonObject['object']['id'].replace('/activity','') + removeModerationPostFromIndex(baseDir,postId,debug) # remove any hashtags index entries removeHashtagIndex=False diff --git a/webinterface.py b/webinterface.py index 51c2803d..9bd87781 100644 --- a/webinterface.py +++ b/webinterface.py @@ -921,7 +921,9 @@ def individualPostAsHtml(baseDir: str, \ '' deleteStr='' - if allowDeletion: + if allowDeletion or \ + ('/'+fullDomain+'/' in postJsonObject['actor'] and \ + postJsonObject['object']['id'].startswith(postJsonObject['actor'])): if '/users/'+nickname+'/' in postJsonObject['object']['id']: deleteStr= \ '' \