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" __email__ = "bob@freedombone.net"
__status__ = "Production" __status__ = "Production"
from http.server import BaseHTTPRequestHandler, HTTPServer from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
#import socketserver #import socketserver
import json import json
import time import time
@ -14,6 +14,7 @@ from pprint import pprint
from session import createSession from session import createSession
from webfinger import webfingerMeta from webfinger import webfingerMeta
from webfinger import webfingerLookup from webfinger import webfingerLookup
from webfinger import webfingerHandle
from person import personLookup from person import personLookup
from person import personKeyLookup from person import personKeyLookup
from person import personOutboxJson 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')) self.wfile.write("<html><head></head><body><h1>404 Not Found</h1></body></html>".encode('utf-8'))
def _webfinger(self) -> bool: def _webfinger(self) -> bool:
print('############### _webfinger well-known')
if not self.path.startswith('/.well-known'): if not self.path.startswith('/.well-known'):
return False return False
print('############### _webfinger host-meta')
if self.path.startswith('/.well-known/host-meta'): if self.path.startswith('/.well-known/host-meta'):
wfResult=webfingerMeta() wfResult=webfingerMeta()
if wfResult: if wfResult:
@ -70,11 +73,13 @@ class PubServer(BaseHTTPRequestHandler):
self.wfile.write(wfResult.encode('utf-8')) self.wfile.write(wfResult.encode('utf-8'))
return return
print('############### _webfinger lookup '+self.path+' '+str(self.server.baseDir))
wfResult=webfingerLookup(self.path,self.server.baseDir) wfResult=webfingerLookup(self.path,self.server.baseDir)
if wfResult: if wfResult:
self._set_headers('application/json') self._set_headers('application/jrd+json')
self.wfile.write(json.dumps(wfResult).encode('utf-8')) self.wfile.write(json.dumps(wfResult).encode('utf-8'))
else: else:
print('############### _webfinger lookup 404 '+self.path)
self._404() self._404()
return True return True
@ -86,23 +91,29 @@ class PubServer(BaseHTTPRequestHandler):
return True return True
def do_GET(self): def do_GET(self):
print('############### GET from '+self.server.baseDir)
if self.server.GETbusy: if self.server.GETbusy:
currTimeGET=int(time.time()) currTimeGET=int(time.time())
if currTimeGET-self.server.lastGET<10: if currTimeGET-self.server.lastGET<10:
print('############### Busy')
self.send_response(429) self.send_response(429)
self.end_headers() self.end_headers()
return return
self.server.lastGET=currTimeGET self.server.lastGET=currTimeGET
self.server.GETbusy=True self.server.GETbusy=True
print('############### _permittedDir')
if not self._permittedDir(self.path): if not self._permittedDir(self.path):
print('############# Not permitted')
self._404() self._404()
self.server.GETbusy=False self.server.GETbusy=False
return return
# get webfinger endpoint for a person # get webfinger endpoint for a person
print('############### _webfinger')
if self._webfinger(): if self._webfinger():
self.server.GETbusy=False self.server.GETbusy=False
return return
print('############### _webfinger end')
# get outbox feed for a person # get outbox feed for a person
outboxFeed=personOutboxJson(self.server.baseDir,self.server.domain,self.server.port,self.path,self.server.https,maxPostsInFeed) outboxFeed=personOutboxJson(self.server.baseDir,self.server.domain,self.server.port,self.path,self.server.https,maxPostsInFeed)
if outboxFeed: if outboxFeed:
@ -137,6 +148,7 @@ class PubServer(BaseHTTPRequestHandler):
return return
# check that a json file was requested # check that a json file was requested
if not self.path.endswith('.json'): if not self.path.endswith('.json'):
print('############# Not json: '+self.path+' '+self.server.baseDir)
self._404() self._404()
self.server.GETbusy=False self.server.GETbusy=False
return return
@ -149,6 +161,7 @@ class PubServer(BaseHTTPRequestHandler):
contentJson=json.loads(content) contentJson=json.loads(content)
self.wfile.write(json.dumps(contentJson).encode('utf8')) self.wfile.write(json.dumps(contentJson).encode('utf8'))
else: else:
print('############# Unknown file')
self._404() self._404()
self.server.GETbusy=False self.server.GETbusy=False
@ -200,24 +213,16 @@ class PubServer(BaseHTTPRequestHandler):
self.server.POSTbusy=False self.server.POSTbusy=False
return return
pprint(messageJson)
print('**************** POST get handle') print('**************** POST get actor url from '+self.server.baseDir)
handle='' personUrl=messageJson['object']['attributedTo']
print('**************** POST create session') print('**************** POST create session')
currSessionTime=int(time.time()) currSessionTime=int(time.time())
if currSessionTime-self.server.sessionLastUpdate>600: if currSessionTime-self.server.sessionLastUpdate>600:
self.server.sessionLastUpdate=currSessionTime self.server.sessionLastUpdate=currSessionTime
self.server.session = createSession(self.server.useTor) self.server.session = createSession(self.server.useTor)
print('**************** POST webfinger the handle') print('**************** POST get public key of '+personUrl+' from '+self.server.baseDir)
wfRequest = webfingerHandle(self.server.session,handle,self.server.https,self.server.cachedWebfingers) pubKey=getPersonPubKey(self.server.session,personUrl,self.server.personCache)
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)
if not pubKey: if not pubKey:
print('**************** POST no sender public key') print('**************** POST no sender public key')
self.send_response(401) self.send_response(401)
@ -233,6 +238,8 @@ class PubServer(BaseHTTPRequestHandler):
# send the message back # send the message back
#self._set_headers('application/json') #self._set_headers('application/json')
#self.wfile.write(json.dumps(message).encode('utf-8')) #self.wfile.write(json.dumps(message).encode('utf-8'))
self.server.receivedMessage=True
self.send_response(200) self.send_response(200)
self.end_headers() self.end_headers()
self.server.POSTbusy=False self.server.POSTbusy=False
@ -244,8 +251,8 @@ def runDaemon(domain: str,port=80,https=True,fedList=[],useTor=False) -> None:
print('Invalid domain: ' + domain) print('Invalid domain: ' + domain)
return return
serverAddress = ('', port) serverAddress = (domain, port)
httpd = HTTPServer(serverAddress, PubServer) httpd = ThreadingHTTPServer(serverAddress, PubServer)
httpd.domain=domain httpd.domain=domain
httpd.port=port httpd.port=port
httpd.https=https httpd.https=https
@ -260,5 +267,6 @@ def runDaemon(domain: str,port=80,https=True,fedList=[],useTor=False) -> None:
httpd.lastPOST=0 httpd.lastPOST=0
httpd.GETbusy=False httpd.GETbusy=False
httpd.POSTbusy=False httpd.POSTbusy=False
httpd.receivedMessage=False
print('Running ActivityPub daemon on ' + domain + ' port ' + str(port)) print('Running ActivityPub daemon on ' + domain + ' port ' + str(port))
httpd.serve_forever() 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','') username=path.replace('/users/','',1).replace('/main-key','')
if not validUsername(username): if not validUsername(username):
return None return None
if ':' in domain:
domain=domain.split(':')[0]
handle=username.lower()+'@'+domain.lower() handle=username.lower()+'@'+domain.lower()
filename=baseDir+'/accounts/'+handle.lower()+'.json' filename=baseDir+'/accounts/'+handle.lower()+'.json'
if not os.path.isfile(filename): if not os.path.isfile(filename):
@ -151,6 +153,8 @@ def personLookup(domain: str,path: str,baseDir: str) -> {}:
return None return None
if not validUsername(username): if not validUsername(username):
return None return None
if ':' in domain:
domain=domain.split(':')[0]
handle=username.lower()+'@'+domain.lower() handle=username.lower()+'@'+domain.lower()
filename=baseDir+'/accounts/'+handle.lower()+'.json' filename=baseDir+'/accounts/'+handle.lower()+'.json'
if not os.path.isfile(filename): 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 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"'} asHeader = {'Accept': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'}
personUrl = getUserUrl(wfRequest)
if not personUrl: if not personUrl:
return None return None
personJson = getPersonFromCache(personUrl,personCache) personJson = getPersonFromCache(personUrl,personCache)
@ -121,7 +120,6 @@ def getPersonPubKey(session,wfRequest,personCache: {}) -> str:
pubKey=personJson['publicKey']['publicKeyPem'] pubKey=personJson['publicKey']['publicKeyPem']
storePersonInCache(personUrl,personJson,personCache) storePersonInCache(personUrl,personJson,personCache)
return pubKey return pubKey
def getUserPosts(session,wfRequest: {},maxPosts: int,maxMentions: int,maxEmoji: int,maxAttachments: int,federationList: [],personCache: {}) -> {}: 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 sessionHeaders=headers
if params: if params:
sessionParams=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() 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: def postJson(session,postJsonObject: {},federationList: [],inboxUrl: str,headers: {}) -> str:
"""Post a json message to the inbox of another person """Post a json message to the inbox of another person

