Option to use dat urls

master
Bob Mottram 2019-07-03 20:00:03 +01:00
parent 0f5592452a
commit 86aaff3c84
11 changed files with 137 additions and 202 deletions

View File

@ -12,7 +12,7 @@ from utils import getStatusNumber
from utils import createOutboxDir from utils import createOutboxDir
from utils import urlPermitted from utils import urlPermitted
def createAcceptReject(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,https: bool,objectUrl: str,acceptType: str) -> {}: def createAcceptReject(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str,acceptType: str) -> {}:
"""Accepts or rejects something (eg. a follow request) """Accepts or rejects something (eg. a follow request)
Typically toUrl will be https://www.w3.org/ns/activitystreams#Public Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
and ccUrl might be a specific person favorited or repeated and the followers url and ccUrl might be a specific person favorited or repeated and the followers url
@ -21,16 +21,12 @@ def createAcceptReject(baseDir: str,federationList: [],nickname: str,domain: str
if not urlPermitted(objectUrl,federationList): if not urlPermitted(objectUrl,federationList):
return None return None
prefix='https'
if not https:
prefix='http'
if port!=80 and port!=443: if port!=80 and port!=443:
domain=domain+':'+str(port) domain=domain+':'+str(port)
newAccept = { newAccept = {
'type': acceptType, 'type': acceptType,
'actor': prefix+'://'+domain+'/users/'+nickname, 'actor': httpPrefix+'://'+domain+'/users/'+nickname,
'to': [toUrl], 'to': [toUrl],
'cc': [], 'cc': [],
'object': objectUrl 'object': objectUrl
@ -40,8 +36,8 @@ def createAcceptReject(baseDir: str,federationList: [],nickname: str,domain: str
newAccept['cc']=ccUrl newAccept['cc']=ccUrl
return newAccept return newAccept
def createAccept(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,https: bool,objectUrl: str) -> {}: def createAccept(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str) -> {}:
return createAcceptReject(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,https,objectUrl,'Accept') return createAcceptReject(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,httpPrefix,objectUrl,'Accept')
def createReject(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,https: bool,objectUrl: str) -> {}: def createReject(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str) -> {}:
return createAcceptReject(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,https,objectUrl,'Reject') return createAcceptReject(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,httpPrefix,objectUrl,'Reject')

View File

@ -14,7 +14,7 @@ from utils import urlPermitted
def createAnnounce(baseDir: str,federationList: [], \ def createAnnounce(baseDir: str,federationList: [], \
nickname: str, domain: str, port: int, \ nickname: str, domain: str, port: int, \
toUrl: str, ccUrl: str, https: bool, \ toUrl: str, ccUrl: str, httpPrefix: str, \
objectUrl: str, saveToFile: bool) -> {}: objectUrl: str, saveToFile: bool) -> {}:
"""Creates an announce message """Creates an announce message
Typically toUrl will be https://www.w3.org/ns/activitystreams#Public Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
@ -24,18 +24,14 @@ def createAnnounce(baseDir: str,federationList: [], \
if not urlPermitted(objectUrl,federationList): if not urlPermitted(objectUrl,federationList):
return None return None
prefix='https'
if not https:
prefix='http'
if port!=80 and port!=443: if port!=80 and port!=443:
domain=domain+':'+str(port) domain=domain+':'+str(port)
statusNumber,published = getStatusNumber() statusNumber,published = getStatusNumber()
newAnnounceId=prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber newAnnounceId=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
newAnnounce = { newAnnounce = {
'actor': prefix+'://'+domain+'/users/'+nickname, 'actor': httpPrefix+'://'+domain+'/users/'+nickname,
'atomUri': prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber, 'atomUri': httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
'cc': [], 'cc': [],
'id': newAnnounceId+'/activity', 'id': newAnnounceId+'/activity',
'object': objectUrl, 'object': objectUrl,
@ -56,40 +52,32 @@ def createAnnounce(baseDir: str,federationList: [], \
return newAnnounce return newAnnounce
def announcePublic(baseDir: str,federationList: [], \ def announcePublic(baseDir: str,federationList: [], \
nickname: str, domain: str, port: int, https: bool, \ nickname: str, domain: str, port: int, httpPrefix: str, \
objectUrl: str, saveToFile: bool) -> {}: objectUrl: str, saveToFile: bool) -> {}:
"""Makes a public announcement """Makes a public announcement
""" """
prefix='https'
if not https:
prefix='http'
fromDomain=domain fromDomain=domain
if port!=80 and port!=443: if port!=80 and port!=443:
fromDomain=fromDomain+':'+str(port) fromDomain=fromDomain+':'+str(port)
toUrl = 'https://www.w3.org/ns/activitystreams#Public' toUrl = 'https://www.w3.org/ns/activitystreams#Public'
ccUrl = prefix + '://'+fromDomain+'/users/'+nickname+'/followers' ccUrl = httpPrefix + '://'+fromDomain+'/users/'+nickname+'/followers'
return createAnnounce(baseDir,nickname, domain, port, \ return createAnnounce(baseDir,nickname, domain, port, \
toUrl, ccUrl, https, objectUrl, saveToFile) toUrl, ccUrl, httpPrefix, objectUrl, saveToFile)
def repeatPost(baseDir: str,federationList: [], \ def repeatPost(baseDir: str,federationList: [], \
nickname: str, domain: str, port: int, https: bool, \ nickname: str, domain: str, port: int, httpPrefix: str, \
announceNickname: str, announceDomain: str, \ announceNickname: str, announceDomain: str, \
announcePort: int, announceHttps: bool, \ announcePort: int, announceHttpsPrefix: str, \
announceStatusNumber: int, saveToFile: bool) -> {}: announceStatusNumber: int, saveToFile: bool) -> {}:
"""Repeats a given status post """Repeats a given status post
""" """
prefix='https'
if not announceHttps:
prefix='http'
announcedDomain=announceDomain announcedDomain=announceDomain
if announcePort!=80 and announcePort!=443: if announcePort!=80 and announcePort!=443:
announcedDomain=announcedDomain+':'+str(announcePort) announcedDomain=announcedDomain+':'+str(announcePort)
objectUrl = prefix + '://'+announcedDomain+'/users/'+ \ objectUrl = announceHttpsPrefix + '://'+announcedDomain+'/users/'+ \
announceNickname+'/statuses/'+str(announceStatusNumber) announceNickname+'/statuses/'+str(announceStatusNumber)
return announcePublic(baseDir,nickname, domain, port, https, objectUrl, saveToFile) return announcePublic(baseDir,nickname, domain, port, httpPrefix, objectUrl, saveToFile)

View File

@ -129,7 +129,7 @@ class PubServer(BaseHTTPRequestHandler):
# get outbox feed for a person # get outbox feed for a person
outboxFeed=personOutboxJson(self.server.baseDir,self.server.domain, \ outboxFeed=personOutboxJson(self.server.baseDir,self.server.domain, \
self.server.port,self.path, \ self.server.port,self.path, \
self.server.https,maxPostsInFeed) self.server.httpPrefix,maxPostsInFeed)
if outboxFeed: if outboxFeed:
self._set_headers('application/json') self._set_headers('application/json')
self.wfile.write(json.dumps(outboxFeed).encode('utf-8')) self.wfile.write(json.dumps(outboxFeed).encode('utf-8'))
@ -137,7 +137,7 @@ class PubServer(BaseHTTPRequestHandler):
return return
following=getFollowingFeed(self.server.baseDir,self.server.domain, \ following=getFollowingFeed(self.server.baseDir,self.server.domain, \
self.server.port,self.path, \ self.server.port,self.path, \
self.server.https,followsPerPage) self.server.httpPrefix,followsPerPage)
if following: if following:
self._set_headers('application/json') self._set_headers('application/json')
self.wfile.write(json.dumps(following).encode('utf-8')) self.wfile.write(json.dumps(following).encode('utf-8'))
@ -145,7 +145,7 @@ class PubServer(BaseHTTPRequestHandler):
return return
followers=getFollowingFeed(self.server.baseDir,self.server.domain, \ followers=getFollowingFeed(self.server.baseDir,self.server.domain, \
self.server.port,self.path, \ self.server.port,self.path, \
self.server.https,followsPerPage,'followers') self.server.httpPrefix,followsPerPage,'followers')
if followers: if followers:
self._set_headers('application/json') self._set_headers('application/json')
self.wfile.write(json.dumps(followers).encode('utf-8')) self.wfile.write(json.dumps(followers).encode('utf-8'))
@ -305,7 +305,7 @@ class PubServer(BaseHTTPRequestHandler):
if self.server.debug: if self.server.debug:
print('DEBUG: POST check signature') print('DEBUG: POST check signature')
if not verifyPostHeaders(self.server.https, pubKey, self.headers, \ if not verifyPostHeaders(self.server.httpPrefix, pubKey, self.headers, \
'/inbox' ,False, json.dumps(messageJson)): '/inbox' ,False, json.dumps(messageJson)):
print('**************** POST signature verification failed') print('**************** POST signature verification failed')
self.send_response(401) self.send_response(401)
@ -336,7 +336,7 @@ class PubServer(BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
self.server.POSTbusy=False self.server.POSTbusy=False
def runDaemon(domain: str,port=80,https=True,fedList=[],useTor=False,debug=False) -> None: def runDaemon(domain: str,port=80,httpPrefix='https',fedList=[],useTor=False,debug=False) -> None:
if len(domain)==0: if len(domain)==0:
domain='localhost' domain='localhost'
if '.' not in domain: if '.' not in domain:
@ -348,7 +348,7 @@ def runDaemon(domain: str,port=80,https=True,fedList=[],useTor=False,debug=False
httpd = ThreadingHTTPServer(serverAddress, PubServer) httpd = ThreadingHTTPServer(serverAddress, PubServer)
httpd.domain=domain httpd.domain=domain
httpd.port=port httpd.port=port
httpd.https=https httpd.httpPrefix=httpPrefix
httpd.debug=debug httpd.debug=debug
httpd.federationList=fedList.copy() httpd.federationList=fedList.copy()
httpd.baseDir=os.getcwd() httpd.baseDir=os.getcwd()

View File

@ -67,6 +67,9 @@ parser.add_argument("--debug", type=str2bool, nargs='?',
parser.add_argument("--http", type=str2bool, nargs='?', parser.add_argument("--http", type=str2bool, nargs='?',
const=True, default=False, const=True, default=False,
help="Use http only") help="Use http only")
parser.add_argument("--dat", type=str2bool, nargs='?',
const=True, default=False,
help="Use dat protocol only")
parser.add_argument("--tor", type=str2bool, nargs='?', parser.add_argument("--tor", type=str2bool, nargs='?',
const=True, default=False, const=True, default=False,
help="Route via Tor") help="Route via Tor")
@ -110,9 +113,11 @@ if not args.domain:
nickname='admin' nickname='admin'
domain=args.domain domain=args.domain
port=args.port port=args.port
https=True httpPrefix='https'
if args.http: if args.http:
https=False httpPrefix='http'
if args.dat:
httpPrefix='dat'
useTor=args.tor useTor=args.tor
baseDir=args.baseDir baseDir=args.baseDir
if baseDir.endswith('/'): if baseDir.endswith('/'):
@ -126,6 +131,6 @@ if args.federationList:
if not os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain): if not os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
print('Creating default admin account '+nickname+'@'+domain) print('Creating default admin account '+nickname+'@'+domain)
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,https,True) privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,True)
runDaemon(domain,port,https,federationList,useTor,debug) runDaemon(domain,port,httpPrefix,federationList,useTor,debug)

View File

@ -114,7 +114,7 @@ def getNoOfFollowers(baseDir: str,nickname: str,domain: str) -> int:
""" """
return getNoOfFollows(baseDir,nickname,domain,'followers.txt') return getNoOfFollows(baseDir,nickname,domain,'followers.txt')
def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,httpPrefix: str, \
followsPerPage=12,followFile='following') -> {}: followsPerPage=12,followFile='following') -> {}:
"""Returns the following and followers feeds from GET requests """Returns the following and followers feeds from GET requests
""" """
@ -147,18 +147,14 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \
if not validNickname(nickname): if not validNickname(nickname):
return None return None
prefix='https'
if not https:
prefix='http'
if port!=80 and port!=443: if port!=80 and port!=443:
domain=domain+':'+str(port) domain=domain+':'+str(port)
if headerOnly: if headerOnly:
following = { following = {
'@context': 'https://www.w3.org/ns/activitystreams', '@context': 'https://www.w3.org/ns/activitystreams',
'first': prefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page=1', 'first': httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page=1',
'id': prefix+'://'+domain+'/users/'+nickname+'/'+followFile, 'id': httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile,
'totalItems': getNoOfFollows(nickname,domain), 'totalItems': getNoOfFollows(nickname,domain),
'type': 'OrderedCollection'} 'type': 'OrderedCollection'}
return following return following
@ -169,9 +165,9 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \
nextPageNumber=int(pageNumber+1) nextPageNumber=int(pageNumber+1)
following = { following = {
'@context': 'https://www.w3.org/ns/activitystreams', '@context': 'https://www.w3.org/ns/activitystreams',
'id': prefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(pageNumber), 'id': httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(pageNumber),
'orderedItems': [], 'orderedItems': [],
'partOf': prefix+'://'+domain+'/users/'+nickname+'/'+followFile, 'partOf': httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile,
'totalItems': 0, 'totalItems': 0,
'type': 'OrderedCollectionPage'} 'type': 'OrderedCollectionPage'}
@ -190,10 +186,10 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \
pageCtr += 1 pageCtr += 1
totalCtr += 1 totalCtr += 1
if currPage==pageNumber: if currPage==pageNumber:
url = prefix + '://' + line.lower().replace('\n','').split('@')[1] + \ url = httpPrefix + '://' + line.lower().replace('\n','').split('@')[1] + \
'/users/' + line.lower().replace('\n','').split('@')[0] '/users/' + line.lower().replace('\n','').split('@')[0]
following['orderedItems'].append(url) following['orderedItems'].append(url)
elif line.startswith('http') and '/users/' in line: elif (line.startswith('http') or line.startswith('dat')) and '/users/' in line:
pageCtr += 1 pageCtr += 1
totalCtr += 1 totalCtr += 1
if currPage==pageNumber: if currPage==pageNumber:
@ -206,7 +202,7 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \
if lastPage<1: if lastPage<1:
lastPage=1 lastPage=1
if nextPageNumber>lastPage: if nextPageNumber>lastPage:
following['next']=prefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(lastPage) following['next']=httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(lastPage)
return following return following
def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> bool: def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> bool:
@ -216,7 +212,7 @@ def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> boo
return False return False
if '/users/' not in messageJson['actor']: if '/users/' not in messageJson['actor']:
return False return False
domain=messageJson['actor'].split('/users/')[0].replace('https://','').replace('http://','') domain=messageJson['actor'].split('/users/')[0].replace('https://','').replace('http://','').replace('dat://','')
if not domainPermitted(domain,federationList): if not domainPermitted(domain,federationList):
return False return False
nickname=messageJson['actor'].split('/users/')[1].replace('@','') nickname=messageJson['actor'].split('/users/')[1].replace('@','')
@ -225,7 +221,7 @@ def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> boo
return False return False
if '/users/' not in messageJson['object']: if '/users/' not in messageJson['object']:
return False return False
domainToFollow=messageJson['object'].split('/users/')[0].replace('https://','').replace('http://','') domainToFollow=messageJson['object'].split('/users/')[0].replace('https://','').replace('http://','').replace('dat://','')
if not domainPermitted(domainToFollow,federationList): if not domainPermitted(domainToFollow,federationList):
return False return False
nicknameToFollow=messageJson['object'].split('/users/')[1].replace('@','') nicknameToFollow=messageJson['object'].split('/users/')[1].replace('@','')
@ -235,22 +231,14 @@ def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> boo
return False return False
return followerOfPerson(baseDir,nickname,domain,nicknameToFollow,domainToFollow,federationList) return followerOfPerson(baseDir,nickname,domain,nicknameToFollow,domainToFollow,federationList)
def sendFollowRequest(baseDir: str,nickname: str,domain: str,port: int,https: bool, \ def sendFollowRequest(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
followNickname: str,followDomain: str,followPort: bool,followHttps: bool, \ followNickname: str,followDomain: str,followPort: bool,followHttpPrefix: str, \
federationList: []) -> {}: federationList: []) -> {}:
"""Gets the json object for sending a follow request """Gets the json object for sending a follow request
""" """
if not domainPermitted(followDomain,federationList): if not domainPermitted(followDomain,federationList):
return None return None
prefix='https'
if not https:
prefix='http'
followPrefix='https'
if not followHttps:
followPrefix='http'
if port!=80 and port!=443: if port!=80 and port!=443:
domain=domain+':'+str(port) domain=domain+':'+str(port)
@ -259,8 +247,8 @@ def sendFollowRequest(baseDir: str,nickname: str,domain: str,port: int,https: bo
newFollow = { newFollow = {
'type': 'Follow', 'type': 'Follow',
'actor': prefix+'://'+domain+'/users/'+nickname, 'actor': httpPrefix+'://'+domain+'/users/'+nickname,
'object': followPrefix+'://'+followDomain+'/users/'+followNickname, 'object': followHttpPrefix+'://'+followDomain+'/users/'+followNickname,
'to': [toUrl], 'to': [toUrl],
'cc': [] 'cc': []
} }

View File

@ -17,18 +17,14 @@ import json
def signPostHeaders(privateKeyPem: str, nickname: str, domain: str, \ def signPostHeaders(privateKeyPem: str, nickname: str, domain: str, \
port: int,path: str, \ port: int,path: str, \
https: bool, messageBodyJson: {}) -> str: httpPrefix: str, messageBodyJson: {}) -> str:
"""Returns a raw signature string that can be plugged into a header and """Returns a raw signature string that can be plugged into a header and
used to verify the authenticity of an HTTP transmission. used to verify the authenticity of an HTTP transmission.
""" """
prefix='https'
if not https:
prefix='http'
if port!=80 and port!=443: if port!=80 and port!=443:
domain=domain+':'+str(port) domain=domain+':'+str(port)
keyID = prefix+'://'+domain+'/users/'+nickname+'/main-key' keyID = httpPrefix+'://'+domain+'/users/'+nickname+'/main-key'
if not messageBodyJson: if not messageBodyJson:
headers = {'host': domain} headers = {'host': domain}
else: else:
@ -63,7 +59,7 @@ def signPostHeaders(privateKeyPem: str, nickname: str, domain: str, \
return signatureHeader return signatureHeader
def createSignedHeader(privateKeyPem: str,nickname: str,domain: str,port: int, \ def createSignedHeader(privateKeyPem: str,nickname: str,domain: str,port: int, \
path: str,https: bool,withDigest: bool, \ path: str,httpPrefix: str,withDigest: bool, \
messageBodyJson: {}) -> {}: messageBodyJson: {}) -> {}:
headerDomain=domain headerDomain=domain
@ -79,12 +75,12 @@ def createSignedHeader(privateKeyPem: str,nickname: str,domain: str,port: int, \
headers = {'host': headerDomain, 'digest': f'SHA-256={bodyDigest}'} headers = {'host': headerDomain, 'digest': f'SHA-256={bodyDigest}'}
path='/inbox' path='/inbox'
signatureHeader = signPostHeaders(privateKeyPem, nickname, domain, port, \ signatureHeader = signPostHeaders(privateKeyPem, nickname, domain, port, \
path, https, None) path, httpPrefix, None)
headers['signature'] = signatureHeader headers['signature'] = signatureHeader
headers['Content-type'] = 'application/json' headers['Content-type'] = 'application/json'
return headers return headers
def verifyPostHeaders(https: bool, publicKeyPem: str, headers: dict, \ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict, \
path: str, GETmethod: bool, \ path: str, GETmethod: bool, \
messageBodyJsonStr: str) -> bool: messageBodyJsonStr: str) -> bool:
"""Returns true or false depending on if the key that we plugged in here """Returns true or false depending on if the key that we plugged in here
@ -100,10 +96,6 @@ def verifyPostHeaders(https: bool, publicKeyPem: str, headers: dict, \
else: else:
method='POST' method='POST'
prefix='https'
if not https:
prefix='http'
publicKeyPem = RSA.import_key(publicKeyPem) publicKeyPem = RSA.import_key(publicKeyPem)
# Build a dictionary of the signature values # Build a dictionary of the signature values
signatureHeader = headers['signature'] signatureHeader = headers['signature']

18
like.py
View File

@ -11,7 +11,7 @@ import commentjson
from utils import urlPermitted from utils import urlPermitted
def like(baseDir: str,federationList: [],nickname: str,domain: str,port: int, \ def like(baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
toUrl: str,ccUrl: str,https: bool,objectUrl: str,saveToFile: bool) -> {}: toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str,saveToFile: bool) -> {}:
"""Creates a like """Creates a like
Typically toUrl will be a followers collection Typically toUrl will be a followers collection
and ccUrl might be a specific person whose post was liked and ccUrl might be a specific person whose post was liked
@ -20,16 +20,12 @@ def like(baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
if not urlPermitted(objectUrl,federationList): if not urlPermitted(objectUrl,federationList):
return None return None
prefix='https'
if not https:
prefix='http'
if port!=80 and port!=443: if port!=80 and port!=443:
domain=domain+':'+str(port) domain=domain+':'+str(port)
newLike = { newLike = {
'type': 'Like', 'type': 'Like',
'actor': prefix+'://'+domain+'/users/'+nickname, 'actor': httpPrefix+'://'+domain+'/users/'+nickname,
'object': objectUrl, 'object': objectUrl,
'to': [toUrl], 'to': [toUrl],
'cc': [] 'cc': []
@ -44,19 +40,15 @@ def like(baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
return newLike return newLike
def likePost(baseDir: str,federationList: [], \ def likePost(baseDir: str,federationList: [], \
nickname: str, domain: str, port: int, https: bool, \n nickname: str, domain: str, port: int, httpPrefix: str, \n
likeNickname: str, likeDomain: str, likePort: int, likeHttps: bool, \n likeNickname: str, likeDomain: str, likePort: int, likeHttps: bool, \n
likeStatusNumber: int,saveToFile: bool) -> {}: likeStatusNumber: int,saveToFile: bool) -> {}:
"""Likes a given status post """Likes a given status post
""" """
prefix='https'
if not likeHttps:
prefix='http'
likeDomain=likeDomain likeDomain=likeDomain
if likePort!=80 and likePort!=443: if likePort!=80 and likePort!=443:
likeDomain=likeDomain+':'+str(likePort) likeDomain=likeDomain+':'+str(likePort)
objectUrl = prefix + '://'+likeDomain+'/users/'+likeNickname+'/statuses/'+str(likeStatusNumber) objectUrl = httpPrefix + '://'+likeDomain+'/users/'+likeNickname+'/statuses/'+str(likeStatusNumber)
return like(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,https,objectUrl,saveToFile) return like(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,httpPrefix,objectUrl,saveToFile)

View File

@ -22,16 +22,12 @@ def generateRSAKey() -> (str,str):
return privateKeyPem,publicKeyPem return privateKeyPem,publicKeyPem
def createPerson(baseDir: str,nickname: str,domain: str,port: int, \ def createPerson(baseDir: str,nickname: str,domain: str,port: int, \
https: bool, saveToFile: bool) -> (str,str,{},{}): httpPrefix: str, saveToFile: bool) -> (str,str,{},{}):
"""Returns the private key, public key, actor and webfinger endpoint """Returns the private key, public key, actor and webfinger endpoint
""" """
prefix='https'
if not https:
prefix='http'
privateKeyPem,publicKeyPem=generateRSAKey() privateKeyPem,publicKeyPem=generateRSAKey()
webfingerEndpoint= \ webfingerEndpoint= \
createWebfingerEndpoint(nickname,domain,port,https,publicKeyPem) createWebfingerEndpoint(nickname,domain,port,httpPrefix,publicKeyPem)
if saveToFile: if saveToFile:
storeWebfingerEndpoint(nickname,domain,baseDir,webfingerEndpoint) storeWebfingerEndpoint(nickname,domain,baseDir,webfingerEndpoint)
@ -54,29 +50,29 @@ def createPerson(baseDir: str,nickname: str,domain: str,port: int, \
'toot': 'http://joinmastodon.org/ns#', 'toot': 'http://joinmastodon.org/ns#',
'value': 'schema:value'}], 'value': 'schema:value'}],
'attachment': [], 'attachment': [],
'endpoints': {'sharedInbox': prefix+'://'+domain+'/inbox'}, 'endpoints': {'sharedInbox': httpPrefix+'://'+domain+'/inbox'},
'featured': prefix+'://'+domain+'/users/'+nickname+'/collections/featured', 'featured': httpPrefix+'://'+domain+'/users/'+nickname+'/collections/featured',
'followers': prefix+'://'+domain+'/users/'+nickname+'/followers', 'followers': httpPrefix+'://'+domain+'/users/'+nickname+'/followers',
'following': prefix+'://'+domain+'/users/'+nickname+'/following', 'following': httpPrefix+'://'+domain+'/users/'+nickname+'/following',
'icon': {'mediaType': 'image/png', 'icon': {'mediaType': 'image/png',
'type': 'Image', 'type': 'Image',
'url': prefix+'://'+domain+'/users/'+nickname+'_icon.png'}, 'url': httpPrefix+'://'+domain+'/users/'+nickname+'_icon.png'},
'id': prefix+'://'+domain+'/users/'+nickname, 'id': httpPrefix+'://'+domain+'/users/'+nickname,
'image': {'mediaType': 'image/png', 'image': {'mediaType': 'image/png',
'type': 'Image', 'type': 'Image',
'url': prefix+'://'+domain+'/users/'+nickname+'.png'}, 'url': httpPrefix+'://'+domain+'/users/'+nickname+'.png'},
'inbox': prefix+'://'+domain+'/users/'+nickname+'/inbox', 'inbox': httpPrefix+'://'+domain+'/users/'+nickname+'/inbox',
'manuallyApprovesFollowers': False, 'manuallyApprovesFollowers': False,
'name': nickname, 'name': nickname,
'outbox': prefix+'://'+domain+'/users/'+nickname+'/outbox', 'outbox': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox',
'preferredUsername': ''+nickname, 'preferredUsername': ''+nickname,
'publicKey': {'id': prefix+'://'+domain+'/users/'+nickname+'/main-key', 'publicKey': {'id': httpPrefix+'://'+domain+'/users/'+nickname+'/main-key',
'owner': prefix+'://'+domain+'/users/'+nickname, 'owner': httpPrefix+'://'+domain+'/users/'+nickname,
'publicKeyPem': publicKeyPem, 'publicKeyPem': publicKeyPem,
'summary': '', 'summary': '',
'tag': [], 'tag': [],
'type': 'Person', 'type': 'Person',
'url': prefix+'://'+domain+'/@'+nickname} 'url': httpPrefix+'://'+domain+'/@'+nickname}
} }
if saveToFile: if saveToFile:
@ -170,7 +166,7 @@ def personLookup(domain: str,path: str,baseDir: str) -> {}:
return personJson return personJson
def personOutboxJson(baseDir: str,domain: str,port: int,path: str, \ def personOutboxJson(baseDir: str,domain: str,port: int,path: str, \
https: bool,noOfItems: int) -> []: httpPrefix: str,noOfItems: int) -> []:
"""Obtain the outbox feed for the given person """Obtain the outbox feed for the given person
""" """
if not '/outbox' in path: if not '/outbox' in path:
@ -204,7 +200,7 @@ def personOutboxJson(baseDir: str,domain: str,port: int,path: str, \
return None return None
if not validNickname(nickname): if not validNickname(nickname):
return None return None
return createOutbox(baseDir,nickname,domain,port,https, \ return createOutbox(baseDir,nickname,domain,port,httpPrefix, \
noOfItems,headerOnly,pageNumber) noOfItems,headerOnly,pageNumber)
def setPreferredNickname(baseDir: str,nickname: str, domain: str, \ def setPreferredNickname(baseDir: str,nickname: str, domain: str, \

View File

@ -250,15 +250,11 @@ def deleteAllPosts(baseDir: str,nickname: str, domain: str) -> None:
print(e) print(e)
def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
toUrl: str, ccUrl: str, https: bool, content: str, \ toUrl: str, ccUrl: str, httpPrefix: str, content: str, \
followersOnly: bool, saveToFile: bool, clientToServer: bool, \ followersOnly: bool, saveToFile: bool, clientToServer: bool, \
inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}: inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
"""Creates a message """Creates a message
""" """
prefix='https'
if not https:
prefix='http'
if port!=80 and port!=443: if port!=80 and port!=443:
domain=domain+':'+str(port) domain=domain+':'+str(port)
@ -266,11 +262,11 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
conversationDate=published.split('T')[0] conversationDate=published.split('T')[0]
conversationId=statusNumber conversationId=statusNumber
postTo='https://www.w3.org/ns/activitystreams#Public' postTo='https://www.w3.org/ns/activitystreams#Public'
postCC=prefix+'://'+domain+'/users/'+nickname+'/followers' postCC=httpPrefix+'://'+domain+'/users/'+nickname+'/followers'
if followersOnly: if followersOnly:
postTo=postCC postTo=postCC
postCC='' postCC=''
newPostId=prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber newPostId=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
sensitive=False sensitive=False
summary=None summary=None
if subject: if subject:
@ -280,7 +276,7 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
newPost = { newPost = {
'id': newPostId+'/activity', 'id': newPostId+'/activity',
'type': 'Create', 'type': 'Create',
'actor': prefix+'://'+domain+'/users/'+nickname, 'actor': httpPrefix+'://'+domain+'/users/'+nickname,
'published': published, 'published': published,
'to': [toUrl], 'to': [toUrl],
'cc': [], 'cc': [],
@ -290,12 +286,12 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
'summary': summary, 'summary': summary,
'inReplyTo': inReplyTo, 'inReplyTo': inReplyTo,
'published': published, 'published': published,
'url': prefix+'://'+domain+'/@'+nickname+'/'+statusNumber, 'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber,
'attributedTo': prefix+'://'+domain+'/users/'+nickname, 'attributedTo': httpPrefix+'://'+domain+'/users/'+nickname,
'to': [toUrl], 'to': [toUrl],
'cc': [], 'cc': [],
'sensitive': sensitive, 'sensitive': sensitive,
'atomUri': prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber, 'atomUri': httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
'inReplyToAtomUri': inReplyToAtomUri, 'inReplyToAtomUri': inReplyToAtomUri,
'conversation': 'tag:'+domain+','+conversationDate+':objectId='+conversationId+':objectType=Conversation', 'conversation': 'tag:'+domain+','+conversationDate+':objectId='+conversationId+':objectType=Conversation',
'content': content, 'content': content,
@ -322,12 +318,12 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
'summary': summary, 'summary': summary,
'inReplyTo': inReplyTo, 'inReplyTo': inReplyTo,
'published': published, 'published': published,
'url': prefix+'://'+domain+'/@'+nickname+'/'+statusNumber, 'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber,
'attributedTo': prefix+'://'+domain+'/users/'+nickname, 'attributedTo': httpPrefix+'://'+domain+'/users/'+nickname,
'to': [toUrl], 'to': [toUrl],
'cc': [], 'cc': [],
'sensitive': sensitive, 'sensitive': sensitive,
'atomUri': prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber, 'atomUri': httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
'inReplyToAtomUri': inReplyToAtomUri, 'inReplyToAtomUri': inReplyToAtomUri,
'conversation': 'tag:'+domain+','+conversationDate+':objectId='+conversationId+':objectType=Conversation', 'conversation': 'tag:'+domain+','+conversationDate+':objectId='+conversationId+':objectType=Conversation',
'content': content, 'content': content,
@ -352,19 +348,16 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
return newPost return newPost
def createPublicPost(baseDir: str, def createPublicPost(baseDir: str,
nickname: str, domain: str, port: int,https: bool, \ nickname: str, domain: str, port: int,httpPrefix: str, \
content: str, followersOnly: bool, saveToFile: bool, content: str, followersOnly: bool, saveToFile: bool,
clientToServer: bool, \ clientToServer: bool, \
inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}: inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
"""Public post to the outbox """Public post to the outbox
""" """
prefix='https'
if not https:
prefix='http'
return createPostBase(baseDir,nickname, domain, port, \ return createPostBase(baseDir,nickname, domain, port, \
'https://www.w3.org/ns/activitystreams#Public', \ 'https://www.w3.org/ns/activitystreams#Public', \
prefix+'://'+domain+'/users/'+nickname+'/followers', \ httpPrefix+'://'+domain+'/users/'+nickname+'/followers', \
https, content, followersOnly, saveToFile, clientToServer, \ httpPrefix, content, followersOnly, saveToFile, clientToServer, \
inReplyTo, inReplyToAtomUri, subject) inReplyTo, inReplyToAtomUri, subject)
def threadSendPost(session,postJsonObject: {},federationList: [],inboxUrl: str, \ def threadSendPost(session,postJsonObject: {},federationList: [],inboxUrl: str, \
@ -394,25 +387,21 @@ def threadSendPost(session,postJsonObject: {},federationList: [],inboxUrl: str,
def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \
toNickname: str, toDomain: str, toPort: int, cc: str, \ toNickname: str, toDomain: str, toPort: int, cc: str, \
https: bool, content: str, followersOnly: bool, \ httpPrefix: str, content: str, followersOnly: bool, \
saveToFile: bool, clientToServer: bool, federationList: [], \ saveToFile: bool, clientToServer: bool, federationList: [], \
sendThreads: [], postLog: [], cachedWebfingers: {},personCache: {}, \ sendThreads: [], postLog: [], cachedWebfingers: {},personCache: {}, \
inReplyTo=None, inReplyToAtomUri=None, subject=None) -> int: inReplyTo=None, inReplyToAtomUri=None, subject=None) -> int:
"""Post to another inbox """Post to another inbox
""" """
prefix='https'
if not https:
prefix='http'
withDigest=True withDigest=True
if toPort!=80 and toPort!=443: if toPort!=80 and toPort!=443:
toDomain=toDomain+':'+str(toPort) toDomain=toDomain+':'+str(toPort)
handle=prefix+'://'+toDomain+'/@'+toNickname handle=httpPrefix+'://'+toDomain+'/@'+toNickname
# lookup the inbox for the To handle # lookup the inbox for the To handle
wfRequest = webfingerHandle(session,handle,https,cachedWebfingers) wfRequest = webfingerHandle(session,handle,httpPrefix,cachedWebfingers)
if not wfRequest: if not wfRequest:
return 1 return 1
@ -428,7 +417,7 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \
postJsonObject = \ postJsonObject = \
createPostBase(baseDir,nickname,domain,port, \ createPostBase(baseDir,nickname,domain,port, \
toPersonId,cc,https,content, \ toPersonId,cc,httpPrefix,content, \
followersOnly,saveToFile,clientToServer, \ followersOnly,saveToFile,clientToServer, \
inReplyTo,inReplyToAtomUri, \ inReplyTo,inReplyToAtomUri, \
subject) subject)
@ -446,7 +435,7 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \
# construct the http header # construct the http header
signatureHeaderJson = \ signatureHeaderJson = \
createSignedHeader(privateKeyPem, nickname, domain, port, \ createSignedHeader(privateKeyPem, nickname, domain, port, \
postPath, https, withDigest, postJsonObject) postPath, httpPrefix, withDigest, postJsonObject)
# Keep the number of threads being used small # Keep the number of threads being used small
while len(sendThreads)>10: while len(sendThreads)>10:
@ -462,14 +451,10 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \
thr.start() thr.start()
return 0 return 0
def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
itemsPerPage: int,headerOnly: bool,pageNumber=None) -> {}: itemsPerPage: int,headerOnly: bool,pageNumber=None) -> {}:
"""Constructs the outbox feed """Constructs the outbox feed
""" """
prefix='https'
if not https:
prefix='http'
outboxDir = createOutboxDir(nickname,domain,baseDir) outboxDir = createOutboxDir(nickname,domain,baseDir)
if port!=80 and port!=443: if port!=80 and port!=443:
@ -482,16 +467,16 @@ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
except: except:
pass pass
outboxHeader = {'@context': 'https://www.w3.org/ns/activitystreams', outboxHeader = {'@context': 'https://www.w3.org/ns/activitystreams',
'first': prefix+'://'+domain+'/users/'+nickname+'/outbox?page=true', 'first': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox?page=true',
'id': prefix+'://'+domain+'/users/'+nickname+'/outbox', 'id': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox',
'last': prefix+'://'+domain+'/users/'+nickname+'/outbox?page=true', 'last': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox?page=true',
'totalItems': 0, 'totalItems': 0,
'type': 'OrderedCollection'} 'type': 'OrderedCollection'}
outboxItems = {'@context': 'https://www.w3.org/ns/activitystreams', outboxItems = {'@context': 'https://www.w3.org/ns/activitystreams',
'id': prefix+'://'+domain+'/users/'+nickname+'/outbox'+pageStr, 'id': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox'+pageStr,
'orderedItems': [ 'orderedItems': [
], ],
'partOf': prefix+'://'+domain+'/users/'+nickname+'/outbox', 'partOf': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox',
'type': 'OrderedCollectionPage'} 'type': 'OrderedCollectionPage'}
# counter for posts loop # counter for posts loop
@ -513,7 +498,7 @@ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
if lastPage<1: if lastPage<1:
lastPage=1 lastPage=1
outboxHeader['last']= \ outboxHeader['last']= \
prefix+'://'+domain+'/users/'+nickname+'/outbox?page='+str(lastPage) httpPrefix+'://'+domain+'/users/'+nickname+'/outbox?page='+str(lastPage)
# Insert posts # Insert posts
currPage=1 currPage=1
@ -524,7 +509,7 @@ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
# update the prev entry for the last message id # update the prev entry for the last message id
postId = prevPostFilename.split('#statuses#')[1].replace('#activity','') postId = prevPostFilename.split('#statuses#')[1].replace('#activity','')
outboxHeader['prev']= \ outboxHeader['prev']= \
prefix+'://'+domain+'/users/'+nickname+'/outbox?min_id='+postId+'&page=true' httpPrefix+'://'+domain+'/users/'+nickname+'/outbox?min_id='+postId+'&page=true'
# get the full path of the post file # get the full path of the post file
filePath = os.path.join(outboxDir, postFilename) filePath = os.path.join(outboxDir, postFilename)
try: try:
@ -542,7 +527,7 @@ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
if '/statuses/' in p['id']: if '/statuses/' in p['id']:
postId = p['id'].split('/statuses/')[1].replace('/activity','') postId = p['id'].split('/statuses/')[1].replace('/activity','')
outboxHeader['next']= \ outboxHeader['next']= \
prefix+'://'+domain+'/users/'+ \ httpPrefix+'://'+domain+'/users/'+ \
nickname+'/outbox?max_id='+ \ nickname+'/outbox?max_id='+ \
postId+'&page=true' postId+'&page=true'
postsOnPageCtr += 1 postsOnPageCtr += 1

View File

@ -43,10 +43,10 @@ def testHttpsigBase(withDigest):
print('testHttpsig(' + str(withDigest) + ')') print('testHttpsig(' + str(withDigest) + ')')
nickname='socrates' nickname='socrates'
domain='argumentative.social' domain='argumentative.social'
https=True httpPrefix='https'
port=5576 port=5576
baseDir=os.getcwd() baseDir=os.getcwd()
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,https,False) privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,False)
messageBodyJsonStr = '{"a key": "a value", "another key": "A string"}' messageBodyJsonStr = '{"a key": "a value", "another key": "A string"}'
headersDomain=domain headersDomain=domain
@ -60,11 +60,11 @@ def testHttpsigBase(withDigest):
headers = {'host': headersDomain, 'digest': f'SHA-256={bodyDigest}'} headers = {'host': headersDomain, 'digest': f'SHA-256={bodyDigest}'}
path='/inbox' path='/inbox'
signatureHeader = signPostHeaders(privateKeyPem, nickname, domain, port, path, https, None) signatureHeader = signPostHeaders(privateKeyPem, nickname, domain, port, path, httpPrefix, None)
headers['signature'] = signatureHeader headers['signature'] = signatureHeader
assert verifyPostHeaders(https, publicKeyPem, headers, '/inbox' ,False, messageBodyJsonStr) assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, '/inbox' ,False, messageBodyJsonStr)
assert verifyPostHeaders(https, publicKeyPem, headers, '/parambulator/inbox', False , messageBodyJsonStr) == False assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, '/parambulator/inbox', False , messageBodyJsonStr) == False
assert verifyPostHeaders(https, publicKeyPem, headers, '/inbox', True, messageBodyJsonStr) == False assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, '/inbox', True, messageBodyJsonStr) == False
if not withDigest: if not withDigest:
# fake domain # fake domain
headers = {'host': 'bogon.domain'} headers = {'host': 'bogon.domain'}
@ -74,7 +74,7 @@ def testHttpsigBase(withDigest):
bodyDigest = base64.b64encode(SHA256.new(messageBodyJsonStr.encode()).digest()) bodyDigest = base64.b64encode(SHA256.new(messageBodyJsonStr.encode()).digest())
headers = {'host': domain, 'digest': f'SHA-256={bodyDigest}'} headers = {'host': domain, 'digest': f'SHA-256={bodyDigest}'}
headers['signature'] = signatureHeader headers['signature'] = signatureHeader
assert verifyPostHeaders(https, publicKeyPem, headers, '/inbox', True, messageBodyJsonStr) == False assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, '/inbox', True, messageBodyJsonStr) == False
def testHttpsig(): def testHttpsig():
testHttpsigBase(False) testHttpsigBase(False)
@ -111,20 +111,20 @@ def createServerAlice(path: str,domain: str,port: int,federationList: []):
os.mkdir(path) os.mkdir(path)
os.chdir(path) os.chdir(path)
nickname='alice' nickname='alice'
https=False httpPrefix=False
useTor=False useTor=False
clientToServer=False clientToServer=False
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,https,True) privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,httpPrefix,True)
deleteAllPosts(path,nickname,domain) deleteAllPosts(path,nickname,domain)
followPerson(path,nickname,domain,'bob','127.0.0.100:61936',federationList) followPerson(path,nickname,domain,'bob','127.0.0.100:61936',federationList)
followerOfPerson(path,nickname,domain,'bob','127.0.0.100:61936',federationList) followerOfPerson(path,nickname,domain,'bob','127.0.0.100:61936',federationList)
createPublicPost(path,nickname, domain, port,https, "No wise fish would go anywhere without a porpoise", False, True, clientToServer) createPublicPost(path,nickname, domain, port,httpPrefix, "No wise fish would go anywhere without a porpoise", False, True, clientToServer)
createPublicPost(path,nickname, domain, port,https, "Curiouser and curiouser!", False, True, clientToServer) createPublicPost(path,nickname, domain, port,httpPrefix, "Curiouser and curiouser!", False, True, clientToServer)
createPublicPost(path,nickname, domain, port,https, "In the gardens of memory, in the palace of dreams, that is where you and I shall meet", False, True, clientToServer) createPublicPost(path,nickname, domain, port,httpPrefix, "In the gardens of memory, in the palace of dreams, that is where you and I shall meet", False, True, clientToServer)
global testServerAliceRunning global testServerAliceRunning
testServerAliceRunning = True testServerAliceRunning = True
print('Server running: Alice') print('Server running: Alice')
runDaemon(domain,port,https,federationList,useTor,True) runDaemon(domain,port,httpPrefix,federationList,useTor,True)
def createServerBob(path: str,domain: str,port: int,federationList: []): 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))
@ -133,20 +133,20 @@ def createServerBob(path: str,domain: str,port: int,federationList: []):
os.mkdir(path) os.mkdir(path)
os.chdir(path) os.chdir(path)
nickname='bob' nickname='bob'
https=False httpPrefix='http'
useTor=False useTor=False
clientToServer=False clientToServer=False
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,https,True) privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,httpPrefix,True)
deleteAllPosts(path,nickname,domain) deleteAllPosts(path,nickname,domain)
followPerson(path,nickname,domain,'alice','127.0.0.50:61935',federationList) followPerson(path,nickname,domain,'alice','127.0.0.50:61935',federationList)
followerOfPerson(path,nickname,domain,'alice','127.0.0.50:61935',federationList) followerOfPerson(path,nickname,domain,'alice','127.0.0.50:61935',federationList)
createPublicPost(path,nickname, domain, port,https, "It's your life, live it your way.", False, True, clientToServer) createPublicPost(path,nickname, domain, port,httpPrefix, "It's your life, live it your way.", False, True, clientToServer)
createPublicPost(path,nickname, domain, port,https, "One of the things I've realised is that I am very simple", False, True, clientToServer) createPublicPost(path,nickname, domain, port,httpPrefix, "One of the things I've realised is that I am very simple", False, True, clientToServer)
createPublicPost(path,nickname, domain, port,https, "Quantum physics is a bit of a passion of mine", False, True, clientToServer) createPublicPost(path,nickname, domain, port,httpPrefix, "Quantum physics is a bit of a passion of mine", False, True, clientToServer)
global testServerBobRunning global testServerBobRunning
testServerBobRunning = True testServerBobRunning = True
print('Server running: Bob') print('Server running: Bob')
runDaemon(domain,port,https,federationList,useTor,True) runDaemon(domain,port,httpPrefix,federationList,useTor,True)
def testPostMessageBetweenServers(): def testPostMessageBetweenServers():
print('Testing sending message from one server to the inbox of another') print('Testing sending message from one server to the inbox of another')
@ -156,7 +156,7 @@ def testPostMessageBetweenServers():
testServerAliceRunning = False testServerAliceRunning = False
testServerBobRunning = False testServerBobRunning = False
https=False httpPrefix='http'
useTor=False useTor=False
federationList=['127.0.0.50','127.0.0.100'] federationList=['127.0.0.50','127.0.0.100']
@ -200,7 +200,7 @@ def testPostMessageBetweenServers():
ccUrl=None ccUrl=None
alicePersonCache={} alicePersonCache={}
aliceCachedWebfingers={} aliceCachedWebfingers={}
sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, https, 'Why is a mouse when it spins?', followersOnly, saveToFile, clientToServer, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject) sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Why is a mouse when it spins?', followersOnly, saveToFile, clientToServer, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
print('sendResult: '+str(sendResult)) print('sendResult: '+str(sendResult))
for i in range(10): for i in range(10):
@ -221,14 +221,14 @@ def testFollows():
nickname='test529' nickname='test529'
domain='testdomain.com' domain='testdomain.com'
port=80 port=80
https=True httpPrefix='https'
federationList=['wild.com','mesh.com'] federationList=['wild.com','mesh.com']
baseDir=currDir+'/.tests_testfollows' baseDir=currDir+'/.tests_testfollows'
if os.path.isdir(baseDir): if os.path.isdir(baseDir):
shutil.rmtree(baseDir) shutil.rmtree(baseDir)
os.mkdir(baseDir) os.mkdir(baseDir)
os.chdir(baseDir) os.chdir(baseDir)
createPerson(baseDir,nickname,domain,port,https,True) createPerson(baseDir,nickname,domain,port,httpPrefix,True)
clearFollows(baseDir,nickname,domain) clearFollows(baseDir,nickname,domain)
followPerson(baseDir,nickname,domain,'badger','wild.com',federationList) followPerson(baseDir,nickname,domain,'badger','wild.com',federationList)
@ -280,7 +280,7 @@ def testCreatePerson():
nickname='test382' nickname='test382'
domain='badgerdomain.com' domain='badgerdomain.com'
port=80 port=80
https=True httpPrefix='https'
clientToServer=False clientToServer=False
baseDir=currDir+'/.tests_createperson' baseDir=currDir+'/.tests_createperson'
if os.path.isdir(baseDir): if os.path.isdir(baseDir):
@ -288,12 +288,12 @@ def testCreatePerson():
os.mkdir(baseDir) os.mkdir(baseDir)
os.chdir(baseDir) os.chdir(baseDir)
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,https,True) privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,True)
deleteAllPosts(baseDir,nickname,domain) deleteAllPosts(baseDir,nickname,domain)
setPreferredNickname(baseDir,nickname,domain,'badger') setPreferredNickname(baseDir,nickname,domain,'badger')
setBio(baseDir,nickname,domain,'Randomly roaming in your backyard') setBio(baseDir,nickname,domain,'Randomly roaming in your backyard')
archivePosts(nickname,domain,baseDir,4) archivePosts(nickname,domain,baseDir,4)
createPublicPost(baseDir,nickname, domain, port,https, "G'day world!", False, True, clientToServer, None, None, 'Not suitable for Vogons') createPublicPost(baseDir,nickname, domain, port,httpPrefix, "G'day world!", False, True, clientToServer, None, None, 'Not suitable for Vogons')
os.chdir(currDir) os.chdir(currDir)
shutil.rmtree(baseDir) shutil.rmtree(baseDir)

