From e3be2f43288ad75c49ebfc65fd514771e6340111 Mon Sep 17 00:00:00 2001
From: Bob Mottram <bob@freedombone.net>
Date: Sat, 6 Jul 2019 16:17:21 +0100
Subject: [PATCH] Receive follow accept

---
 acceptreject.py | 35 +++++++++++++++++++++++++++++++++++
 follow.py       | 40 +++++++++++++++++++++++++---------------
 inbox.py        | 17 ++++++++++++++++-
 utils.py        | 22 ++++++++++++++++++++++
 4 files changed, 98 insertions(+), 16 deletions(-)

diff --git a/acceptreject.py b/acceptreject.py
index fcf496d1..840a8e59 100644
--- a/acceptreject.py
+++ b/acceptreject.py
@@ -11,6 +11,9 @@ import commentjson
 from utils import getStatusNumber
 from utils import createOutboxDir
 from utils import urlPermitted
+from utils import getDomainFromActor
+from utils import getNicknameFromActor
+from utils import domainPermitted
 
 def createAcceptReject(baseDir: str,federationList: [],capsList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str,acceptType: str) -> {}:
     """Accepts or rejects something (eg. a follow request)
@@ -41,3 +44,35 @@ def createAccept(baseDir: str,federationList: [],capsList: [],nickname: str,doma
 
 def createReject(baseDir: str,federationList: [],capsList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str) -> {}:
     return createAcceptReject(baseDir,federationList,capsList,nickname,domain,port,toUrl,ccUrl,httpPrefix,objectUrl,'Reject')
+
+def receiveAcceptReject(session,baseDir: str,httpPrefix: str,port: int,sendThreads: [],postLog: [],cachedWebfingers: {},personCache: {},messageJson: {},federationList: [],capsList: [],debug : bool) -> bool:
+    """Receives an Accept or Reject within the POST section of HTTPServer
+    """
+    if messageJson['type']!='Accept' and messageJson['type']!='Reject':
+        return False
+    if not messageJson.get('actor'):
+        if debug:
+            print('DEBUG: '+messageJson['type']+' has no actor')
+        return False
+    if '/users/' not in messageJson['actor']:
+        if debug:
+            print('DEBUG: "users" missing from actor in '+messageJson['type'])
+        return False
+    domain,tempPort=getDomainFromActor(messageJson['actor'])
+    if not domainPermitted(domain,federationList):
+        if debug:
+            print('DEBUG: '+messageJson['type']+' from domain not permitted - '+domain)
+        return False
+    nickname=getNicknameFromActor(messageJson['actor'])
+    if not nickname:
+        if debug:
+            print('DEBUG: '+messageJson['type']+' does not contain a nickname')
+        return False
+    handle=nickname.lower()+'@'+domain.lower()
+    if '/users/' not in messageJson['object']:
+        if debug:
+            print('DEBUG: "users" not found within object of '+messageJson['type'])
+        return False
+    if debug:
+        print('DEBUG: Uh, '+messageJson['type']+', I guess')
+    return True
diff --git a/follow.py b/follow.py
index c6f543ce..05602c59 100644
--- a/follow.py
+++ b/follow.py
@@ -12,6 +12,8 @@ import os
 import sys
 from person import validNickname
 from utils import domainPermitted
+from utils import getDomainFromActor
+from utils import getNicknameFromActor
 from posts import sendSignedJson
 from capabilities import isCapable
 from acceptreject import createAccept
@@ -244,29 +246,34 @@ def receiveFollowRequest(session,baseDir: str,httpPrefix: str,port: int,sendThre
         if debug:
             print('DEBUG: "users" missing from actor')            
         return False
-    domain=messageJson['actor'].split('/users/')[0].replace('https://','').replace('http://','').replace('dat://','')
-    if ':' in domain:
-        domain=domain.split(':')[0]
+    domain,tempPort=getDomainFromActor(messageJson['actor'])
+    fromPort=port
+    if tempPort:
+        fromPort=tempPort
     if not domainPermitted(domain,federationList):
         if debug:
             print('DEBUG: follower from domain not permitted - '+domain)
         return False
-    nickname=messageJson['actor'].split('/users/')[1].replace('@','')
+    nickname=getNicknameFromActor(messageJson['actor'])
+    if not nickname:
+        if debug:
+            print('DEBUG: follow request does not contain a nickname')
+        return False
     handle=nickname.lower()+'@'+domain.lower()
     if '/users/' not in messageJson['object']:
         if debug:
             print('DEBUG: "users" not found within object')
         return False
-    domainToFollow=messageJson['object'].split('/users/')[0].replace('https://','').replace('http://','').replace('dat://','')
-    toPort=port
-    if ':' in domainToFollow:
-        toPort=domainToFollow.split(':')[1]
-        domainToFollow=domainToFollow.split(':')[0]
+    domainToFollow,tempPort=getDomainFromActor(messageJson['object'])
     if not domainPermitted(domainToFollow,federationList):
         if debug:
             print('DEBUG: follow domain not permitted '+domainToFollow)
         return False
-    nicknameToFollow=messageJson['object'].split('/users/')[1].replace('@','')
+    nicknameToFollow=getNicknameFromActor(messageJson['object'])
+    if not nicknameToFollow:
+        if debug:
+            print('DEBUG: follow request does not contain a nickname for the account followed')
+        return False
     handleToFollow=nicknameToFollow.lower()+'@'+domainToFollow.lower()
     if domainToFollow==domain:
         if not os.path.isdir(baseDir+'/accounts/'+handleToFollow):
@@ -283,12 +290,15 @@ def receiveFollowRequest(session,baseDir: str,httpPrefix: str,port: int,sendThre
     personUrl=messageJson['actor']
     acceptJson=createAccept(baseDir,federationList,capsList,nickname,domain,port, \
                             personUrl,'',httpPrefix,messageJson['object'])
+    if debug:
+        pprint(acceptJson)
+        print('DEBUG: sending follow Accept from '+nicknameToFollow+'@'+domainToFollow+' port '+str(port)+' to '+nickname+'@'+domain+' port '+ str(fromPort))
     clientToServer=False
-    sendSignedJson(acceptJson,session,baseDir,nickname,domain,port, \
-                   nicknameToFollow,domainToFollow,port, '', \
-                   httpPrefix,True,clientToServer, \
-                   federationList, capsList, \
-                   sendThreads,postLog,cachedWebfingers,personCache,debug)
+    return sendSignedJson(acceptJson,session,baseDir,nicknameToFollow,domainToFollow,port, \
+                          nickname,domain,fromPort, '', \
+                          httpPrefix,True,clientToServer, \
+                          federationList, capsList, \
+                          sendThreads,postLog,cachedWebfingers,personCache,debug)
 
 def sendFollowRequest(session,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 48626695..5351249d 100644
--- a/inbox.py
+++ b/inbox.py
@@ -23,6 +23,7 @@ from follow import receiveFollowRequest
 from pprint import pprint
 from cache import getPersonFromCache
 from cache import storePersonInCache
+from acceptreject import receiveAcceptReject
 
 def getPersonPubKey(session,personUrl: str,personCache: {},debug: bool) -> str:
     if not personUrl:
@@ -238,7 +239,21 @@ def runInboxQueue(baseDir: str,httpPrefix: str,sendThreads: [],postLog: [],cache
                 os.remove(queueFilename)
                 queue.pop(0)
                 continue
-                    
+
+            if receiveAcceptReject(session, \
+                                   baseDir,httpPrefix,port, \
+                                   sendThreads,postLog, \
+                                   cachedWebfingers,
+                                   personCache,
+                                   queueJson['post'], \
+                                   federationList,capsList, \
+                                   debug):
+                if debug:
+                    print('DEBUG: Accept/Reject received from '+keyId)
+                os.remove(queueFilename)
+                queue.pop(0)
+                continue
+
             if debug:
                 print('DEBUG: Queue post accepted')
 
diff --git a/utils.py b/utils.py
index 9688344a..be2f7061 100644
--- a/utils.py
+++ b/utils.py
@@ -59,3 +59,25 @@ def urlPermitted(url: str, federationList: [],capsList: [],capability: str):
         if domain in url:
             return True
     return False
+
+def getNicknameFromActor(actor: str) -> str:
+    """Returns the nickname from an actor url
+    """
+    if '/users/' not in actor:
+        return None
+    return actor.split('/users/')[1].replace('@','')    
+
+def getDomainFromActor(actor: str) -> (str,int):
+    """Returns the domain name from an actor url
+    """
+    port=None
+    if '/users/' not in actor:
+        domain = actor.replace('https://','').replace('http://','').replace('dat://','')
+    else:
+        domain = actor.split('/users/')[0].replace('https://','').replace('http://','').replace('dat://','')
+    if ':' in domain:
+        port=int(domain.split(':')[1])
+        domain=domain.split(':')[0]
+    return domain,port
+    
+