diff --git a/AUTO_MAA.exe b/AUTO_MAA.exe index 9377276..4218d2d 100644 Binary files a/AUTO_MAA.exe and b/AUTO_MAA.exe differ diff --git a/README.md b/README.md index db92a57..8449e06 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,13 @@ This software is open source, free of charge and for learning and exchange purpo 本软件是MAA的外部工具,需要安装配置MAA后才能使用。 -**MAA安装** +#### MAA安装 什么是MAA? [官网](https://maa.plus/)/[GitHub](https://github.com/CHNZYX/Auto_Simulated_Universe/archive/refs/heads/main.zip) MAA下载地址 [GitHub下载](https://github.com/MaaAssistantArknights/MaaAssistantArknights/releases) -**MAA配置** +#### MAA配置 1.完成MAA的adb配置等基本配置 @@ -46,13 +46,23 @@ GitHub下载地址 [GitHub下载](https://github.com/DLmaster361/AUTO_MAA/rel ## 配置用户信息与相关参数 -**第一次启动** +注意:当前所有的密码输入部分都存在一点“小问题”,请在输入密码时避免输入Delete、F12、Tab等功能键。 -双击启动`manage.exe`,输入MAA所在文件夹路径并回车(注意使用斜杠的种类,不要使用反斜杠) +------------------------------------------------- + +#### 第一次启动 + +双击启动`manage.exe`,输入MAA所在文件夹路径并回车(注意使用斜杠的种类,不要使用反斜杠),然后设置管理密钥。 ![信息配置1](https://github.com/DLmaster361/AUTO_MAA/blob/main/res/README/信息配置1.png "MAA配置1") -**添加用户** +管理密钥是解密用户密码的唯一凭证,与数据库绑定。密钥丢失或`data/key/`目录下任一文件损坏都将导致解密无法正常进行。 + +本项目采用自主组建的混合加密模式,项目组也无法找回您的管理密钥或修复`data/key/`目录下的文件。如果不幸的事发生,建议您删除`data/data.db`重新录入信息。 + +当前暂不支持修改管理密钥,请等待后续更新。 + +#### 添加用户 输入“+”以开始添加用户。依次输入: @@ -66,7 +76,7 @@ GitHub下载地址 [GitHub下载](https://github.com/DLmaster361/AUTO_MAA/rel ![信息配置2](https://github.com/DLmaster361/AUTO_MAA/blob/main/res/README/信息配置2.png "MAA配置2") -**删除用户** +#### 删除用户 输入用户名+“-”以删除用户。格式: @@ -76,7 +86,7 @@ GitHub下载地址 [GitHub下载](https://github.com/DLmaster361/AUTO_MAA/rel ![信息配置3](https://github.com/DLmaster361/AUTO_MAA/blob/main/res/README/信息配置3.png "MAA配置3") -**配置用户状态** +#### 配置用户状态 启用代理:输入用户名+“y”以启用该用户的代理。格式: @@ -94,7 +104,7 @@ GitHub下载地址 [GitHub下载](https://github.com/DLmaster361/AUTO_MAA/rel ![信息配置5](https://github.com/DLmaster361/AUTO_MAA/blob/main/res/README/信息配置5.png "MAA配置5") -**续期** +#### 续期 输入用户名+续期天数+“+”以延长该用户的代理天数。格式: @@ -104,7 +114,7 @@ GitHub下载地址 [GitHub下载](https://github.com/DLmaster361/AUTO_MAA/rel ![信息配置6](https://github.com/DLmaster361/AUTO_MAA/blob/main/res/README/信息配置6.png "MAA配置6") -**修改刷取关卡** +#### 修改刷取关卡 输入用户名+关卡号+“~”以更改该用户的代理关卡。格式: @@ -120,7 +130,7 @@ GitHub下载地址 [GitHub下载](https://github.com/DLmaster361/AUTO_MAA/rel ![gameid](https://github.com/DLmaster361/AUTO_MAA/blob/main/res/README/gameid.png "gameid") -**设置MAA路径** +#### 设置MAA路径 输入“/”+新的MAA文件夹路径以修改MAA安装位置的配置。格式: @@ -132,7 +142,7 @@ GitHub下载地址 [GitHub下载](https://github.com/DLmaster361/AUTO_MAA/rel ![信息配置8](https://github.com/DLmaster361/AUTO_MAA/blob/main/res/README/信息配置8.png "MAA配置8") -**设置启动时间** +#### 设置启动时间 添加启动时间:输入“:+”+时间以添加定时启动时间。格式: @@ -154,7 +164,7 @@ GitHub下载地址 [GitHub下载](https://github.com/DLmaster361/AUTO_MAA/rel ![信息配置10](https://github.com/DLmaster361/AUTO_MAA/blob/main/res/README/信息配置10.png "MAA配置10") -**检索信息** +#### 检索信息 检索所有信息:`manage.exe`打开时会打印所有用户与配置信息。除此之外,你可以通过输入“all ?”以打印所有信息,如下: @@ -188,7 +198,7 @@ time ? ![信息配置14](https://github.com/DLmaster361/AUTO_MAA/blob/main/res/README/信息配置14.png "MAA配置14") -**退出** +#### 退出 输入“-”以退出`manage.exe`,如下: @@ -198,11 +208,11 @@ time ? ## 运行代理 -**直接运行** +#### 直接运行 双击`run.exe`直接运行 -**定时运行** +#### 定时运行 双击`AUTO_MAA.exe`打开,不要关闭。它会读取设定时间,在该时刻自动运行 diff --git a/manage.exe b/manage.exe index 43cf865..f31c148 100644 Binary files a/manage.exe and b/manage.exe differ diff --git a/manage.py b/manage.py index 7e5094e..7b0d583 100644 --- a/manage.py +++ b/manage.py @@ -1,6 +1,107 @@ import sqlite3 import datetime +import msvcrt +import sys import os +import hashlib +import random +import secrets +from Crypto.Cipher import AES +from Crypto.PublicKey import RSA +from Crypto.Cipher import PKCS1_OAEP +from Crypto.Util.Padding import pad,unpad + +#读入密码 +def readpass(text): + sys.stdout=sys.__stdout__ + sys.stdout.write(text) + sys.stdout.flush() + p='' + while True: + typed=msvcrt.getch() + if len(p)!=0: + if typed==b'\r': + sys.stdout.write('\b*') + sys.stdout.flush() + break + elif typed==b'\b': + p=p[:-1] + sys.stdout.write('\b \b') + sys.stdout.flush() + else: + p+=typed.decode("utf-8") + sys.stdout.write('\b*'+typed.decode("utf-8")) + sys.stdout.flush() + elif typed!=b'\r' and typed!=b'\b': + p+=typed.decode("utf-8") + sys.stdout.write(typed.decode("utf-8")) + sys.stdout.flush() + + print('') + return p + +#配置密钥 +def getPASSWORD(PASSWORD): + #生成RSA密钥对 + key=RSA.generate(2048) + public_key_local=key.publickey() + private_key=key + #保存RSA公钥 + with open('data/key/public_key.pem','wb') as f: + f.write(public_key_local.exportKey()) + #生成密钥转换与校验随机盐 + PASSWORDsalt=secrets.token_hex(random.randint(32,1024)) + with open("data/key/PASSWORDsalt.txt","w",encoding="utf-8") as f: + print(PASSWORDsalt,file=f) + verifysalt=secrets.token_hex(random.randint(32,1024)) + with open("data/key/verifysalt.txt","w",encoding="utf-8") as f: + print(verifysalt,file=f) + #将管理密钥转化为AES-256密钥 + AES_password=hashlib.sha256((PASSWORD+PASSWORDsalt).encode("utf-8")).digest() + #生成AES-256密钥校验哈希值并保存 + AES_password_verify=hashlib.sha256(AES_password+verifysalt.encode("utf-8")).digest() + with open("data/key/AES_password_verify.bin","wb") as f: + f.write(AES_password_verify) + #AES-256加密RSA私钥并保存密文 + AES_key=AES.new(AES_password,AES.MODE_ECB) + private_key_local=AES_key.encrypt(pad(private_key.exportKey(),32)) + with open("data/key/private_key.bin","wb") as f: + f.write(private_key_local) + +#加密 +def encryptx(note): + #读取RSA公钥 + with open('data/key/public_key.pem','rb') as f: + public_key_local=RSA.import_key(f.read()) + #使用RSA公钥对数据进行加密 + cipher=PKCS1_OAEP.new(public_key_local) + encrypted=cipher.encrypt(note.encode("utf-8")) + return encrypted + +#解密 +def decryptx(note,PASSWORD): + #读入RSA私钥密文、盐与校验哈希值 + with open("data/key/private_key.bin","rb") as f: + private_key_local=f.read().strip() + with open("data/key/PASSWORDsalt.txt","r",encoding="utf-8") as f: + PASSWORDsalt=f.read().strip() + with open("data/key/verifysalt.txt","r",encoding="utf-8") as f: + verifysalt=f.read().strip() + with open("data/key/AES_password_verify.bin","rb") as f: + AES_password_verify=f.read().strip() + #将管理密钥转化为AES-256密钥并验证 + AES_password=hashlib.sha256((PASSWORD+PASSWORDsalt).encode("utf-8")).digest() + AES_password_SHA=hashlib.sha256(AES_password+verifysalt.encode("utf-8")).digest() + if AES_password_SHA!=AES_password_verify: + return "管理密钥错误" + else: + #AES解密RSA私钥 + AES_key=AES.new(AES_password,AES.MODE_ECB) + private_key_pem=unpad(AES_key.decrypt(private_key_local),32) + private_key=RSA.import_key(private_key_pem) + #使用RSA私钥解密数据 + decrypter=PKCS1_OAEP.new(private_key) + return decrypter.decrypt(note) #添加用户 def add(): @@ -14,9 +115,10 @@ def add(): numberx=input("手机号码:") dayx=int(input("代理天数:")) gamex=input("关卡号:") - passwordx=input("密码:") + passwordx=readpass("密码:") + passwordx=encryptx(passwordx) #应用更新 - cur.execute("INSERT INTO adminx(admin,number,day,status,last,game,password) VALUES('%s','%s',%d,'y','2000-01-01','%s','%s')" %(adminx,numberx,dayx,gamex,passwordx)) + cur.execute("INSERT INTO adminx VALUES(?,?,?,'y','2000-01-01',?,?)",(adminx,numberx,dayx,gamex,passwordx)) db.commit() cur.close() db.close() @@ -27,12 +129,12 @@ def delete(id): db=sqlite3.connect(DATABASE) cur=db.cursor() #检查用户是否存在 - cur.execute("SELECT * FROM adminx WHERE admin='%s'" %(id)) + cur.execute("SELECT * FROM adminx WHERE admin=?",(id,)) data=cur.fetchall() if len(data)==0: return "未找到"+id #应用更新 - cur.execute("DELETE FROM adminx WHERE admin='%s'" %(id)) + cur.execute("DELETE FROM adminx WHERE admin=?",(id,)) db.commit() cur.close() db.close() @@ -71,7 +173,7 @@ def search(id,book): if id=="all": cur.execute("SELECT * FROM adminx WHERE True") else: - cur.execute("SELECT * FROM adminx WHERE admin='%s'" %(id)) + cur.execute("SELECT * FROM adminx WHERE admin=?",(id,)) data=cur.fetchall() #处理全部信息查询时的MAA路径与启动时间查询 if id=="all": @@ -109,6 +211,12 @@ def search(id,book): data[i][3]="禁用" if id=="all": data[i][6]="******" + else: + #解密 + global PASSWORD + if PASSWORD==0: + PASSWORD=input("请输入管理密钥:") + data[i][6]=decryptx(data[i][6],PASSWORD).decode("utf-8") #制表输出 if book==1: print('') @@ -132,14 +240,14 @@ def renewal(readxx): #检查用户是否存在 db=sqlite3.connect(DATABASE) cur=db.cursor() - cur.execute("SELECT * FROM adminx WHERE admin='%s'" %(id)) + cur.execute("SELECT * FROM adminx WHERE admin=?",(id,)) data=cur.fetchall() if len(data)==0: cur.close() db.close() return "未找到"+id #应用更新 - cur.execute("UPDATE adminx SET day=%d WHERE admin='%s'" %(data[0][2]+dayp,id)) + cur.execute("UPDATE adminx SET day=? WHERE admin=?",(data[0][2]+dayp,id)) db.commit() cur.close() db.close() @@ -150,14 +258,14 @@ def turn(id,t): #检查用户是否存在 db=sqlite3.connect(DATABASE) cur=db.cursor() - cur.execute("SELECT * FROM adminx WHERE admin='%s'" %(id)) + cur.execute("SELECT * FROM adminx WHERE admin=?",(id,)) data=cur.fetchall() if len(data)==0: cur.close() db.close() return "未找到"+id #应用更新 - cur.execute("UPDATE adminx SET status='%s' WHERE admin='%s'" %(t,id)) + cur.execute("UPDATE adminx SET status=? WHERE admin=?",(t,id)) db.commit() cur.close() db.close() @@ -177,7 +285,7 @@ def gameid(readxx): #检查用户是否存在 db=sqlite3.connect(DATABASE) cur=db.cursor() - cur.execute("SELECT * FROM adminx WHERE admin='%s'" %(id)) + cur.execute("SELECT * FROM adminx WHERE admin=?",(id,)) data=cur.fetchall() if len(data)==0: cur.close() @@ -197,7 +305,7 @@ def gameid(readxx): if gamep in games: gamep=games[gamep] #应用更新 - cur.execute("UPDATE adminx SET game='%s' WHERE admin='%s'" %(gamep,id)) + cur.execute("UPDATE adminx SET game=? WHERE admin=?",(gamep,id)) db.commit() cur.close() db.close() @@ -210,9 +318,9 @@ def setpath(pathx): cur.execute("SELECT * FROM pathset WHERE True") pathold=cur.fetchall() if len(pathold)>0: - cur.execute("UPDATE pathset SET path='%s' WHERE True" %(pathx)) + cur.execute("UPDATE pathset SET path=? WHERE True",(pathx,)) else: - cur.execute("INSERT INTO pathset(path) VALUES('%s')" %(pathx)) + cur.execute("INSERT INTO pathset VALUES(?)",(pathx,)) db.commit() cur.close() db.close() @@ -235,7 +343,7 @@ def settime(book,timex): db.close() return "已存在"+timex else: - cur.execute("INSERT INTO timeset(time) VALUES('%s')" %(timex)) + cur.execute("INSERT INTO timeset VALUES(?)",(timex,)) db.commit() cur.close() db.close() @@ -243,7 +351,7 @@ def settime(book,timex): #删除时间设置 elif book=='-': if timenew in timeold: - cur.execute("DELETE FROM timeset WHERE time='%s'" %(timex)) + cur.execute("DELETE FROM timeset WHERE time=?",(timex,)) db.commit() cur.close() db.close() @@ -265,17 +373,20 @@ def unit(x,m): #初期检查 DATABASE="data/data.db" +PASSWORD=0 if not os.path.exists(DATABASE): db=sqlite3.connect(DATABASE) cur=db.cursor() - db.execute("CREATE TABLE adminx(admin text,number text,day int,status text,last date,game text,password text)") + db.execute("CREATE TABLE adminx(admin text,number text,day int,status text,last date,game text,password byte)") db.execute("CREATE TABLE pathset(path text)") db.execute("CREATE TABLE timeset(time text)") readx=input("首次启动,请设置MAA路径:") - cur.execute("INSERT INTO pathset(path) VALUES('%s')" %(readx)) + cur.execute("INSERT INTO pathset VALUES(?)",(readx,)) db.commit() cur.close() db.close() + PASSWORD=readpass("请设置管理密钥(密钥与数据库绑定且唯一不可变):") + getPASSWORD(PASSWORD) #初始界面 print("Good evening!") diff --git "a/res/README/\344\277\241\346\201\257\351\205\215\347\275\2561.png" "b/res/README/\344\277\241\346\201\257\351\205\215\347\275\2561.png" index 4dd04d6..5a4320c 100644 Binary files "a/res/README/\344\277\241\346\201\257\351\205\215\347\275\2561.png" and "b/res/README/\344\277\241\346\201\257\351\205\215\347\275\2561.png" differ diff --git a/run.exe b/run.exe index b2af8d5..8dc1cc1 100644 Binary files a/run.exe and b/run.exe differ diff --git a/run.py b/run.py index 548ac0b..2d60c2d 100644 --- a/run.py +++ b/run.py @@ -47,12 +47,11 @@ def runmaa(tel,game,num=2): def updata(id): db=sqlite3.connect(DATABASE) cur=db.cursor() - cur.execute("SELECT * FROM adminx WHERE admin='%s'" %(id)) + cur.execute("SELECT * FROM adminx WHERE admin=?",(id,)) info=cur.fetchall() - cur.execute("UPDATE adminx SET day=%d WHERE admin='%s'" %(info[0][2]-1,id)) + cur.execute("UPDATE adminx SET day=? WHERE admin=?",(info[0][2]-1,id)) db.commit() - cur.execute("UPDATE adminx SET last='%s' WHERE admin='%s'" %(curdate,id)) - print("upcurdate") + cur.execute("UPDATE adminx SET last=? WHERE admin=?",(curdate,id)) db.commit() cur.close() db.close()