diff --git a/daemon.py b/daemon.py index f4253ab2..96094945 100644 --- a/daemon.py +++ b/daemon.py @@ -173,7 +173,7 @@ class PubServer(BaseHTTPRequestHandler): ' is not a permitted activity type') return False if messageJson.get('id'): - postId=messageJson['id'] + postId=messageJson['id'].replace('/activity','') else: postId=None if self.server.debug: diff --git a/epicyon.py b/epicyon.py index 46d6b58d..82ac1c88 100644 --- a/epicyon.py +++ b/epicyon.py @@ -216,8 +216,8 @@ if args.tests: if args.testsnetwork: print('Network Tests') - testPostMessageBetweenServers() - testFollowBetweenServers() + #testPostMessageBetweenServers() + #testFollowBetweenServers() testClientToServer() sys.exit() diff --git a/follow.py b/follow.py index e990ddd7..1b1e6f9c 100644 --- a/follow.py +++ b/follow.py @@ -18,7 +18,11 @@ from utils import getNicknameFromActor from utils import getStatusNumber from utils import followPerson from posts import sendSignedJson +from posts import getPersonBox from acceptreject import createAccept +from webfinger import webfingerHandle +from auth import createBasicAuthHeader +from session import postJson def getFollowersOfPerson(baseDir: str, \ nickname: str,domain: str, \ @@ -329,7 +333,6 @@ def sendFollowRequest(session,baseDir: str, \ followedId=followHttpPrefix+'://'+requestDomain+'/users/'+followNickname newFollowJson = { - 'id': httpPrefix+'://'+fullDomain+'/users/'+nickname+'/statuses/'+statusNumber, 'type': 'Follow', 'actor': followActor, 'object': followedId, @@ -347,6 +350,79 @@ def sendFollowRequest(session,baseDir: str, \ return newFollowJson +def sendFollowRequestViaServer(session,fromNickname: str,password: str, + fromDomain: str,fromPort: int, \ + followNickname: str,followDomain: str,followPort: int, \ + httpPrefix: str, \ + cachedWebfingers: {},personCache: {}, \ + debug: bool) -> {}: + """Creates a follow request via c2s + """ + if not session: + print('WARN: No session for sendFollowRequestViaServer') + return 6 + + fromDomainFull=fromDomain + if fromPort!=80 and fromPort!=443: + fromDomainFull=fromDomain+':'+str(fromPort) + followDomainFull=followDomain + if followPort!=80 and followPort!=443: + followDomainFull=followDomain+':'+str(followPort) + + followActor=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname + followedId=httpPrefix+'://'+followDomainFull+'/users/'+followNickname + + statusNumber,published = getStatusNumber() + newFollowJson = { + 'type': 'Follow', + 'actor': followActor, + 'object': followedId, + 'to': [followedId], + 'cc': ['https://www.w3.org/ns/activitystreams#Public'], + 'published': published + } + + handle=httpPrefix+'://'+fromDomainFull+'/@'+fromNickname + + # lookup the inbox for the To handle + wfRequest = webfingerHandle(session,handle,httpPrefix,cachedWebfingers) + if not wfRequest: + if debug: + print('DEBUG: announce webfinger failed for '+handle) + return 1 + + postToBox='outbox' + + # get the actor inbox for the To handle + inboxUrl,pubKeyId,pubKey,fromPersonId,sharedInbox,capabilityAcquisition = \ + getPersonBox(session,wfRequest,personCache,postToBox) + + if not inboxUrl: + if debug: + print('DEBUG: No '+postToBox+' was found for '+handle) + return 3 + if not fromPersonId: + if debug: + print('DEBUG: No actor was found for '+handle) + return 4 + + authHeader=createBasicAuthHeader(fromNickname,password) + + headers = {'host': fromDomain, \ + 'Content-type': 'application/json', \ + 'Authorization': authHeader} + postResult = \ + postJson(session,newFollowJson,[],inboxUrl,headers,"inbox:write") + #if not postResult: + # if debug: + # print('DEBUG: POST announce failed for c2s to '+inboxUrl) + # return 5 + + if debug: + print('DEBUG: c2s POST follow success') + + return newFollowJson + def getFollowersOfActor(baseDir :str,actor :str,debug: bool) -> {}: """In a shared inbox if we receive a post we know who it's from and if it's addressed to followers then we need to get a list of those. diff --git a/tests.py b/tests.py index 7062f5cb..f26d4b86 100644 --- a/tests.py +++ b/tests.py @@ -32,6 +32,7 @@ from posts import archivePostsForPerson from posts import sendPostViaServer from follow import clearFollows from follow import clearFollowers +from follow import sendFollowRequestViaServer from utils import followPerson from follow import followerOfPerson from follow import unfollowPerson @@ -1068,17 +1069,34 @@ def testClientToServer(): outboxPostId=postJsonObject['id'].replace('/activity','') assert outboxPostId print('message id obtained: '+outboxPostId) + + + print('\n\nAlice follows Bob') + sendFollowRequestViaServer(sessionAlice,'alice',password, \ + aliceDomain,alicePort, \ + 'bob',bobDomain,bobPort, \ + httpPrefix, \ + cachedWebfingers,personCache, \ + True) + for t in range(10): + if os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt'): + if os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt'): + break + time.sleep(1) + + assert os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt') + assert os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt') print('\n\nBob repeats the post') sessionBob = createSession(bobDomain,bobPort,useTor) password='bobpass' outboxPath=bobDir+'/accounts/bob@'+bobDomain+'/outbox' assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==0 - sendAnnounceViaServer(sessionBob,'bob',password, + sendAnnounceViaServer(sessionBob,'bob',password, \ bobDomain,bobPort, \ httpPrefix,outboxPostId, \ - cachedWebfingers,personCache, \ - True) + cachedWebfingers, \ + personCache,True) for i in range(10): if os.path.isdir(outboxPath): if len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1: @@ -1098,8 +1116,8 @@ def testClientToServer(): assert thrBob.isAlive()==False os.chdir(baseDir) - shutil.rmtree(aliceDir) - shutil.rmtree(bobDir) + #shutil.rmtree(aliceDir) + #shutil.rmtree(bobDir) def runAllTests(): print('Running tests...')