Test servers on different ip addresses

master
Bob Mottram 2019-07-01 22:01:43 +01:00
parent 22090a1aef
commit e2de1d1b9c
6 changed files with 74 additions and 51 deletions

View File

@ -6,7 +6,7 @@ __maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
from http.server import BaseHTTPRequestHandler, HTTPServer
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
#import socketserver
import json
import time
@ -14,6 +14,7 @@ from pprint import pprint
from session import createSession
from webfinger import webfingerMeta
from webfinger import webfingerLookup
from webfinger import webfingerHandle
from person import personLookup
from person import personKeyLookup
from person import personOutboxJson
@ -60,9 +61,11 @@ class PubServer(BaseHTTPRequestHandler):
self.wfile.write("<html><head></head><body><h1>404 Not Found</h1></body></html>".encode('utf-8'))
def _webfinger(self) -> bool:
print('############### _webfinger well-known')
if not self.path.startswith('/.well-known'):
return False
print('############### _webfinger host-meta')
if self.path.startswith('/.well-known/host-meta'):
wfResult=webfingerMeta()
if wfResult:
@ -70,11 +73,13 @@ class PubServer(BaseHTTPRequestHandler):
self.wfile.write(wfResult.encode('utf-8'))
return
print('############### _webfinger lookup '+self.path+' '+str(self.server.baseDir))
wfResult=webfingerLookup(self.path,self.server.baseDir)
if wfResult:
self._set_headers('application/json')
self._set_headers('application/jrd+json')
self.wfile.write(json.dumps(wfResult).encode('utf-8'))
else:
print('############### _webfinger lookup 404 '+self.path)
self._404()
return True
@ -85,24 +90,30 @@ class PubServer(BaseHTTPRequestHandler):
return False
return True
def do_GET(self):
def do_GET(self):
print('############### GET from '+self.server.baseDir)
if self.server.GETbusy:
currTimeGET=int(time.time())
if currTimeGET-self.server.lastGET<10:
print('############### Busy')
self.send_response(429)
self.end_headers()
return
self.server.lastGET=currTimeGET
self.server.GETbusy=True
print('############### _permittedDir')
if not self._permittedDir(self.path):
print('############# Not permitted')
self._404()
self.server.GETbusy=False
return
# get webfinger endpoint for a person
print('############### _webfinger')
if self._webfinger():
self.server.GETbusy=False
return
print('############### _webfinger end')
# get outbox feed for a person
outboxFeed=personOutboxJson(self.server.baseDir,self.server.domain,self.server.port,self.path,self.server.https,maxPostsInFeed)
if outboxFeed:
@ -137,6 +148,7 @@ class PubServer(BaseHTTPRequestHandler):
return
# check that a json file was requested
if not self.path.endswith('.json'):
print('############# Not json: '+self.path+' '+self.server.baseDir)
self._404()
self.server.GETbusy=False
return
@ -149,12 +161,13 @@ class PubServer(BaseHTTPRequestHandler):
contentJson=json.loads(content)
self.wfile.write(json.dumps(contentJson).encode('utf8'))
else:
print('############# Unknown file')
self._404()
self.server.GETbusy=False
def do_HEAD(self):
self._set_headers('application/json')
def do_POST(self):
if self.server.POSTbusy:
currTimePOST=int(time.time())
@ -200,24 +213,16 @@ class PubServer(BaseHTTPRequestHandler):
self.server.POSTbusy=False
return
print('**************** POST get handle')
handle=''
pprint(messageJson)
print('**************** POST get actor url from '+self.server.baseDir)
personUrl=messageJson['object']['attributedTo']
print('**************** POST create session')
currSessionTime=int(time.time())
if currSessionTime-self.server.sessionLastUpdate>600:
self.server.sessionLastUpdate=currSessionTime
self.server.session = createSession(self.server.useTor)
print('**************** POST webfinger the handle')
wfRequest = webfingerHandle(self.server.session,handle,self.server.https,self.server.cachedWebfingers)
if not wfRequest:
print('**************** POST unknown webfinger')
self.send_response(401)
self.end_headers()
self.server.POSTbusy=False
return
print('**************** POST get public key')
pubKey=getPersonPubKey(self.server.session,wfRequest,self.server.personCache)
print('**************** POST get public key of '+personUrl+' from '+self.server.baseDir)
pubKey=getPersonPubKey(self.server.session,personUrl,self.server.personCache)
if not pubKey:
print('**************** POST no sender public key')
self.send_response(401)
@ -233,6 +238,8 @@ class PubServer(BaseHTTPRequestHandler):
# send the message back
#self._set_headers('application/json')
#self.wfile.write(json.dumps(message).encode('utf-8'))
self.server.receivedMessage=True
self.send_response(200)
self.end_headers()
self.server.POSTbusy=False
@ -244,8 +251,8 @@ def runDaemon(domain: str,port=80,https=True,fedList=[],useTor=False) -> None:
print('Invalid domain: ' + domain)
return
serverAddress = ('', port)
httpd = HTTPServer(serverAddress, PubServer)
serverAddress = (domain, port)
httpd = ThreadingHTTPServer(serverAddress, PubServer)
httpd.domain=domain
httpd.port=port
httpd.https=https
@ -260,5 +267,6 @@ def runDaemon(domain: str,port=80,https=True,fedList=[],useTor=False) -> None:
httpd.lastPOST=0
httpd.GETbusy=False
httpd.POSTbusy=False
httpd.receivedMessage=False
print('Running ActivityPub daemon on ' + domain + ' port ' + str(port))
httpd.serve_forever()

