{"contents":"# -*- coding: utf-8 -*-#\n# -------------------------------------------------------------------------------\n# Name: __init__.py\n# Description: \n# Author: xaoyaoo\n# Date: 2023/12/14\n# -------------------------------------------------------------------------------\nimport os\nimport subprocess\nimport sys\nimport time\nimport uvicorn\nimport mimetypes\nimport logging\nfrom logging.handlers import RotatingFileHandler\n\nfrom uvicorn.config import LOGGING_CONFIG\nfrom fastapi import FastAPI, Request, Path, Query\nfrom fastapi.staticfiles import StaticFiles\nfrom fastapi.exceptions import RequestValidationError\nfrom starlette.middleware.cors import CORSMiddleware\nfrom starlette.responses import RedirectResponse, FileResponse\n\nfrom .config import gc\nfrom .helpers import is_port_in_use\nfrom wxdump_linux._logging import server_loger\nfrom .response import ReJson\nfrom .remote_server import rs_api\nfrom .local_server import ls_api\n\nfrom wxdump_linux import __version__\n\n\ndef gen_fastapi_app(handler):\n app = FastAPI(title=\"wxdump-linux\", description=\"Linux 版微信数据库解密工具\", version=__version__,\n contact={\"name\": \"wxdump-linux\"},\n license_info={\"name\": \"MIT License\"})\n\n web_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), \"ui\", \"web\") # web文件夹路径\n\n # 跨域\n origins = [\n \"http://localhost:5000\",\n \"http://127.0.0.1:5000\",\n \"http://localhost:8080\", # 开发环境的客户端地址\"\n # \"http://0.0.0.0:5000\",\n # \"*\"\n ]\n app.add_middleware(\n CORSMiddleware,\n allow_origins=origins, # 允许所有源\n allow_credentials=True,\n allow_methods=[\"*\"], # 允许所有方法\n allow_headers=[\"*\"], # 允许所有头\n )\n\n @app.on_event(\"startup\")\n async def startup_event():\n logger = logging.getLogger(\"uvicorn\")\n logger.addHandler(handler)\n\n # 错误处理\n @app.exception_handler(RequestValidationError)\n async def request_validation_exception_handler(request: Request, exc: RequestValidationError):\n # print(request.body)\n return ReJson(1002, {\"detail\": exc.errors()})\n\n # 首页\n @app.get(\"/\")\n @app.get(\"/index.html\")\n async def index():\n response = RedirectResponse(url=\"/s/index.html\", status_code=307)\n return response\n\n # 路由挂载\n app.include_router(rs_api, prefix='/api/rs', tags=['远程api'])\n app.include_router(ls_api, prefix='/api/ls', tags=['本地api'])\n\n # 根据文件类型,设置mime_type,返回文件\n @app.get(\"/s/{filename:path}\")\n async def serve_file(filename: str):\n # 构建完整的文件路径\n file_path = os.path.join(web_path, filename)\n file_path = os.path.abspath(file_path)\n\n # 检查文件是否存在\n if os.path.isfile(file_path):\n # 获取文件 MIME 类型\n mime_type, _ = mimetypes.guess_type(file_path)\n # 如果 MIME 类型为空,则默认为 application/octet-stream\n if mime_type is None:\n mime_type = \"application/octet-stream\"\n server_loger.warning(f\"[+] 无法获取文件 MIME 类型,使用默认值:{mime_type}\")\n if file_path.endswith(\".js\"):\n mime_type = \"text/javascript\"\n server_loger.info(f\"[+] 文件 {file_path} MIME 类型:{mime_type}\")\n # 返回文件\n return FileResponse(file_path, media_type=mime_type)\n\n # 如果文件不存在,返回 404\n return {\"detail\": \"Not Found\"}, 404\n\n # 静态文件挂载\n # if os.path.exists(os.path.join(web_path, \"index.html\")):\n # app.mount(\"/s\", StaticFiles(directory=web_path), name=\"static\")\n\n return app\n\n\ndef start_server(port=5000, online=False, debug=False, isopenBrowser=True,\n merge_path=\"\", wx_path=\"\", my_wxid=\"\", ):\n \"\"\"\n 启动flask\n :param port: 端口号\n :param online: 是否在线查看(局域网查看)\n :param debug: 是否开启debug模式\n :param isopenBrowser: 是否自动打开浏览器\n :return:\n \"\"\"\n work_path = os.path.join(os.getcwd(), \"wxdump_work\") # 临时文件夹,用于存放图片等 # 全局变量\n if not os.path.exists(work_path):\n os.makedirs(work_path, exist_ok=True)\n server_loger.info(f\"[+] 创建临时文件夹:{work_path}\")\n print(f\"[+] 创建临时文件夹:{work_path}\")\n\n # 日志处理,写入到文件\n log_format = '[{levelname[0]}] {asctime} [{name}:{levelno}] {pathname}:{lineno} {message}'\n log_datefmt = '%Y-%m-%d %H:%M:%S'\n log_file_path = os.path.join(work_path, \"wxdump.log\")\n file_handler = RotatingFileHandler(log_file_path, mode=\"a\", maxBytes=10 * 1024 * 1024, backupCount=3)\n formatter = logging.Formatter(fmt=log_format, datefmt=log_datefmt, style='{')\n file_handler.setFormatter(formatter)\n\n wx_core_logger = logging.getLogger(\"wx_core\")\n db_prepare = logging.getLogger(\"db_prepare\")\n\n # 这几个日志处理器为本项目的日志处理器\n server_loger.addHandler(file_handler)\n wx_core_logger.addHandler(file_handler)\n db_prepare.addHandler(file_handler)\n\n conf_file = os.path.join(work_path, \"conf_auto.json\") # 用于存放各种基础信息\n auto_setting = \"auto_setting\"\n env_file = os.path.join(work_path, \".env\") # 用于存放环境变量\n # set 环境变量\n os.environ[\"WXDUMP_WORK_PATH\"] = work_path\n os.environ[\"WXDUMP_CONF_FILE\"] = conf_file\n os.environ[\"WXDUMP_AUTO_SETTING\"] = auto_setting\n\n with open(env_file, \"w\", encoding=\"utf-8\") as f:\n f.write(f\"WXDUMP_WORK_PATH = '{work_path}'\\n\")\n f.write(f\"WXDUMP_CONF_FILE = '{conf_file}'\\n\")\n f.write(f\"WXDUMP_AUTO_SETTING = '{auto_setting}'\\n\")\n\n if merge_path and os.path.exists(merge_path):\n my_wxid = my_wxid if my_wxid else \"wxid_dbshow\"\n gc.set_conf(my_wxid, \"wxid\", my_wxid) # 初始化wxid\n gc.set_conf(my_wxid, \"merge_path\", merge_path) # 初始化merge_path\n gc.set_conf(my_wxid, \"wx_path\", wx_path) # 初始化wx_path\n db_config = {\"key\": my_wxid, \"type\": \"sqlite\", \"path\": merge_path}\n gc.set_conf(my_wxid, \"db_config\", db_config) # 初始化db_config\n gc.set_conf(auto_setting, \"last\", my_wxid) # 初始化last\n\n # 检查端口是否被占用\n if online:\n host = '0.0.0.0'\n else:\n host = \"127.0.0.1\"\n\n if is_port_in_use(host, port):\n server_loger.error(f\"Port {port} is already in use. Choose a different port.\")\n print(f\"Port {port} is already in use. Choose a different port.\")\n input(\"Press Enter to exit...\")\n return # 退出程序\n if isopenBrowser:\n try:\n # 自动打开浏览器\n url = f\"http://127.0.0.1:{port}/\"\n # 根据操作系统使用不同的命令打开默认浏览器\n if sys.platform.startswith('darwin'): # macOS\n subprocess.call(['open', url])\n elif sys.platform.startswith('win'): # Windows\n subprocess.call(['start', url], shell=True)\n elif sys.platform.startswith('linux'): # Linux\n subprocess.call(['xdg-open', url])\n else:\n server_loger.error(f\"Unsupported platform, can't open browser automatically.\", exc_info=True)\n print(\"Unsupported platform, can't open browser automatically.\")\n except Exception as e:\n server_loger.error(f\"自动打开浏览器失败:{e}\", exc_info=True)\n\n time.sleep(1)\n server_loger.info(f\"启动flask服务,host:port:{host}:{port}\")\n print(\"[+] 请使用浏览器访问 http://127.0.0.1:5000/ 查看聊天记录\")\n global app\n print(\"[+] 如需查看api文档,请访问 http://127.0.0.1:5000/docs \")\n app = gen_fastapi_app(file_handler)\n\n LOGGING_CONFIG[\"formatters\"][\"default\"][\"fmt\"] = \"[%(asctime)s] %(levelprefix)s %(message)s\"\n LOGGING_CONFIG[\"formatters\"][\"access\"][\n \"fmt\"] = '[%(asctime)s] %(levelprefix)s %(client_addr)s - \"%(request_line)s\" %(status_code)s'\n\n uvicorn.run(app=app, host=host, port=port, reload=debug, log_level=\"info\", workers=1, env_file=env_file)\n\n\napp = None\n\n__all__ = [\"start_server\", \"gen_fastapi_app\"]\n","is_binary":false,"path":"wxdump_linux/api/__init__.py","ref":""}