Skip to content

Commit

Permalink
Merge pull request #6 from phenobarbital/new-cypher-capabilities
Browse files Browse the repository at this point in the history
New cypher capabilities
  • Loading branch information
phenobarbital authored Apr 20, 2022
2 parents 4dd9958 + 022dffa commit 2f904c2
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.7.8
current_version = 0.8.0
commit = False
tag = True
tag_name = {new_version}
Expand Down
40 changes: 40 additions & 0 deletions examples/encrypt_env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import os
import asyncio
from navconfig import (
SITE_ROOT,
config,
DEBUG
)
import logging
from navconfig.cyphers import FileCypher
from dotenv import load_dotenv, dotenv_values

async def cypher():
path = SITE_ROOT.joinpath('env')
fc = FileCypher(path)
# first: create the key:
await fc.create_key()
# then, encrypt the file:
file = await fc.encrypt(name = '.env')
print(f'Encrypted ENV was saved to {file}')

async def test_cypher():
path = SITE_ROOT.joinpath('env')
fc = FileCypher(path)
file = await fc.decrypt(name = 'env.crypt')
print(file)

async def test_env():
path = SITE_ROOT.joinpath('env')
fc = FileCypher(path)
file = await fc.decrypt(name = 'env.crypt')
print(file)
load_dotenv(
stream=file
)
print(os.getenv('ADFS_SERVER'))

if __name__ == '__main__':
asyncio.run(cypher())
asyncio.run(test_cypher())
asyncio.run(test_env())
26 changes: 26 additions & 0 deletions examples/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Import Config Class
from navconfig import (
BASE_DIR,
config,
DEBUG
)
from navconfig.logging import (
logging
)

"""
Routes
"""
APP_NAME = config.get('APP_NAME', fallback='Navigator')
APP_DIR = BASE_DIR.joinpath("apps")

logging.debug(f'::: STARTING APP: {APP_NAME} in path: {APP_DIR} ::: ')
print(f'STARTING WITH DEBUG: {DEBUG}')

PRODUCTION = config.get('PRODUCTION')
ALLOWED_HOSTS = [
e.strip()
for e in list(config.get("ALLOWED_HOSTS", section="auth", fallback="localhost*").split(","))
]
print(f'Allowed HOSTS: {ALLOWED_HOSTS}')
print(f'Production: {PRODUCTION}')
5 changes: 4 additions & 1 deletion navconfig/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,13 @@ def is_virtualenv():

SETTINGS_DIR = BASE_DIR.joinpath('settings')

# configuration of the environment type:
ENV_TYPE = os.getenv('ENV_TYPE', 'file')

"""
Loading main Configuration Object.
"""
config = navigatorConfig(SITE_ROOT)
config = navigatorConfig(SITE_ROOT, env_type = ENV_TYPE)
ENV = config.ENV

# DEBUG VERSION
Expand Down
32 changes: 28 additions & 4 deletions navconfig/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import ast
import asyncio
from distutils.util import strtobool
import importlib
import sys
Expand All @@ -23,6 +24,7 @@
Union,
List
)
from navconfig.cyphers import FileCypher


class mredis(object):
Expand Down Expand Up @@ -191,7 +193,7 @@ class navigatorConfig(metaclass=Singleton):
_conffile: str = 'etc/config.ini'
__initialized = False

def __init__(self, site_root: str = None, env: str = None):
def __init__(self, site_root: str = None, env: str = None, *args, **kwargs):
if self.__initialized is True:
return
self.__initialized = True
Expand All @@ -211,7 +213,7 @@ def __init__(self, site_root: str = None, env: str = None):
except Exception as err:
raise
# then: configure the instance:
self.configure(env)
self.configure(env, **kwargs)