View File

@ -22,11 +22,11 @@ def parseHandle(handle: str) -> (str,str):
return None, None return None, None
if '/@' in handle: if '/@' in handle:
domain, nickname = \ domain, nickname = \
handle.replace('https://','').replace('http://','').split('/@') handle.replace('https://','').replace('http://','').replace('dat://','').split('/@')
else: else:
if '/users/' in handle: if '/users/' in handle:
domain, nickname = \ domain, nickname = \
handle.replace('https://','').replace('http://','').split('/users/') handle.replace('https://','').replace('http://','').replace('dat://','').split('/users/')
else: else:
if '@' in handle: if '@' in handle:
nickname, domain = handle.split('@') nickname, domain = handle.split('@')
@ -36,7 +36,7 @@ def parseHandle(handle: str) -> (str,str):
return nickname, domain return nickname, domain
def webfingerHandle(session,handle: str,https: bool,cachedWebfingers: {}) -> {}: def webfingerHandle(session,handle: str,httpPrefix: str,cachedWebfingers: {}) -> {}:
nickname, domain = parseHandle(handle) nickname, domain = parseHandle(handle)
if not nickname: if not nickname:
return None return None
@ -47,10 +47,7 @@ def webfingerHandle(session,handle: str,https: bool,cachedWebfingers: {}) -> {}:
wf=getWebfingerFromCache(nickname+'@'+wfDomain,cachedWebfingers) wf=getWebfingerFromCache(nickname+'@'+wfDomain,cachedWebfingers)
if wf: if wf:
return wf return wf
prefix='https' url = '{}://{}/.well-known/webfinger'.format(httpPrefix,domain)
if not https:
prefix='http'
url = '{}://{}/.well-known/webfinger'.format(prefix,domain)
par = {'resource': 'acct:{}'.format(nickname+'@'+wfDomain)} par = {'resource': 'acct:{}'.format(nickname+'@'+wfDomain)}
hdr = {'Accept': 'application/jrd+json'} hdr = {'Accept': 'application/jrd+json'}
#try: #try:
@ -83,39 +80,35 @@ def storeWebfingerEndpoint(nickname: str,domain: str,baseDir: str, \
return True return True
def createWebfingerEndpoint(nickname: str,domain: str,port: int, \ def createWebfingerEndpoint(nickname: str,domain: str,port: int, \
https: bool,publicKeyPem) -> {}: httpPrefix: str,publicKeyPem) -> {}:
"""Creates a webfinger endpoint for a user """Creates a webfinger endpoint for a user
""" """
prefix='https'
if not https:
prefix='http'
if port!=80 and port!=443: if port!=80 and port!=443:
domain=domain+':'+str(port) domain=domain+':'+str(port)
account = { account = {
"aliases": [ "aliases": [
prefix+"://"+domain+"/@"+nickname, httpPrefix+"://"+domain+"/@"+nickname,
prefix+"://"+domain+"/users/"+nickname httpPrefix+"://"+domain+"/users/"+nickname
], ],
"links": [ "links": [
{ {
"href": prefix+"://"+domain+"/@"+nickname, "href": httpPrefix+"://"+domain+"/@"+nickname,
"rel": "http://webfinger.net/rel/profile-page", "rel": "http://webfinger.net/rel/profile-page",
"type": "text/html" "type": "text/html"
}, },
{ {
"href": prefix+"://"+domain+"/users/"+nickname+".atom", "href": httpPrefix+"://"+domain+"/users/"+nickname+".atom",
"rel": "http://schemas.google.com/g/2010#updates-from", "rel": "http://schemas.google.com/g/2010#updates-from",
"type": "application/atom+xml" "type": "application/atom+xml"
}, },
{ {
"href": prefix+"://"+domain+"/users/"+nickname, "href": httpPrefix+"://"+domain+"/users/"+nickname,
"rel": "self", "rel": "self",
"type": "application/activity+json" "type": "application/activity+json"
}, },
{ {
"href": prefix+"://"+domain+"/api/salmon/1", "href": httpPrefix+"://"+domain+"/api/salmon/1",
"rel": "salmon" "rel": "salmon"
}, },
{ {
@ -124,7 +117,7 @@ def createWebfingerEndpoint(nickname: str,domain: str,port: int, \
}, },
{ {
"rel": "http://ostatus.org/schema/1.0/subscribe", "rel": "http://ostatus.org/schema/1.0/subscribe",
"template": prefix+"://"+domain+"/authorize_interaction?uri={uri}" "template": httpPrefix+"://"+domain+"/authorize_interaction?uri={uri}"
} }
], ],
"subject": "acct:"+nickname+"@"+domain "subject": "acct:"+nickname+"@"+domain