-
Notifications
You must be signed in to change notification settings - Fork 0
/
scoresys.py
239 lines (197 loc) · 7.18 KB
/
scoresys.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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
from os import system, path, makedirs
import hashlib as hash
from base64 import standard_b64decode as b64decode, standard_b64encode as b64encode
from ast import literal_eval as eval
from sys import exit
from platform import system as sys
from time import localtime as time
from secrets import token_bytes as salt
if "win" in sys().lower():
from ctypes import windll
windll.kernel32.SetConsoleMode(
windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE := -11),
ENABLE_VIRTUAL_TERMINAL_PROCESSING := 7,
)
def csi(e, *c):
print(end="\x1b[")
if c != tuple():
print(end=f"{c[0]}")
c = c[1:]
for i in c:
print(end=f";{i}")
print(end=f"{e}")
def color(fore: "int" = 39, back: "int" = 49):
csi("m", fore, back)
def style(style: "int" = 0):
csi("m", style)
def cl():
style(0)
def color256(mode: "int", r: "int", g: "int", b: "int"):
print("m", mode, 2, r, g, b)
def cls():
csi("J", 2)
csi("H")
def r(msg):
color(31)
print(msg)
cl()
def g(msg):
color(32)
print(msg)
cl()
def y(msg):
color(33)
print(msg)
cl()
def In(msg: "str") -> str:
i = input(f"{msg}: \x1b[1m")
cl()
return i
def pause():
input("按Enter键继续...")
try:
from Crypto.Cipher import AES
except ImportError:
print("开始安装依赖库")
system(
"python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip"
)
system(
"python -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple"
)
system(
'python -m pip config set global.extra-index-url "https://mirrors.cernet.edu.cn/pypi/simple https://mirrors.cernet.edu.cn/pypi/web/simple https://mirrors.mirrorz.org/pypi/simple https://mirrors.mirrorz.org/pypi/web/simple"'
)
system("python -m pip install pycryptodome")
style(1)
y("请重新启动!")
exit(0)
def setPassword(s: "bytes") -> bytes:
cls()
password = In("设置密码")
for i in range(2, -1, -1):
check = In("确认密码")
if check == password:
return hash.pbkdf2_hmac("sha256", password.encode(), s, 500_000)
else:
r(f"密码错误!你还有{i}次机会.")
return b"\0"
def loadData() -> tuple:
cls()
for i in range(2, -1, -1):
try:
with open("scoresys.dat", "r") as f:
s, p = map(lambda i: i[:-1], f.readlines())
s = b64decode(s.encode())
k = hash.pbkdf2_hmac("sha256", In("输入密码").encode(), s, 500_000)
w = de(k, p)
except:
r(f"密码错误!你还有{i}次机会.")
else:
return (k, s, w)
return (b"\0", s, "\0")
def en(key: "bytes", dat: "str") -> str:
data = dat.encode()
while len(data) % 16 != 0:
data += b"\x00"
return b64encode(AES.new(key, AES.MODE_ECB).encrypt(data)).decode()
def de(key: "bytes", dat: "str") -> str:
data = AES.new(key, AES.MODE_ECB).decrypt(b64decode(dat.encode()))
while data[-1] == 0:
data = data[:-1]
return data.decode()
if not path.exists("scoresys.dat"):
s = salt(32)
k = setPassword(s)
if k != b"\0":
with open("scoresys.dat", "w") as f:
f.write(f"{b64encode(s).decode()}\n{en(k, str({}))}\n")
else:
exit(-1)
t = time()
logdir = f"logs/{t.tm_year:04d}/{t.tm_mon:02d}/"
makedirs(logdir, exist_ok=True)
logf = open(f"{logdir}{t.tm_mday:02d}.log", "a")
def log(msg: "str", type: "str" = "INFO"):
t = time()
logf.write(f"[{t.tm_hour:02d}:{t.tm_min:02d}:{t.tm_sec:02d}] [{type}] {msg}\n")
with open("scoresys.dat", "r") as file:
k, s, d = loadData()
if d == "\0":
exit(-1)
log("登录")
d = eval(d)
menu = ["保存并退出", "分数查询", "分数修改", "小组修改", "修改密码"]
while True:
cls()
print("┌────┬──────────────────────────────┐")
for i, j in enumerate(menu):
print(f"│{i: > 4d}┆{j:\u3000<15}│")
print("└────┴──────────────────────────────┘")
choose = In("请选择")
cls()
if choose == "0":
with open("scoresys.dat", "w") as file:
file.write(f"{b64encode(s).decode()}\n{en(k, str(d))}\n")
log("退出")
exit(0)
elif choose == "1":
no = int(0)
print("┌────┬──────────────────────────────┬─────┐")
for i, j in sorted(d.items(), key=lambda kv: (kv[1], kv[0])):
no = no + 1
print(f"│{no: > 4d}┆{i: ^30}┆{j: < 5d}│")
print("└────┴──────────────────────────────┴─────┘\n")
elif choose == "2":
group = In("输入小组代号")
if group in d:
score = In("输入加/减分(正数加分,负数减分)")
if (score if score[0] != "-" else score[1:]).isdecimal() if len(score)>0 else False:
confirm = In("确认修改?(再次输入小组代号以确认)")
if confirm == group:
d[group] += int(score)
g("修改成功.")
log(f"{group}分数{int(score):+d}")
else:
y("修改失败.")
else:
r("分数输入不正确!")
else:
r("小组不存在!")
elif choose == "3":
group = In("输入小组代号(未有小组将被创建,已有小组将被删除)")
if group.isalnum() and len(group) < 31:
if group in d:
confirm = In("确认删除?(再次输入小组代号以确认)")
if confirm == group:
d.pop(group)
g("删除成功.")
log(f"{group}被删除")
else:
y("删除失败.")
else:
confirm = In("确认创建?(再次输入小组代号以确认)")
if confirm == group:
d[group] = 0
g("创建成功.")
log(f"{group}被创建")
else:
y("创建失败.")
else:
r("小组代号不合规!(由字母和数字组成,30字符以内)")
elif choose == "4":
if loadData()[0] != b"\0":
nk = setPassword(s)
if nk != b"\0":
k = nk
with open("scoresys.dat", "w") as file:
file.write(f"{b64encode(s).decode()}\n{en(k, str(d))}\n")
g("密码修改成功.")
log(f"密码被修改\n当前数据:\n{d}", "WARN")
else:
r("密码修改失败.")
else:
r("密码修改失败.")
else:
r("错误的选项,请重新输入!")
pause()