-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConfigManager.py
More file actions
132 lines (117 loc) · 5.12 KB
/
Copy pathConfigManager.py
File metadata and controls
132 lines (117 loc) · 5.12 KB
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
import os
import json # 需导入json模块
import sys
from pathlib import Path
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
# 配置文件中需要加密的字段
need_encrypt = ['ulConf.sk','sk']
KEY = b'o\xfd\xbb\x9b\x14\x92\x85/W\x1e\xb1\x04\xff\xa0\xa4\x1c' # 替换为你生成的密钥 Fernet.generate_key()
class ConfigManager:
def get_config_path(self):
"""获取 config.json 文件的路径"""
return Path(self.get_project_root()) / 'config.json'
def encrypt_data(self,sensitive_data):
"""加密敏感数据(字符串)"""
# 生成随机IV(16字节,每次加密不同)
iv = get_random_bytes(16)
# 创建AES加密器(CBC模式)
cipher = AES.new(KEY, AES.MODE_CBC, iv)
# 加密:数据填充为16字节倍数 -> 加密 -> 拼接IV(解密时需要)
data_bytes = sensitive_data.encode('utf-8')
encrypted_bytes = cipher.encrypt(pad(data_bytes, AES.block_size))
# 返回:IV + 加密数据(转为十六进制字符串存储,避免乱码)
return (iv + encrypted_bytes).hex()
def decrypt_data(self,encrypted_str):
"""解密数据(输入加密后的十六进制字符串)"""
if not encrypted_str:
return encrypted_str
# 转为字节
encrypted_bytes = bytes.fromhex(encrypted_str)
# 拆分IV(前16字节)和加密数据
iv = encrypted_bytes[:16]
data_bytes = encrypted_bytes[16:]
# 创建AES解密器
cipher = AES.new(KEY, AES.MODE_CBC, iv)
# 解密并去除填充
decrypted_bytes = unpad(cipher.decrypt(data_bytes), AES.block_size)
return decrypted_bytes.decode('utf-8')
def read(self, key, default=None):
"""从 config.json 读取指定键的值(支持嵌套键)"""
config_path = self.get_config_path() # 需用self调用实例方法
if not os.path.exists(config_path):
return default
try:
with open(config_path, 'r', encoding='utf-8') as f:
config = json.load(f)
keys = key.split('.')
current = config
for k in keys:
if isinstance(current, dict) and k in current:
current = current[k]
else:
return default
if key in need_encrypt:
return self.decrypt_data(current)
return current
except (json.JSONDecodeError, IOError):
return default
def write(self, key, value): # 修复缩进:函数定义需缩进
"""向 config.json 写入/更新指定键的值(支持嵌套键)"""
config_path = self.get_config_path() # 需用self调用实例方法
config = {}
print(f'(cfg)配置文件路径:{config_path}')
if os.path.exists(config_path):
try:
with open(config_path, 'r', encoding='utf-8') as f:
config = json.load(f)
except (json.JSONDecodeError, IOError):
return False
keys = key.split('.')
current = config
for k in keys[:-1]:
if k not in current:
current[k] = {}
if not isinstance(current[k], dict):
current[k] = {} # 若当前键不是字典,强制转为字典(避免覆盖非字典值)
current = current[k]
if key in need_encrypt:
value = self.encrypt_data(value)
current[keys[-1]] = value # 设置最终键的值
try:
with open(config_path, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=4, ensure_ascii=False)
return True
except IOError:
return False
def get_project_root(self):
"""获取项目根目录(main.py所在的目录)"""
try:
# 如果当前文件被导入,使用 __file__ 获取项目根目录
if getattr(sys, 'frozen', False):
# print(f'(cfg)打包状态:sys.executable 是.exe的路径{sys.executable}')
exe_dir = os.path.dirname(sys.executable)
return Path(exe_dir).resolve()
else:
# print(f'(cfg)开发状态:__file__ 是当前脚本路径{__file__}')
return Path(__file__).parent.resolve()
except NameError:
print('(cfg)无法获取项目根目录,使用当前工作目录')
# 如果直接执行,使用当前工作目录
return Path(os.getcwd()).resolve()
# 使用示例
if __name__ == "__main__":
# sk = 'UpgradeLink的SecretKey'
sk = '你要加密的sk'
# cfg = ConfigManager()
# 1. 先生成密钥
# key = get_random_bytes(16)
# print(f'生成的密钥:{key}')
# 2. 用密码加密ulConf.sk
# encrypted = cfg.encrypt_data(sk)
# print(f'加密后的字符串:{encrypted}')
# 3. 把加密后的字符串手动写入配置文件
# 4. 解密测试
# decrypted = cfg.read('ulConf.sk')
# print(f'解密后的字符串:{decrypted}')