Reduce some line lengths

master
Bob Mottram 2019-07-06 18:00:22 +01:00
parent e3be2f4328
commit 3a6fe719a9
8 changed files with 192 additions and 95 deletions

View File

@ -8,6 +8,8 @@ Also: https://raw.githubusercontent.com/w3c/activitypub/gh-pages/activitypub-tut
https://blog.dereferenced.org/what-is-ocap-and-why-should-i-care
https://alexcastano.com/what-is-activity-pub
This project is currently *pre alpha* and not recommended for any real world uses.
## Goals

View File

@ -15,11 +15,15 @@ from utils import getDomainFromActor
from utils import getNicknameFromActor
from utils import domainPermitted
def createAcceptReject(baseDir: str,federationList: [],capsList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str,acceptType: str) -> {}:
"""Accepts or rejects something (eg. a follow request)
def createAcceptReject(baseDir: str,federationList: [],capsList: [], \
nickname: str,domain: str,port: int, \
toUrl: str,ccUrl: str,httpPrefix: str, \
objectUrl: str,acceptType: str) -> {}:
"""Accepts or rejects something (eg. a follow request or offer)
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
objectUrl is typically the url of the message, corresponding to url or atomUri in createPostBase
and ccUrl might be a specific person favorited or repeated and
the followers url objectUrl is typically the url of the message,
corresponding to url or atomUri in createPostBase
"""
if not urlPermitted(objectUrl,federationList,capsList,"inbox:write"):
return None
@ -39,13 +43,28 @@ def createAcceptReject(baseDir: str,federationList: [],capsList: [],nickname: st
newAccept['cc']=ccUrl
return newAccept
def createAccept(baseDir: str,federationList: [],capsList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str) -> {}:
return createAcceptReject(baseDir,federationList,capsList,nickname,domain,port,toUrl,ccUrl,httpPrefix,objectUrl,'Accept')
def createAccept(baseDir: str,federationList: [],capsList: [], \
nickname: str,domain: str,port: int, \
toUrl: str,ccUrl: str,httpPrefix: str, \
objectUrl: str) -> {}:
return createAcceptReject(baseDir,federationList,capsList, \
nickname,domain,port, \
toUrl,ccUrl,httpPrefix, \
objectUrl,'Accept')
def createReject(baseDir: str,federationList: [],capsList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str) -> {}:
return createAcceptReject(baseDir,federationList,capsList,nickname,domain,port,toUrl,ccUrl,httpPrefix,objectUrl,'Reject')
def createReject(baseDir: str,federationList: [],capsList: [], \
nickname: str,domain: str,port: int, \
toUrl: str,ccUrl: str,httpPrefix: str, \
objectUrl: str) -> {}:
return createAcceptReject(baseDir,federationList,capsList, \
nickname,domain,port, \
toUrl,ccUrl, \
httpPrefix,objectUrl,'Reject')
def receiveAcceptReject(session,baseDir: str,httpPrefix: str,port: int,sendThreads: [],postLog: [],cachedWebfingers: {},personCache: {},messageJson: {},federationList: [],capsList: [],debug : bool) -> bool:
def receiveAcceptReject(session,baseDir: str,httpPrefix: str,port: int, \
sendThreads: [],postLog: [],cachedWebfingers: {}, \
personCache: {},messageJson: {},federationList: [], \
capsList: [],debug : bool) -> bool:
"""Receives an Accept or Reject within the POST section of HTTPServer
"""
if messageJson['type']!='Accept' and messageJson['type']!='Reject':

View File

@ -18,8 +18,9 @@ def createAnnounce(baseDir: str,federationList: [], capsList: [], \
objectUrl: str, saveToFile: bool) -> {}:
"""Creates an announce message
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
objectUrl is typically the url of the message, corresponding to url or atomUri in createPostBase
and ccUrl might be a specific person favorited or repeated and the
followers url objectUrl is typically the url of the message,
corresponding to url or atomUri in createPostBase
"""
if not urlPermitted(objectUrl,federationList,capsList,"inbox:write"):
return None
@ -28,7 +29,8 @@ def createAnnounce(baseDir: str,federationList: [], capsList: [], \
domain=domain+':'+str(port)
statusNumber,published = getStatusNumber()
newAnnounceId=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
newAnnounceId= \
httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
newAnnounce = {
'actor': httpPrefix+'://'+domain+'/users/'+nickname,
'atomUri': httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
@ -79,5 +81,6 @@ def repeatPost(baseDir: str,federationList: [], \
objectUrl = announceHttpsPrefix + '://'+announcedDomain+'/users/'+ \
announceNickname+'/statuses/'+str(announceStatusNumber)
return announcePublic(baseDir,nickname, domain, port, httpPrefix, objectUrl, saveToFile)
return announcePublic(baseDir,nickname, domain, port, \
httpPrefix, objectUrl, saveToFile)

View File

@ -65,7 +65,9 @@ def authorizeBasic(baseDir: str,path: str,authHeader: str,debug: bool) -> bool:
nickname = plain.split(':')[0]
if nickname!=nicknameFromPath:
if debug:
print('DEBUG: Nickname given in the path ('+nicknameFromPath+') does not match the one in the Authorization header ('+nickname+')')
print('DEBUG: Nickname given in the path ('+nicknameFromPath+ \
') does not match the one in the Authorization header ('+ \
nickname+')')
return False
passwordFile=baseDir+'/accounts/passwords'
if not os.path.isfile(passwordFile):

View File

@ -12,7 +12,10 @@ def storePersonInCache(personUrl: str,personJson: {},personCache: {}) -> None:
"""Store an actor in the cache
"""
currTime=datetime.datetime.utcnow()
personCache[personUrl]={ "actor": personJson, "timestamp": currTime.strftime("%Y-%m-%dT%H:%M:%SZ") }
personCache[personUrl]={
"actor": personJson,
"timestamp": currTime.strftime("%Y-%m-%dT%H:%M:%SZ")
}
def storeWebfingerInCache(handle: str,wf,cachedWebfingers: {}) -> None:
"""Store a webfinger endpoint in the cache
@ -25,7 +28,9 @@ def getPersonFromCache(personUrl: str,personCache: {}) -> {}:
if personCache.get(personUrl):
# how old is the cached data?
currTime=datetime.datetime.utcnow()
cacheTime=datetime.datetime.strptime(personCache[personUrl]['timestamp'],"%Y-%m-%dT%H:%M:%SZ")
cacheTime= \
datetime.datetime.strptime(personCache[personUrl]['timestamp'], \
"%Y-%m-%dT%H:%M:%SZ")
daysSinceCached=(currTime - cacheTime).days
# return cached value if it has not expired
if daysSinceCached <= 2:

