mirror of https://gitlab.com/bashrc2/epicyon
Unit test for federated shared items
parent
ccc0d09ece
commit
0f71fae658
81
daemon.py
81
daemon.py
|
@ -4893,9 +4893,10 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.sharedItemFederationTokens
|
self.server.sharedItemFederationTokens
|
||||||
self.server.sharedItemsFederatedDomains = \
|
self.server.sharedItemsFederatedDomains = \
|
||||||
siDomains
|
siDomains
|
||||||
|
domainFull = self.server.domainFull
|
||||||
self.server.sharedItemFederationTokens = \
|
self.server.sharedItemFederationTokens = \
|
||||||
mergeSharedItemTokens(self.server.baseDir,
|
mergeSharedItemTokens(self.server.baseDir,
|
||||||
self.server.domain,
|
domainFull,
|
||||||
siDomains,
|
siDomains,
|
||||||
siTokens)
|
siTokens)
|
||||||
|
|
||||||
|
@ -10820,13 +10821,15 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
print('Catalog access is not authorized. Checking' +
|
print('Catalog access is not authorized. Checking' +
|
||||||
'Authorization header')
|
'Authorization header')
|
||||||
# basic auth access to shared items catalog
|
# basic auth access to shared items catalog
|
||||||
if self.headers.get('Authorization'):
|
if self.headers.get('Origin') and \
|
||||||
|
self.headers.get('Authorization'):
|
||||||
permittedDomains = \
|
permittedDomains = \
|
||||||
self.server.sharedItemsFederatedDomains
|
self.server.sharedItemsFederatedDomains
|
||||||
sharedItemTokens = self.server.sharedItemFederationTokens
|
sharedItemTokens = self.server.sharedItemFederationTokens
|
||||||
|
originDomain = self.headers.get('Origin')
|
||||||
if authorizeSharedItems(permittedDomains,
|
if authorizeSharedItems(permittedDomains,
|
||||||
self.server.baseDir,
|
self.server.baseDir,
|
||||||
callingDomain,
|
originDomain,
|
||||||
self.headers['Authorization'],
|
self.headers['Authorization'],
|
||||||
self.server.debug,
|
self.server.debug,
|
||||||
sharedItemTokens):
|
sharedItemTokens):
|
||||||
|
@ -10835,8 +10838,12 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
print('Authorization token refused for ' +
|
print('Authorization token refused for ' +
|
||||||
'shared items federation')
|
'shared items federation')
|
||||||
elif self.server.debug:
|
elif self.server.debug:
|
||||||
print('No authorization header is available for ' +
|
if not self.headers.get('Origin'):
|
||||||
'shared items federation')
|
print('No Origin header is available for ' +
|
||||||
|
'shared items federation')
|
||||||
|
else:
|
||||||
|
print('No Authorization header is available for ' +
|
||||||
|
'shared items federation')
|
||||||
# show shared items catalog for federation
|
# show shared items catalog for federation
|
||||||
if self._hasAccept(callingDomain) and catalogAuthorized:
|
if self._hasAccept(callingDomain) and catalogAuthorized:
|
||||||
catalogType = 'json'
|
catalogType = 'json'
|
||||||
|
@ -14625,6 +14632,49 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.defaultTimeline)
|
self.server.defaultTimeline)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# update the shared item federation token for the calling domain
|
||||||
|
# if it is within the permitted federation
|
||||||
|
if self.headers.get('Origin') and \
|
||||||
|
self.headers.get('SharesCatalog'):
|
||||||
|
if self.server.debug:
|
||||||
|
print('SharesCatalog header: ' + self.headers['SharesCatalog'])
|
||||||
|
if not self.server.sharedItemsFederatedDomains:
|
||||||
|
siDomainsStr = getConfigParam(self.server.baseDir,
|
||||||
|
'sharedItemsFederatedDomains')
|
||||||
|
if siDomainsStr:
|
||||||
|
if self.server.debug:
|
||||||
|
print('Loading shared items federated domains list')
|
||||||
|
siDomainsList = siDomainsStr.split(',')
|
||||||
|
domainsList = self.server.sharedItemsFederatedDomains
|
||||||
|
for siDomain in siDomainsList:
|
||||||
|
domainsList.append(siDomain.strip())
|
||||||
|
originDomain = self.headers.get('Origin')
|
||||||
|
if originDomain != self.server.domainFull and \
|
||||||
|
originDomain != self.server.onionDomain and \
|
||||||
|
originDomain != self.server.i2pDomain and \
|
||||||
|
originDomain in self.server.sharedItemsFederatedDomains:
|
||||||
|
if self.server.debug:
|
||||||
|
print('DEBUG: ' +
|
||||||
|
'POST updating shared item federation ' +
|
||||||
|
'token for ' + originDomain + ' to ' +
|
||||||
|
self.server.domainFull)
|
||||||
|
sharedItemTokens = self.server.sharedItemFederationTokens
|
||||||
|
sharesToken = self.headers['SharesCatalog']
|
||||||
|
self.server.sharedItemFederationTokens = \
|
||||||
|
updateSharedItemFederationToken(self.server.baseDir,
|
||||||
|
originDomain,
|
||||||
|
sharesToken,
|
||||||
|
self.server.debug,
|
||||||
|
sharedItemTokens)
|
||||||
|
elif self.server.debug:
|
||||||
|
if originDomain not in self.server.sharedItemsFederatedDomains:
|
||||||
|
print('originDomain is not in federated domains list ' +
|
||||||
|
originDomain)
|
||||||
|
else:
|
||||||
|
print('originDomain is not a different instance. ' +
|
||||||
|
originDomain + ' ' + self.server.domainFull + ' ' +
|
||||||
|
str(self.server.sharedItemsFederatedDomains))
|
||||||
|
|
||||||
self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 14)
|
self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 14)
|
||||||
|
|
||||||
# receive different types of post created by htmlNewPost
|
# receive different types of post created by htmlNewPost
|
||||||
|
@ -14906,23 +14956,6 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
|
|
||||||
self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 23)
|
self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 23)
|
||||||
|
|
||||||
# update the shared item federation token for the calling domain
|
|
||||||
# if it is within the permitted federation
|
|
||||||
if self.headers.get('SharesCatalog') and \
|
|
||||||
callingDomain != self.server.domain and \
|
|
||||||
callingDomain != self.server.domainFull and \
|
|
||||||
callingDomain in self.server.sharedItemsFederatedDomains:
|
|
||||||
if self.server.debug:
|
|
||||||
print('DEBUG: ' +
|
|
||||||
'POST updating shared item federation token for ' +
|
|
||||||
callingDomain)
|
|
||||||
sharedItemTokens = self.server.sharedItemFederationTokens
|
|
||||||
self.server.sharedItemFederationTokens = \
|
|
||||||
updateSharedItemFederationToken(self.server.baseDir,
|
|
||||||
callingDomain,
|
|
||||||
self.headers['SharesCatalog'],
|
|
||||||
sharedItemTokens)
|
|
||||||
|
|
||||||
if self.server.debug:
|
if self.server.debug:
|
||||||
print('DEBUG: POST saving to inbox queue')
|
print('DEBUG: POST saving to inbox queue')
|
||||||
if usersInPath:
|
if usersInPath:
|
||||||
|
@ -15469,7 +15502,7 @@ def runDaemon(maxLikeCount: int,
|
||||||
generateSharedItemFederationTokens(httpd.sharedItemsFederatedDomains,
|
generateSharedItemFederationTokens(httpd.sharedItemsFederatedDomains,
|
||||||
baseDir)
|
baseDir)
|
||||||
httpd.sharedItemFederationTokens = \
|
httpd.sharedItemFederationTokens = \
|
||||||
createSharedItemFederationToken(baseDir, domain,
|
createSharedItemFederationToken(baseDir, httpd.domainFull,
|
||||||
httpd.sharedItemFederationTokens)
|
httpd.sharedItemFederationTokens)
|
||||||
|
|
||||||
# load peertube instances from file into a list
|
# load peertube instances from file into a list
|
||||||
|
@ -15518,7 +15551,7 @@ def runDaemon(maxLikeCount: int,
|
||||||
httpd.thrFederatedSharesDaemon = \
|
httpd.thrFederatedSharesDaemon = \
|
||||||
threadWithTrace(target=runFederatedSharesDaemon,
|
threadWithTrace(target=runFederatedSharesDaemon,
|
||||||
args=(baseDir, httpd,
|
args=(baseDir, httpd,
|
||||||
httpPrefix, domain,
|
httpPrefix, httpd.domainFull,
|
||||||
proxyType, debug,
|
proxyType, debug,
|
||||||
httpd.systemLanguage), daemon=True)
|
httpd.systemLanguage), daemon=True)
|
||||||
|
|
||||||
|
|
|
@ -614,7 +614,6 @@ if args.tests:
|
||||||
if args.testsnetwork:
|
if args.testsnetwork:
|
||||||
print('Network Tests')
|
print('Network Tests')
|
||||||
testSharedItemsFederation()
|
testSharedItemsFederation()
|
||||||
sys.exit()
|
|
||||||
testGroupFollow()
|
testGroupFollow()
|
||||||
testPostMessageBetweenServers()
|
testPostMessageBetweenServers()
|
||||||
testFollowBetweenServers()
|
testFollowBetweenServers()
|
||||||
|
|
40
posts.py
40
posts.py
|
@ -2009,9 +2009,11 @@ def sendPost(projectVersion: str,
|
||||||
federationList: [], sendThreads: [], postLog: [],
|
federationList: [], sendThreads: [], postLog: [],
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
isArticle: bool, systemLanguage: str,
|
isArticle: bool, systemLanguage: str,
|
||||||
|
sharedItemsFederatedDomains: [],
|
||||||
|
sharedItemFederationTokens: {},
|
||||||
debug: bool = False, inReplyTo: str = None,
|
debug: bool = False, inReplyTo: str = None,
|
||||||
inReplyToAtomUri: str = None, subject: str = None) -> int:
|
inReplyToAtomUri: str = None, subject: str = None) -> int:
|
||||||
"""Post to another inbox
|
"""Post to another inbox. Used by unit tests.
|
||||||
"""
|
"""
|
||||||
withDigest = True
|
withDigest = True
|
||||||
|
|
||||||
|
@ -2099,6 +2101,26 @@ def sendPost(projectVersion: str,
|
||||||
toDomain, toPort,
|
toDomain, toPort,
|
||||||
postPath, httpPrefix, withDigest, postJsonStr)
|
postPath, httpPrefix, withDigest, postJsonStr)
|
||||||
|
|
||||||
|
# if the "to" domain is within the shared items
|
||||||
|
# federation list then send the token for this domain
|
||||||
|
# so that it can request a catalog
|
||||||
|
if toDomain in sharedItemsFederatedDomains:
|
||||||
|
domainFull = getFullDomain(domain, port)
|
||||||
|
if sharedItemFederationTokens.get(domainFull):
|
||||||
|
signatureHeaderJson['Origin'] = domainFull
|
||||||
|
signatureHeaderJson['SharesCatalog'] = \
|
||||||
|
sharedItemFederationTokens[domainFull]
|
||||||
|
if debug:
|
||||||
|
print('SharesCatalog added to header')
|
||||||
|
elif debug:
|
||||||
|
print(domainFull + ' not in sharedItemFederationTokens')
|
||||||
|
elif debug:
|
||||||
|
print(toDomain + ' not in sharedItemsFederatedDomains ' +
|
||||||
|
str(sharedItemsFederatedDomains))
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
print('signatureHeaderJson: ' + str(signatureHeaderJson))
|
||||||
|
|
||||||
# Keep the number of threads being used small
|
# Keep the number of threads being used small
|
||||||
while len(sendThreads) > 1000:
|
while len(sendThreads) > 1000:
|
||||||
print('WARN: Maximum threads reached - killing send thread')
|
print('WARN: Maximum threads reached - killing send thread')
|
||||||
|
@ -2139,14 +2161,14 @@ def sendPostViaServer(projectVersion: str,
|
||||||
print('WARN: No session for sendPostViaServer')
|
print('WARN: No session for sendPostViaServer')
|
||||||
return 6
|
return 6
|
||||||
|
|
||||||
fromDomain = getFullDomain(fromDomain, fromPort)
|
fromDomainFull = getFullDomain(fromDomain, fromPort)
|
||||||
|
|
||||||
handle = httpPrefix + '://' + fromDomain + '/@' + fromNickname
|
handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname
|
||||||
|
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomainFull, projectVersion, debug, False)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: post webfinger failed for ' + handle)
|
print('DEBUG: post webfinger failed for ' + handle)
|
||||||
|
@ -2167,7 +2189,7 @@ def sendPostViaServer(projectVersion: str,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
fromNickname,
|
fromNickname,
|
||||||
fromDomain, postToBox,
|
fromDomainFull, postToBox,
|
||||||
82796)
|
82796)
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
@ -2185,7 +2207,6 @@ def sendPostViaServer(projectVersion: str,
|
||||||
clientToServer = True
|
clientToServer = True
|
||||||
if toDomain.lower().endswith('public'):
|
if toDomain.lower().endswith('public'):
|
||||||
toPersonId = 'https://www.w3.org/ns/activitystreams#Public'
|
toPersonId = 'https://www.w3.org/ns/activitystreams#Public'
|
||||||
fromDomainFull = getFullDomain(fromDomain, fromPort)
|
|
||||||
cc = httpPrefix + '://' + fromDomainFull + '/users/' + \
|
cc = httpPrefix + '://' + fromDomainFull + '/users/' + \
|
||||||
fromNickname + '/followers'
|
fromNickname + '/followers'
|
||||||
else:
|
else:
|
||||||
|
@ -2217,7 +2238,7 @@ def sendPostViaServer(projectVersion: str,
|
||||||
|
|
||||||
if attachImageFilename:
|
if attachImageFilename:
|
||||||
headers = {
|
headers = {
|
||||||
'host': fromDomain,
|
'host': fromDomainFull,
|
||||||
'Authorization': authHeader
|
'Authorization': authHeader
|
||||||
}
|
}
|
||||||
postResult = \
|
postResult = \
|
||||||
|
@ -2229,7 +2250,7 @@ def sendPostViaServer(projectVersion: str,
|
||||||
# return 9
|
# return 9
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
'host': fromDomain,
|
'host': fromDomainFull,
|
||||||
'Content-type': 'application/json',
|
'Content-type': 'application/json',
|
||||||
'Authorization': authHeader
|
'Authorization': authHeader
|
||||||
}
|
}
|
||||||
|
@ -2434,7 +2455,10 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
|
||||||
# optionally add a token so that the receiving instance may access
|
# optionally add a token so that the receiving instance may access
|
||||||
# your shared items catalog
|
# your shared items catalog
|
||||||
if sharedItemsToken:
|
if sharedItemsToken:
|
||||||
|
signatureHeaderJson['Origin'] = getFullDomain(domain, port)
|
||||||
signatureHeaderJson['SharesCatalog'] = sharedItemsToken
|
signatureHeaderJson['SharesCatalog'] = sharedItemsToken
|
||||||
|
elif debug:
|
||||||
|
print('Not sending shared items federation token')
|
||||||
|
|
||||||
# Keep the number of threads being used small
|
# Keep the number of threads being used small
|
||||||
while len(sendThreads) > 1000:
|
while len(sendThreads) > 1000:
|
||||||
|
|
95
shares.py
95
shares.py
|
@ -1080,9 +1080,9 @@ def generateSharedItemFederationTokens(sharedItemsFederatedDomains: [],
|
||||||
tokensJson = {}
|
tokensJson = {}
|
||||||
|
|
||||||
tokensAdded = False
|
tokensAdded = False
|
||||||
for domain in sharedItemsFederatedDomains:
|
for domainFull in sharedItemsFederatedDomains:
|
||||||
if not tokensJson.get(domain):
|
if not tokensJson.get(domainFull):
|
||||||
tokensJson[domain] = ''
|
tokensJson[domainFull] = ''
|
||||||
tokensAdded = True
|
tokensAdded = True
|
||||||
|
|
||||||
if not tokensAdded:
|
if not tokensAdded:
|
||||||
|
@ -1093,33 +1093,38 @@ def generateSharedItemFederationTokens(sharedItemsFederatedDomains: [],
|
||||||
|
|
||||||
|
|
||||||
def updateSharedItemFederationToken(baseDir: str,
|
def updateSharedItemFederationToken(baseDir: str,
|
||||||
tokenDomain: str, newToken: str,
|
tokenDomainFull: str, newToken: str,
|
||||||
|
debug: bool,
|
||||||
tokensJson: {} = None) -> {}:
|
tokensJson: {} = None) -> {}:
|
||||||
"""Updates an individual token for shared item federation
|
"""Updates an individual token for shared item federation
|
||||||
"""
|
"""
|
||||||
|
if debug:
|
||||||
|
print('Updating shared items token for ' + tokenDomainFull)
|
||||||
if not tokensJson:
|
if not tokensJson:
|
||||||
tokensJson = {}
|
tokensJson = {}
|
||||||
if baseDir:
|
if baseDir:
|
||||||
tokensFilename = \
|
tokensFilename = \
|
||||||
baseDir + '/accounts/sharedItemsFederationTokens.json'
|
baseDir + '/accounts/sharedItemsFederationTokens.json'
|
||||||
if os.path.isfile(tokensFilename):
|
if os.path.isfile(tokensFilename):
|
||||||
|
if debug:
|
||||||
|
print('Update loading tokens for ' + tokenDomainFull)
|
||||||
tokensJson = loadJson(tokensFilename, 1, 2)
|
tokensJson = loadJson(tokensFilename, 1, 2)
|
||||||
if tokensJson is None:
|
if tokensJson is None:
|
||||||
tokensJson = {}
|
tokensJson = {}
|
||||||
updateRequired = False
|
updateRequired = False
|
||||||
if tokensJson.get(tokenDomain):
|
if tokensJson.get(tokenDomainFull):
|
||||||
if tokensJson[tokenDomain] != newToken:
|
if tokensJson[tokenDomainFull] != newToken:
|
||||||
updateRequired = True
|
updateRequired = True
|
||||||
else:
|
else:
|
||||||
updateRequired = True
|
updateRequired = True
|
||||||
if updateRequired:
|
if updateRequired:
|
||||||
tokensJson[tokenDomain] = newToken
|
tokensJson[tokenDomainFull] = newToken
|
||||||
if baseDir:
|
if baseDir:
|
||||||
saveJson(tokensJson, tokensFilename)
|
saveJson(tokensJson, tokensFilename)
|
||||||
return tokensJson
|
return tokensJson
|
||||||
|
|
||||||
|
|
||||||
def mergeSharedItemTokens(baseDir: str, domain: str,
|
def mergeSharedItemTokens(baseDir: str, domainFull: str,
|
||||||
newSharedItemsFederatedDomains: [],
|
newSharedItemsFederatedDomains: [],
|
||||||
tokensJson: {}) -> {}:
|
tokensJson: {}) -> {}:
|
||||||
"""When the shared item federation domains list has changed, update
|
"""When the shared item federation domains list has changed, update
|
||||||
|
@ -1127,20 +1132,20 @@ def mergeSharedItemTokens(baseDir: str, domain: str,
|
||||||
"""
|
"""
|
||||||
removals = []
|
removals = []
|
||||||
changed = False
|
changed = False
|
||||||
for tokenDomain, tok in tokensJson.items():
|
for tokenDomainFull, tok in tokensJson.items():
|
||||||
if domain:
|
if domainFull:
|
||||||
if tokenDomain.startswith(domain):
|
if tokenDomainFull.startswith(domainFull):
|
||||||
continue
|
continue
|
||||||
if tokenDomain not in newSharedItemsFederatedDomains:
|
if tokenDomainFull not in newSharedItemsFederatedDomains:
|
||||||
removals.append(tokenDomain)
|
removals.append(tokenDomainFull)
|
||||||
# remove domains no longer in the federation list
|
# remove domains no longer in the federation list
|
||||||
for tokenDomain in removals:
|
for tokenDomainFull in removals:
|
||||||
del tokensJson[tokenDomain]
|
del tokensJson[tokenDomainFull]
|
||||||
changed = True
|
changed = True
|
||||||
# add new domains from the federation list
|
# add new domains from the federation list
|
||||||
for tokenDomain in newSharedItemsFederatedDomains:
|
for tokenDomainFull in newSharedItemsFederatedDomains:
|
||||||
if tokenDomain not in tokensJson:
|
if tokenDomainFull not in tokensJson:
|
||||||
tokensJson[tokenDomain] = ''
|
tokensJson[tokenDomainFull] = ''
|
||||||
changed = True
|
changed = True
|
||||||
if baseDir and changed:
|
if baseDir and changed:
|
||||||
tokensFilename = \
|
tokensFilename = \
|
||||||
|
@ -1150,7 +1155,7 @@ def mergeSharedItemTokens(baseDir: str, domain: str,
|
||||||
|
|
||||||
|
|
||||||
def createSharedItemFederationToken(baseDir: str,
|
def createSharedItemFederationToken(baseDir: str,
|
||||||
tokenDomain: str,
|
tokenDomainFull: str,
|
||||||
tokensJson: {} = None) -> {}:
|
tokensJson: {} = None) -> {}:
|
||||||
"""Updates an individual token for shared item federation
|
"""Updates an individual token for shared item federation
|
||||||
"""
|
"""
|
||||||
|
@ -1163,8 +1168,8 @@ def createSharedItemFederationToken(baseDir: str,
|
||||||
tokensJson = loadJson(tokensFilename, 1, 2)
|
tokensJson = loadJson(tokensFilename, 1, 2)
|
||||||
if tokensJson is None:
|
if tokensJson is None:
|
||||||
tokensJson = {}
|
tokensJson = {}
|
||||||
if not tokensJson.get(tokenDomain):
|
if not tokensJson.get(tokenDomainFull):
|
||||||
tokensJson[tokenDomain] = secrets.token_urlsafe(64)
|
tokensJson[tokenDomainFull] = secrets.token_urlsafe(64)
|
||||||
if baseDir:
|
if baseDir:
|
||||||
saveJson(tokensJson, tokensFilename)
|
saveJson(tokensJson, tokensFilename)
|
||||||
return tokensJson
|
return tokensJson
|
||||||
|
@ -1172,7 +1177,7 @@ def createSharedItemFederationToken(baseDir: str,
|
||||||
|
|
||||||
def authorizeSharedItems(sharedItemsFederatedDomains: [],
|
def authorizeSharedItems(sharedItemsFederatedDomains: [],
|
||||||
baseDir: str,
|
baseDir: str,
|
||||||
callingDomain: str,
|
originDomainFull: str,
|
||||||
authHeader: str,
|
authHeader: str,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
tokensJson: {} = None) -> bool:
|
tokensJson: {} = None) -> bool:
|
||||||
|
@ -1181,9 +1186,9 @@ def authorizeSharedItems(sharedItemsFederatedDomains: [],
|
||||||
if not sharedItemsFederatedDomains:
|
if not sharedItemsFederatedDomains:
|
||||||
# no shared item federation
|
# no shared item federation
|
||||||
return False
|
return False
|
||||||
if callingDomain not in sharedItemsFederatedDomains:
|
if originDomainFull not in sharedItemsFederatedDomains:
|
||||||
if debug:
|
if debug:
|
||||||
print(callingDomain +
|
print(originDomainFull +
|
||||||
' is not in the shared items federation list')
|
' is not in the shared items federation list')
|
||||||
return False
|
return False
|
||||||
if 'Basic ' in authHeader:
|
if 'Basic ' in authHeader:
|
||||||
|
@ -1211,21 +1216,22 @@ def authorizeSharedItems(sharedItemsFederatedDomains: [],
|
||||||
tokensJson = loadJson(tokensFilename, 1, 2)
|
tokensJson = loadJson(tokensFilename, 1, 2)
|
||||||
if not tokensJson:
|
if not tokensJson:
|
||||||
return False
|
return False
|
||||||
if not tokensJson.get(callingDomain):
|
if not tokensJson.get(originDomainFull):
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: shared item federation token ' +
|
print('DEBUG: shared item federation token ' +
|
||||||
'check failed for ' + callingDomain)
|
'check failed for ' + originDomainFull)
|
||||||
return False
|
return False
|
||||||
if not constantTimeStringCheck(tokensJson[callingDomain], providedToken):
|
if not constantTimeStringCheck(tokensJson[originDomainFull],
|
||||||
|
providedToken):
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: shared item federation token ' +
|
print('DEBUG: shared item federation token ' +
|
||||||
'mismatch for ' + callingDomain)
|
'mismatch for ' + originDomainFull)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _updateFederatedSharesCache(session, sharedItemsFederatedDomains: [],
|
def _updateFederatedSharesCache(session, sharedItemsFederatedDomains: [],
|
||||||
baseDir: str, domain: str,
|
baseDir: str, domainFull: str,
|
||||||
httpPrefix: str,
|
httpPrefix: str,
|
||||||
tokensJson: {}, debug: bool,
|
tokensJson: {}, debug: bool,
|
||||||
systemLanguage: str) -> None:
|
systemLanguage: str) -> None:
|
||||||
|
@ -1242,37 +1248,38 @@ def _updateFederatedSharesCache(session, sharedItemsFederatedDomains: [],
|
||||||
os.mkdir(catalogsDir)
|
os.mkdir(catalogsDir)
|
||||||
|
|
||||||
asHeader = {
|
asHeader = {
|
||||||
'Accept': 'application/ld+json'
|
"Accept": "application/ld+json",
|
||||||
|
"Origin": domainFull
|
||||||
}
|
}
|
||||||
for federatedDomain in sharedItemsFederatedDomains:
|
for federatedDomainFull in sharedItemsFederatedDomains:
|
||||||
# NOTE: federatedDomain does not have a port extension,
|
# NOTE: federatedDomain does not have a port extension,
|
||||||
# so may not work in some situations
|
# so may not work in some situations
|
||||||
if federatedDomain.startswith(domain):
|
if federatedDomainFull.startswith(domainFull):
|
||||||
# only download from instances other than this one
|
# only download from instances other than this one
|
||||||
continue
|
continue
|
||||||
if not tokensJson.get(federatedDomain):
|
if not tokensJson.get(federatedDomainFull):
|
||||||
# token has been obtained for the other domain
|
# token has been obtained for the other domain
|
||||||
continue
|
continue
|
||||||
if not siteIsActive(httpPrefix + '://' + federatedDomain):
|
if not siteIsActive(httpPrefix + '://' + federatedDomainFull):
|
||||||
continue
|
continue
|
||||||
url = httpPrefix + '://' + federatedDomain + '/catalog'
|
url = httpPrefix + '://' + federatedDomainFull + '/catalog'
|
||||||
asHeader['Authorization'] = tokensJson[federatedDomain]
|
asHeader['Authorization'] = tokensJson[federatedDomainFull]
|
||||||
catalogJson = getJson(session, url, asHeader, None,
|
catalogJson = getJson(session, url, asHeader, None,
|
||||||
debug, __version__, httpPrefix, None)
|
debug, __version__, httpPrefix, None)
|
||||||
if not catalogJson:
|
if not catalogJson:
|
||||||
print('WARN: failed to download shared items catalog for ' +
|
print('WARN: failed to download shared items catalog for ' +
|
||||||
federatedDomain)
|
federatedDomainFull)
|
||||||
continue
|
continue
|
||||||
catalogFilename = catalogsDir + '/' + federatedDomain + '.json'
|
catalogFilename = catalogsDir + '/' + federatedDomainFull + '.json'
|
||||||
if saveJson(catalogJson, catalogFilename):
|
if saveJson(catalogJson, catalogFilename):
|
||||||
print('Downloaded shared items catalog for ' + federatedDomain)
|
print('Downloaded shared items catalog for ' + federatedDomainFull)
|
||||||
sharesJson = _dfcToSharesFormat(catalogJson,
|
sharesJson = _dfcToSharesFormat(catalogJson,
|
||||||
baseDir, systemLanguage)
|
baseDir, systemLanguage)
|
||||||
if sharesJson:
|
if sharesJson:
|
||||||
sharesFilename = \
|
sharesFilename = \
|
||||||
catalogsDir + '/' + federatedDomain + '.shares.json'
|
catalogsDir + '/' + federatedDomainFull + '.shares.json'
|
||||||
saveJson(sharesJson, sharesFilename)
|
saveJson(sharesJson, sharesFilename)
|
||||||
print('Converted shares catalog for ' + federatedDomain)
|
print('Converted shares catalog for ' + federatedDomainFull)
|
||||||
else:
|
else:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
|
@ -1297,7 +1304,7 @@ def runFederatedSharesWatchdog(projectVersion: str, httpd) -> None:
|
||||||
|
|
||||||
|
|
||||||
def runFederatedSharesDaemon(baseDir: str, httpd, httpPrefix: str,
|
def runFederatedSharesDaemon(baseDir: str, httpd, httpPrefix: str,
|
||||||
domain: str, proxyType: str, debug: bool,
|
domainFull: str, proxyType: str, debug: bool,
|
||||||
systemLanguage: str) -> None:
|
systemLanguage: str) -> None:
|
||||||
"""Runs the daemon used to update federated shared items
|
"""Runs the daemon used to update federated shared items
|
||||||
"""
|
"""
|
||||||
|
@ -1334,8 +1341,8 @@ def runFederatedSharesDaemon(baseDir: str, httpd, httpPrefix: str,
|
||||||
|
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
_updateFederatedSharesCache(session, sharedItemsFederatedDomains,
|
_updateFederatedSharesCache(session, sharedItemsFederatedDomains,
|
||||||
baseDir, domain, httpPrefix, tokensJson,
|
baseDir, domainFull, httpPrefix,
|
||||||
debug, systemLanguage)
|
tokensJson, debug, systemLanguage)
|
||||||
time.sleep(secondsPerHour * 6)
|
time.sleep(secondsPerHour * 6)
|
||||||
|
|
||||||
|
|
||||||
|
|
78
tests.py
78
tests.py
|
@ -42,6 +42,7 @@ from follow import clearFollowers
|
||||||
from follow import sendFollowRequestViaServer
|
from follow import sendFollowRequestViaServer
|
||||||
from follow import sendUnfollowRequestViaServer
|
from follow import sendUnfollowRequestViaServer
|
||||||
from siteactive import siteIsActive
|
from siteactive import siteIsActive
|
||||||
|
from utils import setConfigParam
|
||||||
from utils import isGroupActor
|
from utils import isGroupActor
|
||||||
from utils import dateStringToSeconds
|
from utils import dateStringToSeconds
|
||||||
from utils import dateSecondsToString
|
from utils import dateSecondsToString
|
||||||
|
@ -942,6 +943,8 @@ def testPostMessageBetweenServers():
|
||||||
ccUrl = None
|
ccUrl = None
|
||||||
alicePersonCache = {}
|
alicePersonCache = {}
|
||||||
aliceCachedWebfingers = {}
|
aliceCachedWebfingers = {}
|
||||||
|
aliceSharedItemsFederatedDomains = []
|
||||||
|
aliceSharedItemFederationTokens = {}
|
||||||
attachedImageFilename = baseDir + '/img/logo.png'
|
attachedImageFilename = baseDir + '/img/logo.png'
|
||||||
testImageWidth, testImageHeight = \
|
testImageWidth, testImageHeight = \
|
||||||
getImageDimensions(attachedImageFilename)
|
getImageDimensions(attachedImageFilename)
|
||||||
|
@ -967,8 +970,10 @@ def testPostMessageBetweenServers():
|
||||||
attachedImageFilename, mediaType,
|
attachedImageFilename, mediaType,
|
||||||
attachedImageDescription, city, federationList,
|
attachedImageDescription, city, federationList,
|
||||||
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
||||||
alicePersonCache, isArticle, systemLanguage, inReplyTo,
|
alicePersonCache, isArticle, systemLanguage,
|
||||||
inReplyToAtomUri, subject)
|
aliceSharedItemsFederatedDomains,
|
||||||
|
aliceSharedItemFederationTokens,
|
||||||
|
inReplyTo, inReplyToAtomUri, subject)
|
||||||
print('sendResult: ' + str(sendResult))
|
print('sendResult: ' + str(sendResult))
|
||||||
|
|
||||||
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
|
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
|
||||||
|
@ -1284,6 +1289,8 @@ def testFollowBetweenServers():
|
||||||
alicePostLog = []
|
alicePostLog = []
|
||||||
alicePersonCache = {}
|
alicePersonCache = {}
|
||||||
aliceCachedWebfingers = {}
|
aliceCachedWebfingers = {}
|
||||||
|
aliceSharedItemsFederatedDomains = []
|
||||||
|
aliceSharedItemFederationTokens = {}
|
||||||
alicePostLog = []
|
alicePostLog = []
|
||||||
isArticle = False
|
isArticle = False
|
||||||
city = 'London, England'
|
city = 'London, England'
|
||||||
|
@ -1295,8 +1302,10 @@ def testFollowBetweenServers():
|
||||||
clientToServer, True,
|
clientToServer, True,
|
||||||
None, None, None, city, federationList,
|
None, None, None, city, federationList,
|
||||||
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
||||||
alicePersonCache, isArticle, systemLanguage, inReplyTo,
|
alicePersonCache, isArticle, systemLanguage,
|
||||||
inReplyToAtomUri, subject)
|
aliceSharedItemsFederatedDomains,
|
||||||
|
aliceSharedItemFederationTokens,
|
||||||
|
inReplyTo, inReplyToAtomUri, subject)
|
||||||
print('sendResult: ' + str(sendResult))
|
print('sendResult: ' + str(sendResult))
|
||||||
|
|
||||||
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
|
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
|
||||||
|
@ -1413,6 +1422,13 @@ def testSharedItemsFederation():
|
||||||
|
|
||||||
# In the beginning all was calm and there were no follows
|
# In the beginning all was calm and there were no follows
|
||||||
|
|
||||||
|
print('\n\n*********************************************************')
|
||||||
|
print("Alice and Bob agree to share items catalogs")
|
||||||
|
assert os.path.isdir(aliceDir)
|
||||||
|
assert os.path.isdir(bobDir)
|
||||||
|
setConfigParam(aliceDir, 'sharedItemsFederatedDomains', bobAddress)
|
||||||
|
setConfigParam(bobDir, 'sharedItemsFederatedDomains', aliceAddress)
|
||||||
|
|
||||||
print('*********************************************************')
|
print('*********************************************************')
|
||||||
print('Alice sends a follow request to Bob')
|
print('Alice sends a follow request to Bob')
|
||||||
os.chdir(aliceDir)
|
os.chdir(aliceDir)
|
||||||
|
@ -1572,9 +1588,20 @@ def testSharedItemsFederation():
|
||||||
|
|
||||||
print('\n\n*********************************************************')
|
print('\n\n*********************************************************')
|
||||||
print('Alice sends a message to Bob')
|
print('Alice sends a message to Bob')
|
||||||
|
aliceTokensFilename = \
|
||||||
|
aliceDir + '/accounts/sharedItemsFederationTokens.json'
|
||||||
|
assert os.path.isfile(aliceTokensFilename)
|
||||||
|
aliceSharedItemFederationTokens = loadJson(aliceTokensFilename)
|
||||||
|
assert aliceSharedItemFederationTokens
|
||||||
|
print('Alice shared item federation tokens:')
|
||||||
|
pprint(aliceSharedItemFederationTokens)
|
||||||
|
assert len(aliceSharedItemFederationTokens.items()) > 0
|
||||||
|
for hostStr, token in aliceSharedItemFederationTokens.items():
|
||||||
|
assert ':' in hostStr
|
||||||
alicePostLog = []
|
alicePostLog = []
|
||||||
alicePersonCache = {}
|
alicePersonCache = {}
|
||||||
aliceCachedWebfingers = {}
|
aliceCachedWebfingers = {}
|
||||||
|
aliceSharedItemsFederatedDomains = [bobAddress]
|
||||||
alicePostLog = []
|
alicePostLog = []
|
||||||
isArticle = False
|
isArticle = False
|
||||||
city = 'London, England'
|
city = 'London, England'
|
||||||
|
@ -1586,8 +1613,10 @@ def testSharedItemsFederation():
|
||||||
clientToServer, True,
|
clientToServer, True,
|
||||||
None, None, None, city, federationList,
|
None, None, None, city, federationList,
|
||||||
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
||||||
alicePersonCache, isArticle, systemLanguage, inReplyTo,
|
alicePersonCache, isArticle, systemLanguage,
|
||||||
inReplyToAtomUri, subject)
|
aliceSharedItemsFederatedDomains,
|
||||||
|
aliceSharedItemFederationTokens, True,
|
||||||
|
inReplyTo, inReplyToAtomUri, subject)
|
||||||
print('sendResult: ' + str(sendResult))
|
print('sendResult: ' + str(sendResult))
|
||||||
|
|
||||||
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
|
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
|
||||||
|
@ -1605,6 +1634,32 @@ def testSharedItemsFederation():
|
||||||
assert aliceMessageArrived is True
|
assert aliceMessageArrived is True
|
||||||
print('Message from Alice to Bob succeeded')
|
print('Message from Alice to Bob succeeded')
|
||||||
|
|
||||||
|
print('\n\n*********************************************************')
|
||||||
|
print('Check that Alice received the shared items authorization')
|
||||||
|
print('token from Bob')
|
||||||
|
aliceTokensFilename = \
|
||||||
|
aliceDir + '/accounts/sharedItemsFederationTokens.json'
|
||||||
|
bobTokensFilename = \
|
||||||
|
bobDir + '/accounts/sharedItemsFederationTokens.json'
|
||||||
|
assert os.path.isfile(aliceTokensFilename)
|
||||||
|
assert os.path.isfile(bobTokensFilename)
|
||||||
|
aliceTokens = loadJson(aliceTokensFilename)
|
||||||
|
assert aliceTokens
|
||||||
|
for hostStr, token in aliceTokens.items():
|
||||||
|
assert ':' in hostStr
|
||||||
|
assert aliceTokens.get(aliceAddress)
|
||||||
|
print('Alice tokens')
|
||||||
|
pprint(aliceTokens)
|
||||||
|
bobTokens = loadJson(bobTokensFilename)
|
||||||
|
assert bobTokens
|
||||||
|
for hostStr, token in bobTokens.items():
|
||||||
|
assert ':' in hostStr
|
||||||
|
assert bobTokens.get(bobAddress)
|
||||||
|
print("Check that Bob now has Alice's token")
|
||||||
|
assert bobTokens.get(aliceAddress)
|
||||||
|
print('Bob tokens')
|
||||||
|
pprint(bobTokens)
|
||||||
|
|
||||||
# stop the servers
|
# stop the servers
|
||||||
thrAlice.kill()
|
thrAlice.kill()
|
||||||
thrAlice.join()
|
thrAlice.join()
|
||||||
|
@ -1919,6 +1974,8 @@ def testGroupFollow():
|
||||||
alicePostLog = []
|
alicePostLog = []
|
||||||
alicePersonCache = {}
|
alicePersonCache = {}
|
||||||
aliceCachedWebfingers = {}
|
aliceCachedWebfingers = {}
|
||||||
|
aliceSharedItemsFederatedDomains = []
|
||||||
|
aliceSharedItemFederationTokens = {}
|
||||||
alicePostLog = []
|
alicePostLog = []
|
||||||
isArticle = False
|
isArticle = False
|
||||||
city = 'London, England'
|
city = 'London, England'
|
||||||
|
@ -1930,8 +1987,10 @@ def testGroupFollow():
|
||||||
saveToFile, clientToServer, True,
|
saveToFile, clientToServer, True,
|
||||||
None, None, None, city, federationList,
|
None, None, None, city, federationList,
|
||||||
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
|
||||||
alicePersonCache, isArticle, systemLanguage, inReplyTo,
|
alicePersonCache, isArticle, systemLanguage,
|
||||||
inReplyToAtomUri, subject)
|
aliceSharedItemsFederatedDomains,
|
||||||
|
aliceSharedItemFederationTokens,
|
||||||
|
inReplyTo, inReplyToAtomUri, subject)
|
||||||
print('sendResult: ' + str(sendResult))
|
print('sendResult: ' + str(sendResult))
|
||||||
|
|
||||||
queuePath = \
|
queuePath = \
|
||||||
|
@ -5047,7 +5106,8 @@ def _testAuthorizeSharedItems():
|
||||||
False, tokensJson)
|
False, tokensJson)
|
||||||
tokensJson = \
|
tokensJson = \
|
||||||
updateSharedItemFederationToken(None,
|
updateSharedItemFederationToken(None,
|
||||||
'dog.domain', 'testToken', tokensJson)
|
'dog.domain', 'testToken',
|
||||||
|
True, tokensJson)
|
||||||
assert tokensJson['dog.domain'] == 'testToken'
|
assert tokensJson['dog.domain'] == 'testToken'
|
||||||
|
|
||||||
# the shared item federation list changes
|
# the shared item federation list changes
|
||||||
|
|
Loading…
Reference in New Issue