diff --git a/auth.py b/auth.py index 5103365f3..893f814bd 100644 --- a/auth.py +++ b/auth.py @@ -89,7 +89,7 @@ def authorizeBasic(baseDir: str, path: str, authHeader: str, """ if ' ' not in authHeader: if debug: - print('DEBUG: basic auth - Authorixation header does not ' + + print('DEBUG: basic auth - Authorisation header does not ' + 'contain a space character') return False if not hasUsersPath(path): @@ -147,6 +147,61 @@ def authorizeBasic(baseDir: str, path: str, authHeader: str, return False +def authorizeDFC(sharedItemsFederatedDomains: [], + baseDir: str, + callingDomain: str, + authHeader: str, + debug: bool) -> bool: + """HTTP basic auth for shared item federation + """ + if callingDomain not in sharedItemsFederatedDomains: + if debug: + print(callingDomain + + ' is not in the shared items federation list') + return False + if 'Basic ' not in authHeader: + if debug: + print('DEBUG: DFC basic auth - Authorisation header does not ' + + 'contain a space character') + return False + base64Str = \ + authHeader.split(' ')[1].replace('\n', '').replace('\r', '') + plain = base64.b64decode(base64Str).decode('utf-8') + if ':' not in plain: + if debug: + print('DEBUG: DFC basic auth header does not contain a ":" ' + + 'separator for username:password') + return False + basicAuthDomain = plain.split(':')[0] + if basicAuthDomain != callingDomain: + if debug: + print('DEBUG: DFC calling domain does not match ' + + 'the one in the Authorization header (' + + basicAuthDomain + ')') + return False + passwordFile = baseDir + '/accounts/sharedItemsFederationTokens' + if not os.path.isfile(passwordFile): + if debug: + print('DEBUG: shared item federation tokens file missing ' + + passwordFile) + return False + providedPassword = plain.split(':')[1] + passfile = open(passwordFile, 'r') + for line in passfile: + if line.startswith(basicAuthDomain + ':'): + storedPassword = \ + line.split(':')[1].replace('\n', '').replace('\r', '') + success = _verifyPassword(storedPassword, providedPassword) + if not success: + if debug: + print('DEBUG: DFC password check failed for ' + + basicAuthDomain) + return success + print('DEBUG: DFC did not find credentials for ' + basicAuthDomain + + ' in ' + passwordFile) + return False + + def storeBasicCredentials(baseDir: str, nickname: str, password: str) -> bool: """Stores login credentials to a file """ diff --git a/daemon.py b/daemon.py index 5b110b177..17793de0a 100644 --- a/daemon.py +++ b/daemon.py @@ -105,6 +105,7 @@ from skills import actorSkillValue from skills import setActorSkillLevel from auth import recordLoginFailure from auth import authorize +from auth import authorizeDFC from auth import createPassword from auth import createBasicAuthHeader from auth import authorizeBasic @@ -10671,11 +10672,13 @@ class PubServer(BaseHTTPRequestHandler): if authorized: catalogAuthorized = True else: - # basic auth access to catalog + # basic auth access to shared items catalog if self.headers.get('Authorization'): - if authorize(self.server.baseDir, self.path, - self.headers['Authorization'], - self.server.debug): + if authorizeDFC(self.server.sharedItemsFederatedDomains, + self.server.baseDir, + callingDomain, + self.headers['Authorization'], + self.server.debug): catalogAuthorized = True # show shared items DFC catalog if self._hasAccept(callingDomain) and catalogAuthorized: @@ -14808,7 +14811,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None: break -def runDaemon(userAgentsBlocked: [], +def runDaemon(sharedItemsFederatedDomains: [], + userAgentsBlocked: [], logLoginFailures: bool, city: str, showNodeInfoAccounts: bool, @@ -15067,6 +15071,7 @@ def runDaemon(userAgentsBlocked: [], httpd.httpPrefix = httpPrefix httpd.debug = debug httpd.federationList = fedList.copy() + httpd.sharedItemsFederatedDomains = sharedItemsFederatedDomains.copy() httpd.baseDir = baseDir httpd.instanceId = instanceId httpd.personCache = {} diff --git a/epicyon.py b/epicyon.py index f65c29786..6c8fa6c3f 100644 --- a/epicyon.py +++ b/epicyon.py @@ -264,6 +264,10 @@ parser.add_argument('--rss', dest='rss', type=str, default=None, help='Show an rss feed for a given url') parser.add_argument('-f', '--federate', nargs='+', dest='federationList', help='Specify federation list separated by spaces') +parser.add_argument('--federateshares', nargs='+', + dest='sharedItemsFederatedDomains', + help='Specify federation list for shared items, ' + + 'separated by spaces') parser.add_argument("--following", "--followingList", dest='followingList', type=str2bool, nargs='?', @@ -1024,6 +1028,16 @@ else: if configFederationList: federationList = configFederationList +sharedItemsFederatedDomains = [] +if args.sharedItemsFederatedDomains: + setConfigParam(baseDir, 'sharedItemsFederatedDomains', + sharedItemsFederatedDomains) +else: + configSharedItemsFederatedDomains = \ + getConfigParam(baseDir, 'sharedItemsFederatedDomains') + if configSharedItemsFederatedDomains: + sharedItemsFederatedDomains = configSharedItemsFederatedDomains + proxyType = None if args.tor or domain.endswith('.onion'): proxyType = 'tor' @@ -2142,6 +2156,9 @@ if args.desktop: if federationList: print('Federating with: ' + str(federationList)) +if sharedItemsFederatedDomains: + print('Federating shared items with: ' + + str(sharedItemsFederatedDomains)) if args.block: if not nickname: @@ -2657,7 +2674,8 @@ if args.registration: print('New registrations closed') if __name__ == "__main__": - runDaemon(userAgentsBlocked, + runDaemon(sharedItemsFederatedDomains, + userAgentsBlocked, args.logLoginFailures, args.city, args.showNodeInfoAccounts, diff --git a/tests.py b/tests.py index c8f3b3b54..0e79f10bd 100644 --- a/tests.py +++ b/tests.py @@ -457,6 +457,7 @@ def createServerAlice(path: str, domain: str, port: int, shutil.rmtree(path) os.mkdir(path) os.chdir(path) + sharedItemsFederatedDomains = [] systemLanguage = 'en' nickname = 'alice' httpPrefix = 'http' @@ -554,7 +555,8 @@ def createServerAlice(path: str, domain: str, port: int, logLoginFailures = False userAgentsBlocked = [] print('Server running: Alice') - runDaemon(userAgentsBlocked, + runDaemon(sharedItemsFederatedDomains, + userAgentsBlocked, logLoginFailures, city, showNodeInfoAccounts, showNodeInfoVersion, @@ -585,6 +587,7 @@ def createServerBob(path: str, domain: str, port: int, shutil.rmtree(path) os.mkdir(path) os.chdir(path) + sharedItemsFederatedDomains = [] systemLanguage = 'en' nickname = 'bob' httpPrefix = 'http' @@ -680,7 +683,8 @@ def createServerBob(path: str, domain: str, port: int, logLoginFailures = False userAgentsBlocked = [] print('Server running: Bob') - runDaemon(userAgentsBlocked, + runDaemon(sharedItemsFederatedDomains, + userAgentsBlocked, logLoginFailures, city, showNodeInfoAccounts, showNodeInfoVersion, @@ -710,6 +714,7 @@ def createServerEve(path: str, domain: str, port: int, federationList: [], shutil.rmtree(path) os.mkdir(path) os.chdir(path) + sharedItemsFederatedDomains = [] nickname = 'eve' httpPrefix = 'http' proxyType = None @@ -740,7 +745,8 @@ def createServerEve(path: str, domain: str, port: int, federationList: [], logLoginFailures = False userAgentsBlocked = [] print('Server running: Eve') - runDaemon(userAgentsBlocked, + runDaemon(sharedItemsFederatedDomains, + userAgentsBlocked, logLoginFailures, city, showNodeInfoAccounts, showNodeInfoVersion,