From d257b59c3a5cec11354c5d2c7c6b771904cfc093 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 5 Jul 2019 19:57:19 +0100 Subject: [PATCH] Send accept message after follow --- daemon.py | 4 +++- follow.py | 16 ++++++++++++-- inbox.py | 15 +++++++------ posts.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 9 deletions(-) diff --git a/daemon.py b/daemon.py index ec0b8d52..c6d5b67c 100644 --- a/daemon.py +++ b/daemon.py @@ -446,7 +446,9 @@ def runDaemon(baseDir: str,domain: str,port=80,httpPrefix='https',fedList=[],use httpd.POSTbusy=False httpd.receivedMessage=False httpd.inboxQueue=[] + httpd.sendThreads=[] + httpd.postLog=[] print('Running ActivityPub daemon on ' + domain + ' port ' + str(port)) - httpd.thrInboxQueue=threadWithTrace(target=runInboxQueue,args=(baseDir,httpPrefix,httpd.personCache,httpd.inboxQueue,domain,port,useTor,httpd.federationList,debug),daemon=True) + httpd.thrInboxQueue=threadWithTrace(target=runInboxQueue,args=(baseDir,httpPrefix,httpd.sendThreads,httpd.postLog,httpd.cachedWebfingers,httpd.personCache,httpd.inboxQueue,domain,port,useTor,httpd.federationList,debug),daemon=True) httpd.thrInboxQueue.start() httpd.serve_forever() diff --git a/follow.py b/follow.py index 7b2488b8..c0404a02 100644 --- a/follow.py +++ b/follow.py @@ -12,6 +12,7 @@ import os import sys from person import validNickname from utils import domainPermitted +from posts import sendSignedJson def getFollowersOfPerson(baseDir: str,nickname: str,domain: str,followFile='following.txt') -> []: """Returns a list containing the followers of the given person @@ -228,9 +229,11 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,httpPrefix: st following['next']=httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(lastPage) return following -def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> bool: +def receiveFollowRequest(session,baseDir: str,httpPrefix: str,port: int,sendThreads: [],postLog: [],cachedWebfingers: {},personCache: {},messageJson: {},federationList: []) -> bool: """Receives a follow request within the POST section of HTTPServer """ + if not messageJson.get('actor'): + return False if not messageJson['type'].startswith('Follow'): return False if '/users/' not in messageJson['actor']: @@ -252,7 +255,16 @@ def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> boo if domainToFollow==domain: if not os.path.isdir(baseDir+'/accounts/'+handleToFollow): return False - return followerOfPerson(baseDir,nickname,domain,nicknameToFollow,domainToFollow,federationList) + if not followerOfPerson(baseDir,nickname,domain,nicknameToFollow,domainToFollow,federationList): + return False + # send accept back + personUrl=messageJson['actor'] + acceptJson=createAccept(baseDir,federationList,nickname,domain,port, \ + personUrl,'',httpPrefix,messageJson['object']) + sendSignedJson(acceptJson,session,baseDir,nickname,domain,port, \ + nicknameToFollow,domainToFollow,toPort, '', \ + httpPrefix,saveToFile,clientToServer,federationList, \ + sendThreads,postLog,cachedWebfingers,personCache) def sendFollowRequest(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \ followNickname: str,followDomain: str,followPort: bool,followHttpPrefix: str, \ diff --git a/inbox.py b/inbox.py index 190a260f..2a9be6bf 100644 --- a/inbox.py +++ b/inbox.py @@ -129,7 +129,7 @@ def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str commentjson.dump(newQueueItem, fp, indent=4, sort_keys=False) return filename -def runInboxQueue(baseDir: str,httpPrefix: str,personCache: {},queue: [],domain: str,port: int,useTor: bool,federationList: [],debug: bool) -> None: +def runInboxQueue(baseDir: str,httpPrefix: str,sendThreads: [],postLog: [],cachedWebfingers: {},personCache: {},queue: [],domain: str,port: int,useTor: bool,federationList: [],debug: bool) -> None: """Processes received items and moves them to the appropriate directories """ @@ -211,15 +211,18 @@ def runInboxQueue(baseDir: str,httpPrefix: str,personCache: {},queue: [],domain: if debug: print('DEBUG: Signature check success') - if receiveFollowRequest(baseDir, \ + if receiveFollowRequest(session, \ + baseDir,httpPrefix,port, \ + sendThreads,postLog, \ + cachedWebfingers, + personCache, queueJson['post'], \ federationList): - if debug: print('DEBUG: Follow accepted from '+keyId) - os.remove(queueFilename) - queue.pop(0) - continue + os.remove(queueFilename) + queue.pop(0) + continue if debug: print('DEBUG: Queue post accepted') diff --git a/posts.py b/posts.py index 80f7307c..bcc5e09a 100644 --- a/posts.py +++ b/posts.py @@ -521,6 +521,69 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \ thr.start() return 0 +def sendSignedJson(postJsonObject: {},session,baseDir: str,nickname: str, domain: str, port: int, \ + toNickname: str, toDomain: str, toPort: int, cc: str, \ + httpPrefix: str, saveToFile: bool, clientToServer: bool, federationList: [], \ + sendThreads: [], postLog: [], cachedWebfingers: {},personCache: {}) -> int: + """Sends a signed json object to an inbox/outbox + """ + withDigest=True + + if toPort!=80 and toPort!=443: + toDomain=toDomain+':'+str(toPort) + + handle=httpPrefix+'://'+toDomain+'/@'+toNickname + + # lookup the inbox for the To handle + wfRequest = webfingerHandle(session,handle,httpPrefix,cachedWebfingers) + if not wfRequest: + return 1 + + # get the actor inbox for the To handle + inboxUrl,pubKeyId,pubKey,toPersonId,sharedInbox = \ + getPersonBox(session,wfRequest,personCache,'inbox') + + # If there are more than one followers on the target domain + # then send to teh shared inbox indead of the individual inbox + if noOfFollowersOnDomain(baseDir,handle,toDomain)>1 and sharedInbox: + inboxUrl=sharedInbox + + if not inboxUrl: + return 2 + if not pubKey: + return 3 + if not toPersonId: + return 4 + + # get the senders private key + privateKeyPem=getPersonKey(nickname,domain,baseDir,'private') + if len(privateKeyPem)==0: + return 5 + + if not clientToServer: + postPath='/inbox' + else: + postPath='/outbox' + + # construct the http header + signatureHeaderJson = \ + createSignedHeader(privateKeyPem, nickname, domain, port, \ + postPath, httpPrefix, withDigest, postJsonObject) + + # Keep the number of threads being used small + while len(sendThreads)>10: + sendThreads[0].kill() + sendThreads.pop(0) + thr = threadWithTrace(target=threadSendPost,args=(session, \ + postJsonObject.copy(), \ + federationList, \ + inboxUrl,baseDir, \ + signatureHeaderJson.copy(), \ + postLog),daemon=True) + sendThreads.append(thr) + thr.start() + return 0 + def createInbox(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \ itemsPerPage: int,headerOnly: bool,pageNumber=None) -> {}: return createBoxBase(baseDir,'inbox',nickname,domain,port,httpPrefix, \