From 5eefc3a8f23b6f91ed0053bdd640e425dbfabd15 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 12 Jul 2019 10:41:57 +0100 Subject: [PATCH] Undoing announce/repeat --- announce.py | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++ inbox.py | 59 ++++++++++++++++++++++++++++- like.py | 4 +- 3 files changed, 163 insertions(+), 4 deletions(-) diff --git a/announce.py b/announce.py index 422731652..d6adba397 100644 --- a/announce.py +++ b/announce.py @@ -125,3 +125,107 @@ def repeatPost(session,baseDir: str,federationList: [], \ personCache,cachedWebfingers, \ debug) +def undoAnnounce(session,baseDir: str,federationList: [], \ + nickname: str, domain: str, port: int, \ + toUrl: str, ccUrl: str, httpPrefix: str, \ + objectUrl: str, saveToFile: bool, \ + clientToServer: bool, \ + sendThreads: [],postLog: [], \ + personCache: {},cachedWebfingers: {}, \ + debug: bool) -> {}: + """Undoes an announce message + Typically toUrl will be https://www.w3.org/ns/activitystreams#Public + and ccUrl might be a specific person whose post was repeated and the + objectUrl is typically the url of the message which was repeated, + corresponding to url or atomUri in createPostBase + """ + if not urlPermitted(objectUrl,federationList,"inbox:write"): + return None + + if ':' in domain: + domain=domain.split(':')[0] + fullDomain=domain + if port!=80 and port!=443: + fullDomain=domain+':'+str(port) + + newUndoAnnounce = { + 'actor': httpPrefix+'://'+fullDomain+'/users/'+nickname, + 'type': 'Undo', + 'cc': [], + 'to': [toUrl], + 'object': { + 'actor': httpPrefix+'://'+fullDomain+'/users/'+nickname, + 'cc': [], + 'object': objectUrl, + 'to': [toUrl], + 'type': 'Announce' + } + } + if ccUrl: + if len(ccUrl)>0: + newUndoAnnounce['object']['cc']=[ccUrl] + + announceNickname=None + announceDomain=None + announcePort=None + if '/users/' in objectUrl: + announceNickname=getNicknameFromActor(objectUrl) + announceDomain,announcePort=getDomainFromActor(objectUrl) + + if announceNickname and announceDomain: + sendSignedJson(newUndoAnnounce,session,baseDir, \ + nickname,domain,port, \ + announceNickname,announceDomain,announcePort, \ + 'https://www.w3.org/ns/activitystreams#Public', \ + httpPrefix,True,clientToServer,federationList, \ + sendThreads,postLog,cachedWebfingers,personCache,debug) + + return newUndoAnnounce + +def undoAnnouncePublic(session,baseDir: str,federationList: [], \ + nickname: str, domain: str, port: int, httpPrefix: str, \ + objectUrl: str,clientToServer: bool, \ + sendThreads: [],postLog: [], \ + personCache: {},cachedWebfingers: {}, \ + debug: bool) -> {}: + """Undoes a public announcement + """ + fromDomain=domain + if port!=80 and port!=443: + if ':' not in domain: + fromDomain=domain+':'+str(port) + + toUrl = 'https://www.w3.org/ns/activitystreams#Public' + ccUrl = httpPrefix + '://'+fromDomain+'/users/'+nickname+'/followers' + return undoAnnounce(session,baseDir,federationList, \ + nickname,domain,port, \ + toUrl,ccUrl,httpPrefix, \ + objectUrl,True,clientToServer, \ + sendThreads,postLog, \ + personCache,cachedWebfingers, \ + debug) + +def undoRepeatPost(session,baseDir: str,federationList: [], \ + nickname: str, domain: str, port: int, httpPrefix: str, \ + announceNickname: str, announceDomain: str, \ + announcePort: int, announceHttpsPrefix: str, \ + announceStatusNumber: int,clientToServer: bool, \ + sendThreads: [],postLog: [], \ + personCache: {},cachedWebfingers: {}, \ + debug: bool) -> {}: + """Undoes a status post repeat + """ + announcedDomain=announceDomain + if announcePort!=80 and announcePort!=443: + if ':' not in announcedDomain: + announcedDomain=announcedDomain+':'+str(announcePort) + + objectUrl = announceHttpsPrefix + '://'+announcedDomain+'/users/'+ \ + announceNickname+'/statuses/'+str(announceStatusNumber) + + return undoAnnouncePublic(session,baseDir,federationList, \ + nickname,domain,port,httpPrefix, \ + objectUrl,clientToServer, \ + sendThreads,postLog, \ + personCache,cachedWebfingers, \ + debug) diff --git a/inbox.py b/inbox.py index e87272c29..0d9637182 100644 --- a/inbox.py +++ b/inbox.py @@ -481,7 +481,7 @@ def receiveUndoLike(session,handle: str,baseDir: str, \ postFilename=locatePost(baseDir,handle.split('@')[0],handle.split('@')[1],messageJson['object']['object']) if not postFilename: if debug: - print('DEBUG: post not found in inbox or outbox') + print('DEBUG: unliked post not found in inbox or outbox') print(messageJson['object']['object']) return True if debug: @@ -544,7 +544,7 @@ def receiveAnnounce(session,handle: str,baseDir: str, \ sendThreads: [],postLog: [],cachedWebfingers: {}, \ personCache: {},messageJson: {},federationList: [], \ debug : bool) -> bool: - """Receives a Like activity within the POST section of HTTPServer + """Receives an announce activity within the POST section of HTTPServer """ if messageJson['type']!='Announce': return False @@ -585,6 +585,49 @@ def receiveAnnounce(session,handle: str,baseDir: str, \ print('DEBUG: announced/repeated post found in inbox') return True +def receiveUndoAnnounce(session,handle: str,baseDir: str, \ + httpPrefix: str,domain :str,port: int, \ + sendThreads: [],postLog: [],cachedWebfingers: {}, \ + personCache: {},messageJson: {},federationList: [], \ + debug : bool) -> bool: + """Receives an undo announce activity within the POST section of HTTPServer + """ + if messageJson['type']!='Undo': + return False + if not messageJson.get('actor'): + return False + if not messageJson.get('object'): + return False + if not isinstance(messageJson['object'], dict): + return False + if not messageJson['object'].get('object'): + return False + if not isinstance(messageJson['object']['object'], str): + return False + if messageJson['object']['type']!='Announce': + return False + if '/users/' not in messageJson['actor']: + if debug: + print('DEBUG: "users" missing from actor in '+messageJson['type']+' announce') + return False + if '/statuses/' not in messageJson['object']: + if debug: + print('DEBUG: "statuses" missing from object in '+messageJson['type']+' announce') + return False + if not os.path.isdir(baseDir+'/accounts/'+handle): + print('DEBUG: unknown recipient of undo announce - '+handle) + # if this post in the outbox of the person? + postFilename=locatePost(baseDir,handle.split('@')[0],handle.split('@')[1],messageJson['object']) + if not postFilename: + if debug: + print('DEBUG: undo announce post not found in inbox or outbox') + print(messageJson['object']['object']) + return True + if debug: + print('DEBUG: announced/repeated post to be undone found in inbox') + os.remove(postFilename) + return True + def inboxAfterCapabilities(session,keyId: str,handle: str,messageJson: {}, \ baseDir: str,httpPrefix: str,sendThreads: [], \ postLog: [],cachedWebfingers: {},personCache: {}, \ @@ -632,6 +675,18 @@ def inboxAfterCapabilities(session,keyId: str,handle: str,messageJson: {}, \ if debug: print('DEBUG: Announce accepted from '+keyId) + if receiveUndoAnnounce(session,handle, \ + baseDir,httpPrefix, \ + domain,port, \ + sendThreads,postLog, \ + cachedWebfingers, \ + personCache, \ + messageJson, \ + federationList, \ + debug): + if debug: + print('DEBUG: Undo announce accepted from '+keyId) + if receiveDelete(session,handle, \ baseDir,httpPrefix, \ domain,port, \ diff --git a/like.py b/like.py index d19edde49..db5bd33c2 100644 --- a/like.py +++ b/like.py @@ -227,7 +227,7 @@ def undolike(session,baseDir: str,federationList: [],nickname: str,domain: str,p undoLikesCollectionEntry(postFilename,objectUrl,newLikeJson['actor'],debug) - sendSignedJson(newLikeJson,session,baseDir, \ + sendSignedJson(newUndoLikeJson,session,baseDir, \ nickname,domain,port, \ likedPostNickname,likedPostDomain,likedPostPort, \ 'https://www.w3.org/ns/activitystreams#Public', \ @@ -236,7 +236,7 @@ def undolike(session,baseDir: str,federationList: [],nickname: str,domain: str,p else: return None - return newLikeJson + return newUndoLikeJson def undoLikePost(session,baseDir: str,federationList: [], \ nickname: str,domain: str,port: int,httpPrefix: str, \