master
Bob Mottram 2019-07-14 17:57:06 +01:00
parent 9fab084e20
commit e1a6528307
6 changed files with 93 additions and 90 deletions

View File

@ -269,16 +269,16 @@ class PubServer(BaseHTTPRequestHandler):
self.server.baseDir+'/accounts/'+nickname+'@'+self.server.domain+'/outbox/'+ \ self.server.baseDir+'/accounts/'+nickname+'@'+self.server.domain+'/outbox/'+ \
self.server.httpPrefix+':##'+domainFull+'#users#'+nickname+'#statuses#'+statusNumber+'.json' self.server.httpPrefix+':##'+domainFull+'#users#'+nickname+'#statuses#'+statusNumber+'.json'
if os.path.isfile(postFilename): if os.path.isfile(postFilename):
postJson={} postJsonObject={}
with open(postFilename, 'r') as fp: with open(postFilename, 'r') as fp:
postJson=commentjson.load(fp) postJsonObject=commentjson.load(fp)
# Only authorized viewers get to see likes on posts # Only authorized viewers get to see likes on posts
# Otherwize marketers could gain more social graph info # Otherwize marketers could gain more social graph info
if not self._isAuthorized(): if not self._isAuthorized():
if postJson.get('likes'): if postJsonObject.get('likes'):
postJson['likes']={} postJsonObject['likes']={}
self._set_headers('application/json') self._set_headers('application/json')
self.wfile.write(json.dumps(postJson).encode('utf-8')) self.wfile.write(json.dumps(postJsonObject).encode('utf-8'))
self.server.GETbusy=False self.server.GETbusy=False
return return
else: else:
@ -346,17 +346,17 @@ class PubServer(BaseHTTPRequestHandler):
if authorized or \ if authorized or \
'https://www.w3.org/ns/activitystreams#Public' in open(searchFilename).read(): 'https://www.w3.org/ns/activitystreams#Public' in open(searchFilename).read():
with open(searchFilename, 'r') as fp: with open(searchFilename, 'r') as fp:
postJson=commentjson.load(fp) postJsonObject=commentjson.load(fp)
if postJson['object'].get('cc'): if postJsonObject['object'].get('cc'):
if authorized or \ if authorized or \
('https://www.w3.org/ns/activitystreams#Public' in postJson['object']['to'] or \ ('https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['to'] or \
'https://www.w3.org/ns/activitystreams#Public' in postJson['object']['cc']): 'https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['cc']):
repliesJson['orderedItems'].append(postJson) repliesJson['orderedItems'].append(postJsonObject)
replyFound=True replyFound=True
else: else:
if authorized or \ if authorized or \
'https://www.w3.org/ns/activitystreams#Public' in postJson['object']['to']: 'https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['to']:
repliesJson['orderedItems'].append(postJson) repliesJson['orderedItems'].append(postJsonObject)
replyFound=True replyFound=True
break break
# if not in either inbox or outbox then examine the shared inbox # if not in either inbox or outbox then examine the shared inbox
@ -371,16 +371,16 @@ class PubServer(BaseHTTPRequestHandler):
'https://www.w3.org/ns/activitystreams#Public' in open(searchFilename).read(): 'https://www.w3.org/ns/activitystreams#Public' in open(searchFilename).read():
# get the json of the reply and append it to the collection # get the json of the reply and append it to the collection
with open(searchFilename, 'r') as fp: with open(searchFilename, 'r') as fp:
postJson=commentjson.load(fp) postJsonObject=commentjson.load(fp)
if postJson['object'].get('cc'): if postJsonObject['object'].get('cc'):
if authorized or \ if authorized or \
('https://www.w3.org/ns/activitystreams#Public' in postJson['object']['to'] or \ ('https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['to'] or \
'https://www.w3.org/ns/activitystreams#Public' in postJson['object']['cc']): 'https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['cc']):
repliesJson['orderedItems'].append(postJson) repliesJson['orderedItems'].append(postJsonObject)
else: else:
if authorized or \ if authorized or \
'https://www.w3.org/ns/activitystreams#Public' in postJson['object']['to']: 'https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['to']:
repliesJson['orderedItems'].append(postJson) repliesJson['orderedItems'].append(postJsonObject)
# send the replies json # send the replies json
self._set_headers('application/json') self._set_headers('application/json')
self.wfile.write(json.dumps(repliesJson).encode('utf-8')) self.wfile.write(json.dumps(repliesJson).encode('utf-8'))
@ -403,16 +403,16 @@ class PubServer(BaseHTTPRequestHandler):
self.server.baseDir+'/accounts/'+nickname+'@'+self.server.domain+'/outbox/'+ \ self.server.baseDir+'/accounts/'+nickname+'@'+self.server.domain+'/outbox/'+ \
self.server.httpPrefix+':##'+domainFull+'#users#'+nickname+'#statuses#'+statusNumber+'.json' self.server.httpPrefix+':##'+domainFull+'#users#'+nickname+'#statuses#'+statusNumber+'.json'
if os.path.isfile(postFilename): if os.path.isfile(postFilename):
postJson={} postJsonObject={}
with open(postFilename, 'r') as fp: with open(postFilename, 'r') as fp:
postJson=commentjson.load(fp) postJsonObject=commentjson.load(fp)
# Only authorized viewers get to see likes on posts # Only authorized viewers get to see likes on posts
# Otherwize marketers could gain more social graph info # Otherwize marketers could gain more social graph info
if not self._isAuthorized(): if not self._isAuthorized():
if postJson.get('likes'): if postJsonObject.get('likes'):
postJson['likes']={} postJsonObject['likes']={}
self._set_headers('application/json') self._set_headers('application/json')
self.wfile.write(json.dumps(postJson).encode('utf-8')) self.wfile.write(json.dumps(postJsonObject).encode('utf-8'))
self.server.GETbusy=False self.server.GETbusy=False
return return
else: else:

View File

@ -21,6 +21,7 @@ from utils import getNicknameFromActor
from utils import domainPermitted from utils import domainPermitted
from utils import locatePost from utils import locatePost
from utils import deletePost from utils import deletePost
from utils import removeAttachment
from httpsig import verifyPostHeaders from httpsig import verifyPostHeaders
from session import createSession from session import createSession
from session import getJson from session import getJson
@ -110,14 +111,14 @@ def validPublishedDate(published) -> bool:
return False return False
return True return True
def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str,postJson: {},host: str,headers: str,postPath: str,debug: bool) -> str: def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str,postJsonObject: {},host: str,headers: str,postPath: str,debug: bool) -> str:
"""Saves the give json to the inbox queue for the person """Saves the give json to the inbox queue for the person
keyId specifies the actor sending the post keyId specifies the actor sending the post
""" """
if ':' in domain: if ':' in domain:
domain=domain.split(':')[0] domain=domain.split(':')[0]
if postJson.get('id'): if postJsonObject.get('id'):
postId=postJson['id'].replace('/activity','') postId=postJsonObject['id'].replace('/activity','')
else: else:
statusNumber,published = getStatusNumber() statusNumber,published = getStatusNumber()
postId=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber postId=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
@ -147,7 +148,7 @@ def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str
'host': host, 'host': host,
'headers': headers, 'headers': headers,
'path': postPath, 'path': postPath,
'post': postJson, 'post': postJsonObject,
'filename': filename, 'filename': filename,
'destination': destination 'destination': destination
} }
@ -627,9 +628,9 @@ def receiveUndoAnnounce(session,handle: str,baseDir: str, \
if debug: if debug:
print('DEBUG: announced/repeated post to be undone found in inbox') print('DEBUG: announced/repeated post to be undone found in inbox')
with open(postFilename, 'r') as fp: with open(postFilename, 'r') as fp:
postJson=commentjson.load(fp) postJsonObject=commentjson.load(fp)
if not postJson.get('type'): if not postJsonObject.get('type'):
if postJson['type']!='Announce': if postJsonObject['type']!='Announce':
if debug: if debug:
print("DEBUG: Attenpt to undo something which isn't an announcement") print("DEBUG: Attenpt to undo something which isn't an announcement")
return False return False

48
like.py
View File

@ -19,55 +19,55 @@ def undoLikesCollectionEntry(postFilename: str,objectUrl: str, actor: str,debug:
"""Undoes a like for a particular actor """Undoes a like for a particular actor
""" """
with open(postFilename, 'r') as fp: with open(postFilename, 'r') as fp:
postJson=commentjson.load(fp) postJsonObject=commentjson.load(fp)
if not postJson.get('type'): if not postJsonObject.get('type'):
if postJson['type']!='Create': if postJsonObject['type']!='Create':
return return
return return
if not postJson.get('object'): if not postJsonObject.get('object'):
if debug: if debug:
pprint(postJson) pprint(postJsonObject)
print('DEBUG: post '+objectUrl+' has no object') print('DEBUG: post '+objectUrl+' has no object')
return return
if not postJson['object'].get('likes'): if not postJsonObject['object'].get('likes'):
return return
if not postJson['object']['likes'].get('items'): if not postJsonObject['object']['likes'].get('items'):
return return
totalItems=0 totalItems=0
if postJson['object']['likes'].get('totalItems'): if postJsonObject['object']['likes'].get('totalItems'):
totalItems=postJson['object']['likes']['totalItems'] totalItems=postJsonObject['object']['likes']['totalItems']
itemFound=False itemFound=False
for likeItem in postJson['object']['likes']['items']: for likeItem in postJsonObject['object']['likes']['items']:
if likeItem.get('actor'): if likeItem.get('actor'):
if likeItem['actor']==actor: if likeItem['actor']==actor:
if debug: if debug:
print('DEBUG: like was removed for '+actor) print('DEBUG: like was removed for '+actor)
postJson['object']['likes']['items'].remove(likeItem) postJsonObject['object']['likes']['items'].remove(likeItem)
itemFound=True itemFound=True
break break
if itemFound: if itemFound:
if totalItems==1: if totalItems==1:
if debug: if debug:
print('DEBUG: likes was removed from post') print('DEBUG: likes was removed from post')
postJson['object'].remove(postJson['object']['likes']) postJsonObject['object'].remove(postJsonObject['object']['likes'])
else: else:
postJson['object']['likes']['totalItems']=len(postJson['likes']['items']) postJsonObject['object']['likes']['totalItems']=len(postJsonObject['likes']['items'])
with open(postFilename, 'w') as fp: with open(postFilename, 'w') as fp:
commentjson.dump(postJson, fp, indent=4, sort_keys=True) commentjson.dump(postJsonObject, fp, indent=4, sort_keys=True)
def updateLikesCollection(postFilename: str,objectUrl: str, actor: str,debug: bool) -> None: def updateLikesCollection(postFilename: str,objectUrl: str, actor: str,debug: bool) -> None:
"""Updates the likes collection within a post """Updates the likes collection within a post
""" """
with open(postFilename, 'r') as fp: with open(postFilename, 'r') as fp:
postJson=commentjson.load(fp) postJsonObject=commentjson.load(fp)
if not postJson.get('object'): if not postJsonObject.get('object'):
if debug: if debug:
pprint(postJson) pprint(postJsonObject)
print('DEBUG: post '+objectUrl+' has no object') print('DEBUG: post '+objectUrl+' has no object')
return return
if not objectUrl.endswith('/likes'): if not objectUrl.endswith('/likes'):
objectUrl=objectUrl+'/likes' objectUrl=objectUrl+'/likes'
if not postJson['object'].get('likes'): if not postJsonObject['object'].get('likes'):
if debug: if debug:
print('DEBUG: Adding initial likes to '+objectUrl) print('DEBUG: Adding initial likes to '+objectUrl)
likesJson = { likesJson = {
@ -80,10 +80,10 @@ def updateLikesCollection(postFilename: str,objectUrl: str, actor: str,debug: bo
}] }]
} }
postJson['object']['likes']=likesJson postJsonObject['object']['likes']=likesJson
else: else:
if postJson['object']['likes'].get('items'): if postJsonObject['object']['likes'].get('items'):
for likeItem in postJson['likes']['items']: for likeItem in postJsonObject['likes']['items']:
if likeItem.get('actor'): if likeItem.get('actor'):
if likeItem['actor']==actor: if likeItem['actor']==actor:
return return
@ -91,8 +91,8 @@ def updateLikesCollection(postFilename: str,objectUrl: str, actor: str,debug: bo
'type': 'Like', 'type': 'Like',
'actor': actor 'actor': actor
} }
postJson['object']['likes']['items'].append(newLike) postJsonObject['object']['likes']['items'].append(newLike)
postJson['object']['likes']['totalItems']=len(postJson['likes']['items']) postJsonObject['object']['likes']['totalItems']=len(postJsonObject['likes']['items'])
else: else:
if debug: if debug:
print('DEBUG: likes section of post has no items list') print('DEBUG: likes section of post has no items list')
@ -100,7 +100,7 @@ def updateLikesCollection(postFilename: str,objectUrl: str, actor: str,debug: bo
if debug: if debug:
print('DEBUG: saving post with likes added') print('DEBUG: saving post with likes added')
with open(postFilename, 'w') as fp: with open(postFilename, 'w') as fp:
commentjson.dump(postJson, fp, indent=4, sort_keys=True) commentjson.dump(postJsonObject, fp, indent=4, sort_keys=True)
def like(session,baseDir: str,federationList: [],nickname: str,domain: str,port: int, \ def like(session,baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
ccList: [],httpPrefix: str,objectUrl: str,clientToServer: bool, \ ccList: [],httpPrefix: str,objectUrl: str,clientToServer: bool, \

View File

@ -82,22 +82,6 @@ def attachImage(baseDir: str,httpPrefix: str,domain: str,port: int, \
return postJson return postJson
def removeAttachment(baseDir: str,httpPrefix: str,domain: str,postJson: {}):
if not postJson.get('attachment'):
return
if not postJson['attachment'][0].get('url'):
return
if port!=80 and port!=443:
if ':' not in domain:
domain=domain+':'+str(port)
attachmentUrl=postJson['attachment'][0]['url']
if not attachmentUrl:
return
mediaFilename=baseDir+'/'+attachmentUrl.replace(httpPrefix+'://'+domain+'/','')
if os.path.isfile(mediaFilename):
os.remove(mediaFilename)
postJson['attachment']=[]
def archiveMedia(baseDir: str,archiveDirectory: str,maxWeeks=4) -> None: def archiveMedia(baseDir: str,archiveDirectory: str,maxWeeks=4) -> None:
"""Any media older than the given number of weeks gets archived """Any media older than the given number of weeks gets archived
""" """

View File

@ -287,7 +287,7 @@ def deleteAllPosts(baseDir: str,nickname: str, domain: str,boxname: str) -> None
print(e) print(e)
def savePostToBox(baseDir: str,httpPrefix: str,postId: str, \ def savePostToBox(baseDir: str,httpPrefix: str,postId: str, \
nickname: str, domain: str,postJson: {}, \ nickname: str, domain: str,postJsonObject: {}, \
boxname: str) -> None: boxname: str) -> None:
"""Saves the give json to the give box """Saves the give json to the give box
""" """
@ -300,15 +300,15 @@ def savePostToBox(baseDir: str,httpPrefix: str,postId: str, \
statusNumber,published = getStatusNumber() statusNumber,published = getStatusNumber()
postId=httpPrefix+'://'+domain+'/users/'+nickname+ \ postId=httpPrefix+'://'+domain+'/users/'+nickname+ \
'/statuses/'+statusNumber '/statuses/'+statusNumber
postJson['id']=postId+'/activity' postJsonObject['id']=postId+'/activity'
if postJson.get('object'): if postJsonObject.get('object'):
postJson['object']['id']=postId postJsonObject['object']['id']=postId
postJson['object']['atomUri']=postId postJsonObject['object']['atomUri']=postId
boxDir = createPersonDir(nickname,domain,baseDir,boxname) boxDir = createPersonDir(nickname,domain,baseDir,boxname)
filename=boxDir+'/'+postId.replace('/','#')+'.json' filename=boxDir+'/'+postId.replace('/','#')+'.json'
with open(filename, 'w') as fp: with open(filename, 'w') as fp:
commentjson.dump(postJson, fp, indent=4, sort_keys=False) commentjson.dump(postJsonObject, fp, indent=4, sort_keys=False)
def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
toUrl: str, ccUrl: str, httpPrefix: str, content: str, \ toUrl: str, ccUrl: str, httpPrefix: str, content: str, \
@ -472,27 +472,27 @@ def outboxMessageCreateWrap(httpPrefix: str,nickname: str,domain: str, \
def postIsAddressedToFollowers(baseDir: str, def postIsAddressedToFollowers(baseDir: str,
nickname: str, domain: str, port: int,httpPrefix: str, nickname: str, domain: str, port: int,httpPrefix: str,
postJson: {}) -> bool: postJsonObject: {}) -> bool:
"""Returns true if the given post is addressed to followers of the nickname """Returns true if the given post is addressed to followers of the nickname
""" """
if port!=80 and port!=443: if port!=80 and port!=443:
domain=domain+':'+str(port) domain=domain+':'+str(port)
if not postJson.get('object'): if not postJsonObject.get('object'):
return False return False
if not postJson['object'].get('to'): if not postJsonObject['object'].get('to'):
return False return False
followersUrl=httpPrefix+'://'+domain+'/users/'+nickname+'/followers' followersUrl=httpPrefix+'://'+domain+'/users/'+nickname+'/followers'
# does the followers url exist in 'to' or 'cc' lists? # does the followers url exist in 'to' or 'cc' lists?
addressedToFollowers=False addressedToFollowers=False
if followersUrl in postJson['object']['to']: if followersUrl in postJsonObject['object']['to']:
addressedToFollowers=True addressedToFollowers=True
if not addressedToFollowers: if not addressedToFollowers:
if not postJson['object'].get('cc'): if not postJsonObject['object'].get('cc'):
return False return False
if followersUrl in postJson['object']['cc']: if followersUrl in postJsonObject['object']['cc']:
addressedToFollowers=True addressedToFollowers=True
return addressedToFollowers return addressedToFollowers
@ -849,20 +849,20 @@ def createBoxBase(baseDir: str,boxname: str, \
sharedInboxFilename=os.path.join(sharedBoxDir, postFilename) sharedInboxFilename=os.path.join(sharedBoxDir, postFilename)
# get the actor from the shared post # get the actor from the shared post
with open(sharedInboxFilename, 'r') as fp: with open(sharedInboxFilename, 'r') as fp:
postJson=commentjson.load(fp) postJsonObject=commentjson.load(fp)
actorNickname=getNicknameFromActor(postJson['actor']) actorNickname=getNicknameFromActor(postJsonObject['actor'])
actorDomain,actorPort=getDomainFromActor(postJson['actor']) actorDomain,actorPort=getDomainFromActor(postJsonObject['actor'])
if actorNickname and actorDomain: if actorNickname and actorDomain:
# is the actor followed by this account? # is the actor followed by this account?
if actorNickname+'@'+actorDomain in open(followingFilename).read(): if actorNickname+'@'+actorDomain in open(followingFilename).read():
if ocapAlways: if ocapAlways:
capsList=None capsList=None
# Note: should this be in the Create or the object of a post? # Note: should this be in the Create or the object of a post?
if postJson.get('capability'): if postJsonObject.get('capability'):
if isinstance(postJson['capability'], list): if isinstance(postJsonObject['capability'], list):
capsList=postJson['capability'] capsList=postJsonObject['capability']
# Have capabilities been granted for the sender? # Have capabilities been granted for the sender?
ocapFilename=baseDir+'/accounts/'+handle+'/ocap/granted/'+postJson['actor'].replace('/','#')+'.json' ocapFilename=baseDir+'/accounts/'+handle+'/ocap/granted/'+postJsonObject['actor'].replace('/','#')+'.json'
if os.path.isfile(ocapFilename): if os.path.isfile(ocapFilename):
# read the capabilities id # read the capabilities id
with open(ocapFilename, 'r') as fp: with open(ocapFilename, 'r') as fp:

View File

@ -142,9 +142,27 @@ def locatePost(baseDir: str,nickname: str,domain: str,postUrl: str,replies=False
postFilename=None postFilename=None
return postFilename return postFilename
def removeAttachment(baseDir: str,httpPrefix: str,domain: str,postJson: {}):
if not postJson.get('attachment'):
return
if not postJson['attachment'][0].get('url'):
return
if port!=80 and port!=443:
if ':' not in domain:
domain=domain+':'+str(port)
attachmentUrl=postJson['attachment'][0]['url']
if not attachmentUrl:
return
mediaFilename=baseDir+'/'+attachmentUrl.replace(httpPrefix+'://'+domain+'/','')
if os.path.isfile(mediaFilename):
os.remove(mediaFilename)
postJson['attachment']=[]
def deletePost(baseDir: str,nickname: str,domain: str,postFilename: str,debug: bool): def deletePost(baseDir: str,nickname: str,domain: str,postFilename: str,debug: bool):
"""Recursively deletes a post and its replies and attachments """Recursively deletes a post and its replies and attachments
""" """
with open(postFilename, 'r') as fp:
postJsonObject=commentjson.load(fp)
repliesFilename=postFilename.replace('.json','.replies') repliesFilename=postFilename.replace('.json','.replies')
if os.path.isfile(repliesFilename): if os.path.isfile(repliesFilename):
if debug: if debug: