Fixed Crypto errors and uncaught exceptions
The crypto salt file is no longer a thing. Now the salt is merely appended to the `crypt_file` as the last sixteen bytes. The salt is read from the end of the `crypt_file` on subsequent decryptions. Added a setting for enabling 'debug' mode, using `pdb` for dynamic debugging in pappy sessions. When needing to debug a function, or set of functionality add the conditional `if config.debug`, then set an entry point for `pdb` using `import pdb; pdb.set_trace()` May remove this functionality if not desired in the main project.
This commit is contained in:
parent
2df463fc79
commit
976287a67b
3 changed files with 46 additions and 33 deletions
|
@ -164,6 +164,7 @@ class PappyConfig(object):
|
||||||
self.global_config_dict = {}
|
self.global_config_dict = {}
|
||||||
|
|
||||||
self.archive = 'project.archive'
|
self.archive = 'project.archive'
|
||||||
|
self.debug = False
|
||||||
self.crypt_dir = 'crypt'
|
self.crypt_dir = 'crypt'
|
||||||
self.crypt_file = 'project.crypt'
|
self.crypt_file = 'project.crypt'
|
||||||
self.crypt_session = False
|
self.crypt_session = False
|
||||||
|
|
|
@ -32,28 +32,33 @@ class Crypto(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Leave the crypto working directory
|
# Leave the crypto working directory
|
||||||
os.chdir('../')
|
if self.config.crypt_dir in os.getcwd():
|
||||||
|
os.chdir('../')
|
||||||
|
|
||||||
self.compressor.compress_project()
|
self.compressor.compress_project()
|
||||||
|
|
||||||
|
# Get the password and salt, then derive the key
|
||||||
|
self.crypto_ramp_up()
|
||||||
|
|
||||||
# Create project and crypto archive
|
# Create project and crypto archive
|
||||||
archive_file = open(self.archive, 'rb')
|
archive_file = open(self.archive, 'rb')
|
||||||
archive_crypt = open(self.config.crypt_file, 'wb')
|
archive_crypt = open(self.config.crypt_file, 'wb')
|
||||||
|
|
||||||
# Get the password and salt, then derive the key
|
try:
|
||||||
self.crypto_ramp_up()
|
# Encrypt the archive read as a bytestring
|
||||||
|
fern = Fernet(self.key)
|
||||||
# Encrypt the archive read as a bytestring
|
crypt_token = fern.encrypt(archive_file.read())
|
||||||
fern = Fernet(self.key)
|
archive_crypt.write(crypt_token)
|
||||||
crypt_token = fern.encrypt(archive_file.read())
|
except InvalidToken as e:
|
||||||
archive_crypt.write(crypt_token)
|
raise PappyException("Error encrypting project: ", e)
|
||||||
|
return False
|
||||||
# Store the salt for the next decryption
|
|
||||||
self.create_salt_file()
|
|
||||||
|
|
||||||
archive_file.close()
|
archive_file.close()
|
||||||
archive_crypt.close()
|
archive_crypt.close()
|
||||||
|
|
||||||
|
# Store the salt for the next decryption
|
||||||
|
self.create_salt_file()
|
||||||
|
|
||||||
# Delete clear-text files
|
# Delete clear-text files
|
||||||
self.delete_clear_files()
|
self.delete_clear_files()
|
||||||
return True
|
return True
|
||||||
|
@ -79,6 +84,7 @@ class Crypto(object):
|
||||||
cf = self.config.crypt_file
|
cf = self.config.crypt_file
|
||||||
sl = self.config.salt_len
|
sl = self.config.salt_len
|
||||||
crl = os.path.getsize(cf) - sl
|
crl = os.path.getsize(cf) - sl
|
||||||
|
|
||||||
archive_crypt = open(cf, 'rb').read(crl)
|
archive_crypt = open(cf, 'rb').read(crl)
|
||||||
archive_file = open(self.config.archive, 'wb')
|
archive_file = open(self.config.archive, 'wb')
|
||||||
|
|
||||||
|
@ -89,18 +95,16 @@ class Crypto(object):
|
||||||
fern = Fernet(self.key)
|
fern = Fernet(self.key)
|
||||||
archive = fern.decrypt(archive_crypt)
|
archive = fern.decrypt(archive_crypt)
|
||||||
break
|
break
|
||||||
except InvalidToken:
|
except InvalidToken as e:
|
||||||
print "Invalid password"
|
print "Invalid decryption: ", e
|
||||||
retries -= 1
|
retries -= 1
|
||||||
# Quit pappy if user doesn't retry
|
# Quit pappy if user doesn't retry
|
||||||
# or if all retries exhuasted
|
# or if all retries exhuasted
|
||||||
if not self.confirm_password_retry() or retries <= 0:
|
if not self.confirm_password_retry() or retries <= 0:
|
||||||
self.config.crypt_success = False
|
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
self.password = None
|
self.password = None
|
||||||
self.key = None
|
self.key = None
|
||||||
self.salt = None
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
archive_file.write(archive)
|
archive_file.write(archive)
|
||||||
|
@ -112,7 +116,7 @@ class Crypto(object):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def confirm_password_retry(self):
|
def confirm_password_retry(self):
|
||||||
answer = raw_input("Re-enter your password? (y/n)").strip()
|
answer = raw_input("Re-enter your password? (y/n): ").strip()
|
||||||
if answer[0] == "y" or answer[0] == "Y":
|
if answer[0] == "y" or answer[0] == "Y":
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
@ -121,7 +125,8 @@ class Crypto(object):
|
||||||
def crypto_ramp_up(self):
|
def crypto_ramp_up(self):
|
||||||
if not self.password:
|
if not self.password:
|
||||||
self.get_password()
|
self.get_password()
|
||||||
self.set_salt()
|
if not self.salt:
|
||||||
|
self.set_salt()
|
||||||
self.derive_key()
|
self.derive_key()
|
||||||
|
|
||||||
def get_password(self):
|
def get_password(self):
|
||||||
|
@ -137,7 +142,11 @@ class Crypto(object):
|
||||||
raise PappyException("Invalid password, try again")
|
raise PappyException("Invalid password, try again")
|
||||||
|
|
||||||
def set_salt(self):
|
def set_salt(self):
|
||||||
if os.path.isfile(self.config.crypt_file):
|
if self.config.crypt_dir in os.getcwd():
|
||||||
|
os.chdir('../')
|
||||||
|
self.set_salt_from_file()
|
||||||
|
os.chdir(self.config.crypt_dir)
|
||||||
|
elif os.path.isfile(self.config.crypt_file):
|
||||||
self.set_salt_from_file()
|
self.set_salt_from_file()
|
||||||
else:
|
else:
|
||||||
self.salt = os.urandom(16)
|
self.salt = os.urandom(16)
|
||||||
|
@ -152,19 +161,17 @@ class Crypto(object):
|
||||||
# behavior.
|
# behavior.
|
||||||
salt_file = open(self.config.crypt_file, 'rb')
|
salt_file = open(self.config.crypt_file, 'rb')
|
||||||
sl = self.config.salt_len
|
sl = self.config.salt_len
|
||||||
salt_file.seek(sl, 2)
|
# Negate the salt length to seek to the
|
||||||
|
# correct position in the buffer
|
||||||
|
salt_file.seek(-sl, 2)
|
||||||
self.salt = salt_file.read(sl)
|
self.salt = salt_file.read(sl)
|
||||||
|
salt_file.close()
|
||||||
except:
|
except:
|
||||||
cf = self.config.crypt_file
|
cf = self.config.crypt_file
|
||||||
raise PappyException("Unable to read %s" % cf)
|
raise PappyException("Unable to read %s" % cf)
|
||||||
|
|
||||||
def create_salt_file(self):
|
def create_salt_file(self):
|
||||||
# WARNING: must open `crypt_file` in `wb` mode
|
salt_file = open(self.config.crypt_file, 'a')
|
||||||
# or `salt_file.seek()` will result in undefined
|
|
||||||
# behavior.
|
|
||||||
salt_file = open(self.config.crypt_file, 'wb')
|
|
||||||
# Seek to the end of the encrypted archive
|
|
||||||
salt_file.seek(0,2)
|
|
||||||
salt_file.write(self.salt)
|
salt_file.write(self.salt)
|
||||||
salt_file.close()
|
salt_file.close()
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,9 @@ class PappySession(object):
|
||||||
self.config.load_from_file('./config.json')
|
self.config.load_from_file('./config.json')
|
||||||
self.config.global_load_from_file()
|
self.config.global_load_from_file()
|
||||||
self.delete_data_on_quit = False
|
self.delete_data_on_quit = False
|
||||||
|
else:
|
||||||
|
self.complete_defer.callback(None)
|
||||||
|
return
|
||||||
|
|
||||||
# If the data file doesn't exist, create it with restricted permissions
|
# If the data file doesn't exist, create it with restricted permissions
|
||||||
if not os.path.isfile(self.config.datafile):
|
if not os.path.isfile(self.config.datafile):
|
||||||
|
@ -153,10 +156,7 @@ class PappySession(object):
|
||||||
if self.crypto.encrypt_project():
|
if self.crypto.encrypt_project():
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
errmsg = "There was an issue encrypting the project."
|
return False
|
||||||
raise PappyException(errmsg)
|
|
||||||
reactor.stop()
|
|
||||||
defer.returnValue(None)
|
|
||||||
|
|
||||||
def decrypt(self):
|
def decrypt(self):
|
||||||
# Attempt to decrypt project archive
|
# Attempt to decrypt project archive
|
||||||
|
@ -164,10 +164,7 @@ class PappySession(object):
|
||||||
return True
|
return True
|
||||||
# Quit pappy on failure
|
# Quit pappy on failure
|
||||||
else:
|
else:
|
||||||
errmsg = "There was an issue encrypting the project."
|
return False
|
||||||
raise PappyException(errmsg)
|
|
||||||
reactor.stop()
|
|
||||||
defer.returnValue(None)
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def cleanup(self, ignored=None):
|
def cleanup(self, ignored=None):
|
||||||
|
@ -187,6 +184,7 @@ def parse_args():
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='An intercepting proxy for testing web applications.')
|
parser = argparse.ArgumentParser(description='An intercepting proxy for testing web applications.')
|
||||||
parser.add_argument('-l', '--lite', help='Run the proxy in "lite" mode', action='store_true')
|
parser.add_argument('-l', '--lite', help='Run the proxy in "lite" mode', action='store_true')
|
||||||
|
parser.add_argument('-d', '--debug', help='Run the proxy in "debug" mode', action='store_true')
|
||||||
try:
|
try:
|
||||||
hlpmsg = ''.join(['Start pappy in "crypto" mode,',
|
hlpmsg = ''.join(['Start pappy in "crypto" mode,',
|
||||||
'must supply a name for the encrypted',
|
'must supply a name for the encrypted',
|
||||||
|
@ -211,6 +209,10 @@ def parse_args():
|
||||||
else:
|
else:
|
||||||
settings['crypt'] = None
|
settings['crypt'] = None
|
||||||
|
|
||||||
|
if args.debug:
|
||||||
|
settings['debug'] = True
|
||||||
|
else:
|
||||||
|
settings['debug'] = False
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
def set_text_factory(conn):
|
def set_text_factory(conn):
|
||||||
|
@ -257,6 +259,9 @@ def main():
|
||||||
pappy_config.global_load_from_file()
|
pappy_config.global_load_from_file()
|
||||||
session.delete_data_on_quit = False
|
session.delete_data_on_quit = False
|
||||||
|
|
||||||
|
if settings['debug']:
|
||||||
|
pappy_config.debug = True
|
||||||
|
|
||||||
yield session.start()
|
yield session.start()
|
||||||
|
|
||||||
session.complete_defer.addCallback(lambda ignored: reactor.stop())
|
session.complete_defer.addCallback(lambda ignored: reactor.stop())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue