Pep8 corrections

master
Nich 8 years ago
parent f5c53add9c
commit f7d8df69cc
  1. 31
      pappyproxy/compress.py
  2. 100
      pappyproxy/crypto.py
  3. 13
      pappyproxy/pappy.py

@ -14,7 +14,8 @@ except ImportError:
print "BZ2 not installed on your system"
from base64 import b64encode, b64decode
from os import getcwd, sep, path, urandom
from os import getcwd, sep, path, urandom
class Compress(object):
def __init__(self, sessconfig):
@ -27,17 +28,17 @@ class Compress(object):
self.tar_project()
else:
self.zip_project()
def decompress_project(self):
if bz2:
self.untar_project()
else:
self.unzip_project()
def zip_project(self):
"""
Zip project files
Using append mode (mode='a') will create a zip archive
if none exists in the project.
"""
@ -47,32 +48,32 @@ class Compress(object):
zf.close()
except zipfile.LargeZipFile as e:
raise PappyException("Project zipfile too large. Error: ", e)
def unzip_project(self):
"""
Extract project files from decrypted zip archive.
Initially checks the zip archive's magic number and
attempts to extract pappy.json to validate integrity
attempts to extract pappy.json to validate integrity
of the zipfile.
"""
if not zipfile.is_zipfile(self.zip_archive):
raise PappyException("Project archive corrupted.")
zf = zipfile.ZipFile(self.zip_archive)
try:
zf.extract("config.json")
except zipfile.BadZipfile as e:
raise PappyException("Project archive contents corrupted. Error: ", e)
raise PappyException("Zip archive corrupted. Error: ", e)
zf.extractall()
def tar_project(self):
archive = tarfile.open(self.bz2_archive, 'w:bz2')
archive.add(self.config.crypt_dir)
archive.close()
archive.close()
def untar_project(self):
if tarfile.is_tarfile(self.bz2_archive):
# Raise exception if there is a failure
@ -80,4 +81,4 @@ class Compress(object):
with tarfile.open(self.bz2_archive, "r:bz2") as archive:
archive.extractall()
except tarfile.ExtractError as e:
raise PappyException("Project archive contents corrupted. Error: ", e)
raise PappyException("Tar archive corrupted. Error: ", e)

@ -14,53 +14,55 @@ from base64 import b64encode, b64decode
from cryptography.fernet import Fernet, InvalidToken
from twisted.internet import reactor, defer
class Crypto(object):
def __init__(self, sessconfig):
self.config = sessconfig
self.archive = sessconfig.archive
self.archive = sessconfig.archive
self.compressor = compress.Compress(sessconfig)
self.key = None
self.password = None
self.salt = None
def encrypt_project(self):
"""
Compress and encrypt the project files, deleting clear-text files afterwards
Compress and encrypt the project files,
deleting clear-text files afterwards
"""
# Leave the crypto working directory
os.chdir('../')
self.compressor.compress_project()
# Create project and crypto archive
archive_file = open(self.archive, 'rb')
# 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()
archive_file.close()
archive_crypt.close()
# Delete clear-text files
self.delete_clear_files()
def decrypt_project(self):
"""
Decrypt and decompress the project files
"""
# If project hasn't been encrypted before, setup crypt working directory
# If project hasn't been encrypted before,
# setup crypt working directory
if not os.path.isfile(self.config.crypt_file):
os.mkdir(self.config.crypt_dir)
@ -69,17 +71,17 @@ class Crypto(object):
shutil.copy2(pf, self.config.crypt_dir)
os.chdir(self.config.crypt_dir)
return True
# Otherwise, decrypt and decompress the project
else:
# Otherwise, decrypt and decompress the project
else:
archive_crypt = open(self.config.crypt_file, 'rb').read()
archive_file = open(self.config.archive, 'wb')
retries = 3
while True:
try:
self.crypto_ramp_up()
fern = Fernet(self.key)
self.crypto_ramp_up()
fern = Fernet(self.key)
archive = fern.decrypt(archive_crypt)
break
except InvalidToken:
@ -93,35 +95,35 @@ class Crypto(object):
self.password = None
self.key = None
self.salt = None
pass
pass
archive_file.write(archive)
archive_file.close()
self.compressor.decompress_project()
# Force generation of new salt and crypt archive
self.delete_crypt_files()
os.chdir(self.config.crypt_dir)
return True
def confirm_password_retry(self):
answer = raw_input("Would you like to 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:
return False
def crypto_ramp_up(self):
if not self.password:
self.get_password()
self.set_salt()
self.derive_key()
def get_password(self):
"""
Retrieve password from the user. Raise an exception if the
Retrieve password from the user. Raise an exception if the
password is not capable of utf-8 encoding.
"""
encoded_passwd = ""
@ -130,75 +132,75 @@ class Crypto(object):
self.password = passwd.encode("utf-8")
except:
raise PappyException("Invalid password, try again")
def set_salt(self):
if os.path.isfile(self.config.salt_file):
self.set_salt_from_file()
else:
self.salt = os.urandom(16)
self.salt = os.urandom(16)
def set_salt_from_file(self):
try:
salt_file = open(self.config.salt_file, 'rb')
self.salt = salt_file.readline().strip()
except:
raise PappyException("Unable to read project.salt")
def create_salt_file(self):
salt_file = open(self.config.salt_file, 'wb')
salt_file.write(self.salt)
salt_file.close()
def derive_key(self):
"""
Derive a key sufficient for use as a cryptographic key
used to encrypt the project (currently: cryptography.Fernet).
cryptography.Fernet utilizes AES-CBC-128, requiring a 32-byte key.
Parameter notes from the py-scrypt source-code:
https://bitbucket.org/mhallin/py-scrypt/
Compute scrypt(password, salt, N, r, p, buflen).
The parameters r, p, and buflen must satisfy r * p < 2^30 and
buflen <= (2^32 - 1) * 32. The parameter N must be a power of 2
greater than 1. N, r and p must all be positive.
Notes for Python 2:
- `password` and `salt` must be str instances
- The result will be a str instance
Notes for Python 3:
- `password` and `salt` can be both str and bytes. If they are str
instances, they wil be encoded with utf-8.
- The result will be a bytes instance
Exceptions raised:
- TypeError on invalid input
- scrypt.error if scrypt failed
"""
try:
if not self.key:
self.key = b64encode(scrypt.hash(self.password, self.salt, buflen=32))
shash = scrypt.hash(self.password, self.salt, buflen=32)
self.key = b64encode(shash)
except TypeError as e:
raise PappyException("Scrypt failed with type error: ", e)
except scrypt.error, e:
raise PappyException("Scrypt failed with internal error: ", e)
def delete_clear_files(self):
"""
Deletes all clear-text files left in the project directory.
"""
shutil.rmtree(self.config.crypt_dir)
os.remove(self.config.archive)
def delete_crypt_files(self):
"""
Deletes all encrypted-text files in the project directory.
Forces generation of new salt after opening and closing the project.
Adds security in the case of a one-time compromise of the system.
"""
#os.remove(self.config.salt_file)
os.remove(self.config.crypt_file)

@ -159,9 +159,9 @@ class PappySession(object):
yield True
# Quit pappy on failure
else:
reactor.stop()
reactor.stop()
defer.returnValue(None)
@defer.inlineCallbacks
def cleanup(self, ignored=None):
for port in self.ports:
@ -181,10 +181,13 @@ 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')
try:
parser.add_argument('-c', '--crypt', type=str, nargs=1, help='Start pappy in "crypto" mode, must supply a name for the encrypted project archive [CRYPT]')
hlpmsg = 'Start pappy in "crypto" mode,'+
'must supply a name for the encrypted'+
'project archive [CRYPT]'
parser.add_argument('-c', '--crypt', type=str, nargs=1, help=hlpmsg)
except:
print 'Must supply a project name: pappy -c <project_name>'
reactor.stop()
reactor.stop()
defer.returnValue(None)
args = parser.parse_args(sys.argv[1:])
@ -197,7 +200,7 @@ def parse_args():
if args.crypt:
# Convert from single-item list produced by argparse `nargs=1`
settings['crypt'] = args.crypt[0].encode('utf-8')
settings['crypt'] = args.crypt[0].encode('utf-8')
else:
settings['crypt'] = None

Loading…
Cancel
Save