forked from indymedia/epicyon
unfollowing functions
parent
3813809958
commit
c55b5c9e15
|
@ -29,6 +29,7 @@ from inbox import inboxMessageHasParams
|
|||
from inbox import runInboxQueue
|
||||
from inbox import savePostToInboxQueue
|
||||
from follow import getFollowingFeed
|
||||
from follow import outboxUndoFollow
|
||||
from auth import authorize
|
||||
from auth import createPassword
|
||||
from threads import threadWithTrace
|
||||
|
@ -200,6 +201,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.cachedWebfingers, \
|
||||
self.server.personCache, \
|
||||
messageJson,self.server.debug)
|
||||
if self.server.debug:
|
||||
print('DEBUG: handle any unfollow requests')
|
||||
outboxUndoFollow(self.server.baseDir,messageJson,self.server.debug)
|
||||
if self.server.debug:
|
||||
print('DEBUG: sending c2s post to named addresses')
|
||||
print('c2s sender: '+self.postToNickname+'@'+self.server.domain+':'+str(self.server.port))
|
||||
|
|
144
follow.py
144
follow.py
|
@ -62,7 +62,7 @@ def followerOfPerson(baseDir: str,nickname: str, domain: str, \
|
|||
|
||||
def unfollowPerson(baseDir: str,nickname: str, domain: str, \
|
||||
followNickname: str, followDomain: str, \
|
||||
followFile='following.txt') -> None:
|
||||
followFile='following.txt') -> bool:
|
||||
"""Removes a person to the follow list
|
||||
"""
|
||||
handle=nickname.lower()+'@'+domain.lower()
|
||||
|
@ -72,15 +72,16 @@ def unfollowPerson(baseDir: str,nickname: str, domain: str, \
|
|||
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||
os.mkdir(baseDir+'/accounts/'+handle)
|
||||
filename=baseDir+'/accounts/'+handle+'/'+followFile
|
||||
if os.path.isfile(filename):
|
||||
if handleToUnfollow not in open(filename).read():
|
||||
return
|
||||
with open(filename, "r") as f:
|
||||
lines = f.readlines()
|
||||
with open(filename, "w") as f:
|
||||
for line in lines:
|
||||
if line.strip("\n") != handleToUnfollow:
|
||||
f.write(line)
|
||||
if not os.path.isfile(filename):
|
||||
return False
|
||||
if handleToUnfollow not in open(filename).read():
|
||||
return
|
||||
with open(filename, "r") as f:
|
||||
lines = f.readlines()
|
||||
with open(filename, "w") as f:
|
||||
for line in lines:
|
||||
if line.strip("\n") != handleToUnfollow:
|
||||
f.write(line)
|
||||
|
||||
def unfollowerOfPerson(baseDir: str,nickname: str,domain: str, \
|
||||
followerNickname: str,followerDomain: str) -> None:
|
||||
|
@ -432,6 +433,81 @@ def sendFollowRequestViaServer(session,fromNickname: str,password: str,
|
|||
|
||||
return newFollowJson
|
||||
|
||||
def sendUnfollowRequestViaServer(session,fromNickname: str,password: str,
|
||||
fromDomain: str,fromPort: int, \
|
||||
followNickname: str,followDomain: str,followPort: int, \
|
||||
httpPrefix: str, \
|
||||
cachedWebfingers: {},personCache: {}, \
|
||||
debug: bool) -> {}:
|
||||
"""Creates a unfollow request via c2s
|
||||
"""
|
||||
if not session:
|
||||
print('WARN: No session for sendUnfollowRequestViaServer')
|
||||
return 6
|
||||
|
||||
fromDomainFull=fromDomain
|
||||
if fromPort!=80 and fromPort!=443:
|
||||
fromDomainFull=fromDomain+':'+str(fromPort)
|
||||
followDomainFull=followDomain
|
||||
if followPort!=80 and followPort!=443:
|
||||
followDomainFull=followDomain+':'+str(followPort)
|
||||
|
||||
followActor=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname
|
||||
followedId=httpPrefix+'://'+followDomainFull+'/users/'+followNickname
|
||||
|
||||
unfollowJson = {
|
||||
'type': 'Undo',
|
||||
'actor': followActor,
|
||||
'object': {
|
||||
'type': 'Follow',
|
||||
'actor': followActor,
|
||||
'object': followedId,
|
||||
'to': [followedId],
|
||||
'cc': ['https://www.w3.org/ns/activitystreams#Public']
|
||||
}
|
||||
}
|
||||
|
||||
handle=httpPrefix+'://'+fromDomainFull+'/@'+fromNickname
|
||||
|
||||
# lookup the inbox for the To handle
|
||||
wfRequest = webfingerHandle(session,handle,httpPrefix,cachedWebfingers)
|
||||
if not wfRequest:
|
||||
if debug:
|
||||
print('DEBUG: announce webfinger failed for '+handle)
|
||||
return 1
|
||||
|
||||
postToBox='outbox'
|
||||
|
||||
# get the actor inbox for the To handle
|
||||
inboxUrl,pubKeyId,pubKey,fromPersonId,sharedInbox,capabilityAcquisition = \
|
||||
getPersonBox(session,wfRequest,personCache,postToBox)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
return 3
|
||||
if not fromPersonId:
|
||||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
headers = {'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
'Authorization': authHeader}
|
||||
postResult = \
|
||||
postJson(session,unfollowJson,[],inboxUrl,headers,"inbox:write")
|
||||
#if not postResult:
|
||||
# if debug:
|
||||
# print('DEBUG: POST announce failed for c2s to '+inboxUrl)
|
||||
# return 5
|
||||
|
||||
if debug:
|
||||
print('DEBUG: c2s POST unfollow success')
|
||||
|
||||
return unfollowJson
|
||||
|
||||
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.
|
||||
|
@ -493,3 +569,51 @@ def getFollowersOfActor(baseDir :str,actor :str,debug: bool) -> {}:
|
|||
print(ocapFilename)
|
||||
recipientsDict[account]=None
|
||||
return recipientsDict
|
||||
|
||||
def outboxUndoFollow(baseDir: str,messageJson: {},debug: bool) -> None:
|
||||
"""When an unfollow request is received by the outbox from c2s
|
||||
This removes the followed handle from the following.txt file
|
||||
of the relevant account
|
||||
"""
|
||||
if not messageJson.get('type'):
|
||||
return
|
||||
if not messageJson['type']=='Undo':
|
||||
return
|
||||
if not messageJson.get('object'):
|
||||
return
|
||||
if not isinstance(messageJson['object'], dict):
|
||||
return
|
||||
if not messageJson['object'].get('type'):
|
||||
return
|
||||
if not messageJson['object']['type']=='Follow':
|
||||
return
|
||||
if not messageJson['object'].get('object'):
|
||||
return
|
||||
if not messageJson['object'].get('actor'):
|
||||
return
|
||||
if not isinstance(messageJson['object']['object'], str):
|
||||
return
|
||||
if debug:
|
||||
print('DEBUG: undo follow arrived in outbox')
|
||||
|
||||
nicknameFollower=getNicknameFromActor(messageJson['object']['actor'])
|
||||
domainFollower,portFollower=getDomainFromActor(messageJson['object']['actor'])
|
||||
domainFollowerFull=domainFollower
|
||||
if portFollower:
|
||||
if portFollower!=80 and portFollower!=443:
|
||||
domainFollowerFull=domainFollower+':'+str(portFollower)
|
||||
|
||||
nicknameFollowing=getNicknameFromActor(messageJson['object']['object'])
|
||||
domainFollowing,portFollowing=getDomainFromActor(messageJson['object']['object'])
|
||||
domainFollowingFull=domainFollowing
|
||||
if portFollowing:
|
||||
if portFollowing!=80 and portFollowing!=443:
|
||||
domainFollowingFull=domainFollowing+':'+str(portFollowing)
|
||||
|
||||
if unfollowPerson(baseDir,nicknameFollower,domainFollowerFull, \
|
||||
nicknameFollowing,domainFollowingFull):
|
||||
if debug:
|
||||
print('DEBUG: '+nicknameFollower+' unfollowed '+nicknameFollowing+'@'+domainFollowingFull)
|
||||
else:
|
||||
if debug:
|
||||
print('WARN: '+nicknameFollower+' could not unfollow '+nicknameFollowing+'@'+domainFollowingFull)
|
||||
|
|
91
inbox.py
91
inbox.py
|
@ -379,6 +379,82 @@ def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain :
|
|||
|
||||
return recipientsDict,recipientsDictFollowers
|
||||
|
||||
def receiveUndoFollow(session,baseDir: str,httpPrefix: str, \
|
||||
port: int,messageJson: {},debug : bool) -> bool:
|
||||
if not messageJson['object'].get('actor'):
|
||||
if debug:
|
||||
print('DEBUG: follow request has no actor within object')
|
||||
return False
|
||||
if '/users/' not in messageJson['object']['actor']:
|
||||
if debug:
|
||||
print('DEBUG: "users" missing from actor within object')
|
||||
return False
|
||||
if messageJson['object']['actor'] != messageJson['actor']:
|
||||
if debug:
|
||||
print('DEBUG: actors do not match')
|
||||
return False
|
||||
|
||||
nicknameFollower=getNicknameFromActor(messageJson['object']['actor'])
|
||||
domainFollower,portFollower=getDomainFromActor(messageJson['object']['actor'])
|
||||
domainFollowerFull=domainFollower
|
||||
if portFollower:
|
||||
if portFollower!=80 and portFollower!=443:
|
||||
domainFollowerFull=domainFollower+':'+str(portFollower)
|
||||
|
||||
nicknameFollowing=getNicknameFromActor(messageJson['object']['object'])
|
||||
domainFollowing,portFollowing=getDomainFromActor(messageJson['object']['object'])
|
||||
domainFollowingFull=domainFollowing
|
||||
if portFollowing:
|
||||
if portFollowing!=80 and portFollowing!=443:
|
||||
domainFollowingFull=domainFollowing+':'+str(portFollowing)
|
||||
|
||||
unfollowerOfPerson(baseDir,nicknameFollower,domainFollowerFull, \
|
||||
nicknameFollowing,domainFollowingFull,federationList,debug)
|
||||
return True
|
||||
|
||||
def receiveUndo(session,baseDir: str,httpPrefix: str, \
|
||||
port: int,sendThreads: [],postLog: [], \
|
||||
cachedWebfingers: {},personCache: {}, \
|
||||
messageJson: {},federationList: [], \
|
||||
debug : bool, \
|
||||
acceptedCaps=["inbox:write","objects:read"]) -> bool:
|
||||
"""Receives an undo request within the POST section of HTTPServer
|
||||
"""
|
||||
if not messageJson['type'].startswith('Undo'):
|
||||
return False
|
||||
if not messageJson.get('actor'):
|
||||
if debug:
|
||||
print('DEBUG: follow request has no actor')
|
||||
return False
|
||||
if '/users/' not in messageJson['actor']:
|
||||
if debug:
|
||||
print('DEBUG: "users" missing from actor')
|
||||
return False
|
||||
if not messageJson.get('object'):
|
||||
if debug:
|
||||
print('DEBUG: '+messageJson['type']+' has no object')
|
||||
return False
|
||||
if not isinstance(messageJson['object'], dict):
|
||||
if debug:
|
||||
print('DEBUG: '+messageJson['type']+' object is not a dict')
|
||||
return False
|
||||
if not messageJson['object'].get('type'):
|
||||
if debug:
|
||||
print('DEBUG: '+messageJson['type']+' has no object type')
|
||||
return False
|
||||
if not messageJson['object'].get('object'):
|
||||
if debug:
|
||||
print('DEBUG: '+messageJson['type']+' has no object within object')
|
||||
return False
|
||||
if not isinstance(messageJson['object']['object'], str):
|
||||
if debug:
|
||||
print('DEBUG: '+messageJson['type']+' object within object is not a string')
|
||||
return False
|
||||
if messageJson['object']['type']=='Follow':
|
||||
return receiveUndoFollow(session,baseDir,httpPrefix, \
|
||||
port,messageJson,debug)
|
||||
return False
|
||||
|
||||
def receiveUpdate(session,baseDir: str, \
|
||||
httpPrefix: str,domain :str,port: int, \
|
||||
sendThreads: [],postLog: [],cachedWebfingers: {}, \
|
||||
|
@ -953,6 +1029,21 @@ def runInboxQueue(baseDir: str,httpPrefix: str,sendThreads: [],postLog: [], \
|
|||
if debug:
|
||||
print('DEBUG: Signature check success')
|
||||
|
||||
if receiveUndo(session, \
|
||||
baseDir,httpPrefix,port, \
|
||||
sendThreads,postLog, \
|
||||
cachedWebfingers,
|
||||
personCache,
|
||||
queueJson['post'], \
|
||||
federationList, \
|
||||
debug, \
|
||||
acceptedCaps=["inbox:write","objects:read"]):
|
||||
if debug:
|
||||
print('DEBUG: Undo accepted from '+keyId)
|
||||
os.remove(queueFilename)
|
||||
queue.pop(0)
|
||||
continue
|
||||
|
||||
if receiveFollowRequest(session, \
|
||||
baseDir,httpPrefix,port, \
|
||||
sendThreads,postLog, \
|
||||
|
|
Loading…
Reference in New Issue