View File

@ -98,21 +98,19 @@ def testThreads():
thr.join() thr.join()
assert thr.isAlive()==False 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)) print('Creating test server: Alice on port '+str(port))
if os.path.isdir(path): if os.path.isdir(path):
shutil.rmtree(path) shutil.rmtree(path)
os.mkdir(path) os.mkdir(path)
os.chdir(path) os.chdir(path)
federationList=['127.0.0.1']
username='alice' username='alice'
domain='127.0.0.1'
https=False https=False
useTor=False useTor=False
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,username,domain,port,https,True) privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,username,domain,port,https,True)
deleteAllPosts(username,domain,path) deleteAllPosts(username,domain,path)
followPerson(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.0.1: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, "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, "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) 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') print('Server running: Alice')
runDaemon(domain,port,https,federationList,useTor) 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)) print('Creating test server: Bob on port '+str(port))
if os.path.isdir(path): if os.path.isdir(path):
shutil.rmtree(path) shutil.rmtree(path)
os.mkdir(path) os.mkdir(path)
os.chdir(path) os.chdir(path)
federationList=['127.0.0.1']
username='bob' username='bob'
domain='127.0.0.1'
https=False https=False
useTor=False useTor=False
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,username,domain,port,https,True) privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,username,domain,port,https,True)
deleteAllPosts(username,domain,path) deleteAllPosts(username,domain,path)
followPerson(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.0.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, "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, "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) 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 https=False
useTor=False useTor=False
federationList=['127.0.0.1'] federationList=['127.0.0.1','127.0.10.1','127.0.10.2']
baseDir=os.getcwd() baseDir=os.getcwd()
if not os.path.isdir(baseDir+'/.tests'): if not os.path.isdir(baseDir+'/.tests'):
@ -162,22 +158,25 @@ def testPostMessageBetweenServers():
# create the servers # create the servers
aliceDir=baseDir+'/.tests/alice' aliceDir=baseDir+'/.tests/alice'
aliceDomain='127.0.10.1'
alicePort=61935 alicePort=61935
thrAlice = threadWithTrace(target=createServerAlice,args=(aliceDir,alicePort),daemon=True) thrAlice = threadWithTrace(target=createServerAlice,args=(aliceDir,aliceDomain,alicePort,federationList),daemon=True)
thrAlice.start()
assert thrAlice.isAlive()==True
bobDir=baseDir+'/.tests/bob' bobDir=baseDir+'/.tests/bob'
bobDomain='127.0.10.2'
bobPort=61936 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() thrBob.start()
assert thrAlice.isAlive()==True
assert thrBob.isAlive()==True assert thrBob.isAlive()==True
# wait for both servers to be running # wait for both servers to be running
while not (testServerAliceRunning and testServerBobRunning): while not (testServerAliceRunning and testServerBobRunning):
time.sleep(1) time.sleep(1)
time.sleep(5) time.sleep(6)
print('Alice sends to Bob') print('Alice sends to Bob')
os.chdir(aliceDir) os.chdir(aliceDir)
@ -192,10 +191,11 @@ def testPostMessageBetweenServers():
ccUrl=None ccUrl=None
alicePersonCache={} alicePersonCache={}
aliceCachedWebfingers={} 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)) print('sendResult: '+str(sendResult))
time.sleep(15) for i in range(10):
time.sleep(1)
# stop the servers # stop the servers
thrAlice.kill() thrAlice.kill()

View File

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