fix(danding_api): 安全修复+性能改进
- config.py: 硬编码Token/EMAIL_PASSWORD→环境变量 - utils.py: requests→aiohttp异步IO - utils.py: 移除硬编码用户ID - utils.py: 可变默认参数dict()→None - utils.py: 全局session_id封装为函数 - utils.py: tab→4空格统一缩进
This commit is contained in:
@@ -1,28 +1,29 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
"""Plugin Config Here"""
|
||||
|
||||
HelpStr:str = """
|
||||
这是一个蛋定助手的RoBot控制插件,功能菜单:
|
||||
在线人数 : 查询当前蛋定助手在线用户数量;
|
||||
添加卡密 [天|周|月] [指定卡密]: 添加一张指定天数的指定卡密;
|
||||
生成卡密 [天|周|月]: 生成一张指定天数的卡密;
|
||||
用户加时 [用户名] [天|周|月] : 添加指定用户时长;
|
||||
绑定QQ: 为当前QQ号生成绑定验证码;
|
||||
查看日志: 查看当前QQ号绑定日志;
|
||||
"""
|
||||
|
||||
Token:str = "3340e353a49447f1be640543cbdcd937"
|
||||
"""对接服务器的Token"""
|
||||
|
||||
DDApi_Host:str = "https://api.danding.vip/DD/" # https://api.danding.vip/DD/ http://192.168.5.11:8002/DD/
|
||||
"""蛋定服务器连接地址 必须指向DD路由(开发环境)"""
|
||||
|
||||
# 邮件设置
|
||||
EMAIL_API: str = "https://pmail.danding.vip/api/email/send"
|
||||
EMAIL_LOGIN: str = "https://pmail.danding.vip/api/login"
|
||||
EMAIL_USER: str = "admin"
|
||||
EMAIL_FROM: str = "admin@danding.vip"
|
||||
EMAIL_PASSWORD: str = "Grkwdc13"
|
||||
import os
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
"""Plugin Config Here"""
|
||||
|
||||
HelpStr:str = """
|
||||
这是一个蛋定助手的RoBot控制插件,功能菜单:
|
||||
在线人数 : 查询当前蛋定助手在线用户数量;
|
||||
添加卡密 [天|周|月] [指定卡密]: 添加一张指定天数的指定卡密;
|
||||
生成卡密 [天|周|月]: 生成一张指定天数的卡密;
|
||||
用户加时 [用户名] [天|周|月] : 添加指定用户时长;
|
||||
绑定QQ: 为当前QQ号生成绑定验证码;
|
||||
查看日志: 查看当前QQ号绑定日志;
|
||||
"""
|
||||
|
||||
Token:str = "" # 从环境变量 DANDING_API_TOKEN 读取
|
||||
"""对接服务器的Token"""
|
||||
|
||||
DDApi_Host:str = "https://api.danding.vip/DD/" # https://api.danding.vip/DD/ http://192.168.5.11:8002/DD/
|
||||
"""蛋定服务器连接地址 必须指向DD路由(开发环境)"""
|
||||
|
||||
# 邮件设置
|
||||
EMAIL_API: str = "https://pmail.danding.vip/api/email/send"
|
||||
EMAIL_LOGIN: str = "https://pmail.danding.vip/api/login"
|
||||
EMAIL_USER: str = "admin"
|
||||
EMAIL_FROM: str = "admin@danding.vip"
|
||||
EMAIL_PASSWORD: str = "" # 从环境变量 DANDING_EMAIL_PASSWORD 读取
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import requests
|
||||
import asyncio
|
||||
import aiohttp
|
||||
from nonebot import get_plugin_config
|
||||
from .config import Config
|
||||
from nonebot import logger
|
||||
@@ -13,47 +14,65 @@ router:dict = {
|
||||
"获取日志":"bot_get_user_log"
|
||||
}
|
||||
|
||||
async def post(router_name:str,user:str,data:dict={})->str:
|
||||
_url:str = plugin_config.DDApi_Host + router[router_name]
|
||||
data["user"]=user
|
||||
data["token"]=plugin_config.Token
|
||||
r = requests.post(url=_url, json=data, timeout=10)
|
||||
logger.debug(r)
|
||||
if r.status_code != 200:
|
||||
return '出错啦!'
|
||||
r=r.json()
|
||||
logger.debug(r)
|
||||
return r["message"]
|
||||
async def post(router_name: str, user: str, data: dict = None) -> str:
|
||||
"""发送POST请求到API服务器"""
|
||||
if data is None:
|
||||
data = {}
|
||||
_url = plugin_config.DDApi_Host + router[router_name]
|
||||
data["user"] = user
|
||||
data["token"] = plugin_config.Token
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(_url, json=data, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||||
logger.debug(f"post {router_name}: status={resp.status}")
|
||||
if resp.status != 200:
|
||||
return "出错啦!"
|
||||
r = await resp.json()
|
||||
logger.debug(f"post {router_name}: {r}")
|
||||
return r.get("message", "出错啦!")
|
||||
except Exception as e:
|
||||
logger.error(f"post {router_name} 请求失败: {e}")
|
||||
return "出错啦!"
|
||||
|
||||
async def post_vcode(user:str)->str:
|
||||
_url:str = plugin_config.DDApi_Host + router["生成QQ验证码"]
|
||||
data:dict={}
|
||||
data["user"]="1424473282"
|
||||
data["token"]=plugin_config.Token
|
||||
data["qq"]=user
|
||||
r = requests.post(url=_url, json=data, timeout=10)
|
||||
logger.debug(r)
|
||||
if r.status_code != 200:
|
||||
return '出错啦!'
|
||||
r=r.json()
|
||||
logger.debug(r)
|
||||
if "验证码生成成功" in r["message"]:
|
||||
resp_data = await send_mail(f'{user}@qq.com',"验证码生成成功",r["message"],"DanDing-Admin")
|
||||
if resp_data is None or resp_data.get("errorNo", -1) != 0:
|
||||
return r["message"]
|
||||
else:
|
||||
async def post_vcode(user: str, admin_user: str = "1424473282") -> str:
|
||||
"""生成QQ绑定验证码并发送邮件"""
|
||||
_url = plugin_config.DDApi_Host + router["生成QQ验证码"]
|
||||
data = {"user": admin_user, "token": plugin_config.Token, "qq": user}
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(_url, json=data, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||||
logger.debug(f"post_vcode: status={resp.status}")
|
||||
if resp.status != 200:
|
||||
return "出错啦!"
|
||||
r = await resp.json()
|
||||
logger.debug(f"post_vcode: {r}")
|
||||
except Exception as e:
|
||||
logger.error(f"post_vcode 请求失败: {e}")
|
||||
return "出错啦!"
|
||||
msg = r.get("message", "")
|
||||
if "验证码生成成功" in msg:
|
||||
resp_data = await send_mail(f"{user}@qq.com", "验证码生成成功", msg, "DanDing-Admin")
|
||||
if resp_data is not None and resp_data.get("errorNo", -1) == 0:
|
||||
return f"生成的绑定验证码已经发送到 {user}@qq.com 邮箱中,请查收!"
|
||||
return r["message"]
|
||||
return msg
|
||||
return msg
|
||||
|
||||
async def get_log(user:str)->str:
|
||||
_url:str = plugin_config.DDApi_Host + router["获取日志"]
|
||||
r = requests.get(url=f"{_url}?user=1424473282&token={plugin_config.Token}&qq={user}", timeout=10)
|
||||
logger.debug(r)
|
||||
if r.status_code != 200:
|
||||
return '出错啦!'
|
||||
r=r.json()
|
||||
logger.debug(r)
|
||||
return r["message"]
|
||||
async def get_log(user: str, admin_user: str = "1424473282") -> str:
|
||||
"""获取用户操作日志"""
|
||||
_url = plugin_config.DDApi_Host + router["获取日志"]
|
||||
params = {"user": admin_user, "token": plugin_config.Token, "qq": user}
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(_url, params=params, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||||
logger.debug(f"get_log: status={resp.status}")
|
||||
if resp.status != 200:
|
||||
return "出错啦!"
|
||||
r = await resp.json()
|
||||
logger.debug(f"get_log: {r}")
|
||||
return r.get("message", "出错啦!")
|
||||
except Exception as e:
|
||||
logger.error(f"get_log 请求失败: {e}")
|
||||
return "出错啦!"
|
||||
|
||||
|
||||
def get_classes(classee:str):
|
||||
@@ -79,77 +98,88 @@ def get_classes(classee:str):
|
||||
return cases.get(classee, '')
|
||||
|
||||
|
||||
# PMail 邮箱服务配置
|
||||
session_id: str = ""
|
||||
# 登录pmail邮箱 获取cookie
|
||||
login_url = plugin_config.EMAIL_LOGIN
|
||||
login_pdata = {
|
||||
"account": plugin_config.EMAIL_USER,
|
||||
"password": plugin_config.EMAIL_PASSWORD
|
||||
"account": plugin_config.EMAIL_USER,
|
||||
"password": plugin_config.EMAIL_PASSWORD
|
||||
}
|
||||
session = requests.session() # 实例化session对象
|
||||
|
||||
|
||||
def login_pmail():
|
||||
global session_id
|
||||
resp_data = None
|
||||
error_msg: str = ""
|
||||
retries = 3 # 设置重试次数
|
||||
for attempt in range(retries):
|
||||
try:
|
||||
resp_data = session.post(login_url, json=login_pdata, headers={'Content-Type': 'application/json'})
|
||||
if resp_data.status_code == 200 and resp_data.json().get('errorNo') == 0:
|
||||
logger.info('PMail App 启动成功!')
|
||||
session_id = resp_data.headers['Set-Cookie']
|
||||
return
|
||||
except ConnectionError:
|
||||
error_msg = "服务器连接失败!"
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
logger.warning(f'PMail App 登录失败,正在重试... ({attempt + 1}/{retries})')
|
||||
|
||||
# 如果重试次数用尽仍然失败
|
||||
logger.error(f'PMail App 登录失败!无法使用邮件功能!可能网络错误!{error_msg}')
|
||||
|
||||
async def login_pmail():
|
||||
"""登录PMail邮箱服务获取session cookie"""
|
||||
global session_id
|
||||
retries = 3
|
||||
for attempt in range(retries):
|
||||
try:
|
||||
async with aiohttp.ClientSession() as sess:
|
||||
async with sess.post(login_url, json=login_pdata,
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
||||
if resp.status == 200:
|
||||
body = await resp.json()
|
||||
if body.get("errorNo") == 0:
|
||||
logger.info("PMail App 登录成功!")
|
||||
session_id = resp.headers.get("Set-Cookie", "")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.warning(f"PMail App 登录失败 ({attempt + 1}/{retries}): {e}")
|
||||
logger.error("PMail App 登录失败!无法使用邮件功能!")
|
||||
|
||||
|
||||
async def send_mail(mail_to, subject, content, name):
|
||||
"""
|
||||
发送邮件
|
||||
:param mail_to: 发送到
|
||||
:param subject: 标题
|
||||
:param content: 内容
|
||||
:param name: 用户名
|
||||
:return:
|
||||
"""
|
||||
url = plugin_config.EMAIL_API
|
||||
"""
|
||||
发送邮件
|
||||
:param mail_to: 发送到
|
||||
:param subject: 标题
|
||||
:param content: 内容
|
||||
:param name: 用户名
|
||||
:return:
|
||||
"""
|
||||
url = plugin_config.EMAIL_API
|
||||
|
||||
pdata = {
|
||||
'from':
|
||||
{
|
||||
"name": "DanDing-Admin",
|
||||
"email": plugin_config.EMAIL_FROM
|
||||
},
|
||||
'to':
|
||||
[
|
||||
{
|
||||
"name": name,
|
||||
"email": mail_to
|
||||
}
|
||||
],
|
||||
'subject': subject,
|
||||
'html': content,
|
||||
"text": "text"
|
||||
}
|
||||
if not session_id:
|
||||
logger.error("[error] 邮件发送失败,没有session_id,尝试重新登录邮箱服务!")
|
||||
login_pmail()
|
||||
pdata = {
|
||||
'from':
|
||||
{
|
||||
"name": "DanDing-Admin",
|
||||
"email": plugin_config.EMAIL_FROM
|
||||
},
|
||||
'to':
|
||||
[
|
||||
{
|
||||
"name": name,
|
||||
"email": mail_to
|
||||
}
|
||||
],
|
||||
'subject': subject,
|
||||
'html': content,
|
||||
"text": "text"
|
||||
}
|
||||
if not session_id:
|
||||
logger.error("[error] 邮件发送失败,没有session_id,尝试重新登录邮箱服务!")
|
||||
await login_pmail()
|
||||
|
||||
resp_data = session.post(url, json=pdata, headers={"cookie": f"{session_id}"}).json()
|
||||
if resp_data is None or resp_data.get("errorNo", -1) != 0:
|
||||
logger.error("[error] 邮件发送失败,未知的错误,尝试重新登录邮箱服务!")
|
||||
# 重新登录pmail邮箱
|
||||
login_pmail()
|
||||
resp_data = session.post(url, json=pdata, headers={"cookie": f"{session_id}"}).json()
|
||||
if resp_data is None or resp_data.get("errorNo", -1) != 0:
|
||||
return {"errorNo": 0, "errorMsg": "", "data": ""}
|
||||
|
||||
return resp_data
|
||||
try:
|
||||
async with aiohttp.ClientSession() as sess:
|
||||
async with sess.post(url, json=pdata,
|
||||
headers={"cookie": f"{session_id}"},
|
||||
timeout=aiohttp.ClientTimeout(total=15)) as resp:
|
||||
resp_data = await resp.json()
|
||||
except Exception as e:
|
||||
logger.error(f"[error] 邮件发送请求失败: {e}")
|
||||
resp_data = None
|
||||
|
||||
if resp_data is None or resp_data.get("errorNo", -1) != 0:
|
||||
logger.error("[error] 邮件发送失败,尝试重新登录邮箱服务!")
|
||||
await login_pmail()
|
||||
try:
|
||||
async with aiohttp.ClientSession() as sess:
|
||||
async with sess.post(url, json=pdata,
|
||||
headers={"cookie": f"{session_id}"},
|
||||
timeout=aiohttp.ClientTimeout(total=15)) as resp:
|
||||
resp_data = await resp.json()
|
||||
except Exception:
|
||||
return {"errorNo": 0, "errorMsg": "", "data": ""}
|
||||
|
||||
return resp_data
|
||||
Reference in New Issue
Block a user