Browse Source

Test for announce via c2s

Bob Mottram 1 month ago
parent
commit
a819c4ae57
5 changed files with 149 additions and 22 deletions
  1. 79 0
      announce.py
  2. 2 8
      daemon.py
  3. 2 2
      epicyon.py
  4. 31 11
      posts.py
  5. 35 1
      tests.py

+ 79 - 0
announce.py

@@ -14,6 +14,10 @@ from utils import urlPermitted
 from utils import getNicknameFromActor
 from utils import getDomainFromActor
 from posts import sendSignedJson
+from posts import getPersonBox
+from session import postJson
+from webfinger import webfingerHandle
+from auth import createBasicAuthHeader
 
 def createAnnounce(session,baseDir: str,federationList: [], \
                    nickname: str, domain: str, port: int, \
@@ -229,3 +233,78 @@ def undoRepeatPost(session,baseDir: str,federationList: [], \
                               sendThreads,postLog, \
                               personCache,cachedWebfingers, \
                               debug)
+
+def sendAnnounceViaServer(session,fromNickname: str,password: str,
+                          fromDomain: str,fromPort: int, \
+                          httpPrefix: str,repeatObjectUrl: str, \
+                          cachedWebfingers: {},personCache: {}, \
+                          debug: bool) -> {}:
+    """Creates an announce message via c2s
+    """
+    if not session:
+        print('WARN: No session for sendAnnounceViaServer')
+        return 6
+
+    withDigest=True
+
+    fromDomainFull=fromDomain
+    if fromPort!=80 and fromPort!=443:
+        fromDomainFull=fromDomain+':'+str(fromPort)
+
+    toUrl = 'https://www.w3.org/ns/activitystreams#Public'
+    ccUrl = httpPrefix + '://'+fromDomainFull+'/users/'+fromNickname+'/followers'
+
+    statusNumber,published = getStatusNumber()
+    newAnnounceId= \
+        httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname+'/statuses/'+statusNumber
+    newAnnounceJson = {
+        'actor': httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname,
+        'atomUri': newAnnounceId,
+        'cc': [ccUrl],
+        'id': newAnnounceId+'/activity',
+        'object': repeatObjectUrl,
+        'published': published,
+        'to': [toUrl],
+        'type': 'Announce'
+    }
+
+    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,newAnnounceJson,[],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 announce success')
+
+    return newAnnounceJson

+ 2 - 8
daemon.py

@@ -703,15 +703,9 @@ class PubServer(BaseHTTPRequestHandler):
         # https://www.w3.org/TR/activitypub/#object-without-create
         if self.outboxAuthenticated:
             if self._postToOutbox(messageJson):                
-                if messageJson.get('object'):
-                    #self.send_header('Location', \
+                if messageJson.get('id'):
                     self.headers['Location']= \
-                                     messageJson['object']['id'].replace('/activity','')
-                else:
-                    if messageJson.get('id'):
-                        #self.send_header('Location', \
-                        self.headers['Location']= \
-                                         messageJson['id'].replace('/activity','')
+                        messageJson['id'].replace('/activity','')
                 self.send_response(201)
                 self.end_headers()
                 self.server.POSTbusy=False

+ 2 - 2
epicyon.py

@@ -214,8 +214,8 @@ if args.tests:
 
 if args.testsnetwork:
     print('Network Tests')
-    testPostMessageBetweenServers()
-    testFollowBetweenServers()
+    #testPostMessageBetweenServers()
+    #testFollowBetweenServers()
     testClientToServer()
     sys.exit()
 

+ 31 - 11
posts.py

@@ -305,8 +305,9 @@ def savePostToBox(baseDir: str,httpPrefix: str,postId: str, \
             '/statuses/'+statusNumber
         postJsonObject['id']=postId+'/activity'
     if postJsonObject.get('object'):
-        postJsonObject['object']['id']=postId
-        postJsonObject['object']['atomUri']=postId
+        if isinstance(postJsonObject['object'], dict):
+            postJsonObject['object']['id']=postId
+            postJsonObject['object']['atomUri']=postId
          
     boxDir = createPersonDir(nickname,domain,baseDir,boxname)
     filename=boxDir+'/'+postId.replace('/','#')+'.json'
@@ -493,19 +494,29 @@ def postIsAddressedToFollowers(baseDir: str,
 
     if not postJsonObject.get('object'):
         return False
-    if not postJsonObject['object'].get('to'):
-        return False
+    toList=[]
+    ccList=[]
+    if isinstance(postJsonObject['object'], dict):
+        if not postJsonObject['object'].get('to'):
+            return False
+        toList=postJsonObject['object']['to']
+        if postJsonObject['object'].get('cc'):
+            ccList=postJsonObject['object']['cc']
+    else:
+        if not postJsonObject.get('to'):
+            return False
+        toList=postJsonObject['to']
+        if postJsonObject.get('cc'):
+            ccList=postJsonObject['cc']
         
     followersUrl=httpPrefix+'://'+domain+'/users/'+nickname+'/followers'
 
     # does the followers url exist in 'to' or 'cc' lists?
     addressedToFollowers=False
-    if followersUrl in postJsonObject['object']['to']:
+    if followersUrl in toList:
         addressedToFollowers=True
     if not addressedToFollowers:
-        if not postJsonObject['object'].get('cc'):
-            return False
-        if followersUrl in postJsonObject['object']['cc']:
+        if followersUrl in ccList:
             addressedToFollowers=True
     return addressedToFollowers
 
@@ -872,13 +883,22 @@ def sendToNamedAddresses(session,baseDir: str, \
         return
     if not postJsonObject.get('object'):
         return
-    if not postJsonObject['object'].get('to'):
-        return
+    toList=[]
+    if isinstance(postJsonObject['object'], dict): 
+        if not postJsonObject['object'].get('to'):
+            return
+        toList=postJsonObject['object']['to']
+        recipientsObject=postJsonObject['object']
+    else: 
+        if not postJsonObject.get('to'):
+            return
+        toList=postJsonObject['to']
+        recipientsObject=postJsonObject
 
     recipients=[]
     recipientType=['to','cc']
     for rType in recipientType:
-        for address in postJsonObject['object'][rType]:
+        for address in recipientsObject[rType]:
             if address.endswith('#Public'):
                 continue
             if address.endswith('/followers'):

+ 35 - 1
tests.py

@@ -48,6 +48,7 @@ from auth import authorizeBasic
 from auth import storeBasicCredentials
 from like import likePost
 from announce import announcePublic
+from announce import sendAnnounceViaServer
 from media import getMediaPath
 
 testServerAliceRunning = False
@@ -1043,7 +1044,7 @@ def testClientToServer():
 
     assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1
     print(">>> c2s post arrived in Alice's outbox")
-
+    
     for i in range(30):
         if os.path.isdir(inboxPath):
             if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1:
@@ -1054,6 +1055,39 @@ def testClientToServer():
     print(">>> s2s post arrived in Bob's inbox")
     print("c2s send success")
 
+    print('\n\nGetting message id for the post')
+    statusNumber=0
+    outboxPostFilename=None
+    outboxPostId=None
+    for name in os.listdir(outboxPath):
+        if '#statuses#' in name:
+            statusNumber=int(name.split('#statuses#')[1].replace('.json','').replace('#activity',''))
+            outboxPostFilename=outboxPath+'/'+name
+            with open(outboxPostFilename, 'r') as fp:
+                postJsonObject=commentjson.load(fp)
+                outboxPostId=postJsonObject['id'].replace('/activity','')
+    assert outboxPostId
+    print('message id obtained: '+outboxPostId)
+    
+    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,
+                          bobDomain,bobPort, \
+                          httpPrefix,outboxPostId, \
+                          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:
+                break
+        time.sleep(1)
+
+    assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1
+    print('Post repeated')
+    
     # stop the servers
     thrAlice.kill()
     thrAlice.join()