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.archive = 'project.archive'
|
||||
self.debug = False
|
||||
self.crypt_dir = 'crypt'
|
||||
self.crypt_file = 'project.crypt'
|
||||
self.crypt_session = False
|
||||
|
|
|
@ -32,28 +32,33 @@ class Crypto(object):
|
|||
"""
|
||||
|
||||
# Leave the crypto working directory
|
||||
os.chdir('../')
|
||||
if self.config.crypt_dir in os.getcwd():
|
||||
os.chdir('../')
|
||||
|
||||
self.compressor.compress_project()
|
||||
|
||||
# Get the password and salt, then derive the key
|
||||
self.crypto_ramp_up()
|
||||
|
||||
# Create project and crypto archive
|
||||
archive_file = open(self.archive, 'rb')
|
||||
archive_crypt = open(self.config.crypt_file, 'wb')
|
||||
|
||||
# Get the password and salt, then derive the key
|
||||
self.crypto_ramp_up()
|
||||
|
||||
# Encrypt the archive read as a bytestring
|
||||
fern = Fernet(self.key)
|
||||
crypt_token = fern.encrypt(archive_file.read())
|
||||
archive_crypt.write(crypt_token)
|
||||
|
||||
# Store the salt for the next decryption
|
||||
self.create_salt_file()
|
||||
try:
|
||||
# Encrypt the archive read as a bytestring
|
||||
fern = Fernet(self.key)
|
||||
crypt_token = fern.encrypt(archive_file.read())
|
||||
archive_crypt.write(crypt_token)
|
||||
except InvalidToken as e:
|
||||
raise PappyException("Error encrypting project: ", e)
|
||||
return False
|
||||
|
||||
archive_file.close()
|
||||
archive_crypt.close()
|
||||
|
||||
# Store the salt for the next decryption
|
||||
self.create_salt_file()
|
||||
|
||||
# Delete clear-text files
|
||||
self.delete_clear_files()
|
||||
return True
|
||||
|
@ -79,6 +84,7 @@ class Crypto(object):
|
|||
cf = self.config.crypt_file
|
||||
sl = self.config.salt_len
|
||||
crl = os.path.getsize(cf) - sl
|
||||
|
||||
archive_crypt = open(cf, 'rb').read(crl)
|
||||
archive_file = open(self.config.archive, 'wb')
|
||||
|
||||
|
@ -89,18 +95,16 @@ class Crypto(object):
|
|||
fern = Fernet(self.key)
|
||||
archive = fern.decrypt(archive_crypt)
|
||||
break
|
||||
except InvalidToken:
|
||||
print "Invalid password"
|
||||
except InvalidToken as e:
|
||||
print "Invalid decryption: ", e
|
||||
retries -= 1
|
||||
# Quit pappy if user doesn't retry
|
||||
# or if all retries exhuasted
|
||||
if not self.confirm_password_retry() or retries <= 0:
|
||||
self.config.crypt_success = False
|
||||
return False
|
||||
else:
|
||||
self.password = None
|
||||
self.key = None
|
||||
self.salt = None
|
||||
pass
|
||||
|
||||
archive_file.write(archive)
|
||||
|
@ -112,7 +116,7 @@ class Crypto(object):
|
|||
return True
|
||||
|
||||
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":
|
||||
return True
|
||||
else:
|
||||
|
@ -121,7 +125,8 @@ class Crypto(object):
|
|||
def crypto_ramp_up(self):
|
||||
if not self.password:
|
||||
self.get_password()
|
||||
self.set_salt()
|
||||
if not self.salt:
|
||||
self.set_salt()
|
||||
self.derive_key()
|
||||
|
||||
def get_password(self):
|
||||
|
@ -137,7 +142,11 @@ class Crypto(object):
|
|||
raise PappyException("Invalid password, try again")
|
||||
|
||||
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()
|
||||
else:
|
||||
self.salt = os.urandom(16)
|
||||
|
@ -152,19 +161,17 @@ class Crypto(object):
|
|||
# behavior.
|
||||
salt_file = open(self.config.crypt_file, 'rb')
|
||||
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)
|
||||
salt_file.close()
|
||||
except:
|
||||
cf = self.config.crypt_file
|
||||
raise PappyException("Unable to read %s" % cf)
|
||||
|
||||
def create_salt_file(self):
|
||||
# WARNING: must open `crypt_file` in `wb` mode
|
||||
# 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 = open(self.config.crypt_file, 'a')
|
||||
salt_file.write(self.salt)
|
||||
salt_file.close()
|
||||
|
||||
|
|
|
@ -76,6 +76,9 @@ class PappySession(object):
|
|||
self.config.load_from_file('./config.json')
|
||||
self.config.global_load_from_file()
|
||||
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 not os.path.isfile(self.config.datafile):
|
||||
|
@ -153,10 +156,7 @@ class PappySession(object):
|
|||
if self.crypto.encrypt_project():
|
||||
return True
|
||||
else:
|
||||
errmsg = "There was an issue encrypting the project."
|
||||
raise PappyException(errmsg)
|
||||
reactor.stop()
|
||||
defer.returnValue(None)
|
||||
return False
|
||||
|
||||
def decrypt(self):
|
||||
# Attempt to decrypt project archive
|
||||
|
@ -164,10 +164,7 @@ class PappySession(object):
|
|||
return True
|
||||
# Quit pappy on failure
|
||||
else:
|
||||
errmsg = "There was an issue encrypting the project."
|
||||
raise PappyException(errmsg)
|
||||
reactor.stop()
|
||||
defer.returnValue(None)
|
||||
return False
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def cleanup(self, ignored=None):
|
||||
|
@ -187,6 +184,7 @@ def parse_args():
|
|||
|
||||
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('-d', '--debug', help='Run the proxy in "debug" mode', action='store_true')
|
||||
try:
|
||||
hlpmsg = ''.join(['Start pappy in "crypto" mode,',
|
||||
'must supply a name for the encrypted',
|
||||
|
@ -211,6 +209,10 @@ def parse_args():
|
|||
else:
|
||||
settings['crypt'] = None
|
||||
|
||||
if args.debug:
|
||||
settings['debug'] = True
|
||||
else:
|
||||
settings['debug'] = False
|
||||
return settings
|
||||
|
||||
def set_text_factory(conn):
|
||||
|
@ -257,6 +259,9 @@ def main():
|
|||
pappy_config.global_load_from_file()
|
||||
session.delete_data_on_quit = False
|
||||
|
||||
if settings['debug']:
|
||||
pappy_config.debug = True
|
||||
|
||||
yield session.start()
|
||||
|
||||
session.complete_defer.addCallback(lambda ignored: reactor.stop())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue