forked from indymedia/epicyon
Deprecate capabilities module
parent
38302fd686
commit
b064d6f4d6
|
@ -7,8 +7,6 @@ __email__ = "bob@freedombone.net"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from capabilities import capabilitiesAccept
|
|
||||||
from capabilities import capabilitiesGrantedSave
|
|
||||||
from utils import urlPermitted
|
from utils import urlPermitted
|
||||||
from utils import getDomainFromActor
|
from utils import getDomainFromActor
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
|
@ -19,7 +17,7 @@ from utils import followPerson
|
||||||
def createAcceptReject(baseDir: str, federationList: [],
|
def createAcceptReject(baseDir: str, federationList: [],
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
toUrl: str, ccUrl: str, httpPrefix: str,
|
toUrl: str, ccUrl: str, httpPrefix: str,
|
||||||
objectJson: {}, ocapJson, acceptType: str) -> {}:
|
objectJson: {}, acceptType: str) -> {}:
|
||||||
"""Accepts or rejects something (eg. a follow request or offer)
|
"""Accepts or rejects something (eg. a follow request or offer)
|
||||||
Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
|
Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
|
||||||
and ccUrl might be a specific person favorited or repeated and
|
and ccUrl might be a specific person favorited or repeated and
|
||||||
|
@ -48,9 +46,6 @@ def createAcceptReject(baseDir: str, federationList: [],
|
||||||
if ccUrl:
|
if ccUrl:
|
||||||
if len(ccUrl) > 0:
|
if len(ccUrl) > 0:
|
||||||
newAccept['cc'] = [ccUrl]
|
newAccept['cc'] = [ccUrl]
|
||||||
# attach capabilities for follow accept
|
|
||||||
if ocapJson:
|
|
||||||
newAccept['capabilities'] = ocapJson
|
|
||||||
return newAccept
|
return newAccept
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,14 +54,10 @@ def createAccept(baseDir: str, federationList: [],
|
||||||
toUrl: str, ccUrl: str, httpPrefix: str,
|
toUrl: str, ccUrl: str, httpPrefix: str,
|
||||||
objectJson: {},
|
objectJson: {},
|
||||||
acceptedCaps=["inbox:write", "objects:read"]) -> {}:
|
acceptedCaps=["inbox:write", "objects:read"]) -> {}:
|
||||||
# create capabilities accept
|
|
||||||
ocapNew = capabilitiesAccept(baseDir, httpPrefix,
|
|
||||||
nickname, domain, port,
|
|
||||||
toUrl, True, acceptedCaps)
|
|
||||||
return createAcceptReject(baseDir, federationList,
|
return createAcceptReject(baseDir, federationList,
|
||||||
nickname, domain, port,
|
nickname, domain, port,
|
||||||
toUrl, ccUrl, httpPrefix,
|
toUrl, ccUrl, httpPrefix,
|
||||||
objectJson, ocapNew, 'Accept')
|
objectJson, 'Accept')
|
||||||
|
|
||||||
|
|
||||||
def createReject(baseDir: str, federationList: [],
|
def createReject(baseDir: str, federationList: [],
|
||||||
|
@ -154,13 +145,6 @@ def acceptFollow(baseDir: str, domain: str, messageJson: {},
|
||||||
if acceptedPort:
|
if acceptedPort:
|
||||||
acceptedDomainFull = acceptedDomain + ':' + str(acceptedPort)
|
acceptedDomainFull = acceptedDomain + ':' + str(acceptedPort)
|
||||||
|
|
||||||
# are capabilities attached? If so then store them
|
|
||||||
if messageJson.get('capabilities'):
|
|
||||||
if isinstance(messageJson['capabilities'], dict):
|
|
||||||
capabilitiesGrantedSave(baseDir,
|
|
||||||
nickname, acceptedDomainFull,
|
|
||||||
messageJson['capabilities'])
|
|
||||||
|
|
||||||
# has this person already been unfollowed?
|
# has this person already been unfollowed?
|
||||||
unfollowedFilename = baseDir + '/accounts/' + \
|
unfollowedFilename = baseDir + '/accounts/' + \
|
||||||
nickname + '@' + acceptedDomainFull + '/unfollowed.txt'
|
nickname + '@' + acceptedDomainFull + '/unfollowed.txt'
|
||||||
|
|
283
capabilities.py
283
capabilities.py
|
@ -1,283 +0,0 @@
|
||||||
__filename__ = "capabilities.py"
|
|
||||||
__author__ = "Bob Mottram"
|
|
||||||
__license__ = "AGPL3+"
|
|
||||||
__version__ = "1.1.0"
|
|
||||||
__maintainer__ = "Bob Mottram"
|
|
||||||
__email__ = "bob@freedombone.net"
|
|
||||||
__status__ = "Production"
|
|
||||||
|
|
||||||
import os
|
|
||||||
from auth import createPassword
|
|
||||||
from utils import getNicknameFromActor
|
|
||||||
from utils import getDomainFromActor
|
|
||||||
from utils import loadJson
|
|
||||||
from utils import saveJson
|
|
||||||
|
|
||||||
|
|
||||||
def getOcapFilename(baseDir: str,
|
|
||||||
nickname: str, domain: str,
|
|
||||||
actor: str, subdir: str) -> str:
|
|
||||||
"""Returns the filename for a particular capability accepted or granted
|
|
||||||
Also creates directories as needed
|
|
||||||
"""
|
|
||||||
if not actor:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if ':' in domain:
|
|
||||||
domain = domain.split(':')[0]
|
|
||||||
|
|
||||||
if not os.path.isdir(baseDir + '/accounts'):
|
|
||||||
os.mkdir(baseDir + '/accounts')
|
|
||||||
|
|
||||||
ocDir = baseDir + '/accounts/' + nickname + '@' + domain
|
|
||||||
if not os.path.isdir(ocDir):
|
|
||||||
os.mkdir(ocDir)
|
|
||||||
|
|
||||||
ocDir = baseDir + '/accounts/' + nickname + '@' + domain + '/ocap'
|
|
||||||
if not os.path.isdir(ocDir):
|
|
||||||
os.mkdir(ocDir)
|
|
||||||
|
|
||||||
ocDir = baseDir + '/accounts/' + \
|
|
||||||
nickname + '@' + domain + '/ocap/' + subdir
|
|
||||||
if not os.path.isdir(ocDir):
|
|
||||||
os.mkdir(ocDir)
|
|
||||||
|
|
||||||
return baseDir + '/accounts/' + \
|
|
||||||
nickname + '@' + domain + '/ocap/' + \
|
|
||||||
subdir + '/' + actor.replace('/', '#') + '.json'
|
|
||||||
|
|
||||||
|
|
||||||
def CapablePost(postJson: {}, capabilityList: [], debug: bool) -> bool:
|
|
||||||
"""Determines whether a post arriving in the inbox
|
|
||||||
should be accepted accoring to the list of capabilities
|
|
||||||
"""
|
|
||||||
if postJson.get('type'):
|
|
||||||
# No announces/repeats
|
|
||||||
if postJson['type'] == 'Announce':
|
|
||||||
if 'inbox:noannounce' in capabilityList:
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: ' +
|
|
||||||
'inbox post rejected because inbox:noannounce')
|
|
||||||
return False
|
|
||||||
# No likes
|
|
||||||
if postJson['type'] == 'Like':
|
|
||||||
if 'inbox:nolike' in capabilityList:
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: ' +
|
|
||||||
'inbox post rejected because inbox:nolike')
|
|
||||||
return False
|
|
||||||
if postJson['type'] == 'Create':
|
|
||||||
if postJson.get('object'):
|
|
||||||
# Does this have a reply?
|
|
||||||
if postJson['object'].get('inReplyTo'):
|
|
||||||
if postJson['object']['inReplyTo']:
|
|
||||||
if 'inbox:noreply' in capabilityList:
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: ' +
|
|
||||||
'inbox post rejected because ' +
|
|
||||||
'inbox:noreply')
|
|
||||||
return False
|
|
||||||
# are content warnings enforced?
|
|
||||||
if postJson['object'].get('sensitive'):
|
|
||||||
if not postJson['object']['sensitive']:
|
|
||||||
if 'inbox:cw' in capabilityList:
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: ' +
|
|
||||||
'inbox post rejected because inbox:cw')
|
|
||||||
return False
|
|
||||||
# content warning must have non-zero summary
|
|
||||||
if postJson['object'].get('summary'):
|
|
||||||
if len(postJson['object']['summary']) < 2:
|
|
||||||
if 'inbox:cw' in capabilityList:
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: ' +
|
|
||||||
'inbox post rejected because ' +
|
|
||||||
'inbox:cw, summary missing')
|
|
||||||
return False
|
|
||||||
if 'inbox:write' in capabilityList:
|
|
||||||
return True
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def capabilitiesRequest(baseDir: str, httpPrefix: str, domain: str,
|
|
||||||
requestedActor: str, requestedDomain: str,
|
|
||||||
requestedCaps=["inbox:write", "objects:read"]) -> {}:
|
|
||||||
# This is sent to the capabilities endpoint /caps/new
|
|
||||||
# which could be instance wide or for a particular person
|
|
||||||
# This could also be added to a follow activity
|
|
||||||
ocapId = createPassword(32)
|
|
||||||
ocapRequest = {
|
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
|
||||||
"id": httpPrefix + "://" + requestedDomain + "/caps/request/" + ocapId,
|
|
||||||
"type": "Request",
|
|
||||||
"capability": requestedCaps,
|
|
||||||
"actor": requestedActor
|
|
||||||
}
|
|
||||||
return ocapRequest
|
|
||||||
|
|
||||||
|
|
||||||
def capabilitiesAccept(baseDir: str, httpPrefix: str,
|
|
||||||
nickname: str, domain: str, port: int,
|
|
||||||
acceptedActor: str, saveToFile: bool,
|
|
||||||
acceptedCaps=["inbox:write", "objects:read"]) -> {}:
|
|
||||||
# This gets returned to capabilities requester
|
|
||||||
# This could also be added to a follow Accept activity
|
|
||||||
|
|
||||||
# reject excessively long actors
|
|
||||||
if len(acceptedActor) > 256:
|
|
||||||
return None
|
|
||||||
|
|
||||||
fullDomain = domain
|
|
||||||
if port:
|
|
||||||
if port != 80 and port != 443:
|
|
||||||
if ':' not in domain:
|
|
||||||
fullDomain = domain + ':' + str(port)
|
|
||||||
|
|
||||||
# make directories to store capabilities
|
|
||||||
ocapFilename = \
|
|
||||||
getOcapFilename(baseDir, nickname, fullDomain, acceptedActor, 'accept')
|
|
||||||
if not ocapFilename:
|
|
||||||
return None
|
|
||||||
ocapAccept = None
|
|
||||||
|
|
||||||
# if the capability already exists then load it from file
|
|
||||||
if os.path.isfile(ocapFilename):
|
|
||||||
ocapAccept = loadJson(ocapFilename)
|
|
||||||
# otherwise create a new capability
|
|
||||||
if not ocapAccept:
|
|
||||||
acceptedActorNickname = getNicknameFromActor(acceptedActor)
|
|
||||||
if not acceptedActorNickname:
|
|
||||||
print('WARN: unable to find nickname in ' + acceptedActor)
|
|
||||||
return None
|
|
||||||
acceptedActorDomain, acceptedActorPort = \
|
|
||||||
getDomainFromActor(acceptedActor)
|
|
||||||
if acceptedActorPort:
|
|
||||||
ocapId = acceptedActorNickname + '@' + acceptedActorDomain + \
|
|
||||||
':' + str(acceptedActorPort) + '#'+createPassword(32)
|
|
||||||
else:
|
|
||||||
ocapId = acceptedActorNickname + '@' + acceptedActorDomain + \
|
|
||||||
'#' + createPassword(32)
|
|
||||||
ocapAccept = {
|
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
|
||||||
"id": httpPrefix + "://" + fullDomain + "/caps/" + ocapId,
|
|
||||||
"type": "Capability",
|
|
||||||
"capability": acceptedCaps,
|
|
||||||
"scope": acceptedActor,
|
|
||||||
"actor": httpPrefix + "://" + fullDomain
|
|
||||||
}
|
|
||||||
if nickname:
|
|
||||||
ocapAccept['actor'] = \
|
|
||||||
httpPrefix + "://" + fullDomain + '/users/' + nickname
|
|
||||||
|
|
||||||
if saveToFile:
|
|
||||||
saveJson(ocapAccept, ocapFilename)
|
|
||||||
return ocapAccept
|
|
||||||
|
|
||||||
|
|
||||||
def capabilitiesGrantedSave(baseDir: str,
|
|
||||||
nickname: str, domain: str, ocap: {}) -> bool:
|
|
||||||
"""A capabilities accept is received, so stor it for
|
|
||||||
reference when sending to the actor
|
|
||||||
"""
|
|
||||||
if not ocap.get('actor'):
|
|
||||||
return False
|
|
||||||
ocapFilename = \
|
|
||||||
getOcapFilename(baseDir, nickname, domain, ocap['actor'], 'granted')
|
|
||||||
if not ocapFilename:
|
|
||||||
return False
|
|
||||||
saveJson(ocap, ocapFilename)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def capabilitiesUpdate(baseDir: str, httpPrefix: str,
|
|
||||||
nickname: str, domain: str, port: int,
|
|
||||||
updateActor: str,
|
|
||||||
updateCaps: []) -> {}:
|
|
||||||
"""Used to sends an update for a change of object capabilities
|
|
||||||
Note that the capability id gets changed with a new random token
|
|
||||||
so that the old capabilities can't continue to be used
|
|
||||||
"""
|
|
||||||
|
|
||||||
# reject excessively long actors
|
|
||||||
if len(updateActor) > 256:
|
|
||||||
return None
|
|
||||||
|
|
||||||
fullDomain = domain
|
|
||||||
if port:
|
|
||||||
if port != 80 and port != 443:
|
|
||||||
if ':' not in domain:
|
|
||||||
fullDomain = domain + ':' + str(port)
|
|
||||||
|
|
||||||
# Get the filename of the capability
|
|
||||||
ocapFilename = \
|
|
||||||
getOcapFilename(baseDir, nickname, fullDomain, updateActor, 'accept')
|
|
||||||
if not ocapFilename:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# The capability should already exist for it to be updated
|
|
||||||
if not os.path.isfile(ocapFilename):
|
|
||||||
return None
|
|
||||||
|
|
||||||
# create an update activity
|
|
||||||
ocapUpdate = {
|
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
|
||||||
'type': 'Update',
|
|
||||||
'actor': httpPrefix + '://' + fullDomain + '/users/' + nickname,
|
|
||||||
'to': [updateActor],
|
|
||||||
'cc': [],
|
|
||||||
'object': {}
|
|
||||||
}
|
|
||||||
|
|
||||||
# read the existing capability
|
|
||||||
ocapJson = loadJson(ocapFilename)
|
|
||||||
|
|
||||||
# set the new capabilities list. eg. ["inbox:write","objects:read"]
|
|
||||||
ocapJson['capability'] = updateCaps
|
|
||||||
|
|
||||||
# change the id, so that the old capabilities can't continue to be used
|
|
||||||
updateActorNickname = getNicknameFromActor(updateActor)
|
|
||||||
if not updateActorNickname:
|
|
||||||
print('WARN: unable to find nickname in ' + updateActor)
|
|
||||||
return None
|
|
||||||
updateActorDomain, updateActorPort = getDomainFromActor(updateActor)
|
|
||||||
if updateActorPort:
|
|
||||||
ocapId = updateActorNickname + '@' + updateActorDomain + \
|
|
||||||
':' + str(updateActorPort) + '#' + createPassword(32)
|
|
||||||
else:
|
|
||||||
ocapId = updateActorNickname + '@' + updateActorDomain + \
|
|
||||||
'#' + createPassword(32)
|
|
||||||
ocapJson['id'] = httpPrefix + "://" + fullDomain + "/caps/" + ocapId
|
|
||||||
ocapUpdate['object'] = ocapJson
|
|
||||||
|
|
||||||
# save it again
|
|
||||||
saveJson(ocapJson, ocapFilename)
|
|
||||||
|
|
||||||
return ocapUpdate
|
|
||||||
|
|
||||||
|
|
||||||
def capabilitiesReceiveUpdate(baseDir: str,
|
|
||||||
nickname: str, domain: str, port: int,
|
|
||||||
actor: str,
|
|
||||||
newCapabilitiesId: str,
|
|
||||||
capabilityList: [], debug: bool) -> bool:
|
|
||||||
"""An update for a capability or the given actor has arrived
|
|
||||||
"""
|
|
||||||
ocapFilename = \
|
|
||||||
getOcapFilename(baseDir, nickname, domain, actor, 'granted')
|
|
||||||
if not ocapFilename:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not os.path.isfile(ocapFilename):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: capabilities file not found during update')
|
|
||||||
print(ocapFilename)
|
|
||||||
return False
|
|
||||||
|
|
||||||
ocapJson = loadJson(ocapFilename)
|
|
||||||
|
|
||||||
if ocapJson:
|
|
||||||
ocapJson['id'] = newCapabilitiesId
|
|
||||||
ocapJson['capability'] = capabilityList
|
|
||||||
|
|
||||||
return saveJson(ocapJson, ocapFilename)
|
|
||||||
return False
|
|
|
@ -10299,7 +10299,6 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.path.endswith('/inbox') or
|
self.path.endswith('/inbox') or
|
||||||
self.path.endswith('/shares') or
|
self.path.endswith('/shares') or
|
||||||
self.path.endswith('/moderationaction') or
|
self.path.endswith('/moderationaction') or
|
||||||
self.path.endswith('/caps/new') or
|
|
||||||
self.path == '/sharedInbox'):
|
self.path == '/sharedInbox'):
|
||||||
print('Attempt to POST to invalid path ' + self.path)
|
print('Attempt to POST to invalid path ' + self.path)
|
||||||
self._400()
|
self._400()
|
||||||
|
|
24
epicyon.py
24
epicyon.py
|
@ -230,26 +230,6 @@ parser.add_argument("--testsnetwork", type=str2bool, nargs='?',
|
||||||
parser.add_argument("--testdata", type=str2bool, nargs='?',
|
parser.add_argument("--testdata", type=str2bool, nargs='?',
|
||||||
const=True, default=False,
|
const=True, default=False,
|
||||||
help="Generate some data for testing purposes")
|
help="Generate some data for testing purposes")
|
||||||
parser.add_argument("--ocap", type=str2bool, nargs='?',
|
|
||||||
const=True, default=False,
|
|
||||||
help="Always strictly enforce object capabilities")
|
|
||||||
parser.add_argument("--noreply", type=str2bool, nargs='?',
|
|
||||||
const=True, default=False,
|
|
||||||
help="Default capabilities don't allow replies on posts")
|
|
||||||
parser.add_argument("--nolike", type=str2bool, nargs='?',
|
|
||||||
const=True, default=False,
|
|
||||||
help="Default capabilities don't allow " +
|
|
||||||
"likes/favourites on posts")
|
|
||||||
parser.add_argument("--nopics", type=str2bool, nargs='?',
|
|
||||||
const=True, default=False,
|
|
||||||
help="Default capabilities don't allow attached pictures")
|
|
||||||
parser.add_argument("--noannounce", "--norepeat", type=str2bool, nargs='?',
|
|
||||||
const=True, default=False,
|
|
||||||
help="Default capabilities don't allow announce/repeat")
|
|
||||||
parser.add_argument("--cw", type=str2bool, nargs='?',
|
|
||||||
const=True, default=False,
|
|
||||||
help="Default capabilities don't allow posts " +
|
|
||||||
"without content warnings")
|
|
||||||
parser.add_argument('--icon', '--avatar', dest='avatar', type=str,
|
parser.add_argument('--icon', '--avatar', dest='avatar', type=str,
|
||||||
default=None,
|
default=None,
|
||||||
help='Set the avatar filename for an account')
|
help='Set the avatar filename for an account')
|
||||||
|
@ -1920,8 +1900,8 @@ if __name__ == "__main__":
|
||||||
port, proxyPort, httpPrefix,
|
port, proxyPort, httpPrefix,
|
||||||
federationList, args.maxMentions,
|
federationList, args.maxMentions,
|
||||||
args.maxEmoji, args.authenticatedFetch,
|
args.maxEmoji, args.authenticatedFetch,
|
||||||
args.noreply, args.nolike, args.nopics,
|
False, False, False,
|
||||||
args.noannounce, args.cw, ocapAlways,
|
False, False, ocapAlways,
|
||||||
proxyType, args.maxReplies,
|
proxyType, args.maxReplies,
|
||||||
args.domainMaxPostsPerDay,
|
args.domainMaxPostsPerDay,
|
||||||
args.accountMaxPostsPerDay,
|
args.accountMaxPostsPerDay,
|
||||||
|
|
32
follow.py
32
follow.py
|
@ -1045,14 +1045,12 @@ def getFollowersOfActor(baseDir: str, actor: str, debug: bool) -> {}:
|
||||||
"""In a shared inbox if we receive a post we know who it's from
|
"""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.
|
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
|
This returns a list of account handles which follow the given actor
|
||||||
and also the corresponding capability id if it exists
|
|
||||||
"""
|
"""
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: getting followers of ' + actor)
|
print('DEBUG: getting followers of ' + actor)
|
||||||
recipientsDict = {}
|
recipientsDict = {}
|
||||||
if ':' not in actor:
|
if ':' not in actor:
|
||||||
return recipientsDict
|
return recipientsDict
|
||||||
httpPrefix = actor.split(':')[0]
|
|
||||||
nickname = getNicknameFromActor(actor)
|
nickname = getNicknameFromActor(actor)
|
||||||
if not nickname:
|
if not nickname:
|
||||||
if debug:
|
if debug:
|
||||||
|
@ -1084,35 +1082,7 @@ def getFollowersOfActor(baseDir: str, actor: str, debug: bool) -> {}:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: ' + account +
|
print('DEBUG: ' + account +
|
||||||
' follows ' + actorHandle)
|
' follows ' + actorHandle)
|
||||||
ocapFilename = baseDir + '/accounts/' + \
|
recipientsDict[account] = None
|
||||||
account + '/ocap/accept/' + httpPrefix + \
|
|
||||||
':##' + domain + ':' + str(port) + \
|
|
||||||
'#users#' + nickname + '.json'
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: checking capabilities of' + account)
|
|
||||||
if os.path.isfile(ocapFilename):
|
|
||||||
ocapJson = loadJson(ocapFilename)
|
|
||||||
if ocapJson:
|
|
||||||
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
|
return recipientsDict
|
||||||
|
|
||||||
|
|
||||||
|
|
220
inbox.py
220
inbox.py
|
@ -40,9 +40,6 @@ from pprint import pprint
|
||||||
from cache import getPersonFromCache
|
from cache import getPersonFromCache
|
||||||
from cache import storePersonInCache
|
from cache import storePersonInCache
|
||||||
from acceptreject import receiveAcceptReject
|
from acceptreject import receiveAcceptReject
|
||||||
from capabilities import getOcapFilename
|
|
||||||
from capabilities import CapablePost
|
|
||||||
from capabilities import capabilitiesReceiveUpdate
|
|
||||||
from bookmarks import updateBookmarksCollection
|
from bookmarks import updateBookmarksCollection
|
||||||
from bookmarks import undoBookmarksCollectionEntry
|
from bookmarks import undoBookmarksCollectionEntry
|
||||||
from blocking import isBlocked
|
from blocking import isBlocked
|
||||||
|
@ -437,81 +434,12 @@ def savePostToInboxQueue(baseDir: str, httpPrefix: str,
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
|
||||||
def inboxCheckCapabilities(baseDir: str, nickname: str, domain: str,
|
|
||||||
actor: str, queueFilename: str, queue: [],
|
|
||||||
queueJson: {}, capabilityId: str,
|
|
||||||
debug: bool) -> bool:
|
|
||||||
if nickname == 'inbox':
|
|
||||||
return True
|
|
||||||
|
|
||||||
ocapFilename = \
|
|
||||||
getOcapFilename(baseDir,
|
|
||||||
queueJson['nickname'], queueJson['domain'],
|
|
||||||
actor, 'accept')
|
|
||||||
if not ocapFilename:
|
|
||||||
return False
|
|
||||||
if not os.path.isfile(ocapFilename):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: capabilities for ' +
|
|
||||||
actor + ' do not exist')
|
|
||||||
if os.path.isfile(queueFilename):
|
|
||||||
os.remove(queueFilename)
|
|
||||||
if len(queue) > 0:
|
|
||||||
queue.pop(0)
|
|
||||||
return False
|
|
||||||
|
|
||||||
oc = loadJson(ocapFilename)
|
|
||||||
if not oc:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not oc.get('id'):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: capabilities for ' + actor + ' do not contain an id')
|
|
||||||
if os.path.isfile(queueFilename):
|
|
||||||
os.remove(queueFilename)
|
|
||||||
if len(queue) > 0:
|
|
||||||
queue.pop(0)
|
|
||||||
return False
|
|
||||||
|
|
||||||
if oc['id'] != capabilityId:
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: capability id mismatch')
|
|
||||||
if os.path.isfile(queueFilename):
|
|
||||||
os.remove(queueFilename)
|
|
||||||
if len(queue) > 0:
|
|
||||||
queue.pop(0)
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not oc.get('capability'):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: missing capability list')
|
|
||||||
if os.path.isfile(queueFilename):
|
|
||||||
os.remove(queueFilename)
|
|
||||||
if len(queue) > 0:
|
|
||||||
queue.pop(0)
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not CapablePost(queueJson['post'], oc['capability'], debug):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: insufficient capabilities to write to inbox from ' +
|
|
||||||
actor)
|
|
||||||
if os.path.isfile(queueFilename):
|
|
||||||
os.remove(queueFilename)
|
|
||||||
if len(queue) > 0:
|
|
||||||
queue.pop(0)
|
|
||||||
return False
|
|
||||||
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: object capabilities check success')
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def inboxPostRecipientsAdd(baseDir: str, httpPrefix: str, toList: [],
|
def inboxPostRecipientsAdd(baseDir: str, httpPrefix: str, toList: [],
|
||||||
recipientsDict: {},
|
recipientsDict: {},
|
||||||
domainMatch: str, domain: str,
|
domainMatch: str, domain: str,
|
||||||
actor: str, debug: bool) -> bool:
|
actor: str, debug: bool) -> bool:
|
||||||
"""Given a list of post recipients (toList) from 'to' or 'cc' parameters
|
"""Given a list of post recipients (toList) from 'to' or 'cc' parameters
|
||||||
populate a recipientsDict with the handle and capabilities id for each
|
populate a recipientsDict with the handle for each
|
||||||
"""
|
"""
|
||||||
followerRecipients = False
|
followerRecipients = False
|
||||||
for recipient in toList:
|
for recipient in toList:
|
||||||
|
@ -523,24 +451,7 @@ def inboxPostRecipientsAdd(baseDir: str, httpPrefix: str, toList: [],
|
||||||
nickname = recipient.split(domainMatch)[1]
|
nickname = recipient.split(domainMatch)[1]
|
||||||
handle = nickname+'@'+domain
|
handle = nickname+'@'+domain
|
||||||
if os.path.isdir(baseDir + '/accounts/' + handle):
|
if os.path.isdir(baseDir + '/accounts/' + handle):
|
||||||
# are capabilities granted for this account to the
|
recipientsDict[handle] = None
|
||||||
# sender (actor) of the post?
|
|
||||||
ocapFilename = \
|
|
||||||
baseDir + '/accounts/' + handle + \
|
|
||||||
'/ocap/accept/' + actor.replace('/', '#') + '.json'
|
|
||||||
if os.path.isfile(ocapFilename):
|
|
||||||
# read the granted capabilities and obtain the id
|
|
||||||
ocapJson = loadJson(ocapFilename)
|
|
||||||
if ocapJson:
|
|
||||||
if ocapJson.get('id'):
|
|
||||||
# append with the capabilities id
|
|
||||||
recipientsDict[handle] = ocapJson['id']
|
|
||||||
else:
|
|
||||||
recipientsDict[handle] = None
|
|
||||||
else:
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: ' + ocapFilename + ' not found')
|
|
||||||
recipientsDict[handle] = None
|
|
||||||
else:
|
else:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: ' + baseDir + '/accounts/' +
|
print('DEBUG: ' + baseDir + '/accounts/' +
|
||||||
|
@ -1005,24 +916,6 @@ def receiveUpdate(recentPostsCache: {}, session, baseDir: str,
|
||||||
print('DEBUG: Profile update was received for ' +
|
print('DEBUG: Profile update was received for ' +
|
||||||
messageJson['object']['url'])
|
messageJson['object']['url'])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if messageJson['object'].get('capability') and \
|
|
||||||
messageJson['object'].get('scope'):
|
|
||||||
nickname = getNicknameFromActor(messageJson['object']['scope'])
|
|
||||||
if nickname:
|
|
||||||
domain, tempPort = \
|
|
||||||
getDomainFromActor(messageJson['object']['scope'])
|
|
||||||
|
|
||||||
if messageJson['object']['type'] == 'Capability':
|
|
||||||
capability = messageJson['object']['capability']
|
|
||||||
if capabilitiesReceiveUpdate(baseDir, nickname, domain, port,
|
|
||||||
messageJson['actor'],
|
|
||||||
messageJson['object']['id'],
|
|
||||||
capability,
|
|
||||||
debug):
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: An update was received')
|
|
||||||
return True
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -2124,20 +2017,20 @@ def inboxUpdateIndex(boxname: str, baseDir: str, handle: str,
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def inboxAfterCapabilities(recentPostsCache: {}, maxRecentPosts: int,
|
def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
session, keyId: str, handle: str, messageJson: {},
|
session, keyId: str, handle: str, messageJson: {},
|
||||||
baseDir: str, httpPrefix: str, sendThreads: [],
|
baseDir: str, httpPrefix: str, sendThreads: [],
|
||||||
postLog: [], cachedWebfingers: {}, personCache: {},
|
postLog: [], cachedWebfingers: {}, personCache: {},
|
||||||
queue: [], domain: str,
|
queue: [], domain: str,
|
||||||
onionDomain: str, i2pDomain: str,
|
onionDomain: str, i2pDomain: str,
|
||||||
port: int, proxyType: str,
|
port: int, proxyType: str,
|
||||||
federationList: [], ocapAlways: bool, debug: bool,
|
federationList: [], ocapAlways: bool, debug: bool,
|
||||||
acceptedCaps: [],
|
acceptedCaps: [],
|
||||||
queueFilename: str, destinationFilename: str,
|
queueFilename: str, destinationFilename: str,
|
||||||
maxReplies: int, allowDeletion: bool,
|
maxReplies: int, allowDeletion: bool,
|
||||||
maxMentions: int, maxEmoji: int, translate: {},
|
maxMentions: int, maxEmoji: int, translate: {},
|
||||||
unitTest: bool, YTReplacementDomain: str) -> bool:
|
unitTest: bool, YTReplacementDomain: str) -> bool:
|
||||||
""" Anything which needs to be done after capabilities checks have passed
|
""" Anything which needs to be done after initial checks have passed
|
||||||
"""
|
"""
|
||||||
actor = keyId
|
actor = keyId
|
||||||
if '#' in actor:
|
if '#' in actor:
|
||||||
|
@ -2247,7 +2140,7 @@ def inboxAfterCapabilities(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: object capabilities passed')
|
print('DEBUG: initial checks passed')
|
||||||
print('copy queue file from ' + queueFilename +
|
print('copy queue file from ' + queueFilename +
|
||||||
' to ' + destinationFilename)
|
' to ' + destinationFilename)
|
||||||
|
|
||||||
|
@ -2929,10 +2822,6 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
# Copy any posts addressed to followers into the shared inbox
|
# Copy any posts addressed to followers into the shared inbox
|
||||||
# this avoid copying file multiple times to potentially many
|
# this avoid copying file multiple times to potentially many
|
||||||
# individual inboxes
|
# individual inboxes
|
||||||
# This obviously bypasses object capabilities and so
|
|
||||||
# any checking will needs to be handled at the time when inbox
|
|
||||||
# GET happens on individual accounts.
|
|
||||||
# See posts.py/createBoxBase
|
|
||||||
if len(recipientsDictFollowers) > 0:
|
if len(recipientsDictFollowers) > 0:
|
||||||
sharedInboxPostFilename = \
|
sharedInboxPostFilename = \
|
||||||
queueJson['destination'].replace(inboxHandle, inboxHandle)
|
queueJson['destination'].replace(inboxHandle, inboxHandle)
|
||||||
|
@ -2943,61 +2832,26 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
for handle, capsId in recipientsDict.items():
|
for handle, capsId in recipientsDict.items():
|
||||||
destination = \
|
destination = \
|
||||||
queueJson['destination'].replace(inboxHandle, handle)
|
queueJson['destination'].replace(inboxHandle, handle)
|
||||||
# check that capabilities are accepted
|
inboxAfterInitial(recentPostsCache,
|
||||||
if queueJson['post'].get('capability'):
|
maxRecentPosts,
|
||||||
capabilityIdList = queueJson['post']['capability']
|
session, keyId, handle,
|
||||||
# does the capability id list within the post
|
queueJson['post'],
|
||||||
# contain the id of the recipient with this handle?
|
baseDir, httpPrefix,
|
||||||
# Here the capability id begins with the handle,
|
sendThreads, postLog,
|
||||||
# so this could also be matched separately, but it's
|
cachedWebfingers,
|
||||||
# probably not necessary
|
personCache, queue,
|
||||||
if capsId in capabilityIdList:
|
domain,
|
||||||
inboxAfterCapabilities(recentPostsCache,
|
onionDomain, i2pDomain,
|
||||||
maxRecentPosts,
|
port, proxyType,
|
||||||
session, keyId, handle,
|
federationList, ocapAlways,
|
||||||
queueJson['post'],
|
debug, acceptedCaps,
|
||||||
baseDir, httpPrefix,
|
queueFilename, destination,
|
||||||
sendThreads, postLog,
|
maxReplies, allowDeletion,
|
||||||
cachedWebfingers,
|
maxMentions, maxEmoji,
|
||||||
personCache, queue,
|
translate, unitTest,
|
||||||
domain,
|
YTReplacementDomain)
|
||||||
onionDomain, i2pDomain,
|
if debug:
|
||||||
port, proxyType,
|
pprint(queueJson['post'])
|
||||||
federationList, ocapAlways,
|
|
||||||
debug, acceptedCaps,
|
|
||||||
queueFilename, destination,
|
|
||||||
maxReplies, allowDeletion,
|
|
||||||
maxMentions, maxEmoji,
|
|
||||||
translate, unitTest,
|
|
||||||
YTReplacementDomain)
|
|
||||||
else:
|
|
||||||
print('Queue: object capabilities check has failed')
|
|
||||||
if debug:
|
|
||||||
pprint(queueJson['post'])
|
|
||||||
else:
|
|
||||||
if not ocapAlways:
|
|
||||||
inboxAfterCapabilities(recentPostsCache,
|
|
||||||
maxRecentPosts,
|
|
||||||
session, keyId, handle,
|
|
||||||
queueJson['post'],
|
|
||||||
baseDir, httpPrefix,
|
|
||||||
sendThreads, postLog,
|
|
||||||
cachedWebfingers,
|
|
||||||
personCache, queue,
|
|
||||||
domain,
|
|
||||||
onionDomain, i2pDomain,
|
|
||||||
port, proxyType,
|
|
||||||
federationList, ocapAlways,
|
|
||||||
debug, acceptedCaps,
|
|
||||||
queueFilename, destination,
|
|
||||||
maxReplies, allowDeletion,
|
|
||||||
maxMentions, maxEmoji,
|
|
||||||
translate, unitTest,
|
|
||||||
YTReplacementDomain)
|
|
||||||
if debug:
|
|
||||||
pprint(queueJson['post'])
|
|
||||||
print('No capability list within post')
|
|
||||||
print('ocapAlways: ' + str(ocapAlways))
|
|
||||||
|
|
||||||
print('Queue: Queue post accepted')
|
print('Queue: Queue post accepted')
|
||||||
if os.path.isfile(queueFilename):
|
if os.path.isfile(queueFilename):
|
||||||
|
|
10
person.py
10
person.py
|
@ -259,7 +259,6 @@ def createPersonBase(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
'id': personId+'/endpoints',
|
'id': personId+'/endpoints',
|
||||||
'sharedInbox': httpPrefix+'://'+domain+'/inbox',
|
'sharedInbox': httpPrefix+'://'+domain+'/inbox',
|
||||||
},
|
},
|
||||||
'capabilityAcquisitionEndpoint': httpPrefix+'://'+domain+'/caps/new',
|
|
||||||
'followers': personId+'/followers',
|
'followers': personId+'/followers',
|
||||||
'following': personId+'/following',
|
'following': personId+'/following',
|
||||||
'shares': personId+'/shares',
|
'shares': personId+'/shares',
|
||||||
|
@ -506,15 +505,6 @@ def createSharedInbox(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
True, True, None)
|
True, True, None)
|
||||||
|
|
||||||
|
|
||||||
def createCapabilitiesInbox(baseDir: str, nickname: str,
|
|
||||||
domain: str, port: int,
|
|
||||||
httpPrefix: str) -> (str, str, {}, {}):
|
|
||||||
"""Generates the capabilities inbox to sign requests
|
|
||||||
"""
|
|
||||||
return createPersonBase(baseDir, nickname, domain, port,
|
|
||||||
httpPrefix, True, True, None)
|
|
||||||
|
|
||||||
|
|
||||||
def personUpgradeActor(baseDir: str, personJson: {},
|
def personUpgradeActor(baseDir: str, personJson: {},
|
||||||
handle: str, filename: str) -> None:
|
handle: str, filename: str) -> None:
|
||||||
"""Alter the actor to add any new properties
|
"""Alter the actor to add any new properties
|
||||||
|
|
111
posts.py
111
posts.py
|
@ -45,8 +45,6 @@ from utils import validNickname
|
||||||
from utils import locatePost
|
from utils import locatePost
|
||||||
from utils import loadJson
|
from utils import loadJson
|
||||||
from utils import saveJson
|
from utils import saveJson
|
||||||
from capabilities import getOcapFilename
|
|
||||||
from capabilities import capabilitiesUpdate
|
|
||||||
from media import attachMedia
|
from media import attachMedia
|
||||||
from media import replaceYouTube
|
from media import replaceYouTube
|
||||||
from content import removeHtml
|
from content import removeHtml
|
||||||
|
@ -893,24 +891,12 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
if not clientToServer:
|
if not clientToServer:
|
||||||
actorUrl = httpPrefix + '://' + domain + '/users/' + nickname
|
actorUrl = httpPrefix + '://' + domain + '/users/' + nickname
|
||||||
|
|
||||||
# if capabilities have been granted for this actor
|
|
||||||
# then get the corresponding id
|
|
||||||
capabilityIdList = []
|
|
||||||
ocapFilename = getOcapFilename(baseDir, nickname, domain,
|
|
||||||
toUrl, 'granted')
|
|
||||||
if ocapFilename:
|
|
||||||
if os.path.isfile(ocapFilename):
|
|
||||||
oc = loadJson(ocapFilename)
|
|
||||||
if oc:
|
|
||||||
if oc.get('id'):
|
|
||||||
capabilityIdList = [oc['id']]
|
|
||||||
idStr = \
|
idStr = \
|
||||||
httpPrefix + '://' + domain + '/users/' + nickname + \
|
httpPrefix + '://' + domain + '/users/' + nickname + \
|
||||||
'/statuses/' + statusNumber + '/replies'
|
'/statuses/' + statusNumber + '/replies'
|
||||||
newPost = {
|
newPost = {
|
||||||
'@context': postContext,
|
'@context': postContext,
|
||||||
'id': newPostId + '/activity',
|
'id': newPostId + '/activity',
|
||||||
'capability': capabilityIdList,
|
|
||||||
'type': 'Create',
|
'type': 'Create',
|
||||||
'actor': actorUrl,
|
'actor': actorUrl,
|
||||||
'published': published,
|
'published': published,
|
||||||
|
@ -1674,20 +1660,13 @@ def sendPost(projectVersion: str,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, postToBox)
|
nickname, domain, postToBox)
|
||||||
|
|
||||||
# If there are more than one followers on the target domain
|
|
||||||
# then send to the shared inbox indead of the individual inbox
|
|
||||||
if nickname == 'capabilities':
|
|
||||||
inboxUrl = capabilityAcquisition
|
|
||||||
if not capabilityAcquisition:
|
|
||||||
return 2
|
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
return 3
|
return 3
|
||||||
if not pubKey:
|
if not pubKey:
|
||||||
return 4
|
return 4
|
||||||
if not toPersonId:
|
if not toPersonId:
|
||||||
return 5
|
return 5
|
||||||
# sharedInbox and capabilities are optional
|
# sharedInbox is optional
|
||||||
|
|
||||||
postJsonObject = \
|
postJsonObject = \
|
||||||
createPostBase(baseDir, nickname, domain, port,
|
createPostBase(baseDir, nickname, domain, port,
|
||||||
|
@ -2003,7 +1982,7 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
|
||||||
else:
|
else:
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox/outbox/capabilities for the To handle
|
# get the actor inbox/outbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey, toPersonId, sharedInboxUrl,
|
(inboxUrl, pubKeyId, pubKey, toPersonId, sharedInboxUrl,
|
||||||
capabilityAcquisition, avatarUrl,
|
capabilityAcquisition, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
|
@ -2011,17 +1990,12 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, postToBox)
|
nickname, domain, postToBox)
|
||||||
|
|
||||||
if nickname == 'capabilities':
|
print("inboxUrl: " + str(inboxUrl))
|
||||||
inboxUrl = capabilityAcquisition
|
print("toPersonId: " + str(toPersonId))
|
||||||
if not capabilityAcquisition:
|
print("sharedInboxUrl: " + str(sharedInboxUrl))
|
||||||
return 2
|
if inboxUrl:
|
||||||
else:
|
if inboxUrl.endswith('/actor/inbox'):
|
||||||
print("inboxUrl: " + str(inboxUrl))
|
inboxUrl = sharedInboxUrl
|
||||||
print("toPersonId: " + str(toPersonId))
|
|
||||||
print("sharedInboxUrl: " + str(sharedInboxUrl))
|
|
||||||
if inboxUrl:
|
|
||||||
if inboxUrl.endswith('/actor/inbox'):
|
|
||||||
inboxUrl = sharedInboxUrl
|
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
@ -2039,7 +2013,7 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: missing personId')
|
print('DEBUG: missing personId')
|
||||||
return 5
|
return 5
|
||||||
# sharedInbox and capabilities are optional
|
# sharedInbox is optional
|
||||||
|
|
||||||
# get the senders private key
|
# get the senders private key
|
||||||
privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private', debug)
|
privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private', debug)
|
||||||
|
@ -2791,32 +2765,8 @@ def createSharedInboxIndex(baseDir: str, sharedBoxDir: str,
|
||||||
if actorNickname + '@' + actorDomain not in followingHandles:
|
if actorNickname + '@' + actorDomain not in followingHandles:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if ocapAlways:
|
postsInBoxDict[statusNumber] = sharedInboxFilename
|
||||||
capsList = None
|
postsCtr += 1
|
||||||
# Note: should this be in the Create or the object of a post?
|
|
||||||
if postJsonObject.get('capability'):
|
|
||||||
if isinstance(postJsonObject['capability'], list):
|
|
||||||
capsList = postJsonObject['capability']
|
|
||||||
|
|
||||||
# Have capabilities been granted for the sender?
|
|
||||||
ocapFilename = \
|
|
||||||
baseDir + '/accounts/' + handle + '/ocap/granted/' + \
|
|
||||||
postJsonObject['actor'].replace('/', '#') + '.json'
|
|
||||||
if not os.path.isfile(ocapFilename):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# read the capabilities id
|
|
||||||
ocapJson = loadJson(ocapFilename, 0)
|
|
||||||
if not ocapJson:
|
|
||||||
print('WARN: json load exception createSharedInboxIndex')
|
|
||||||
else:
|
|
||||||
if ocapJson.get('id'):
|
|
||||||
if ocapJson['id'] in capsList:
|
|
||||||
postsInBoxDict[statusNumber] = sharedInboxFilename
|
|
||||||
postsCtr += 1
|
|
||||||
else:
|
|
||||||
postsInBoxDict[statusNumber] = sharedInboxFilename
|
|
||||||
postsCtr += 1
|
|
||||||
return postsCtr
|
return postsCtr
|
||||||
|
|
||||||
|
|
||||||
|
@ -3413,45 +3363,6 @@ def checkDomains(session, baseDir: str,
|
||||||
print(followerWarningStr)
|
print(followerWarningStr)
|
||||||
|
|
||||||
|
|
||||||
def sendCapabilitiesUpdate(session, baseDir: str, httpPrefix: str,
|
|
||||||
nickname: str, domain: str, port: int,
|
|
||||||
followerUrl, updateCaps: [],
|
|
||||||
sendThreads: [], postLog: [],
|
|
||||||
cachedWebfingers: {}, personCache: {},
|
|
||||||
federationList: [], debug: bool,
|
|
||||||
projectVersion: str) -> int:
|
|
||||||
"""When the capabilities for a follower are changed this
|
|
||||||
sends out an update. followerUrl is the actor of the follower.
|
|
||||||
"""
|
|
||||||
updateJson = \
|
|
||||||
capabilitiesUpdate(baseDir, httpPrefix,
|
|
||||||
nickname, domain, port,
|
|
||||||
followerUrl, updateCaps)
|
|
||||||
|
|
||||||
if not updateJson:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
if debug:
|
|
||||||
pprint(updateJson)
|
|
||||||
print('DEBUG: sending capabilities update from ' +
|
|
||||||
nickname + '@' + domain + ' port ' + str(port) +
|
|
||||||
' to ' + followerUrl)
|
|
||||||
|
|
||||||
clientToServer = False
|
|
||||||
followerNickname = getNicknameFromActor(followerUrl)
|
|
||||||
if not followerNickname:
|
|
||||||
print('WARN: unable to find nickname in ' + followerUrl)
|
|
||||||
return 1
|
|
||||||
followerDomain, followerPort = getDomainFromActor(followerUrl)
|
|
||||||
return sendSignedJson(updateJson, session, baseDir,
|
|
||||||
nickname, domain, port,
|
|
||||||
followerNickname, followerDomain, followerPort, '',
|
|
||||||
httpPrefix, True, clientToServer,
|
|
||||||
federationList,
|
|
||||||
sendThreads, postLog, cachedWebfingers,
|
|
||||||
personCache, debug, projectVersion)
|
|
||||||
|
|
||||||
|
|
||||||
def populateRepliesJson(baseDir: str, nickname: str, domain: str,
|
def populateRepliesJson(baseDir: str, nickname: str, domain: str,
|
||||||
postRepliesFilename: str, authorized: bool,
|
postRepliesFilename: str, authorized: bool,
|
||||||
repliesJson: {}) -> None:
|
repliesJson: {}) -> None:
|
||||||
|
|
|
@ -141,13 +141,6 @@ def postJsonString(session, postJsonStr: str,
|
||||||
conversions between string and json format don't invalidate
|
conversions between string and json format don't invalidate
|
||||||
the message body digest of http signatures
|
the message body digest of http signatures
|
||||||
"""
|
"""
|
||||||
# always allow capability requests
|
|
||||||
if not capability.startswith('cap'):
|
|
||||||
# check that we are posting to a permitted domain
|
|
||||||
if not urlPermitted(inboxUrl, federationList, capability):
|
|
||||||
print('postJson: ' + inboxUrl + ' not permitted by capabilities')
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
postResult = \
|
postResult = \
|
||||||
session.post(url=inboxUrl, data=postJsonStr, headers=headers)
|
session.post(url=inboxUrl, data=postJsonStr, headers=headers)
|
||||||
|
|
2
utils.py
2
utils.py
|
@ -669,7 +669,7 @@ def validNickname(domain: str, nickname: str) -> bool:
|
||||||
return False
|
return False
|
||||||
reservedNames = ('inbox', 'dm', 'outbox', 'following',
|
reservedNames = ('inbox', 'dm', 'outbox', 'following',
|
||||||
'public', 'followers',
|
'public', 'followers',
|
||||||
'channel', 'capabilities', 'calendar',
|
'channel', 'calendar',
|
||||||
'tlreplies', 'tlmedia', 'tlblogs',
|
'tlreplies', 'tlmedia', 'tlblogs',
|
||||||
'tlevents',
|
'tlevents',
|
||||||
'moderation', 'activity', 'undo',
|
'moderation', 'activity', 'undo',
|
||||||
|
|
Loading…
Reference in New Issue