2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								__filename__ = "auth.py"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								__author__ = "Bob Mottram"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								__license__ = "AGPL3+"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								__version__ = "1.1.0"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								__maintainer__ = "Bob Mottram"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								__email__ = "bob@freedombone.net"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								__status__ = "Production"
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import base64
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import hashlib
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import binascii
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import os
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:13:29 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import secrets
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-23 09:51:26 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from utils import isSystemAccount
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-23 10:57:44 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from utils import hasUsersPath
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def _hashPassword(password: str) -> str:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """Hash a password for storing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pwdhash = hashlib.pbkdf2_hmac('sha512',
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                  password.encode('utf-8'),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                  salt, 100000)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    pwdhash = binascii.hexlify(pwdhash)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return (salt + pwdhash).decode('ascii')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def _getPasswordHash(salt: str, providedPassword: str) -> str:
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:07:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Returns the hash of a password
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pwdhash = hashlib.pbkdf2_hmac('sha512',
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                  providedPassword.encode('utf-8'),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                  salt.encode('ascii'),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                  100000)
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:07:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return binascii.hexlify(pwdhash).decode('ascii')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:13:29 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:48:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def constantTimeStringCheck(string1: str, string2: str) -> bool:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """Compares two string and returns if they are the same
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    using a constant amount of time
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    See https://sqreen.github.io/DevelopersSecurityBestPractices/
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    timing-attack/python
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:07:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:48:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # strings must be of equal length
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if len(string1) != len(string2):
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:07:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ctr = 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    matched = True
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:48:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    for ch in string1:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if ch != string2[ctr]:
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:07:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            matched = False
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:13:29 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # this is to make the timing more even
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # and not provide clues
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            matched = matched
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:07:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        ctr += 1
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return matched
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def _verifyPassword(storedPassword: str, providedPassword: str) -> bool:
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:48:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Verify a stored password against one provided by user
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if not storedPassword:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if not providedPassword:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    salt = storedPassword[:64]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    storedPassword = storedPassword[64:]
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pwHash = _getPasswordHash(salt, providedPassword)
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 18:48:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return constantTimeStringCheck(pwHash, storedPassword)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def createBasicAuthHeader(nickname: str, password: str) -> str:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """This is only used by tests
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    authStr = \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        nickname.replace('\n', '').replace('\r', '') + \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ':' + \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        password.replace('\n', '').replace('\r', '')
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return 'Basic ' + base64.b64encode(authStr.encode('utf-8')).decode('utf-8')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def authorizeBasic(baseDir: str, path: str, authHeader: str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                   debug: bool) -> bool:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """HTTP basic auth
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ' ' not in authHeader:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-23 09:51:26 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            print('DEBUG: basic auth - Authorixation header does not ' +
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-30 19:09:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                  'contain a space character')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-23 10:57:44 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not hasUsersPath(path):
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-23 09:51:26 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            print('DEBUG: basic auth - ' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                  'path for Authorization does not contain a user')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pathUsersSection = path.split('/users/')[1]
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if '/' not in pathUsersSection:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-23 09:51:26 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            print('DEBUG: basic auth - this is not a users endpoint')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    nicknameFromPath = pathUsersSection.split('/')[0]
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-23 09:51:26 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if isSystemAccount(nicknameFromPath):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        print('basic auth - attempted login using system account ' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              nicknameFromPath + ' in path')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    base64Str = \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        authHeader.split(' ')[1].replace('\n', '').replace('\r', '')
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    plain = base64.b64decode(base64Str).decode('utf-8')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ':' not in plain:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-23 10:18:52 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            print('DEBUG: basic auth header does not contain a ":" ' +
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-30 19:09:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                  'separator for username:password')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    nickname = plain.split(':')[0]
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-23 09:51:26 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if isSystemAccount(nickname):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        print('basic auth - attempted login using system account ' + nickname +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              ' in Auth header')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if nickname != nicknameFromPath:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            print('DEBUG: Nickname given in the path (' + nicknameFromPath +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                  ') does not match the one in the Authorization header (' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                  nickname + ')')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    passwordFile = baseDir+'/accounts/passwords'
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if not os.path.isfile(passwordFile):
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if debug:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            print('DEBUG: passwords file missing')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    providedPassword = plain.split(':')[1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    passfile = open(passwordFile, "r")
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    for line in passfile:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if line.startswith(nickname+':'):
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            storedPassword = \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                line.split(':')[1].replace('\n', '').replace('\r', '')
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            success = _verifyPassword(storedPassword, providedPassword)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if not success:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    print('DEBUG: Password check failed for ' + nickname)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-04 08:56:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return success
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    print('DEBUG: Did not find credentials for ' + nickname +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          ' in ' + passwordFile)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return False
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def storeBasicCredentials(baseDir: str, nickname: str, password: str) -> bool:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-05 09:51:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Stores login credentials to a file
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ':' in nickname or ':' in password:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    nickname = nickname.replace('\n', '').replace('\r', '').strip()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    password = password.replace('\n', '').replace('\r', '').strip()
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not os.path.isdir(baseDir + '/accounts'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        os.mkdir(baseDir + '/accounts')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    passwordFile = baseDir + '/accounts/passwords'
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    storeStr = nickname + ':' + _hashPassword(password)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if os.path.isfile(passwordFile):
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if nickname + ':' in open(passwordFile).read():
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            with open(passwordFile, "r") as fin:
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-29 11:14:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                with open(passwordFile + '.new', 'w+') as fout:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    for line in fin:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        if not line.startswith(nickname + ':'):
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                            fout.write(line)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        else:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                            fout.write(storeStr + '\n')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            os.rename(passwordFile + '.new', passwordFile)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # append to password file
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-20 11:34:39 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            with open(passwordFile, 'a+') as passfile:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                passfile.write(storeStr + '\n')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-29 11:14:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        with open(passwordFile, 'w+') as passfile:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            passfile.write(storeStr + '\n')
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return True
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def removePassword(baseDir: str, nickname: str) -> None:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-05 09:51:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Removes the password entry for the given nickname
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    This is called during account removal
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    passwordFile = baseDir + '/accounts/passwords'
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-05 09:49:57 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if os.path.isfile(passwordFile):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        with open(passwordFile, "r") as fin:
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-29 11:14:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            with open(passwordFile + '.new', 'w+') as fout:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-05 09:49:57 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                for line in fin:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    if not line.startswith(nickname + ':'):
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-05 09:49:57 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        fout.write(line)
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        os.rename(passwordFile + '.new', passwordFile)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-05 09:49:57 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def authorize(baseDir: str, path: str, authHeader: str, debug: bool) -> bool:
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-05 09:51:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Authorize using http header
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if authHeader.lower().startswith('basic '):
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return authorizeBasic(baseDir, path, authHeader, debug)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-03 18:24:44 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return False
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-05 11:27:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-05 11:27:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def createPassword(length=10):
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-01 19:29:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    validChars = 'abcdefghijklmnopqrstuvwxyz' + \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-08 15:09:27 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return ''.join((secrets.choice(validChars) for i in range(length)))
							 |