From 3ddfef6dc062289637a759e820be4f2caf7d5fc5 Mon Sep 17 00:00:00 2001 From: Joey Robertson Date: Tue, 11 Feb 2025 16:12:44 -0500 Subject: [PATCH 1/3] Initial implementation wrapping python-dotenv --- src/dotenvx/main.py | 50 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/dotenvx/main.py b/src/dotenvx/main.py index e9fe591..3276ddc 100644 --- a/src/dotenvx/main.py +++ b/src/dotenvx/main.py @@ -1,2 +1,48 @@ -def load_dotenvx(): - raise NotImplementedError("go to [github.com/dotenvx/dotenvx] and follow python directions there") +from typing import Optional, IO +import dotenv + +import ecies +import base64 +import os + +def decrypt_value(value: str, private_key: str) -> str: + private_key = ecies.PrivateKey.from_hex(private_key) + base64_ciphertext = value.lstrip('encrypted:') + ciphertext = base64.b64decode(base64_ciphertext) + decrypted_value = ecies.decrypt(private_key.to_hex(), ciphertext) + return decrypted_value.decode() + +def load_dotenvx( + dotenv_path: Optional[str] = None, + stream : Optional[IO[str]] = None, + verbose : bool = False, + override : bool = False, + interpolate: bool = True, + encoding : Optional[str] = "utf-8", +) -> bool: + + return_value = False # Set to True if at least one variable is set, otherwise False + + env_values = dotenv.dotenv_values( + dotenv_path = dotenv_path, + stream = stream, + verbose = verbose, + interpolate = interpolate, + encoding = encoding) + + env_keys_values = dotenv.dotenv_values('.env.keys') + dotenv_private_key = env_keys_values['DOTENV_PRIVATE_KEY'] + + # Decrypt encrypted values + for key, value in env_values.items(): + if value.startswith('encrypted:'): + env_values[key] = decrypt_value(value, dotenv_private_key) + + # Set environment variables + for key, value in env_values.items(): + if key in os.environ and not override: + continue + os.environ[key] = value + return_value = True + + return return_value From d6f8575c8b67389235d5e4e8b34ea299510fd745 Mon Sep 17 00:00:00 2001 From: Joey Robertson Date: Tue, 11 Feb 2025 16:13:46 -0500 Subject: [PATCH 2/3] Add requirements to setup.py --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 858079d..c93e94a 100644 --- a/setup.py +++ b/setup.py @@ -39,5 +39,7 @@ def read_files(files): 'dotenvx' ], install_requires=[ + 'eciespy>=0.4.3', + 'python-dotenv>=1.0.1', ], ) From 8c0384fde5f9859b9a90c0281c9bfb89e40dc8eb Mon Sep 17 00:00:00 2001 From: Joey Robertson Date: Thu, 19 Jun 2025 15:37:57 -0400 Subject: [PATCH 3/3] Explicitly specify secp256k1 curve to handle breaking change from the ecies module --- src/dotenvx/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotenvx/main.py b/src/dotenvx/main.py index 3276ddc..71dfa60 100644 --- a/src/dotenvx/main.py +++ b/src/dotenvx/main.py @@ -6,7 +6,7 @@ import os def decrypt_value(value: str, private_key: str) -> str: - private_key = ecies.PrivateKey.from_hex(private_key) + private_key = ecies.PrivateKey.from_hex(curve='secp256k1', sk_hex=private_key) base64_ciphertext = value.lstrip('encrypted:') ciphertext = base64.b64decode(base64_ciphertext) decrypted_value = ecies.decrypt(private_key.to_hex(), ciphertext)