-
Notifications
You must be signed in to change notification settings - Fork 1
/
configure_enc_utils.py
203 lines (162 loc) · 7.22 KB
/
configure_enc_utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import io
import json
import logging
import os
import pickle
from pathlib import Path
import configparser
from cryptography.fernet import Fernet
import sys
import argparse
import base64
# Ensure CONFIG_ENCRYPTION_KEY is set
if "CONFIG_ENCRYPTION_KEY" not in os.environ:
os.environ["CONFIG_ENCRYPTION_KEY"] = "YOUR_ENCRYPTION_KEY"
# use it like this
# Encode the JSON file and save it to a variable
# base64 google_creds.json > google_creds_base64.txt
def create_google_creds_file(filename):
# Fetch the Base64 encoded JSON string from the environment variable
google_creds_base64 = os.getenv("GOOGLE_CREDS_JSON")
if not google_creds_base64:
raise ValueError("GOOGLE_CREDS_JSON environment variable is not set")
try:
# Decode the Base64 string to get the JSON string
google_creds_json = base64.b64decode(google_creds_base64).decode("utf-8")
# Parse the JSON string to ensure it's formatted correctly
google_creds_dict = json.loads(google_creds_json)
# Write the JSON dictionary back to a file if needed
with open(filename, "w") as f:
json.dump(google_creds_dict, f, indent=4)
except (json.JSONDecodeError, base64.binascii.Error) as e:
raise ValueError(f"Failed to decode and parse GOOGLE_CREDS_BASE64: {e}")
def load_encryption_key():
"""Loads the encryption key from the environment variable."""
encryption_key = os.getenv("CONFIG_ENCRYPTION_KEY")
if not encryption_key:
logging.error("CONFIG_ENCRYPTION_KEY environment variable is not set.")
raise EnvironmentError("CONFIG_ENCRYPTION_KEY environment variable is not set.")
return encryption_key.encode()
def prepare_config_enc(output_path="config.enc"):
"""Prepares and encrypts the configuration from environment variables into config.enc."""
required_keys = [
"MICROSOFT_TOKEN",
"MICROSOFT_REGION",
"MICROSOFT_TOKEN_TRANS",
"GOOGLE_CREDS_JSON",
]
config = {}
# Collect configuration from environment variables
for key in required_keys:
value = os.getenv(key)
if not value:
logging.error(f"Missing required environment variable: {key}")
raise EnvironmentError(f"Missing required environment variable: {key}")
config[key] = value
# Convert the config dictionary to JSON bytes
config_json = json.dumps(config).encode()
# Load the encryption key and encrypt the configuration
encryption_key = load_encryption_key()
fernet = Fernet(encryption_key)
encrypted_config = fernet.encrypt(config_json)
# Save the encrypted configuration to the file
with open(output_path, "wb") as config_file:
config_file.write(encrypted_config)
logging.info(f"Encrypted configuration saved to {output_path}.")
def load_config(custom_config_path=""):
"""Load configuration from the encrypted config.enc file and optionally from settings.cfg."""
if getattr(sys, "frozen", False):
# Running as a bundled executable
app_data = Path.home() / "AppData" / "Roaming" / "Ace Centre" / "AACSpeakHelper"
else:
# Running as a script (development)
# Assume that config.enc is at the repository root,
app_data = Path(os.path.dirname(__file__))
encrypted_config_path = app_data / "config.enc"
settings_cfg_path = app_data / "settings.cfg"
encrypted_json_path = app_data / "google_creds.enc"
# Load configuration from the encrypted file
try:
encryption_key = load_encryption_key()
fernet = Fernet(encryption_key)
# Read and decrypt the configuration
with encrypted_config_path.open("rb") as f:
encrypted_data = f.read()
decrypted_data = fernet.decrypt(encrypted_data)
# Load the decrypted JSON into a dictionary
config = json.loads(decrypted_data.decode())
# Overwrite the creds with base64 encoded creds. This is mad - it already is but somehow it gets decrypted
# google_creds_json = config.get("GOOGLE_CREDS_JSON")
# google_creds_bytes = google_creds_json.encode("utf-8")
# base64_encoded_creds = base64.b64encode(google_creds_bytes)
# base64_encoded_creds_str = base64_encoded_creds.decode("utf-8")
config["GOOGLE_CREDS_JSON"] = str(encrypted_json_path)
logging.info("Successfully decrypted configuration from config.enc.")
except Exception as e:
logging.error(f"Failed to load configuration from encrypted file: {e}")
raise
# Load configuration from settings.cfg if it exists or if a custom path is provided
if custom_config_path:
settings_cfg_path = Path(custom_config_path)
if settings_cfg_path.is_file():
logging.info(f"Loading configuration overrides from {settings_cfg_path}")
config_parser = configparser.ConfigParser()
config_parser.read(settings_cfg_path)
config_dict = {
section: dict(config_parser.items(section))
for section in config_parser.sections()
}
config_dict["azureTTS"]["key"] = config.get("MICROSOFT_TOKEN")
config_dict["azureTTS"]["location"] = config.get("MICROSOFT_REGION")
config_dict["googleTTS"]["creds"] = config.get("GOOGLE_CREDS_JSON")
config_dict["translate"]["microsofttranslator_secret_key"] = config.get(
"MICROSOFT_TOKEN_TRANS"
)
else:
config_dict = None
logging.info("No settings.cfg file found. Skipping overrides.")
logging.info("Final configuration loaded successfully.")
return config_dict
def load_credentials(fp: str) -> object:
encryption_key = load_encryption_key()
fernet = Fernet(encryption_key)
with open(fp, "rb") as f:
return pickle.loads(fernet.decrypt(f.read()))
def save_credentials(obj: object, fp: str):
encryption_key = load_encryption_key()
fernet = Fernet(encryption_key)
with open(fp, "wb") as f:
f.write(fernet.encrypt(pickle.dumps(obj)))
# Example usage
# prepare_config_enc() # Run this to create config.enc
# config = load_config() # Load config when needed
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="AACSpeakHelper Encryption Utility")
parser.add_argument(
"-i", "--input", help="Path to a defined JSON file", required=False
)
parser.add_argument(
"-use-env",
action="store_true",
help="Create JSON from environment variables instead of input file",
)
args = vars(parser.parse_args())
# Check if -use-env is provided
if args["use_env"]:
# Set a default filename for the JSON file to be created from the environment variable
filename = Path("google_creds.json")
create_google_creds_file(filename)
prepare_config_enc()
else:
# Handle the input flag normally
if not args["input"]:
print("Either --input or --use-env must be specified.")
sys.exit(1)
filename = Path(args["input"])
file_path = filename.resolve().parent
with io.open(filename, "r", encoding="utf-8") as json_file:
json_dict = json.load(json_file)
new_file = filename.with_suffix(".enc")
save_credentials(json_dict, os.path.join(file_path, new_file))
files = os.listdir(".")
print(files)