def __del__(self):
try:
Expand All @@ -232,7 +234,6 @@ def configure(self, env: str = None, env_type: str = 'file', override: bool = Fa
environment = os.getenv('ENV', '')
self.ENV = environment
# getting type of enviroment consumer:
env_type = os.getenv('NAVCONFIG_ENV', env_type) # file by default
try:
self.load_enviroment(env_type, override=override)
except FileNotFoundError:
Expand Down Expand Up @@ -273,7 +274,30 @@ def load_enviroment(self, env_type: str = 'file', file: Union[str, Path] = None,
"""
Load an environment from a File or any pluggable Origin.
"""
if env_type == 'file':
if env_type == 'crypt':
loop = asyncio.get_event_loop()
# TODO: load dynamically
env_path = self.site_root.joinpath('env', self.ENV)
logging.debug(f'Environment File: {env_path!s}')
fc = FileCypher(directory = env_path)
if not env_path.exists():
raise FileExistsError(
f'No Directory Path: {env_path}'
)
try:
decrypted = asyncio.run(
fc.decrypt(name = 'env.crypt')
)
load_dotenv(
stream=decrypted,
override=override
)
except FileNotFoundError:
raise
except Exception as err:
print(err)
raise
elif env_type == 'file':
env_path = self.site_root.joinpath('env', self.ENV, '.env')
logging.debug(f'Environment File: {env_path!s}')
# warning if env_path is an empty file or doesn't exists
Expand Down
3 changes: 3 additions & 0 deletions navconfig/cyphers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .fernet import FileCypher

__all__ = ('FileCypher', )
78 changes: 78 additions & 0 deletions navconfig/cyphers/fernet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import hashlib
import aiofiles
from cryptography.fernet import Fernet
from pathlib import PurePath, PosixPath
from io import StringIO


class FileCypher(object):
def __init__(self, directory: PurePath):
self.path = directory

async def create_key(self):
#generate the key
key = Fernet.generate_key()
file = self.path.joinpath('unlock.key')
#string the key into a file
async with aiofiles.open(file, 'wb') as unlock:
await unlock.write(key)
return file

async def open_file(self, path: PurePath):
content = None
if not path.exists():
raise FileNotFoundError(
f'File {path} does not exist'
)
try:
async with aiofiles.open(path) as f:
content = await f.read()
except IOError:
raise Exception(
f'NavConfig: Error loading Environment File {path}'
)
return content

async def save_file(self, path: PurePath, content):
async with aiofiles.open(path, 'wb') as file:
await file.write(content)

async def get_key(self):
fkey = self.path.joinpath('unlock.key')
key = None
async with aiofiles.open(fkey) as f:
key = await f.read()
if not key:
raise Exception(
f'Missing the Unlock Key: {fkey!s}'
)
#use the generated key
f = Fernet(key)
return f

async def encrypt(self, name: str = '.env'):
#use the generated key
f = await self.get_key()
file = self.path.joinpath(name)
# original content
original = await self.open_file(file)
#encrypt the file
encrypted = f.encrypt(original.encode())
# at now, save it into the same directory
file = self.path.joinpath('env.crypt')
await self.save_file(file, encrypted)
return file

async def decrypt(self, name: str = 'env.crypt'):
#use the generated key
f = await self.get_key()
#open the original file to encrypt
file = self.path.joinpath(name)
content = await self.open_file(file)
#decrypt the file
decrypted = f.decrypt(content.encode())
s = StringIO()
s.write(decrypted.decode())
s.seek(0)
# returned a StringIO
return s
2 changes: 1 addition & 1 deletion navconfig/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
__title__ = 'navconfig'
__description__ = ('Configuration tool for all Navigator Services '
'Tool for accessing Config info from different sources.')
__version__ = '0.7.8'
__version__ = '0.8.0'
__author__ = 'Jesus Lara'
__author_email__ = '[email protected]'
__license__ = 'BSD'
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ def readme():
'redis==3.5.3',
'python-rapidjson==1.5',
'python-logstash-async==2.3.0',
'aiologstash==2.0.0'
'aiologstash==2.0.0',
'pycryptodomex==3.14.1',
'cryptography==36.0.2',
'aiofiles==0.8.0'
],
project_urls={ # Optional
'Source': 'https://github.com/phenobarbital/NavConfig',
Expand Down

0 comments on commit 2f904c2

Please sign in to comment.