mirror of https://gitlab.com/bashrc2/epicyon
baseDir as parameter
parent
bee4f185a2
commit
eeb74f6e16
12
daemon.py
12
daemon.py
|
@ -69,7 +69,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.wfile.write(wfResult.encode('utf-8'))
|
self.wfile.write(wfResult.encode('utf-8'))
|
||||||
return
|
return
|
||||||
|
|
||||||
wfResult=webfingerLookup(self.path)
|
wfResult=webfingerLookup(self.path,self.server.baseDir)
|
||||||
if wfResult:
|
if wfResult:
|
||||||
self._set_headers('application/json')
|
self._set_headers('application/json')
|
||||||
self.wfile.write(json.dumps(wfResult).encode('utf-8'))
|
self.wfile.write(json.dumps(wfResult).encode('utf-8'))
|
||||||
|
@ -103,7 +103,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.GETbusy=False
|
self.GETbusy=False
|
||||||
return
|
return
|
||||||
# get outbox feed for a person
|
# get outbox feed for a person
|
||||||
outboxFeed=personOutboxJson(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:
|
||||||
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'))
|
||||||
|
@ -122,13 +122,13 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.GETbusy=False
|
self.GETbusy=False
|
||||||
return
|
return
|
||||||
# look up a person
|
# look up a person
|
||||||
getPerson = personLookup(self.server.domain,self.path)
|
getPerson = personLookup(self.server.domain,self.path,self.server.baseDir)
|
||||||
if getPerson:
|
if getPerson:
|
||||||
self._set_headers('application/json')
|
self._set_headers('application/json')
|
||||||
self.wfile.write(json.dumps(getPerson).encode('utf-8'))
|
self.wfile.write(json.dumps(getPerson).encode('utf-8'))
|
||||||
self.GETbusy=False
|
self.GETbusy=False
|
||||||
return
|
return
|
||||||
personKey = personKeyLookup(self.server.domain,self.path)
|
personKey = personKeyLookup(self.server.domain,self.path,self.server.baseDir)
|
||||||
if personKey:
|
if personKey:
|
||||||
self._set_headers('text/html; charset=utf-8')
|
self._set_headers('text/html; charset=utf-8')
|
||||||
self.wfile.write(personKey.encode('utf-8'))
|
self.wfile.write(personKey.encode('utf-8'))
|
||||||
|
@ -140,8 +140,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.GETbusy=False
|
self.GETbusy=False
|
||||||
return
|
return
|
||||||
# check that the file exists
|
# check that the file exists
|
||||||
baseDir=os.getcwd()
|
filename=self.server.baseDir+self.path
|
||||||
filename=baseDir+self.path
|
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
self._set_headers('application/json')
|
self._set_headers('application/json')
|
||||||
with open(filename, 'r', encoding='utf8') as File:
|
with open(filename, 'r', encoding='utf8') as File:
|
||||||
|
@ -208,5 +207,6 @@ def runDaemon(domain: str,port=80,https=True,fedList=[],useTor=False) -> None:
|
||||||
httpd.port=port
|
httpd.port=port
|
||||||
httpd.https=https
|
httpd.https=https
|
||||||
httpd.federationList=fedList.copy()
|
httpd.federationList=fedList.copy()
|
||||||
|
httpd.baseDir=os.getcwd()
|
||||||
print('Running ActivityPub daemon on ' + domain + ' port ' + str(port))
|
print('Running ActivityPub daemon on ' + domain + ' port ' + str(port))
|
||||||
httpd.serve_forever()
|
httpd.serve_forever()
|
||||||
|
|
13
epicyon.py
13
epicyon.py
|
@ -19,6 +19,7 @@ from posts import sendPost
|
||||||
from session import createSession
|
from session import createSession
|
||||||
from session import getJson
|
from session import getJson
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import requests
|
import requests
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
@ -43,8 +44,10 @@ domain='127.0.0.1'
|
||||||
port=6227
|
port=6227
|
||||||
https=False
|
https=False
|
||||||
useTor=False
|
useTor=False
|
||||||
|
baseDir=os.getcwd()
|
||||||
session = createSession(useTor)
|
session = createSession(useTor)
|
||||||
|
|
||||||
|
|
||||||
clearFollows(username,domain)
|
clearFollows(username,domain)
|
||||||
followPerson(username,domain,'badger','wild.com',federationList)
|
followPerson(username,domain,'badger','wild.com',federationList)
|
||||||
followPerson(username,domain,'squirrel','secret.com',federationList)
|
followPerson(username,domain,'squirrel','secret.com',federationList)
|
||||||
|
@ -70,17 +73,17 @@ followerOfPerson(username,domain,'giraffe','trees.com',federationList)
|
||||||
#sys.exit()
|
#sys.exit()
|
||||||
|
|
||||||
|
|
||||||
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(username,domain,port,https,True)
|
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,username,domain,port,https,True)
|
||||||
#deleteAllPosts(username,domain)
|
#deleteAllPosts(username,domain)
|
||||||
setPreferredUsername(username,domain,'badger')
|
setPreferredUsername(username,domain,'badger')
|
||||||
setBio(username,domain,'Some personal info')
|
setBio(username,domain,'Some personal info')
|
||||||
#createPublicPost(username, domain, https, "G'day world!", False, True, None, None, 'Not suitable for Vogons')
|
#createPublicPost(username, domain, https, "G'day world!", False, True, None, None, 'Not suitable for Vogons')
|
||||||
#archivePosts(username,domain,4)
|
#archivePosts(username,domain,baseDir,4)
|
||||||
#outboxJson=createOutbox(username,domain,port,https,2,True,None)
|
#outboxJson=createOutbox(baseDir,username,domain,port,https,2,True,None)
|
||||||
#pprint(outboxJson)
|
#pprint(outboxJson)
|
||||||
|
|
||||||
testPostMessageBetweenServers()
|
#testPostMessageBetweenServers()
|
||||||
#runDaemon(domain,port,https,federationList,useTor)
|
runDaemon(domain,port,https,federationList,useTor)
|
||||||
|
|
||||||
#testHttpsig()
|
#testHttpsig()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
3
inbox.py
3
inbox.py
|
@ -53,7 +53,7 @@ def validPublishedDate(published):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def receiveMessage(message):
|
def receiveMessage(message,baseDir: str):
|
||||||
if not message.get('type'):
|
if not message.get('type'):
|
||||||
return
|
return
|
||||||
if message['type']!='Create':
|
if message['type']!='Create':
|
||||||
|
@ -76,7 +76,6 @@ def receiveMessage(message):
|
||||||
domain=''
|
domain=''
|
||||||
messageId=message['id'].replace('/','_')
|
messageId=message['id'].replace('/','_')
|
||||||
handle=username.lower()+'@'+domain.lower()
|
handle=username.lower()+'@'+domain.lower()
|
||||||
baseDir=os.getcwd()
|
|
||||||
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||||
os.mkdir(baseDir+'/accounts/'+handle)
|
os.mkdir(baseDir+'/accounts/'+handle)
|
||||||
if not os.path.isdir(baseDir+'/accounts/'+handle+'/inbox'):
|
if not os.path.isdir(baseDir+'/accounts/'+handle+'/inbox'):
|
||||||
|
|
15
person.py
15
person.py
|
@ -21,7 +21,7 @@ def generateRSAKey() -> (str,str):
|
||||||
publicKeyPem = key.publickey().exportKey("PEM").decode("utf-8")
|
publicKeyPem = key.publickey().exportKey("PEM").decode("utf-8")
|
||||||
return privateKeyPem,publicKeyPem
|
return privateKeyPem,publicKeyPem
|
||||||
|
|
||||||
def createPerson(username: str,domain: str,port: int,https: bool, saveToFile: bool) -> (str,str,{},{}):
|
def createPerson(baseDir: str,username: str,domain: str,port: int,https: bool, 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'
|
prefix='https'
|
||||||
|
@ -31,7 +31,7 @@ def createPerson(username: str,domain: str,port: int,https: bool, saveToFile: bo
|
||||||
privateKeyPem,publicKeyPem=generateRSAKey()
|
privateKeyPem,publicKeyPem=generateRSAKey()
|
||||||
webfingerEndpoint=createWebfingerEndpoint(username,domain,port,https,publicKeyPem)
|
webfingerEndpoint=createWebfingerEndpoint(username,domain,port,https,publicKeyPem)
|
||||||
if saveToFile:
|
if saveToFile:
|
||||||
storeWebfingerEndpoint(username,domain,webfingerEndpoint)
|
storeWebfingerEndpoint(username,domain,baseDir,webfingerEndpoint)
|
||||||
|
|
||||||
handle=username.lower()+'@'+domain.lower()
|
handle=username.lower()+'@'+domain.lower()
|
||||||
if port!=80 and port!=443:
|
if port!=80 and port!=443:
|
||||||
|
@ -79,7 +79,6 @@ def createPerson(username: str,domain: str,port: int,https: bool, saveToFile: bo
|
||||||
|
|
||||||
if saveToFile:
|
if saveToFile:
|
||||||
# save person to file
|
# save person to file
|
||||||
baseDir=os.getcwd()
|
|
||||||
peopleSubdir='/accounts'
|
peopleSubdir='/accounts'
|
||||||
if not os.path.isdir(baseDir+peopleSubdir):
|
if not os.path.isdir(baseDir+peopleSubdir):
|
||||||
os.mkdir(baseDir+peopleSubdir)
|
os.mkdir(baseDir+peopleSubdir)
|
||||||
|
@ -114,7 +113,7 @@ def validUsername(username):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def personKeyLookup(domain: str,path: str) -> str:
|
def personKeyLookup(domain: str,path: str,baseDir: str) -> str:
|
||||||
"""Lookup the public key of the person with a given username
|
"""Lookup the public key of the person with a given username
|
||||||
"""
|
"""
|
||||||
if not path.endswith('/main-key'):
|
if not path.endswith('/main-key'):
|
||||||
|
@ -125,7 +124,6 @@ def personKeyLookup(domain: str,path: str) -> str:
|
||||||
if not validUsername(username):
|
if not validUsername(username):
|
||||||
return None
|
return None
|
||||||
handle=username.lower()+'@'+domain.lower()
|
handle=username.lower()+'@'+domain.lower()
|
||||||
baseDir=os.getcwd()
|
|
||||||
filename=baseDir+'/accounts/'+handle.lower()+'.json'
|
filename=baseDir+'/accounts/'+handle.lower()+'.json'
|
||||||
if not os.path.isfile(filename):
|
if not os.path.isfile(filename):
|
||||||
return None
|
return None
|
||||||
|
@ -137,7 +135,7 @@ def personKeyLookup(domain: str,path: str) -> str:
|
||||||
return personJson['publicKey']['publicKeyPem']
|
return personJson['publicKey']['publicKeyPem']
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def personLookup(domain: str,path: str) -> {}:
|
def personLookup(domain: str,path: str,baseDir: str) -> {}:
|
||||||
"""Lookup the person for an given username
|
"""Lookup the person for an given username
|
||||||
"""
|
"""
|
||||||
notPersonLookup=['/inbox','/outbox','/outboxarchive','/followers','/following','/featured','.png','.jpg','.gif','.mpv','#main-key','/main-key']
|
notPersonLookup=['/inbox','/outbox','/outboxarchive','/followers','/following','/featured','.png','.jpg','.gif','.mpv','#main-key','/main-key']
|
||||||
|
@ -154,7 +152,6 @@ def personLookup(domain: str,path: str) -> {}:
|
||||||
if not validUsername(username):
|
if not validUsername(username):
|
||||||
return None
|
return None
|
||||||
handle=username.lower()+'@'+domain.lower()
|
handle=username.lower()+'@'+domain.lower()
|
||||||
baseDir=os.getcwd()
|
|
||||||
filename=baseDir+'/accounts/'+handle.lower()+'.json'
|
filename=baseDir+'/accounts/'+handle.lower()+'.json'
|
||||||
if not os.path.isfile(filename):
|
if not os.path.isfile(filename):
|
||||||
return None
|
return None
|
||||||
|
@ -163,7 +160,7 @@ def personLookup(domain: str,path: str) -> {}:
|
||||||
personJson=commentjson.load(fp)
|
personJson=commentjson.load(fp)
|
||||||
return personJson
|
return personJson
|
||||||
|
|
||||||
def personOutboxJson(domain: str,port: int,path: str,https: bool,noOfItems: int) -> []:
|
def personOutboxJson(baseDir: str,domain: str,port: int,path: str,https: bool,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:
|
||||||
|
@ -197,7 +194,7 @@ def personOutboxJson(domain: str,port: int,path: str,https: bool,noOfItems: int)
|
||||||
return None
|
return None
|
||||||
if not validUsername(username):
|
if not validUsername(username):
|
||||||
return None
|
return None
|
||||||
return createOutbox(username,domain,port,https,noOfItems,headerOnly,pageNumber)
|
return createOutbox(baseDir,username,domain,port,https,noOfItems,headerOnly,pageNumber)
|
||||||
|
|
||||||
def setPreferredUsername(username: str, domain: str, preferredName: str) -> bool:
|
def setPreferredUsername(username: str, domain: str, preferredName: str) -> bool:
|
||||||
if len(preferredName)>32:
|
if len(preferredName)>32:
|
||||||
|
|
55
posts.py
55
posts.py
|
@ -23,22 +23,16 @@ from pprint import pprint
|
||||||
from random import randint
|
from random import randint
|
||||||
from session import getJson
|
from session import getJson
|
||||||
from session import postJson
|
from session import postJson
|
||||||
|
from webfinger import webfingerHandle
|
||||||
try:
|
try:
|
||||||
from BeautifulSoup import BeautifulSoup
|
from BeautifulSoup import BeautifulSoup
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
# Contains threads for posts being sent
|
def getPersonKey(username: str,domain: str,baseDir: str,keyType='public'):
|
||||||
sendThreads = []
|
|
||||||
|
|
||||||
# stores the results from recent post sending attempts
|
|
||||||
postLog = []
|
|
||||||
|
|
||||||
def getPersonKey(username: str,domain: str,keyType='public'):
|
|
||||||
"""Returns the public or private key of a person
|
"""Returns the public or private key of a person
|
||||||
"""
|
"""
|
||||||
handle=username+'@'+domain
|
handle=username+'@'+domain
|
||||||
baseDir=os.getcwd()
|
|
||||||
keyFilename=baseDir+'/keys/'+keyType+'/'+handle.lower()+'.key'
|
keyFilename=baseDir+'/keys/'+keyType+'/'+handle.lower()+'.key'
|
||||||
if not os.path.isfile(keyFilename):
|
if not os.path.isfile(keyFilename):
|
||||||
return ''
|
return ''
|
||||||
|
@ -200,11 +194,10 @@ def getUserPosts(session,wfRequest,maxPosts,maxMentions,maxEmoji,maxAttachments,
|
||||||
break
|
break
|
||||||
return userPosts
|
return userPosts
|
||||||
|
|
||||||
def createOutboxDir(username: str,domain: str) -> str:
|
def createOutboxDir(username: str,domain: str,baseDir: str) -> str:
|
||||||
"""Create an outbox for a person and returns the feed filename and directory
|
"""Create an outbox for a person and returns the feed filename and directory
|
||||||
"""
|
"""
|
||||||
handle=username.lower()+'@'+domain.lower()
|
handle=username.lower()+'@'+domain.lower()
|
||||||
baseDir=os.getcwd()
|
|
||||||
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||||
os.mkdir(baseDir+'/accounts/'+handle)
|
os.mkdir(baseDir+'/accounts/'+handle)
|
||||||
outboxDir=baseDir+'/accounts/'+handle+'/outbox'
|
outboxDir=baseDir+'/accounts/'+handle+'/outbox'
|
||||||
|
@ -212,11 +205,10 @@ def createOutboxDir(username: str,domain: str) -> str:
|
||||||
os.mkdir(outboxDir)
|
os.mkdir(outboxDir)
|
||||||
return outboxDir
|
return outboxDir
|
||||||
|
|
||||||
def createOutboxArchive(username: str,domain: str) -> str:
|
def createOutboxArchive(username: str,domain: str,baseDir: str) -> str:
|
||||||
"""Creates an archive directory for outbox posts
|
"""Creates an archive directory for outbox posts
|
||||||
"""
|
"""
|
||||||
handle=username.lower()+'@'+domain.lower()
|
handle=username.lower()+'@'+domain.lower()
|
||||||
baseDir=os.getcwd()
|
|
||||||
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||||
os.mkdir(baseDir+'/accounts/'+handle)
|
os.mkdir(baseDir+'/accounts/'+handle)
|
||||||
outboxArchiveDir=baseDir+'/accounts/'+handle+'/outboxarchive'
|
outboxArchiveDir=baseDir+'/accounts/'+handle+'/outboxarchive'
|
||||||
|
@ -224,10 +216,10 @@ def createOutboxArchive(username: str,domain: str) -> str:
|
||||||
os.mkdir(outboxArchiveDir)
|
os.mkdir(outboxArchiveDir)
|
||||||
return outboxArchiveDir
|
return outboxArchiveDir
|
||||||
|
|
||||||
def deleteAllPosts(username: str, domain: str) -> None:
|
def deleteAllPosts(username: str, domain: str,baseDir: str) -> None:
|
||||||
"""Deletes all posts for a person
|
"""Deletes all posts for a person
|
||||||
"""
|
"""
|
||||||
outboxDir = createOutboxDir(username,domain)
|
outboxDir = createOutboxDir(username,domain,baseDir)
|
||||||
for deleteFilename in os.listdir(outboxDir):
|
for deleteFilename in os.listdir(outboxDir):
|
||||||
filePath = os.path.join(outboxDir, deleteFilename)
|
filePath = os.path.join(outboxDir, deleteFilename)
|
||||||
try:
|
try:
|
||||||
|
@ -248,7 +240,7 @@ def getStatusNumber() -> (str,str):
|
||||||
conversationDate=currTime.strftime("%Y-%m-%d")
|
conversationDate=currTime.strftime("%Y-%m-%d")
|
||||||
return statusNumber,published
|
return statusNumber,published
|
||||||
|
|
||||||
def createPostBase(username: str, domain: str, toUrl: str, ccUrl: str, https: bool, content: str, followersOnly: bool, saveToFile: bool, inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
|
def createPostBase(baseDir: str,username: str, domain: str, toUrl: str, ccUrl: str, https: bool, content: str, followersOnly: bool, saveToFile: bool, inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
|
||||||
"""Creates a public post
|
"""Creates a public post
|
||||||
"""
|
"""
|
||||||
prefix='https'
|
prefix='https'
|
||||||
|
@ -306,7 +298,7 @@ def createPostBase(username: str, domain: str, toUrl: str, ccUrl: str, https: bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if saveToFile:
|
if saveToFile:
|
||||||
outboxDir = createOutboxDir(username,domain)
|
outboxDir = createOutboxDir(username,domain,baseDir)
|
||||||
filename=outboxDir+'/'+newPostId.replace('/','#')+'.json'
|
filename=outboxDir+'/'+newPostId.replace('/','#')+'.json'
|
||||||
with open(filename, 'w') as fp:
|
with open(filename, 'w') as fp:
|
||||||
commentjson.dump(newPost, fp, indent=4, sort_keys=False)
|
commentjson.dump(newPost, fp, indent=4, sort_keys=False)
|
||||||
|
@ -320,7 +312,7 @@ def createPublicPost(username: str, domain: str, https: bool, content: str, foll
|
||||||
prefix='http'
|
prefix='http'
|
||||||
return createPostBase(username, domain, 'https://www.w3.org/ns/activitystreams#Public', prefix+'://'+domain+'/users/'+username+'/followers', https, content, followersOnly, saveToFile, inReplyTo, inReplyToAtomUri, subject)
|
return createPostBase(username, domain, 'https://www.w3.org/ns/activitystreams#Public', prefix+'://'+domain+'/users/'+username+'/followers', https, content, followersOnly, saveToFile, inReplyTo, inReplyToAtomUri, subject)
|
||||||
|
|
||||||
def threadSendPost(session,postJsonObject,federationList,inboxUrl: str,signatureHeader) -> None:
|
def threadSendPost(session,postJsonObject,federationList,inboxUrl: str,baseDir: str,signatureHeader,postLog) -> None:
|
||||||
"""Sends a post with exponential backoff
|
"""Sends a post with exponential backoff
|
||||||
"""
|
"""
|
||||||
tries=0
|
tries=0
|
||||||
|
@ -334,7 +326,6 @@ def threadSendPost(session,postJsonObject,federationList,inboxUrl: str,signature
|
||||||
while len(postLog)>64:
|
while len(postLog)>64:
|
||||||
postlog.pop(0)
|
postlog.pop(0)
|
||||||
# save the log file
|
# save the log file
|
||||||
baseDir=os.getcwd()
|
|
||||||
filename=baseDir+'/post.log'
|
filename=baseDir+'/post.log'
|
||||||
with open(filename, "w") as logFile:
|
with open(filename, "w") as logFile:
|
||||||
for line in postLog:
|
for line in postLog:
|
||||||
|
@ -344,19 +335,24 @@ def threadSendPost(session,postJsonObject,federationList,inboxUrl: str,signature
|
||||||
time.sleep(backoffTime)
|
time.sleep(backoffTime)
|
||||||
backoffTime *= 2
|
backoffTime *= 2
|
||||||
|
|
||||||
def sendPost(session,username: str, domain: str, toUsername: str, toDomain: str, cc: str, https: bool, content: str, followersOnly: bool, saveToFile: bool, federationList, inReplyTo=None, inReplyToAtomUri=None, subject=None) -> int:
|
def sendPost(session,baseDir,username: str, domain: str, port: int, toUsername: str, toDomain: str, toPort: int, cc: str, https: bool, content: str, followersOnly: bool, saveToFile: bool, federationList, sendThreads, postLog, inReplyTo=None, inReplyToAtomUri=None, subject=None) -> int:
|
||||||
"""Post to another inbox
|
"""Post to another inbox
|
||||||
"""
|
"""
|
||||||
prefix='https'
|
prefix='https'
|
||||||
if not https:
|
if not https:
|
||||||
prefix='http'
|
prefix='http'
|
||||||
|
|
||||||
# lookup the inbox
|
if toPort!=80 and toPort!=443:
|
||||||
handle=prefix+'://'+domain+'/@'+username
|
toDomain=toDomain+':'+str(toPort)
|
||||||
wfRequest = webfingerHandle(session,handle,True)
|
|
||||||
|
handle=prefix+'://'+toDomain+'/@'+toUsername
|
||||||
|
|
||||||
|
# lookup the inbox for the To handle
|
||||||
|
wfRequest = webfingerHandle(session,handle,https)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
# get the actor inbox for the To handle
|
||||||
inboxUrl,pubKey,toPersonId = getPersonBox(session,wfRequest,'inbox')
|
inboxUrl,pubKey,toPersonId = getPersonBox(session,wfRequest,'inbox')
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
return 2
|
return 2
|
||||||
|
@ -367,7 +363,8 @@ def sendPost(session,username: str, domain: str, toUsername: str, toDomain: str,
|
||||||
|
|
||||||
postJsonObject=createPostBase(username, domain, toPersonId, cc, https, content, followersOnly, saveToFile, inReplyTo, inReplyToAtomUri, subject)
|
postJsonObject=createPostBase(username, domain, toPersonId, cc, https, content, followersOnly, saveToFile, inReplyTo, inReplyToAtomUri, subject)
|
||||||
|
|
||||||
privateKeyPem=getPersonKey(username,domain,'private')
|
# get the senders private key
|
||||||
|
privateKeyPem=getPersonKey(username,domain,baseDir,'private')
|
||||||
if len(privateKeyPem)==0:
|
if len(privateKeyPem)==0:
|
||||||
return 5
|
return 5
|
||||||
|
|
||||||
|
@ -379,19 +376,19 @@ def sendPost(session,username: str, domain: str, toUsername: str, toDomain: str,
|
||||||
while len(sendThreads)>10:
|
while len(sendThreads)>10:
|
||||||
sendThreads[0].kill()
|
sendThreads[0].kill()
|
||||||
sendThreads.pop(0)
|
sendThreads.pop(0)
|
||||||
thr = threadWithTrace(target=threadSendPost,args=(session,postJsonObject.copy(),federationList,inboxUrl,signatureHeader.copy()),daemon=True)
|
thr = threadWithTrace(target=threadSendPost,args=(session,postJsonObject.copy(),federationList,inboxUrl,baseDir,signatureHeader.copy(),postLog),daemon=True)
|
||||||
sendThreads.append(thr)
|
sendThreads.append(thr)
|
||||||
thr.start()
|
thr.start()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def createOutbox(username: str,domain: str,port: int,https: bool,itemsPerPage: int,headerOnly: bool,pageNumber=None) -> {}:
|
def createOutbox(baseDir: str,username: str,domain: str,port: int,https: bool,itemsPerPage: int,headerOnly: bool,pageNumber=None) -> {}:
|
||||||
"""Constructs the outbox feed
|
"""Constructs the outbox feed
|
||||||
"""
|
"""
|
||||||
prefix='https'
|
prefix='https'
|
||||||
if not https:
|
if not https:
|
||||||
prefix='http'
|
prefix='http'
|
||||||
|
|
||||||
outboxDir = createOutboxDir(username,domain)
|
outboxDir = createOutboxDir(username,domain,baseDir)
|
||||||
|
|
||||||
if port!=80 and port!=443:
|
if port!=80 and port!=443:
|
||||||
domain = domain+':'+str(port)
|
domain = domain+':'+str(port)
|
||||||
|
@ -482,12 +479,12 @@ def createOutbox(username: str,domain: str,port: int,https: bool,itemsPerPage: i
|
||||||
return outboxHeader
|
return outboxHeader
|
||||||
return outboxItems
|
return outboxItems
|
||||||
|
|
||||||
def archivePosts(username: str,domain: str,maxPostsInOutbox=256) -> None:
|
def archivePosts(username: str,domain: str,baseDir: str,maxPostsInOutbox=256) -> None:
|
||||||
"""Retain a maximum number of posts within the outbox
|
"""Retain a maximum number of posts within the outbox
|
||||||
Move any others to an archive directory
|
Move any others to an archive directory
|
||||||
"""
|
"""
|
||||||
outboxDir = createOutboxDir(username,domain)
|
outboxDir = createOutboxDir(username,domain,baseDir)
|
||||||
archiveDir = createOutboxArchive(username,domain)
|
archiveDir = createOutboxArchive(username,domain,baseDir)
|
||||||
postsInOutbox=sorted(os.listdir(outboxDir), reverse=False)
|
postsInOutbox=sorted(os.listdir(outboxDir), reverse=False)
|
||||||
noOfPosts=len(postsInOutbox)
|
noOfPosts=len(postsInOutbox)
|
||||||
if noOfPosts<=maxPostsInOutbox:
|
if noOfPosts<=maxPostsInOutbox:
|
||||||
|
|
39
tests.py
39
tests.py
|
@ -22,6 +22,7 @@ from session import createSession
|
||||||
from person import createPerson
|
from person import createPerson
|
||||||
from posts import deleteAllPosts
|
from posts import deleteAllPosts
|
||||||
from posts import createPublicPost
|
from posts import createPublicPost
|
||||||
|
from posts import sendPost
|
||||||
from follow import followPerson
|
from follow import followPerson
|
||||||
from follow import followerOfPerson
|
from follow import followerOfPerson
|
||||||
|
|
||||||
|
@ -34,7 +35,8 @@ def testHttpsigBase(withDigest):
|
||||||
domain='argumentative.social'
|
domain='argumentative.social'
|
||||||
https=True
|
https=True
|
||||||
port=80
|
port=80
|
||||||
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(username,domain,port,https,False)
|
baseDir=os.getcwd()
|
||||||
|
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,username,domain,port,https,False)
|
||||||
messageBodyJson = '{"a key": "a value", "another key": "A string"}'
|
messageBodyJson = '{"a key": "a value", "another key": "A string"}'
|
||||||
if not withDigest:
|
if not withDigest:
|
||||||
headers = {'host': domain}
|
headers = {'host': domain}
|
||||||
|
@ -96,9 +98,8 @@ def createServerAlice(path: str,port: int):
|
||||||
domain='127.0.0.1'
|
domain='127.0.0.1'
|
||||||
https=False
|
https=False
|
||||||
useTor=False
|
useTor=False
|
||||||
session = createSession(useTor)
|
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,username,domain,port,https,True)
|
||||||
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(username,domain,port,https,True)
|
deleteAllPosts(username,domain,path)
|
||||||
deleteAllPosts(username,domain)
|
|
||||||
followPerson(username,domain,'bob','127.0.0.1:61936',federationList)
|
followPerson(username,domain,'bob','127.0.0.1:61936',federationList)
|
||||||
followerOfPerson(username,domain,'bob','127.0.0.1:61936',federationList)
|
followerOfPerson(username,domain,'bob','127.0.0.1:61936',federationList)
|
||||||
createPublicPost(username, domain, https, "No wise fish would go anywhere without a porpoise", False, True)
|
createPublicPost(username, domain, https, "No wise fish would go anywhere without a porpoise", False, True)
|
||||||
|
@ -120,9 +121,8 @@ def createServerBob(path: str,port: int):
|
||||||
domain='127.0.0.1'
|
domain='127.0.0.1'
|
||||||
https=False
|
https=False
|
||||||
useTor=False
|
useTor=False
|
||||||
session = createSession(useTor)
|
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,username,domain,port,https,True)
|
||||||
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(username,domain,port,https,True)
|
deleteAllPosts(username,domain,path)
|
||||||
deleteAllPosts(username,domain)
|
|
||||||
followPerson(username,domain,'alice','127.0.0.1:61935',federationList)
|
followPerson(username,domain,'alice','127.0.0.1:61935',federationList)
|
||||||
followerOfPerson(username,domain,'alice','127.0.0.1:61935',federationList)
|
followerOfPerson(username,domain,'alice','127.0.0.1:61935',federationList)
|
||||||
createPublicPost(username, domain, https, "It's your life, live it your way.", False, True)
|
createPublicPost(username, domain, https, "It's your life, live it your way.", False, True)
|
||||||
|
@ -141,16 +141,24 @@ def testPostMessageBetweenServers():
|
||||||
testServerAliceRunning = False
|
testServerAliceRunning = False
|
||||||
testServerBobRunning = False
|
testServerBobRunning = False
|
||||||
|
|
||||||
|
https=False
|
||||||
|
useTor=False
|
||||||
|
federationList=['127.0.0.1']
|
||||||
|
|
||||||
baseDir=os.getcwd()
|
baseDir=os.getcwd()
|
||||||
if not os.path.isdir(baseDir+'/.tests'):
|
if not os.path.isdir(baseDir+'/.tests'):
|
||||||
os.mkdir(baseDir+'/.tests')
|
os.mkdir(baseDir+'/.tests')
|
||||||
|
|
||||||
# create the servers
|
# create the servers
|
||||||
thrAlice = threadWithTrace(target=createServerAlice,args=(baseDir+'/.tests/alice',61935),daemon=True)
|
aliceDir=baseDir+'/.tests/alice'
|
||||||
|
alicePort=61935
|
||||||
|
thrAlice = threadWithTrace(target=createServerAlice,args=(aliceDir,alicePort),daemon=True)
|
||||||
thrAlice.start()
|
thrAlice.start()
|
||||||
assert thrAlice.isAlive()==True
|
assert thrAlice.isAlive()==True
|
||||||
|
|
||||||
thrBob = threadWithTrace(target=createServerBob,args=(baseDir+'/.tests/bob',61936),daemon=True)
|
bobDir=baseDir+'/.tests/bob'
|
||||||
|
bobPort=61936
|
||||||
|
thrBob = threadWithTrace(target=createServerBob,args=(bobDir,bobPort),daemon=True)
|
||||||
thrBob.start()
|
thrBob.start()
|
||||||
assert thrBob.isAlive()==True
|
assert thrBob.isAlive()==True
|
||||||
|
|
||||||
|
@ -160,6 +168,19 @@ def testPostMessageBetweenServers():
|
||||||
|
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
|
|
||||||
|
print('Alice sends to Bob')
|
||||||
|
os.chdir(aliceDir)
|
||||||
|
sessionAlice = createSession(useTor)
|
||||||
|
inReplyTo=None
|
||||||
|
inReplyToAtomUri=None
|
||||||
|
subject=None
|
||||||
|
aliceSendThreads = []
|
||||||
|
alicePostLog = []
|
||||||
|
sendResult = sendPost(sessionAlice,aliceDir,'alice', '127.0.0.1', alicePort, 'bob', '127.0.0.1', bobPort, '', https, 'Why is a mouse when it spins?', False, True, federationList, aliceSendThreads, alicePostLog, inReplyTo, inReplyToAtomUri, subject)
|
||||||
|
print('sendResult: '+str(sendResult))
|
||||||
|
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
# stop the servers
|
# stop the servers
|
||||||
thrAlice.kill()
|
thrAlice.kill()
|
||||||
thrAlice.join()
|
thrAlice.join()
|
||||||
|
|
13
webfinger.py
13
webfinger.py
|
@ -45,9 +45,13 @@ def webfingerHandle(session,handle: str,https: bool):
|
||||||
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:
|
||||||
|
domain=domain.split(':')[0]
|
||||||
par = {'resource': 'acct:{}'.format(username+'@'+domain)}
|
par = {'resource': 'acct:{}'.format(username+'@'+domain)}
|
||||||
hdr = {'Accept': 'application/jrd+json'}
|
hdr = {'Accept': 'application/jrd+json'}
|
||||||
#try:
|
#try:
|
||||||
|
print("webfinger url = "+url)
|
||||||
|
print("webfinger par = "+str(par))
|
||||||
result = getJson(session, url, hdr, par)
|
result = getJson(session, url, hdr, par)
|
||||||
#except:
|
#except:
|
||||||
# print("Unable to webfinger " + url)
|
# print("Unable to webfinger " + url)
|
||||||
|
@ -64,11 +68,10 @@ def generateMagicKey(publicKeyPem):
|
||||||
pubexp = base64.urlsafe_b64encode(number.long_to_bytes(privkey.e)).decode("utf-8")
|
pubexp = base64.urlsafe_b64encode(number.long_to_bytes(privkey.e)).decode("utf-8")
|
||||||
return f"data:application/magic-public-key,RSA.{mod}.{pubexp}"
|
return f"data:application/magic-public-key,RSA.{mod}.{pubexp}"
|
||||||
|
|
||||||
def storeWebfingerEndpoint(username: str,domain: str,wfJson) -> bool:
|
def storeWebfingerEndpoint(username: str,domain: str,baseDir: str,wfJson) -> bool:
|
||||||
"""Stores webfinger endpoint for a user to a file
|
"""Stores webfinger endpoint for a user to a file
|
||||||
"""
|
"""
|
||||||
handle=username+'@'+domain
|
handle=username+'@'+domain
|
||||||
baseDir=os.getcwd()
|
|
||||||
wfSubdir='/wfendpoints'
|
wfSubdir='/wfendpoints'
|
||||||
if not os.path.isdir(baseDir+wfSubdir):
|
if not os.path.isdir(baseDir+wfSubdir):
|
||||||
os.mkdir(baseDir+wfSubdir)
|
os.mkdir(baseDir+wfSubdir)
|
||||||
|
@ -140,25 +143,27 @@ def webfingerMeta() -> str:
|
||||||
" </Link>" \
|
" </Link>" \
|
||||||
"</XRD>"
|
"</XRD>"
|
||||||
|
|
||||||
def webfingerLookup(path: str):
|
def webfingerLookup(path: str,baseDir: str):
|
||||||
"""Lookup the webfinger endpoint for an account
|
"""Lookup the webfinger endpoint for an account
|
||||||
"""
|
"""
|
||||||
if not path.startswith('/.well-known/webfinger?'):
|
if not path.startswith('/.well-known/webfinger?'):
|
||||||
return None
|
return None
|
||||||
handle=None
|
handle=None
|
||||||
|
print('************** '+path)
|
||||||
if 'resource=acct:' in path:
|
if 'resource=acct:' in path:
|
||||||
handle=path.split('resource=acct:')[1].strip()
|
handle=path.split('resource=acct:')[1].strip()
|
||||||
else:
|
else:
|
||||||
if 'resource=acct%3A' in path:
|
if 'resource=acct%3A' in path:
|
||||||
handle=path.split('resource=acct%3A')[1].replace('%40','@').strip()
|
handle=path.split('resource=acct%3A')[1].replace('%40','@').strip()
|
||||||
|
print('************** handle: '+handle)
|
||||||
if not handle:
|
if not handle:
|
||||||
return None
|
return None
|
||||||
if '&' in handle:
|
if '&' in handle:
|
||||||
handle=handle.split('&')[0].strip()
|
handle=handle.split('&')[0].strip()
|
||||||
if '@' not in handle:
|
if '@' not in handle:
|
||||||
return None
|
return None
|
||||||
baseDir=os.getcwd()
|
|
||||||
filename=baseDir+'/wfendpoints/'+handle.lower()+'.json'
|
filename=baseDir+'/wfendpoints/'+handle.lower()+'.json'
|
||||||
|
print('************** filename: '+filename)
|
||||||
if not os.path.isfile(filename):
|
if not os.path.isfile(filename):
|
||||||
return None
|
return None
|
||||||
wfJson={"user": "unknown"}
|
wfJson={"user": "unknown"}
|
||||||
|
|
Loading…
Reference in New Issue