Move shared inbox account into daemon

master
Bob Mottram 2019-07-11 13:29:31 +01:00
parent cb79ddb760
commit c301f45b33
8 changed files with 294 additions and 117 deletions

View File

@ -18,6 +18,7 @@ from webfinger import webfingerLookup
from webfinger import webfingerHandle
from person import personLookup
from person import personBoxJson
from person import createSharedInbox
from posts import outboxMessageCreateWrap
from posts import savePostToBox
from inbox import inboxPermittedMessage
@ -540,6 +541,10 @@ def runDaemon(baseDir: str,domain: str,port=80,httpPrefix='https', \
httpd.acceptedCaps.append('inbox:noannounce')
if cw:
httpd.acceptedCaps.append('inbox:cw')
print('Creating shared inbox: inbox@'+domain)
createSharedInbox(baseDir,'inbox',domain,port,httpPrefix)
print('Running ActivityPub daemon on ' + domain + ' port ' + str(port))
httpd.thrInboxQueue= \
threadWithTrace(target=runInboxQueue, \

View File

@ -400,13 +400,9 @@ if not os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
setConfigParam(baseDir,'adminPassword',adminPassword)
createPerson(baseDir,nickname,domain,port,httpPrefix,True,adminPassword)
if not os.path.isdir(baseDir+'/accounts/inbox@'+domain):
print('Creating shared inbox: inbox@'+domain)
createSharedInbox(baseDir,'inbox',domain,port,httpPrefix)
if not os.path.isdir(baseDir+'/accounts/capabilities@'+domain):
print('Creating capabilities account which can sign requests')
createCapabilitiesInbox(baseDir,'capabilities',domain,port,httpPrefix)
#if not os.path.isdir(baseDir+'/accounts/capabilities@'+domain):
# print('Creating capabilities account which can sign requests')
# createCapabilitiesInbox(baseDir,'capabilities',domain,port,httpPrefix)
if args.testdata:
nickname='testuser567'

View File

@ -27,6 +27,8 @@ def getFollowersOfPerson(baseDir: str, \
Used by the shared inbox to know who to send incoming mail to
"""
followers=[]
if ':' in domain:
domain=domain.split(':')[0]
handle=nickname.lower()+'@'+domain.lower()
if not os.path.isdir(baseDir+'/accounts/'+handle):
return followers
@ -345,38 +347,64 @@ def sendFollowRequest(session,baseDir: str, \
return newFollowJson
def getFollowersOfActor(baseDir :str,actor :str,recipientsDict: {}) -> {}:
def getFollowersOfActor(baseDir :str,actor :str,debug: bool) -> {}:
"""In a shared inbox if we receive a post we know who it's from
and if it's addressed to followers then we need to get a list of those.
This returns a list of account handles which follow the given actor
and also the corresponding capability id if it exists
"""
if debug:
print('DEBUG: getting followers of '+actor)
recipientsDict={}
if ':' not in actor:
return recipientsDict
httpPrefix=actor.split(':')[0]
nickname=getNicknameFromActor(actor)
if not nickname:
if debug:
print('DEBUG: no nickname found in '+actor)
return recipientsDict
domain,port=getDomainFromActor(actor)
if not domain:
if debug:
print('DEBUG: no domain found in '+actor)
return recipientsDict
actorHandle=nickname+'@'+domain
if debug:
print('DEBUG: searching for handle '+actorHandle)
# for each of the accounts
for subdir, dirs, files in os.walk(baseDir+'/accounts'):
for account in dirs:
if '@' in account and not account.startswith('inbox@'):
followingFilename = os.path.join(subdir, account)+'/following.txt'
if debug:
print('DEBUG: examining follows of '+account)
print(followingFilename)
if os.path.isfile(followingFilename):
# does this account follow the given actor?
if debug:
print('DEBUG: checking if '+actorHandle+' in '+followingFilename)
if actorHandle in open(followingFilename).read():
if debug:
print('DEBUG: '+account+' follows '+actorHandle)
ocapFilename=baseDir+'/accounts/'+account+'/ocap/accept/'+httpPrefix+':##'+domain+':'+str(port)+'#users#'+nickname+'.json'
if debug:
print('DEBUG: checking capabilities of'+account)
if os.path.isfile(ocapFilename):
with open(ocapFilename, 'r') as fp:
ocapJson=commentjson.load(fp)
if ocapJson.get('id'):
recipientsDict[account]=ocapJson['id']
else:
recipientsDict[account]=None
if ocapJson.get('id'):
if debug:
print('DEBUG: capabilities id found for '+account)
recipientsDict[account]=ocapJson['id']
else:
if debug:
print('DEBUG: capabilities has no id attribute')
recipientsDict[account]=None
else:
if debug:
print('DEBUG: No capabilities file found for '+account+' granted by '+actorHandle)
print(ocapFilename)
recipientsDict[account]=None
return recipientsDict

View File

@ -19,6 +19,7 @@ from utils import getStatusNumber
from utils import getDomainFromActor
from utils import getNicknameFromActor
from utils import domainPermitted
from utils import locatePost
from httpsig import verifyPostHeaders
from session import createSession
from session import getJson
@ -87,7 +88,7 @@ def inboxPermittedMessage(domain: str,messageJson: {},federationList: []) -> boo
if not urlPermitted(actor,federationList,"inbox:write"):
return False
if messageJson['type']!='Follow':
if messageJson['type']!='Follow' and messageJson['type']!='Like':
if messageJson.get('object'):
if messageJson['object'].get('inReplyTo'):
inReplyTo=messageJson['object']['inReplyTo']
@ -210,7 +211,7 @@ def inboxCheckCapabilities(baseDir :str,nickname :str,domain :str, \
def inboxPostRecipientsAdd(baseDir :str,httpPrefix :str,toList :[], \
recipientsDict :{}, \
domainMatch: str,domain :str, \
actor :str) -> bool:
actor :str,debug: bool) -> bool:
"""Given a list of post recipients (toList) from 'to' or 'cc' parameters
populate a recipientsDict with the handle and capabilities id for each
"""
@ -235,12 +236,23 @@ def inboxPostRecipientsAdd(baseDir :str,httpPrefix :str,toList :[], \
else:
recipientsDict[handle]=None
else:
if debug:
print('DEBUG: '+ocapFilename+' not found')
recipientsDict[handle]=None
else:
if debug:
print('DEBUG: '+baseDir+'/accounts/'+handle+' does not exist')
else:
if debug:
print('DEBUG: '+recipient+' is not local to '+domainMatch)
print(str(toList))
if recipient.endswith('followers'):
if debug:
print('DEBUG: followers detected as post recipients')
followerRecipients=True
return followerRecipients,recipientsDict
def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain : str,port :int) -> ([],[]):
def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain : str,port :int, debug :bool) -> ([],[]):
"""Returns dictionaries containing the recipients of the given post
The shared dictionary contains followers
"""
@ -248,6 +260,9 @@ def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain :
recipientsDictFollowers={}
if not postJsonObject.get('actor'):
if debug:
pprint(postJsonObject)
print('WARNING: inbox post has no actor')
return recipientsDict,recipientsDictFollowers
if ':' in domain:
@ -264,29 +279,48 @@ def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain :
if postJsonObject.get('object'):
if isinstance(postJsonObject['object'], dict):
if postJsonObject['object'].get('to'):
if debug:
print('DEBUG: resolving "to"')
includesFollowers,recipientsDict= \
inboxPostRecipientsAdd(baseDir,httpPrefix, \
postJsonObject['object']['to'], \
recipientsDict, \
domainMatch,domainBase,actor)
domainMatch,domainBase, \
actor,debug)
if includesFollowers:
followerRecipients=True
else:
if debug:
print('DEBUG: inbox post has no "to"')
if postJsonObject['object'].get('cc'):
includesFollowers,recipientsDict= \
inboxPostRecipientsAdd(baseDir,httpPrefix, \
postJsonObject['object']['cc'], \
recipientsDict, \
domainMatch,domainBase,actor)
domainMatch,domainBase, \
actor,debug)
if includesFollowers:
followerRecipients=True
else:
if debug:
print('DEBUG: inbox post has no cc')
else:
if debug:
if isinstance(postJsonObject['object'], str):
if '/statuses/' in postJsonObject['object']:
print('DEBUG: inbox item is a link to a post')
else:
if '/users/' in postJsonObject['object']:
print('DEBUG: inbox item is a link to an actor')
if postJsonObject.get('to'):
includesFollowers,recipientsDict= \
inboxPostRecipientsAdd(baseDir,httpPrefix, \
postJsonObject['to'], \
recipientsDict, \
domainMatch,domainBase,actor)
domainMatch,domainBase, \
actor,debug)
if includesFollowers:
followerRecipients=True
@ -295,16 +329,19 @@ def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain :
inboxPostRecipientsAdd(baseDir,httpPrefix, \
postJsonObject['cc'], \
recipientsDict, \
domainMatch,domainBase,actor)
domainMatch,domainBase, \
actor,debug)
if includesFollowers:
followerRecipients=True
if not followerRecipients:
if debug:
print('DEBUG: no followers were resolved')
return recipientsDict,recipientsDictFollowers
# now resolve the followers
recipientsDictFollowers= \
getFollowersOfActor(baseDir,actor,recipientsDict)
getFollowersOfActor(baseDir,actor,debug)
return recipientsDict,recipientsDictFollowers
@ -388,18 +425,7 @@ def receiveLike(session,handle: str,baseDir: str, \
if not os.path.isdir(baseDir+'/accounts/'+handle):
print('DEBUG: unknown recipient of like - '+handle)
# if this post in the outbox of the person?
boxName='outbox'
postFilename=baseDir+'/accounts/'+handle+'/'+boxName+'/'+messageJson['object'].replace('/','#')+'.json'
if not os.path.isfile(postFilename):
# if this post in the inbox of the person?
boxName='inbox'
postFilename=baseDir+'/accounts/'+handle+'/'+boxName+'/'+messageJson['object'].replace('/','#')+'.json'
if not os.path.isfile(postFilename):
# if this post in the shared inbox?
handle='inbox@'+domain
postFilename=baseDir+'/accounts/'+handle+'/'+boxName+'/'+messageJson['object'].replace('/','#')+'.json'
if not os.path.isfile(postFilename):
postFilename=None
postFilename=locatePost(baseDir,handle.split('@')[0],handle.split('@')[1],messageJson['object'])
if not postFilename:
if debug:
print('DEBUG: post not found in inbox or outbox')
@ -569,7 +595,15 @@ def runInboxQueue(baseDir: str,httpPrefix: str,sendThreads: [],postLog: [],cache
# get recipients list
recipientsDict,recipientsDictFollowers= \
inboxPostRecipients(baseDir,queueJson['post'],httpPrefix,domain,port)
inboxPostRecipients(baseDir,queueJson['post'],httpPrefix,domain,port,debug)
if len(recipientsDict.items())==0 and \
len(recipientsDictFollowers.items())==0:
if debug:
pprint(queueJson['post'])
print('DEBUG: no recipients were resolved for post arriving in inbox')
os.remove(queueFilename)
queue.pop(0)
continue
# if there are only a small number of followers then process them as if they
# were specifically addresses to particular accounts
@ -579,7 +613,7 @@ def runInboxQueue(baseDir: str,httpPrefix: str,sendThreads: [],postLog: [],cache
if debug:
print('DEBUG: moving '+str(noOfFollowItems)+' inbox posts addressed to followers')
for handle,postItem in recipientsDictFollowers.items():
recipientsDict['handle']=postItem
recipientsDict[handle]=postItem
recipientsDictFollowers={}
recipientsList=[recipientsDict,recipientsDictFollowers]
@ -587,7 +621,7 @@ def runInboxQueue(baseDir: str,httpPrefix: str,sendThreads: [],postLog: [],cache
print('*************************************')
print('Resolved recipients list:')
pprint(recipientsDict)
print('Resolved sollowers list:')
print('Resolved followers list:')
pprint(recipientsDictFollowers)
print('*************************************')

174
like.py
View File

@ -8,80 +8,28 @@ __status__ = "Production"
import json
import commentjson
from pprint import pprint
from utils import urlPermitted
from utils import getNicknameFromActor
from utils import getDomainFromActor
from utils import locatePost
from posts import sendSignedJson
def like(session,baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
ccUrl: str,httpPrefix: str,objectUrl: str,clientToServer: bool, \
sendThreads: [],postLog: [],personCache: {},cachedWebfingers: {}) -> {}:
"""Creates a like
ccUrl might be a specific person whose post was liked
objectUrl is typically the url of the message, corresponding to url or atomUri in createPostBase
"""
if not urlPermitted(objectUrl,federationList,"inbox:write"):
return None
if port!=80 and port!=443:
domain=domain+':'+str(port)
newLikeJson = {
'type': 'Like',
'actor': httpPrefix+'://'+domain+'/users/'+nickname,
'object': objectUrl,
'to': [httpPrefix+'://'+domain+'/users/'+nickname+'/followers'],
'cc': []
}
if ccUrl:
if len(ccUrl)>0:
newLikeJson['cc']=ccUrl
# Extract the domain and nickname from a statuses link
likedPostNickname=None
likedPostDomain=None
likedPostPort=None
if '/users/' in objectUrl:
likedPostNickname=getNicknameFromActor(objectUrl)
likedPostDomain,likedPostPort=getDomainFromActor(objectUrl)
if likedPostNickname:
sendSignedJson(newlikeJson,session,baseDir, \
nickname,domain,port, \
likedPostNickname,likedPostDomain,likedPostPort, \
'https://www.w3.org/ns/activitystreams#Public', \
httpPrefix,True,clientToServer,federationList, \
sendThreads,postLog,cachedWebfingers,personCache,debug)
return newLikeJson
def likePost(session,baseDir: str,federationList: [], \
nickname: str, domain: str, port: int, httpPrefix: str, \
likeNickname: str, likeDomain: str, likePort: int, \
likeHttps: bool, likeStatusNumber: int, \
clientToServer: bool,sendThreads: [],postLog: [], \
personCache: {},cachedWebfingers: {}) -> {}:
"""Likes a given status post
"""
likeDomain=likeDomain
if likePort!=80 and likePort!=443:
likeDomain=likeDomain+':'+str(likePort)
objectUrl = \
httpPrefix + '://'+likeDomain+'/users/'+likeNickname+ \
'/statuses/'+str(likeStatusNumber)
return like(session,baseDir,federationList,nickname,domain,port, \
ccUrl,httpPrefix,objectUrl,clientToServer, \
sendThreads,postLog,personCache,cachedWebfingers)
def updateLikesCollection(postFilename: str,objectUrl: str, actor: str) -> None:
def updateLikesCollection(postFilename: str,objectUrl: str, actor: str,debug: bool) -> None:
"""Updates the likes collection within a post
"""
with open(postFilename, 'r') as fp:
postJson=commentjson.load(fp)
if not postJson.get('object'):
if debug:
pprint(postJson)
print('DEBUG: post '+objectUrl+' has no object')
return
if not objectUrl.endswith('/likes'):
objectUrl=objectUrl+'/likes'
if not postJson.get('likes'):
if not postJson['object'].get('likes'):
if debug:
print('DEBUG: Adding initial likes to '+objectUrl)
likesJson = {
'id': objectUrl,
'type': 'Collection',
@ -92,17 +40,103 @@ def updateLikesCollection(postFilename: str,objectUrl: str, actor: str) -> None:
}]
}
postJson['likes']=likesJson
postJson['object']['likes']=likesJson
else:
if postJson['likes'].get('items'):
if postJson['object']['likes'].get('items'):
for likeItem in postJson['likes']['items']:
if likeItem['actor']==actor:
return
if likeItem.get('actor'):
if likeItem['actor']==actor:
return
newLike={
'type': 'Like',
'actor': actor
}
postJson['likes']['items'].append(newLike)
postJson['likes']['totalItems']=len(postJson['likes']['items'])
postJson['object']['likes']['items'].append(newLike)
postJson['object']['likes']['totalItems']=len(postJson['likes']['items'])
else:
if debug:
print('DEBUG: likes section of post has no items list')
if debug:
print('DEBUG: saving post with likes added')
with open(postFilename, 'w') as fp:
commentjson.dump(postJson, fp, indent=4, sort_keys=True)
def like(session,baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
ccList: [],httpPrefix: str,objectUrl: str,clientToServer: bool, \
sendThreads: [],postLog: [],personCache: {},cachedWebfingers: {}, \
debug: bool) -> {}:
"""Creates a like
ccUrl might be a specific person whose post was liked
objectUrl is typically the url of the message, corresponding to url or atomUri in createPostBase
"""
if not urlPermitted(objectUrl,federationList,"inbox:write"):
return None
fullDomain=domain
if port!=80 and port!=443:
if ':' not in domain:
fullDomain=domain+':'+str(port)
newLikeJson = {
'type': 'Like',
'actor': httpPrefix+'://'+fullDomain+'/users/'+nickname,
'object': objectUrl,
'to': [httpPrefix+'://'+fullDomain+'/users/'+nickname+'/followers'],
'cc': []
}
if ccList:
if len(ccList)>0:
newLikeJson['cc']=ccList
# Extract the domain and nickname from a statuses link
likedPostNickname=None
likedPostDomain=None
likedPostPort=None
if '/users/' in objectUrl:
likedPostNickname=getNicknameFromActor(objectUrl)
likedPostDomain,likedPostPort=getDomainFromActor(objectUrl)
if likedPostNickname:
postFilename=locatePost(baseDir,nickname,domain,objectUrl)
if not postFilename:
return None
updateLikesCollection(postFilename,objectUrl,newLikeJson['actor'],debug)
sendSignedJson(newLikeJson,session,baseDir, \
nickname,domain,port, \
likedPostNickname,likedPostDomain,likedPostPort, \
'https://www.w3.org/ns/activitystreams#Public', \
httpPrefix,True,clientToServer,federationList, \
sendThreads,postLog,cachedWebfingers,personCache,debug)
return newLikeJson
def likePost(session,baseDir: str,federationList: [], \
nickname: str,domain: str,port: int,httpPrefix: str, \
likeNickname: str,likeDomain: str,likePort: int, \
ccList: [], \
likeStatusNumber: int,clientToServer: bool, \
sendThreads: [],postLog: [], \
personCache: {},cachedWebfingers: {}, \
debug: bool) -> {}:
"""Likes a given status post
"""
likeDomain=likeDomain
if likePort!=80 and likePort!=443:
likeDomain=likeDomain+':'+str(likePort)
objectUrl = \
httpPrefix + '://'+likeDomain+'/users/'+likeNickname+ \
'/statuses/'+str(likeStatusNumber)
if likePort!=80 and likePort!=443:
ccUrl=httpPrefix+'://'+likeDomain+':'+str(likePort)+'/users/'+likeNickname
else:
ccUrl=httpPrefix+'://'+likeDomain+'/users/'+likeNickname
return like(session,baseDir,federationList,nickname,domain,port, \
ccList,httpPrefix,objectUrl,clientToServer, \
sendThreads,postLog,personCache,cachedWebfingers,debug)

View File

@ -88,6 +88,14 @@ def createPersonBase(baseDir: str,nickname: str,domain: str,port: int, \
os.mkdir(baseDir+peopleSubdir)
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle):
os.mkdir(baseDir+peopleSubdir+'/'+handle)
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle+'/inbox'):
os.mkdir(baseDir+peopleSubdir+'/'+handle+'/inbox')
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle+'/outbox'):
os.mkdir(baseDir+peopleSubdir+'/'+handle+'/outbox')
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle+'/ocap'):
os.mkdir(baseDir+peopleSubdir+'/'+handle+'/ocap')
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle+'/queue'):
os.mkdir(baseDir+peopleSubdir+'/'+handle+'/queue')
filename=baseDir+peopleSubdir+'/'+handle+'.json'
with open(filename, 'w') as fp:
commentjson.dump(newPerson, fp, indent=4, sort_keys=False)

View File

@ -36,13 +36,13 @@ from follow import unfollowPerson
from follow import unfollowerOfPerson
from follow import getFollowersOfPerson
from follow import sendFollowRequest
from follow import getFollowersOfActor
from person import createPerson
from person import setPreferredNickname
from person import setBio
from auth import createBasicAuthHeader
from auth import authorizeBasic
from auth import storeBasicCredentials
from like import likePost
testServerAliceRunning = False
testServerBobRunning = False
@ -210,7 +210,6 @@ def testPostMessageBetweenServers():
httpPrefix='http'
useTor=False
federationList=['127.0.0.50','127.0.0.100']
baseDir=os.getcwd()
if os.path.isdir(baseDir+'/.tests'):
@ -223,12 +222,13 @@ def testPostMessageBetweenServers():
aliceDir=baseDir+'/.tests/alice'
aliceDomain='127.0.0.50'
alicePort=61935
thrAlice = threadWithTrace(target=createServerAlice,args=(aliceDir,aliceDomain,alicePort,federationList,True,True,ocapAlways),daemon=True)
bobDir=baseDir+'/.tests/bob'
bobDomain='127.0.0.100'
bobPort=61936
thrBob = threadWithTrace(target=createServerBob,args=(bobDir,bobDomain,bobPort,federationList,True,True,ocapAlways),daemon=True)
federationList=[bobDomain,aliceDomain]
thrAlice = threadWithTrace(target=createServerAlice,args=(aliceDir,aliceDomain,alicePort,federationList,False,False,ocapAlways),daemon=True)
thrBob = threadWithTrace(target=createServerBob,args=(bobDir,bobDomain,bobPort,federationList,False,False,ocapAlways),daemon=True)
thrAlice.start()
thrBob.start()
@ -241,6 +241,7 @@ def testPostMessageBetweenServers():
time.sleep(1)
print('\n\n*******************************************************')
print('Alice sends to Bob')
os.chdir(aliceDir)
sessionAlice = createSession(aliceDomain,alicePort,useTor)
@ -255,6 +256,11 @@ def testPostMessageBetweenServers():
ccUrl=None
alicePersonCache={}
aliceCachedWebfingers={}
# nothing in Alice's outbox
outboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/outbox'
assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==0
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))
@ -263,9 +269,53 @@ def testPostMessageBetweenServers():
for i in range(30):
if os.path.isdir(inboxPath):
if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])>0:
break
if len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1:
break
time.sleep(1)
# inbox item created
assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
# queue item removed
assert len([name for name in os.listdir(queuePath) if os.path.isfile(os.path.join(queuePath, name))])==0
#print('\n\n*******************************************************')
#print("Bob likes Alice's post")
#followerOfPerson(bobDir,'bob',bobDomain,'alice',aliceDomain+':'+str(alicePort),federationList,True)
#followPerson(aliceDir,'alice',aliceDomain,'bob',bobDomain+':'+str(bobPort),federationList,True)
#followList=getFollowersOfPerson(bobDir,'bob',bobDomain,'followers.txt')
#assert len(followList)==1
#sessionBob = createSession(bobDomain,bobPort,useTor)
#bobSendThreads = []
#bobPostLog = []
#bobPersonCache={}
#bobCachedWebfingers={}
#statusNumber=None
#outboxPostFilename=None
#outboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/outbox'
#for name in os.listdir(outboxPath):
# if '#statuses#' in name:
# statusNumber=int(name.split('#statuses#')[1].replace('.json',''))
# outboxPostFilename=outboxPath+'/'+name
#assert statusNumber
#assert outboxPostFilename
#assert likePost(sessionBob,bobDir,federationList, \
# 'bob',bobDomain,bobPort,httpPrefix, \
# 'alice',aliceDomain,alicePort,[], \
# statusNumber,False,bobSendThreads,bobPostLog, \
# bobPersonCache,bobCachedWebfingers,True)
#for i in range(20):
# if 'likes' in open(outboxPostFilename).read():
# break
# time.sleep(1)
#with open(outboxPostFilename, 'r') as fp:
# alicePostJson=commentjson.load(fp)
# pprint(alicePostJson)
#assert 'likes' in open(outboxPostFilename).read()
# stop the servers
thrAlice.kill()
thrAlice.join()
@ -275,11 +325,6 @@ def testPostMessageBetweenServers():
thrBob.join()
assert thrBob.isAlive()==False
# inbox item created
assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
# queue item removed
assert len([name for name in os.listdir(queuePath) if os.path.isfile(os.path.join(queuePath, name))])==0
os.chdir(baseDir)
shutil.rmtree(aliceDir)
shutil.rmtree(bobDir)
@ -439,7 +484,7 @@ def testFollowBetweenServers():
assert aliceMessageArrived==True
print('Message from Alice to Bob succeeded, since it was granted capabilities')
print('\n\n*********************************************************')
print("\nBob changes Alice's capabilities so that she can't reply on his posts")
bobCapsFilename=bobDir+'/accounts/bob@'+bobDomain+'/ocap/accept/'+httpPrefix+':##'+aliceDomain+':'+str(alicePort)+'#users#alice.json'

View File

@ -44,6 +44,8 @@ def createInboxQueueDir(nickname: str,domain: str,baseDir: str) -> str:
def domainPermitted(domain: str, federationList: []):
if len(federationList)==0:
return True
if ':' in domain:
domain=domain.split(':')[0]
if domain in federationList:
return True
return False
@ -91,6 +93,8 @@ def followPerson(baseDir: str,nickname: str, domain: str, \
if debug:
print('DEBUG: follow of domain '+followDomain+' not permitted')
return False
if debug:
print('DEBUG: follow of domain '+followDomain)
handle=nickname.lower()+'@'+domain.lower()
handleToFollow=followNickname.lower()+'@'+followDomain.lower()
if not os.path.isdir(baseDir+'/accounts'):
@ -100,10 +104,33 @@ def followPerson(baseDir: str,nickname: str, domain: str, \
filename=baseDir+'/accounts/'+handle+'/'+followFile
if os.path.isfile(filename):
if handleToFollow in open(filename).read():
if debug:
print('DEBUG: follow already exists')
return True
with open(filename, "a") as followfile:
followfile.write(handleToFollow+'\n')
if debug:
print('DEBUG: follow added')
return True
if debug:
print('DEBUG: creating new following file')
with open(filename, "w") as followfile:
followfile.write(handleToFollow+'\n')
return True
def locatePost(baseDir: str,nickname: str,domain: str,postUrl: str):
"""Returns the filename for the given status post url
"""
boxName='outbox'
postFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/'+boxName+'/'+postUrl.replace('/','#')+'.json'
if not os.path.isfile(postFilename):
# if this post in the inbox of the person?
boxName='inbox'
postFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/'+boxName+'/'+postUrl.replace('/','#')+'.json'
if not os.path.isfile(postFilename):
# if this post in the shared inbox?
handle='inbox@'+domain
postFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/'+boxName+'/'+postUrl.replace('/','#')+'.json'
if not os.path.isfile(postFilename):
postFilename=None
return postFilename