View File

@ -123,6 +123,8 @@ def personKeyLookup(domain: str,path: str,baseDir: str) -> str:
username=path.replace('/users/','',1).replace('/main-key','')
if not validUsername(username):
return None
if ':' in domain:
domain=domain.split(':')[0]
handle=username.lower()+'@'+domain.lower()
filename=baseDir+'/accounts/'+handle.lower()+'.json'
if not os.path.isfile(filename):
@ -151,6 +153,8 @@ def personLookup(domain: str,path: str,baseDir: str) -> {}:
return None
if not validUsername(username):
return None
if ':' in domain:
domain=domain.split(':')[0]
handle=username.lower()+'@'+domain.lower()
filename=baseDir+'/accounts/'+handle.lower()+'.json'
if not os.path.isfile(filename):

View File

@ -107,9 +107,8 @@ def getPersonBox(session,wfRequest: {},personCache: {},boxName='inbox') -> (str,
return personJson[boxName],pubKeyId,pubKey,personId
def getPersonPubKey(session,wfRequest,personCache: {}) -> str:
def getPersonPubKey(session,personUrl: str,personCache: {}) -> str:
asHeader = {'Accept': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'}
personUrl = getUserUrl(wfRequest)
if not personUrl:
return None
personJson = getPersonFromCache(personUrl,personCache)
@ -121,7 +120,6 @@ def getPersonPubKey(session,wfRequest,personCache: {}) -> str:
pubKey=personJson['publicKey']['publicKeyPem']
storePersonInCache(personUrl,personJson,personCache)
return pubKey
def getUserPosts(session,wfRequest: {},maxPosts: int,maxMentions: int,maxEmoji: int,maxAttachments: int,federationList: [],personCache: {}) -> {}:

View File

@ -26,9 +26,11 @@ def getJson(session,url: str,headers: {},params: {}) -> {}:
sessionHeaders=headers
if params:
sessionParams=params
sessionHeaders['User-agent'] = "HotJava/1.1.2 FCS"
sessionHeaders['User-agent'] = "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 5 Build/LMY48B; wv)"
session.cookies.clear()
return session.get(url, headers=sessionHeaders, params=sessionParams).json()
result=session.get(url, headers=sessionHeaders, params=sessionParams)
print("*****result "+url+' ' + str(result))
return result.json()
def postJson(session,postJsonObject: {},federationList: [],inboxUrl: str,headers: {}) -> str:
"""Post a json message to the inbox of another person

View File

@ -98,21 +98,19 @@ def testThreads():
thr.join()
assert thr.isAlive()==False
def createServerAlice(path: str,port: int):
def createServerAlice(path: str,domain: str,port: int,federationList: []):
print('Creating test server: Alice on port '+str(port))
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
federationList=['127.0.0.1']
username='alice'
domain='127.0.0.1'
https=False
useTor=False
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,username,domain,port,https,True)
deleteAllPosts(username,domain,path)
followPerson(path,username,domain,'bob','127.0.0.1:61936',federationList)
followerOfPerson(path,username,domain,'bob','127.0.0.1:61936',federationList)
followPerson(path,username,domain,'bob','127.0.10.2:61936',federationList)
followerOfPerson(path,username,domain,'bob','127.0.10.2:61936',federationList)
createPublicPost(path,username, domain, port,https, "No wise fish would go anywhere without a porpoise", False, True)
createPublicPost(path,username, domain, port,https, "Curiouser and curiouser!", False, True)
createPublicPost(path,username, domain, port,https, "In the gardens of memory, in the palace of dreams, that is where you and I shall meet", False, True)
@ -121,21 +119,19 @@ def createServerAlice(path: str,port: int):
print('Server running: Alice')
runDaemon(domain,port,https,federationList,useTor)
def createServerBob(path: str,port: int):
def createServerBob(path: str,domain: str,port: int,federationList: []):
print('Creating test server: Bob on port '+str(port))
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
federationList=['127.0.0.1']
username='bob'
domain='127.0.0.1'
https=False
useTor=False
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,username,domain,port,https,True)
deleteAllPosts(username,domain,path)
followPerson(path,username,domain,'alice','127.0.0.1:61935',federationList)
followerOfPerson(path,username,domain,'alice','127.0.0.1:61935',federationList)
followPerson(path,username,domain,'alice','127.0.10.1:61935',federationList)
followerOfPerson(path,username,domain,'alice','127.0.10.1:61935',federationList)
createPublicPost(path,username, domain, port,https, "It's your life, live it your way.", False, True)
createPublicPost(path,username, domain, port,https, "One of the things I've realised is that I am very simple", False, True)
createPublicPost(path,username, domain, port,https, "Quantum physics is a bit of a passion of mine", False, True)
@ -154,7 +150,7 @@ def testPostMessageBetweenServers():
https=False
useTor=False
federationList=['127.0.0.1']
federationList=['127.0.0.1','127.0.10.1','127.0.10.2']
baseDir=os.getcwd()
if not os.path.isdir(baseDir+'/.tests'):
@ -162,22 +158,25 @@ def testPostMessageBetweenServers():
# create the servers
aliceDir=baseDir+'/.tests/alice'
aliceDomain='127.0.10.1'
alicePort=61935
thrAlice = threadWithTrace(target=createServerAlice,args=(aliceDir,alicePort),daemon=True)
thrAlice.start()
assert thrAlice.isAlive()==True
thrAlice = threadWithTrace(target=createServerAlice,args=(aliceDir,aliceDomain,alicePort,federationList),daemon=True)
bobDir=baseDir+'/.tests/bob'
bobDomain='127.0.10.2'
bobPort=61936
thrBob = threadWithTrace(target=createServerBob,args=(bobDir,bobPort),daemon=True)
thrBob = threadWithTrace(target=createServerBob,args=(bobDir,bobDomain,bobPort,federationList),daemon=True)
thrAlice.start()
thrBob.start()
assert thrAlice.isAlive()==True
assert thrBob.isAlive()==True
# wait for both servers to be running
while not (testServerAliceRunning and testServerBobRunning):
time.sleep(1)
time.sleep(5)
time.sleep(6)
print('Alice sends to Bob')
os.chdir(aliceDir)
@ -192,10 +191,11 @@ def testPostMessageBetweenServers():
ccUrl=None
alicePersonCache={}
aliceCachedWebfingers={}
sendResult = sendPost(sessionAlice,aliceDir,'alice', '127.0.0.1', alicePort, 'bob', '127.0.0.1', bobPort, ccUrl, https, 'Why is a mouse when it spins?', followersOnly, saveToFile, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, https, 'Why is a mouse when it spins?', followersOnly, saveToFile, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
print('sendResult: '+str(sendResult))
time.sleep(15)
for i in range(10):
time.sleep(1)
# stop the servers
thrAlice.kill()

View File

@ -38,23 +38,24 @@ def webfingerHandle(session,handle: str,https: bool,cachedWebfingers: {}) -> {}:
username, domain = parseHandle(handle)
if not username:
return None
wf=getWebfingerFromCache(username+'@'+domain,cachedWebfingers)
wfDomain=domain
if ':' in wfDomain:
wfDomain=wfDomain.split(':')[0]
print('***********cachedWebfingers '+str(cachedWebfingers))
wf=getWebfingerFromCache(username+'@'+wfDomain,cachedWebfingers)
if wf:
return wf
prefix='https'
if not https:
prefix='http'
prefix='http'
url = '{}://{}/.well-known/webfinger'.format(prefix,domain)
if ':' in domain:
domain=domain.split(':')[0]
par = {'resource': 'acct:{}'.format(username+'@'+domain)}
par = {'resource': 'acct:{}'.format(username+'@'+wfDomain)}
hdr = {'Accept': 'application/jrd+json'}
#try:
result = getJson(session, url, hdr, par)
#except:
# print("Unable to webfinger " + url)
# return None
storeWebfingerInCache(username+'@'+domain, result,cachedWebfingers)
# print("Unable to webfinger " + url + ' ' + str(hdr) + ' ' + str(par))
storeWebfingerInCache(username+'@'+wfDomain,result,cachedWebfingers)
return result
def generateMagicKey(publicKeyPem) -> str:
@ -144,23 +145,33 @@ def webfingerMeta() -> str:
def webfingerLookup(path: str,baseDir: str) -> {}:
"""Lookup the webfinger endpoint for an account
"""
print('############### _webfinger lookup 1')
if not path.startswith('/.well-known/webfinger?'):
return None
print('############### _webfinger lookup 2')
handle=None
if 'resource=acct:' in path:
print('############### _webfinger lookup 3')
handle=path.split('resource=acct:')[1].strip()
else:
print('############### _webfinger lookup 4')
if 'resource=acct%3A' in path:
handle=path.split('resource=acct%3A')[1].replace('%40','@').strip()
print('############### _webfinger lookup 5')
handle=path.split('resource=acct%3A')[1].replace('%40','@').strip()
print('############### _webfinger lookup 6')
if not handle:
return None
print('############### _webfinger lookup 7')
if '&' in handle:
handle=handle.split('&')[0].strip()
print('############### _webfinger lookup 8')
if '@' not in handle:
return None
filename=baseDir+'/wfendpoints/'+handle.lower()+'.json'
print('############### _webfinger lookup 9: '+filename)
if not os.path.isfile(filename):
return None
print('############### _webfinger lookup 10')
wfJson={"user": "unknown"}
with open(filename, 'r') as fp:
wfJson=commentjson.load(fp)