summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKomorebi <[email protected]>2023-10-01 02:18:25 +0800
committerKomorebi <[email protected]>2023-10-01 02:18:25 +0800
commit7cbe8a046f10c776b3c9ae80fd75b30a5d810f29 (patch)
treef03721b92a81bfd6208d462204b4ae99e9391800
parentcae8dfa08f870e463259521803426d2b3d169918 (diff)
downloadATRI-7cbe8a046f10c776b3c9ae80fd75b30a5d810f29.tar.gz
ATRI-7cbe8a046f10c776b3c9ae80fd75b30a5d810f29.tar.bz2
ATRI-7cbe8a046f10c776b3c9ae80fd75b30a5d810f29.zip
🔥 删除 console 插件
-rw-r--r--ATRI/plugins/console/__init__.py110
-rw-r--r--ATRI/plugins/console/backend/__init__.py20
-rw-r--r--ATRI/plugins/console/backend/api.py211
-rw-r--r--ATRI/plugins/console/backend/models.py15
-rw-r--r--ATRI/plugins/console/data_source.py93
-rw-r--r--ATRI/plugins/console/listener.py61
-rw-r--r--ATRI/plugins/console/models.py16
-rw-r--r--README.md2
8 files changed, 1 insertions, 527 deletions
diff --git a/ATRI/plugins/console/__init__.py b/ATRI/plugins/console/__init__.py
deleted file mode 100644
index 39fcc26..0000000
--- a/ATRI/plugins/console/__init__.py
+++ /dev/null
@@ -1,110 +0,0 @@
-from datetime import datetime
-
-from nonebot.params import ArgPlainText
-from nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent
-
-from ATRI import conf
-from ATRI.log import log
-from ATRI.service import Service
-from ATRI.permission import MASTER
-from ATRI.message import MessageBuilder
-from ATRI.utils.apscheduler import scheduler
-
-from .data_source import AuthDealer, get_host_ip
-
-
-plugin = (
- Service("控制台")
- .document("前端管理页面")
- .only_admin(True)
- .permission(MASTER)
- .main_cmd("/con")
-)
-
-
-async def __del_auth_key():
- await AuthDealer.clear()
- log.warning("控制台验证密钥已过期")
-
-
-gen_console_key = plugin.cmd_as_group("auth", "获取进入网页后台的凭证")
-
-
-@gen_console_key.got("is_pub_n", "咱的运行环境是否有公网(y/n)")
-async def _(event: PrivateMessageEvent, is_pub_n: str = ArgPlainText("is_pub_n")):
- is_access_key = conf.BotConfig.access_token
- if not is_access_key:
- await gen_console_key.finish(
- MessageBuilder("缺少设置: access_token")
- .text("请先填写该内容, 以保证ATRI与协议端链接的安全性")
- .text("填写并重启, 方可启用控制台")
- .text("Tip: 该内容请尽可能地复杂, 请勿使用中文")
- )
-
- auth_info = AuthDealer.get()
- if auth_info:
- now_time = datetime.now().timestamp()
- if now_time < auth_info.dead_time:
- raw_last_time = auth_info.dead_time - now_time
- last_time = datetime.fromtimestamp(raw_last_time).minute
- await gen_console_key.finish(
- MessageBuilder("之前生成的密钥还在有效时间内奥")
- .text(f"Token: {auth_info.token}")
- .text(f"剩余有效时间: {last_time} min")
- )
- await AuthDealer.clear()
-
- if is_pub_n != "y":
- host = str(await get_host_ip(False))
- await gen_console_key.send("没有公网吗...嗯知道了")
- else:
- host = str(await get_host_ip(True))
- port = conf.BotConfig.port
- auth = AuthDealer()
- data = await auth.store()
-
- msg = (
- MessageBuilder("控制台信息已生成!")
- .text(f"请访问: {host}:{port}")
- .text(f"Token: {auth.get_token()}")
- .text("该 token 有效时间为 15min")
- )
-
- scheduler.add_job(
- __del_auth_key,
- name="清除后台验证凭证",
- next_run_time=datetime.fromtimestamp(data.dead_time),
- misfire_grace_time=15,
- )
-
- await gen_console_key.finish(msg)
-
-
-@gen_console_key.handle()
-async def _(event: GroupMessageEvent):
- await gen_console_key.finish("请私戳咱获取(")
-
-
-del_console_key = plugin.cmd_as_group("del", "销毁进入网页后台的凭证")
-
-
-@del_console_key.got("is_sure_d", "...你确定吗(y/n)")
-async def _(is_sure: str = ArgPlainText("is_sure_d")):
- if is_sure != "y":
- await del_console_key.finish("反悔了呢...")
-
- data = AuthDealer.get()
- if data is None:
- await del_console_key.finish("你还没向咱索取凭证呢...私戳咱键入 /con.auth 以获取")
-
- await AuthDealer.clear()
-
- await del_console_key.finish("销毁成功!如需再次获取: /con.auth")
-
-
-import nonebot
-
-from .backend import app
-
-driver = nonebot.get_app()
-driver.mount("/", app, name="test")
diff --git a/ATRI/plugins/console/backend/__init__.py b/ATRI/plugins/console/backend/__init__.py
deleted file mode 100644
index 4fb5a37..0000000
--- a/ATRI/plugins/console/backend/__init__.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from fastapi import FastAPI
-
-# from fastapi.staticfiles import StaticFiles
-from fastapi.middleware.cors import CORSMiddleware
-
-from .api import router as api_router
-
-# from ..data_source import FRONTEND_DIR
-
-
-app = FastAPI(
- title="Console for ATRI",
- description="A admin UI controller for ATRI",
-)
-
-app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["GET"])
-
-app.include_router(api_router, prefix="/capi")
-
-# app.mount("/", StaticFiles(directory=FRONTEND_DIR, html=True), name="Console for ATRI")
diff --git a/ATRI/plugins/console/backend/api.py b/ATRI/plugins/console/backend/api.py
deleted file mode 100644
index 25e9da5..0000000
--- a/ATRI/plugins/console/backend/api.py
+++ /dev/null
@@ -1,211 +0,0 @@
-import os
-import asyncio
-from typing import Union
-from datetime import datetime
-
-from fastapi import APIRouter, status, Depends, Query, HTTPException
-from fastapi.websockets import WebSocket, WebSocketState
-from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError
-
-from ATRI.utils import machine
-from ATRI.service import SERVICES_DIR, ServiceInfo, ServiceTools
-
-from ..data_source import *
-from ..listener import get_message_info
-from . import models
-
-
-def _author(token: Union[str, None] = Query(default=None)):
- data = AuthDealer.get()
- if data is None:
- raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="缺少信息")
-
- now_time = datetime.now().timestamp()
- if token != data.token:
- raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="密钥不正确")
- elif now_time > data.dead_time:
- raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="密钥已过期")
- else:
- return "OK"
-
-
-router = APIRouter(tags=["capi"], dependencies=[Depends(_author)])
-
-
[email protected]("/", response_model=models.Response)
-async def _():
- return models.Response(status=status.HTTP_200_OK, detail="控制台 API 路径", data=dict())
-
-
[email protected]("/auth", response_model=models.Response)
-async def _():
- return models.Response(status=status.HTTP_200_OK, detail="OK", data=dict())
-
-
-async def _(websocket: WebSocket):
- await websocket.accept()
-
- try:
- while websocket.client_state == WebSocketState.CONNECTED:
- await websocket.send_json(
- models.Response(
- status=status.HTTP_200_OK,
- detail="OK",
- data=models.StatusInfo(
- platform=machine.get_platform_info().dict(),
- cpu=machine.get_cpu_info().dict(),
- mem=machine.get_mem_info().dict(),
- disk=machine.get_disk_info().dict(),
- net=machine.get_net_info().dict(),
- ).dict(),
- ).dict()
- )
- await asyncio.sleep(2)
- except ConnectionClosedOK:
- pass
- except ConnectionClosedError:
- pass
- finally:
- await websocket.close()
- return
-
-
[email protected]("/status/message")
-async def _(websocket: WebSocket):
- await websocket.accept()
-
- try:
- while websocket.client_state == WebSocketState.CONNECTED:
- await websocket.send_json(
- models.Response(
- status=status.HTTP_200_OK,
- detail="OK",
- data=get_message_info().dict(),
- ).dict()
- )
- await asyncio.sleep(1)
- except ConnectionClosedOK:
- pass
- except ConnectionClosedError:
- pass
- finally:
- await websocket.close()
- return
-
-
[email protected]("/service/list", response_model=models.Response)
-async def _():
- result = dict()
- files = os.listdir(SERVICES_DIR)
- for f in files:
- if f == ".DS_Store":
- continue
- serv_path = SERVICES_DIR / f
- data = ServiceInfo.parse_file(serv_path)
- result[data.service] = data.dict()
-
- return models.Response(status=status.HTTP_200_OK, detail="OK", data=result)
-
-
[email protected]("/service/edit", response_model=models.Response)
-async def _(
- service: str,
- enabled: int,
- for_global: int = 1,
- user_id: int = int(),
- group_id: int = int(),
-):
- msg = "OK"
- data = ServiceTools(service).load_service()
- if enabled and for_global:
- data.enabled = True
- elif not enabled and for_global:
- data.enabled = False
-
- if user_id or group_id:
- if enabled:
- if user_id not in data.disable_user:
- msg = "用户不存在于禁用名单"
- else:
- data.disable_user.remove(user_id)
-
- if group_id not in data.disable_group:
- msg = "群不存在于禁用名单"
- else:
- data.disable_group.remove(group_id)
- else:
- if user_id in data.disable_user:
- msg = "用户已存在于禁用名单"
- else:
- data.disable_user.append(user_id)
-
- if group_id in data.disable_group:
- msg = "群已存在于禁用名单"
- else:
- data.disable_group.append(group_id)
-
- ServiceTools(service).save_service(data.dict())
-
- return models.Response(status=status.HTTP_200_OK, detail=msg, data=dict())
-
-
-def _get_block_list():
- # 该处有一 typo
- file_dir = Path(".") / "data" / "plugins" / "manege"
- path = file_dir / "block_user.json"
- user_data = json.loads(path.read_bytes())
-
- path = file_dir / "block_group.json"
- group_data = json.loads(path.read_bytes())
-
- return {"user": user_data, "group": group_data}
-
-
[email protected]("/block/list", response_model=models.Response)
-async def _():
- return models.Response(
- status=status.HTTP_200_OK, detail="OK", data=_get_block_list()
- )
-
-
[email protected]("/block/edit", response_model=models.Response)
-async def _(enabled: int, user_id: int = int(), group_id: int = int()):
- data = _get_block_list()
- now_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- msg = "OK"
- if enabled:
- if user_id:
- if user_id in data["user"]:
- msg = "用户已存在于黑名单"
- else:
- data["user"][user_id] = now_time
- if group_id:
- if group_id in data["group"]:
- msg = "群已存在于黑名单"
- else:
- data["group"][group_id] = now_time
- else:
- if user_id:
- if user_id not in data["user"]:
- msg = "用户不存在于黑名单"
- else:
- del data["user"][user_id]
- if group_id:
- if group_id not in data["group"]:
- msg = "群不存在于黑名单"
- else:
- del data["group"][group_id]
-
- file_dir = Path(".") / "data" / "plugins" / "manege"
- path = file_dir / "block_user.json"
- await FileDealer(path).write(json.dumps(data["user"]))
-
- path = file_dir / "block_group.json"
- await FileDealer(path).write(json.dumps(data["group"]))
-
- return models.Response(
- status=status.HTTP_200_OK,
- detail=msg,
- data=data,
- )
diff --git a/ATRI/plugins/console/backend/models.py b/ATRI/plugins/console/backend/models.py
deleted file mode 100644
index e7aeb54..0000000
--- a/ATRI/plugins/console/backend/models.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from pydantic import BaseModel
-
-
-class Response(BaseModel):
- status: int
- detail: str
- data: dict
-
-
-class StatusInfo(BaseModel):
- platform: dict
- cpu: dict
- mem: dict
- disk: dict
- net: dict
diff --git a/ATRI/plugins/console/data_source.py b/ATRI/plugins/console/data_source.py
deleted file mode 100644
index cab951d..0000000
--- a/ATRI/plugins/console/data_source.py
+++ /dev/null
@@ -1,93 +0,0 @@
-import json
-import socket
-import string
-import hashlib
-from pathlib import Path
-from random import sample
-from typing import Optional
-from datetime import datetime, timedelta
-
-from ATRI.utils import request, FileDealer
-from ATRI.log import log
-
-from .models import AuthData
-
-
-CONSOLE_DIR = Path(".") / "data" / "plugins" / "console"
-CONSOLE_DIR.mkdir(parents=True, exist_ok=True)
-
-
-class AuthDealer:
- AUTH_FILE_PATH = CONSOLE_DIR / "data.json"
-
- def __init__(self):
- self.token = str().join(sample(string.ascii_letters + string.digits, 20))
-
- def get_token(self):
- return self.token
-
- def get_md5(self):
- hl = hashlib.md5()
- hl.update(self.token.encode(encoding="utf-8"))
- return hl.hexdigest()
-
- async def store(self) -> AuthData:
- dead_time = (datetime.now() + timedelta(minutes=15)).timestamp()
- data = AuthData(token=self.token, md5=self.get_md5(), dead_time=int(dead_time))
- await FileDealer(self.AUTH_FILE_PATH).write_json(data.dict())
- return data
-
- @classmethod
- def get(cls) -> Optional[AuthData]:
- return (
- AuthData.parse_file(cls.AUTH_FILE_PATH)
- if cls.AUTH_FILE_PATH.is_file()
- and json.loads(cls.AUTH_FILE_PATH.read_bytes())
- else None
- )
-
- @classmethod
- async def clear(cls):
- await FileDealer(cls.AUTH_FILE_PATH).write_json(dict())
-
-
-async def get_host_ip(is_pub: bool):
- if is_pub:
- data = await request.get("https://ifconfig.me/ip")
- return data.text
-
- s = None
- try:
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- s.connect(("8.8.8.8", 80))
- ip = s.getsockname()[0]
- return ip
- finally:
- if s:
- s.close()
-
-
-# FRONTEND_DIR = CONSOLE_DIR / "frontend"
-# FRONTEND_DIR.mkdir(parents=True, exist_ok=True)
-# __CONSOLE_RESOURCE_URL = (
-# "https://guc.imki.moe/kyomotoi/Project-ATRI-Console/main/archive/dist.zip"
-# )
-
-
-# async def init_resource():
-# log.info("控制台初始化中...")
-
-# try:
-# resp = await request.get(__CONSOLE_RESOURCE_URL)
-# except Exception:
-# log.error("控制台资源装载失败, 将无法访问管理界面")
-# return
-
-# file_path = CONSOLE_DIR / "dist.zip"
-# with open(file_path, "wb") as w:
-# w.write(resp.read())
-
-# with zipfile.ZipFile(file_path, "r") as zr:
-# zr.extractall(FRONTEND_DIR)
-
-# log.success("控制台初始化完成")
diff --git a/ATRI/plugins/console/listener.py b/ATRI/plugins/console/listener.py
deleted file mode 100644
index 1bd553c..0000000
--- a/ATRI/plugins/console/listener.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from typing import Optional
-from pydantic import BaseModel
-
-from nonebot.message import run_postprocessor
-
-from ATRI.utils.apscheduler import scheduler
-
-
-interval_deal_message = int()
-interval_recv_message = int()
-interval_failed_message = int()
-
-total_deal_message = int()
-total_recv_message = int()
-total_failed_message = int()
-
-
-@run_postprocessor
-async def _(exception: Optional[Exception]):
- global interval_deal_message, interval_recv_message, interval_failed_message
- global total_deal_message, total_recv_message, total_failed_message
-
- if exception:
- interval_failed_message += 1
- total_failed_message += 1
- else:
- interval_deal_message += 1
- total_deal_message += 1
-
- interval_recv_message += 1
- total_recv_message += 1
-
-
[email protected]_job("interval", name="消息统计数据重置", seconds=15, misfire_grace_time=30)
-async def _():
- global interval_deal_message, interval_recv_message, interval_failed_message
-
- interval_deal_message = 0
- interval_recv_message = 0
- interval_failed_message = 0
-
-
-class MessageInfo(BaseModel):
- interval_deal: int
- interval_recv: int
- interval_failed: int
-
- total_deal: int
- total_recv: int
- total_failed: int
-
-
-def get_message_info() -> MessageInfo:
- return MessageInfo(
- interval_deal=interval_deal_message,
- interval_recv=interval_recv_message,
- interval_failed=interval_failed_message,
- total_deal=total_deal_message,
- total_recv=total_deal_message,
- total_failed=total_failed_message,
- )
diff --git a/ATRI/plugins/console/models.py b/ATRI/plugins/console/models.py
deleted file mode 100644
index f7ddf8d..0000000
--- a/ATRI/plugins/console/models.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from pydantic import BaseModel
-
-
-class AuthData(BaseModel):
- token: str
- md5: str
- dead_time: int
-
-
-class MessageDealerInfo(BaseModel):
- recv_msg: str
- deal_msg: str
- failed_deal_msg: str
- total_r_m: str
- total_d_m: str
- total_f_m: str
diff --git a/README.md b/README.md
index 022f316..27db58a 100644
--- a/README.md
+++ b/README.md
@@ -78,7 +78,7 @@
请参考文档: [部署项目](https://atri.imki.moe/install/installation/)
## 📖 文档 | Documentation
-所有公开的信息都可在 [atri.imki.moe](https://atri.imki.moe) 获取. 使用 [MkDocs](https://github.com/mkdocs/mkdocs/) 构建.
+所有公开的信息都可在 [atri.imki.moe](https://atri.imki.moe) 获取. 使用 [VitePress](https://vitepress.dev/) 构建.
[文档仓库](https://github.com/Kyomotoi/Project-ATRI-Docs)