View File

@ -132,16 +132,22 @@ class PubServer(BaseHTTPRequestHandler):
return False
# https://www.w3.org/TR/activitypub/#create-activity-outbox
messageJson['object']['attributedTo']=messageJson['actor']
permittedOutboxTypes=['Create','Announce','Like','Follow','Undo','Update','Add','Remove','Block','Delete']
permittedOutboxTypes=[
'Create','Announce','Like','Follow','Undo', \
'Update','Add','Remove','Block','Delete'
]
if messageJson['type'] not in permittedOutboxTypes:
if self.server.debug:
print('DEBUG: POST to outbox - '+messageJson['type']+' is not a permitted activity type')
print('DEBUG: POST to outbox - '+messageJson['type']+ \
' is not a permitted activity type')
return False
if messageJson.get('id'):
postId=messageJson['id']
else:
postId=None
savePostToBox(self.server.baseDir,postId,self.postToNickname,self.server.domain,messageJson,'outbox')
savePostToBox(self.server.baseDir,postId, \
self.postToNickname, \
self.server.domain,messageJson,'outbox')
return True
def _updateInboxQueue(self,nickname: str,messageJson: {}) -> bool:
@ -158,7 +164,6 @@ class PubServer(BaseHTTPRequestHandler):
'/'+self.path.split('/')[-1],
self.server.debug)
if queueFilename:
print('**************************************')
if queueFilename not in self.server.inboxQueue:
self.server.inboxQueue.append(queueFilename)
self.send_response(201)
@ -169,7 +174,9 @@ class PubServer(BaseHTTPRequestHandler):
def do_GET(self):
if self.server.debug:
print('DEBUG: GET from '+self.server.baseDir+' path: '+self.path+' busy: '+str(self.server.GETbusy))
print('DEBUG: GET from '+self.server.baseDir+ \
' path: '+self.path+' busy: '+ \
str(self.server.GETbusy))
if self.server.GETbusy:
currTimeGET=int(time.time())
if currTimeGET-self.server.lastGET<10:
@ -211,7 +218,8 @@ class PubServer(BaseHTTPRequestHandler):
return
else:
if self.server.debug:
print('DEBUG: '+nickname+' was not authorized to access '+self.path)
print('DEBUG: '+nickname+ \
' was not authorized to access '+self.path)
if self.server.debug:
print('DEBUG: GET access to inbox is unauthorized')
self.send_response(405)
@ -239,7 +247,8 @@ class PubServer(BaseHTTPRequestHandler):
return
followers=getFollowingFeed(self.server.baseDir,self.server.domain, \
self.server.port,self.path, \
self.server.httpPrefix,followsPerPage,'followers')
self.server.httpPrefix, \
followsPerPage,'followers')
if followers:
self._set_headers('application/json')
self.wfile.write(json.dumps(followers).encode('utf-8'))
@ -279,7 +288,9 @@ class PubServer(BaseHTTPRequestHandler):
def do_POST(self):
if self.server.debug:
print('DEBUG: POST to from '+self.server.baseDir+' path: '+self.path+' busy: '+str(self.server.POSTbusy))
print('DEBUG: POST to from '+self.server.baseDir+ \
' path: '+self.path+' busy: '+ \
str(self.server.POSTbusy))
if self.server.POSTbusy:
currTimePOST=int(time.time())
if currTimePOST-self.server.lastPOST<10:
@ -314,7 +325,9 @@ class PubServer(BaseHTTPRequestHandler):
if self.path.endswith('/outbox'):
if '/users/' in self.path:
if self.headers.get('Authorization'):
if authorize(self.server.baseDir,self.path,self.headers['Authorization'],self.server.debug):
if authorize(self.server.baseDir,self.path, \
self.headers['Authorization'], \
self.server.debug):
self.outboxAuthenticated=True
pathUsersSection=path.split('/users/')[1]
self.postToNickname=pathUsersSection.split('/')[0]
@ -354,7 +367,8 @@ class PubServer(BaseHTTPRequestHandler):
# https://www.w3.org/TR/activitypub/#object-without-create
if self.outboxAuthenticated:
if self._postToOutbox(messageJson):
self.send_header('Location',messageJson['object']['atomUri'])
self.send_header('Location', \
messageJson['object']['atomUri'])
self.send_response(201)
self.end_headers()
self.server.POSTbusy=False
@ -379,7 +393,10 @@ class PubServer(BaseHTTPRequestHandler):
self.server.POSTbusy=False
return
if not inboxPermittedMessage(self.server.domain,messageJson,self.server.federationList,self.server.capsList):
if not inboxPermittedMessage(self.server.domain, \
messageJson, \
self.server.federationList, \
self.server.capsList):
if self.server.debug:
# https://www.youtube.com/watch?v=K3PrSj9XEu4
print('DEBUG: Ah Ah Ah')
@ -425,7 +442,8 @@ class PubServer(BaseHTTPRequestHandler):
self.end_headers()
self.server.POSTbusy=False
def runDaemon(baseDir: str,domain: str,port=80,httpPrefix='https',fedList=[],capsList=[],useTor=False,debug=False) -> None:
def runDaemon(baseDir: str,domain: str,port=80,httpPrefix='https', \
fedList=[],capsList=[],useTor=False,debug=False) -> None:
if len(domain)==0:
domain='localhost'
if '.' not in domain:
@ -456,6 +474,12 @@ def runDaemon(baseDir: str,domain: str,port=80,httpPrefix='https',fedList=[],cap
httpd.sendThreads=[]
httpd.postLog=[]
print('Running ActivityPub daemon on ' + domain + ' port ' + str(port))
httpd.thrInboxQueue=threadWithTrace(target=runInboxQueue,args=(baseDir,httpPrefix,httpd.sendThreads,httpd.postLog,httpd.cachedWebfingers,httpd.personCache,httpd.inboxQueue,domain,port,useTor,httpd.federationList,httpd.capsList,debug),daemon=True)
httpd.thrInboxQueue= \
threadWithTrace(target=runInboxQueue, \
args=(baseDir,httpPrefix,httpd.sendThreads, \
httpd.postLog,httpd.cachedWebfingers, \
httpd.personCache,httpd.inboxQueue, \
domain,port,useTor,httpd.federationList, \
httpd.capsList,debug),daemon=True)
httpd.thrInboxQueue.start()
httpd.serve_forever()

View File

@ -18,7 +18,9 @@ from posts import sendSignedJson
from capabilities import isCapable
from acceptreject import createAccept
def getFollowersOfPerson(baseDir: str,nickname: str,domain: str,followFile='following.txt') -> []:
def getFollowersOfPerson(baseDir: str, \
nickname: str,domain: str, \
followFile='following.txt') -> []:
"""Returns a list containing the followers of the given person
Used by the shared inbox to know who to send incoming mail to
"""
@ -46,7 +48,8 @@ def followPerson(baseDir: str,nickname: str, domain: str, \
federationList: [], followFile='following.txt') -> bool:
"""Adds a person to the follow list
"""
if not domainPermitted(followDomain.lower().replace('\n',''), federationList):
if not domainPermitted(followDomain.lower().replace('\n',''), \
federationList):
return False
handle=nickname.lower()+'@'+domain.lower()
handleToFollow=followNickname.lower()+'@'+followDomain.lower()
@ -100,9 +103,11 @@ def unfollowerOfPerson(baseDir: str,nickname: str,domain: str, \
followerNickname: str,followerDomain: str) -> None:
"""Remove a follower of a person
"""
unfollowPerson(baseDir,nickname,domain,followerNickname,followerDomain,'followers.txt')
unfollowPerson(baseDir,nickname,domain, \
followerNickname,followerDomain,'followers.txt')
def clearFollows(baseDir: str,nickname: str,domain: str,followFile='following.txt') -> None:
def clearFollows(baseDir: str,nickname: str,domain: str, \
followFile='following.txt') -> None:
"""Removes all follows
"""
handle=nickname.lower()+'@'+domain.lower()
@ -119,7 +124,8 @@ def clearFollowers(baseDir: str,nickname: str,domain: str) -> None:
"""
clearFollows(baseDir,nickname, domain,'followers.txt')
def getNoOfFollows(baseDir: str,nickname: str,domain: str,followFile='following.txt') -> int:
def getNoOfFollows(baseDir: str,nickname: str,domain: str, \
followFile='following.txt') -> int:
"""Returns the number of follows or followers
"""
handle=nickname.lower()+'@'+domain.lower()
@ -142,8 +148,9 @@ def getNoOfFollowers(baseDir: str,nickname: str,domain: str) -> int:
"""
return getNoOfFollows(baseDir,nickname,domain,'followers.txt')
def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,httpPrefix: str, \
followsPerPage=12,followFile='following') -> {}:
def getFollowingFeed(baseDir: str,domain: str,port: int,path: str, \
httpPrefix: str, followsPerPage=12, \
followFile='following') -> {}:
"""Returns the following and followers feeds from GET requests
"""
if '/'+followFile not in path:
@ -233,7 +240,11 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,httpPrefix: st
following['next']=httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(lastPage)
return following
def receiveFollowRequest(session,baseDir: str,httpPrefix: str,port: int,sendThreads: [],postLog: [],cachedWebfingers: {},personCache: {},messageJson: {},federationList: [],capsList: [],debug : bool) -> bool:
def receiveFollowRequest(session,baseDir: str,httpPrefix: str, \
port: int,sendThreads: [],postLog: [], \
cachedWebfingers: {},personCache: {}, \
messageJson: {},federationList: [], \
capsList: [],debug : bool) -> bool:
"""Receives a follow request within the POST section of HTTPServer
"""
if not messageJson['type'].startswith('Follow'):
@ -278,33 +289,46 @@ def receiveFollowRequest(session,baseDir: str,httpPrefix: str,port: int,sendThre
if domainToFollow==domain:
if not os.path.isdir(baseDir+'/accounts/'+handleToFollow):
if debug:
print('DEBUG: followed account not found - '+baseDir+'/accounts/'+handleToFollow)
print('DEBUG: followed account not found - '+ \
baseDir+'/accounts/'+handleToFollow)
return False
if not followerOfPerson(baseDir,nickname,domain,nicknameToFollow,domainToFollow,federationList):
if not followerOfPerson(baseDir,nickname,domain, \
nicknameToFollow,domainToFollow,federationList):
if debug:
print('DEBUG: '+nickname+'@'+domain+' is already a follower of '+nicknameToFollow+'@'+domainToFollow)
print('DEBUG: '+nickname+'@'+domain+ \
' is already a follower of '+ \
nicknameToFollow+'@'+domainToFollow)
return False
# send accept back
if debug:
print('DEBUG: sending Accept for follow request which arrived at '+nicknameToFollow+'@'+domainToFollow+' back to '+nickname+'@'+domain)
print('DEBUG: sending Accept for follow request which arrived at '+ \
nicknameToFollow+'@'+domainToFollow+' back to '+nickname+'@'+domain)
personUrl=messageJson['actor']
acceptJson=createAccept(baseDir,federationList,capsList,nickname,domain,port, \
acceptJson=createAccept(baseDir,federationList,capsList, \
nickname,domain,port, \
personUrl,'',httpPrefix,messageJson['object'])
if debug:
pprint(acceptJson)
print('DEBUG: sending follow Accept from '+nicknameToFollow+'@'+domainToFollow+' port '+str(port)+' to '+nickname+'@'+domain+' port '+ str(fromPort))
print('DEBUG: sending follow Accept from '+ \
nicknameToFollow+'@'+domainToFollow+ \
' port '+str(port)+' to '+ \
nickname+'@'+domain+' port '+ str(fromPort))
clientToServer=False
return sendSignedJson(acceptJson,session,baseDir,nicknameToFollow,domainToFollow,port, \
return sendSignedJson(acceptJson,session,baseDir, \
nicknameToFollow,domainToFollow,port, \
nickname,domain,fromPort, '', \
httpPrefix,True,clientToServer, \
federationList, capsList, \
sendThreads,postLog,cachedWebfingers,personCache,debug)
sendThreads,postLog,cachedWebfingers, \
personCache,debug)
def sendFollowRequest(session,baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
followNickname: str,followDomain: str,followPort: bool,followHttpPrefix: str, \
def sendFollowRequest(session,baseDir: str, \
nickname: str,domain: str,port: int,httpPrefix: str, \
followNickname: str,followDomain: str, \
followPort: bool,followHttpPrefix: str, \
clientToServer: bool,federationList: [],capsList: [], \
sendThreads: [],postLog: [],cachedWebfingers: {},personCache: {},
debug : bool) -> {}:
sendThreads: [],postLog: [],cachedWebfingers: {}, \
personCache: {},debug : bool) -> {}:
"""Gets the json object for sending a follow request
"""
if not domainPermitted(followDomain,federationList):

110
posts.py
View File

@ -36,7 +36,8 @@ try:
except ImportError:
from bs4 import BeautifulSoup
def noOfFollowersOnDomain(baseDir: str,handle: str, domain: str, followFile='followers.txt') -> int:
def noOfFollowersOnDomain(baseDir: str,handle: str, \
domain: str, followFile='followers.txt') -> int:
"""Returns the number of followers of the given handle from the given domain
"""
filename=baseDir+'/accounts/'+handle+'/'+followFile
@ -47,12 +48,14 @@ def noOfFollowersOnDomain(baseDir: str,handle: str, domain: str, followFile='fol
with open(filename, "r") as followersFilename:
for followerHandle in followersFilename:
if '@' in followerHandle:
followerDomain=followerHandle.split('@')[1].replace('\n','')
followerDomain= \
followerHandle.split('@')[1].replace('\n','')
if domain==followerDomain:
ctr+=1
return ctr
def getPersonKey(nickname: str,domain: str,baseDir: str,keyType='public',debug=False):
def getPersonKey(nickname: str,domain: str,baseDir: str,keyType='public', \
debug=False):
"""Returns the public or private key of a person
"""
handle=nickname+'@'+domain
@ -101,7 +104,8 @@ def parseUserFeed(session,feedUrl: str,asHeader: {}) -> None:
for item in parseUserFeed(session,nextUrl,asHeader):
yield item
def getPersonBox(session,wfRequest: {},personCache: {},boxName='inbox') -> (str,str,str,str,str):
def getPersonBox(session,wfRequest: {},personCache: {}, \
boxName='inbox') -> (str,str,str,str,str):
asHeader = {'Accept': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'}
personUrl = getUserUrl(wfRequest)
if not personUrl:
@ -140,18 +144,8 @@ def getPersonBox(session,wfRequest: {},personCache: {},boxName='inbox') -> (str,
if personJson['endpoints'].get('sharedInbox'):
sharedInbox=personJson['endpoints']['sharedInbox']
capabilityAcquisition=None
if personJson.get('capabilityAcquisition'):
capabilityAcquisition=personJson['capabilityAcquisition']
else:
if personJson.get('capabilityAcquisitionEndpoint'):
capabilityAcquisition=personJson['capabilityAcquisitionEndpoint']
else:
if personJson.get('endpoints'):
if personJson['endpoints'].get('capabilityAcquisition'):
capabilityAcquisition=personJson['endpoints']['capabilityAcquisition']
else:
if personJson['endpoints'].get('capabilityAcquisitionEndpoint'):
capabilityAcquisition=personJson['endpoints']['capabilityAcquisitionEndpoint']
if personJson.get('capabilityAcquisitionEndpoint'):
capabilityAcquisition=personJson['capabilityAcquisitionEndpoint']
storePersonInCache(personUrl,personJson,personCache)
@ -198,7 +192,9 @@ def getPosts(session,outboxUrl: str,maxPosts: int,maxMentions: int, \
if tagItem.get('name') and tagItem.get('icon'):
if tagItem['icon'].get('url'):
# No emoji from non-permitted domains
if urlPermitted(tagItem['icon']['url'],federationList,capsList,"objects:read"):
if urlPermitted(tagItem['icon']['url'], \
federationList,capsList, \
"objects:read"):
emojiName=tagItem['name']
emojiIcon=tagItem['icon']['url']
emoji[emojiName]=emojiIcon
@ -220,7 +216,9 @@ def getPosts(session,outboxUrl: str,maxPosts: int,maxMentions: int, \
if item['object'].get('inReplyTo'):
if item['object']['inReplyTo']:
# No replies to non-permitted domains
if not urlPermitted(item['object']['inReplyTo'],federationList,capsList,"objects:read"):
if not urlPermitted(item['object']['inReplyTo'], \
federationList,capsList, \
"objects:read"):
continue
inReplyTo = item['object']['inReplyTo']
@ -228,7 +226,8 @@ def getPosts(session,outboxUrl: str,maxPosts: int,maxMentions: int, \
if item['object'].get('conversation'):
if item['object']['conversation']:
# no conversations originated in non-permitted domains
if urlPermitted(item['object']['conversation'],federationList,"objects:read"):
if urlPermitted(item['object']['conversation'], \
federationList,"objects:read"):
conversation = item['object']['conversation']
attachment = []
@ -237,7 +236,9 @@ def getPosts(session,outboxUrl: str,maxPosts: int,maxMentions: int, \
for attach in item['object']['attachment']:
if attach.get('name') and attach.get('url'):
# no attachments from non-permitted domains
if urlPermitted(attach['url'],federationList,capsList,"objects:read"):
if urlPermitted(attach['url'], \
federationList,capsList, \
"objects:read"):
attachment.append([attach['name'],attach['url']])
sensitive = False
@ -264,7 +265,8 @@ def getPosts(session,outboxUrl: str,maxPosts: int,maxMentions: int, \
break
return personPosts
def createBoxArchive(nickname: str,domain: str,baseDir: str,boxname: str) -> str:
def createBoxArchive(nickname: str,domain: str,baseDir: str, \
boxname: str) -> str:
"""Creates an archive directory for inbox/outbox posts
"""
handle=nickname.lower()+'@'+domain.lower()
@ -290,7 +292,9 @@ def deleteAllPosts(baseDir: str,nickname: str, domain: str,boxname: str) -> None
except Exception as e:
print(e)
def savePostToBox(baseDir: str,httpPrefix: str,postId: str,nickname: str, domain: str,postJson: {},boxname: str) -> None:
def savePostToBox(baseDir: str,httpPrefix: str,postId: str, \
nickname: str, domain: str,postJson: {}, \
boxname: str) -> None:
"""Saves the give json to the give box
"""
if boxname!='inbox' and boxname!='outbox':
@ -300,7 +304,8 @@ def savePostToBox(baseDir: str,httpPrefix: str,postId: str,nickname: str, domain
if not postId:
statusNumber,published = getStatusNumber()
postId=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
postId=httpPrefix+'://'+domain+'/users/'+nickname+ \
'/statuses/'+statusNumber
postJson['id']=postId+'/activity'
if postJson.get('object'):
postJson['object']['id']=postId
@ -410,10 +415,12 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
newPost['cc']=ccUrl
newPost['object']['cc']=ccUrl
if saveToFile:
savePostToBox(baseDir,httpPrefix,newPostId,nickname,domain,newPost,'outbox')
savePostToBox(baseDir,httpPrefix,newPostId, \
nickname,domain,newPost,'outbox')
return newPost
def outboxMessageCreateWrap(httpPrefix: str,nickname: str,domain: str,messageJson: {}) -> {}:
def outboxMessageCreateWrap(httpPrefix: str,nickname: str,domain: str, \
messageJson: {}) -> {}:
"""Wraps a received message in a Create
https://www.w3.org/TR/activitypub/#object-without-create
"""
@ -438,8 +445,10 @@ def outboxMessageCreateWrap(httpPrefix: str,nickname: str,domain: str,messageJso
'object': messageJson
}
newPost['object']['id']=newPost['id']
newPost['object']['url']=httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber
newPost['object']['atomUri']=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
newPost['object']['url']= \
httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber
newPost['object']['atomUri']= \
httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
return newPost
def createPublicPost(baseDir: str,
@ -452,8 +461,8 @@ def createPublicPost(baseDir: str,
return createPostBase(baseDir,nickname, domain, port, \
'https://www.w3.org/ns/activitystreams#Public', \
httpPrefix+'://'+domain+'/users/'+nickname+'/followers', \
httpPrefix, content, followersOnly, saveToFile, clientToServer, \
capsList,
httpPrefix, content, followersOnly, saveToFile, \
clientToServer, capsList, \
inReplyTo, inReplyToAtomUri, subject)
def threadSendPost(session,postJsonObject: {},federationList: [],capsList: [],\
@ -483,7 +492,8 @@ def threadSendPost(session,postJsonObject: {},federationList: [],capsList: [],\
# our work here is done
break
if debug:
print('DEBUG: json post to '+inboxUrl+' failed. Waiting for '+str(backoffTime)+' seconds.')
print('DEBUG: json post to '+inboxUrl+' failed. Waiting for '+ \
str(backoffTime)+' seconds.')
time.sleep(backoffTime)
backoffTime *= 2
@ -573,12 +583,13 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \
thr.start()
return 0
def sendSignedJson(postJsonObject: {},session,baseDir: str,nickname: str, domain: str, port: int, \
def sendSignedJson(postJsonObject: {},session,baseDir: str, \
nickname: str, domain: str, port: int, \
toNickname: str, toDomain: str, toPort: int, cc: str, \
httpPrefix: str, saveToFile: bool, clientToServer: bool, \
federationList: [], capsList: [], \
sendThreads: [], postLog: [], cachedWebfingers: {},personCache: {}, \
debug: bool) -> int:
sendThreads: [], postLog: [], cachedWebfingers: {}, \
personCache: {}, debug: bool) -> int:
"""Sends a signed json object to an inbox/outbox
"""
withDigest=True
@ -646,14 +657,15 @@ def sendSignedJson(postJsonObject: {},session,baseDir: str,nickname: str, domain
while len(sendThreads)>10:
sendThreads[0].kill()
sendThreads.pop(0)
thr = threadWithTrace(target=threadSendPost,args=(session, \
postJsonObject.copy(), \
federationList, \
capsList, \
inboxUrl,baseDir, \
signatureHeaderJson.copy(), \
postLog,
debug),daemon=True)
thr = threadWithTrace(target=threadSendPost, \
args=(session, \
postJsonObject.copy(), \
federationList, \
capsList, \
inboxUrl,baseDir, \
signatureHeaderJson.copy(), \
postLog,
debug),daemon=True)
sendThreads.append(thr)
thr.start()
return 0
@ -667,7 +679,8 @@ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: st
return createBoxBase(baseDir,'outbox',nickname,domain,port,httpPrefix, \
itemsPerPage,headerOnly,pageNumber)
def createBoxBase(baseDir: str,boxname: str,nickname: str,domain: str,port: int,httpPrefix: str, \
def createBoxBase(baseDir: str,boxname: str, \
nickname: str,domain: str,port: int,httpPrefix: str, \
itemsPerPage: int,headerOnly: bool,pageNumber=None) -> {}:
"""Constructs the box feed
"""
@ -727,7 +740,8 @@ def createBoxBase(baseDir: str,boxname: str,nickname: str,domain: str,port: int,
# update the prev entry for the last message id
postId = prevPostFilename.split('#statuses#')[1].replace('#activity','')
boxHeader['prev']= \
httpPrefix+'://'+domain+'/users/'+nickname+'/'+boxname+'?min_id='+postId+'&page=true'
httpPrefix+'://'+domain+'/users/'+nickname+'/'+ \
boxname+'?min_id='+postId+'&page=true'
# get the full path of the post file
filePath = os.path.join(boxDir, postFilename)
try:
@ -788,7 +802,8 @@ def archivePosts(nickname: str,domain: str,baseDir: str, \
if noOfPosts <= maxPostsInBox:
break
def getPublicPostsOfPerson(nickname: str,domain: str,raw: bool,simple: bool) -> None:
def getPublicPostsOfPerson(nickname: str,domain: str, \
raw: bool,simple: bool) -> None:
""" This is really just for test purposes
"""
useTor=True
@ -800,7 +815,8 @@ def getPublicPostsOfPerson(nickname: str,domain: str,raw: bool,simple: bool) ->
httpPrefix='https'
handle=httpPrefix+"://"+domain+"/@"+nickname
wfRequest = webfingerHandle(session,handle,httpPrefix,cachedWebfingers)
wfRequest = \
webfingerHandle(session,handle,httpPrefix,cachedWebfingers)
if not wfRequest:
sys.exit()
@ -811,5 +827,7 @@ def getPublicPostsOfPerson(nickname: str,domain: str,raw: bool,simple: bool) ->
maxMentions=10
maxEmoji=10
maxAttachments=5
userPosts = getPosts(session,personUrl,30,maxMentions,maxEmoji,maxAttachments,federationList,personCache,raw,simple)
userPosts = getPosts(session,personUrl,30,maxMentions,maxEmoji, \
maxAttachments,federationList,personCache, \
raw,simple)
#print(str(userPosts))