diff --git a/.env b/.env deleted file mode 100644 index 0c0ebaa..0000000 --- a/.env +++ /dev/null @@ -1,14 +0,0 @@ -# VPS 环境配置(66.hyf2.cc @ 47.76.87.111) -# 部署路径:/opt/jiedian - -VPS_IP=47.76.87.111 -DOMAIN=66.hyf2.cc -ACME_EMAIL=admin@hyf2.cc -REALITY_SERVER_NAME=www.microsoft.com - -PANEL_USERNAME=dekun -PANEL_PASSWORD=Woaini521@ - -REALITY_PRIVATE_KEY=IPKtaw1aVb4fS0TPcimu8zwaVGml-JJ5H1rj-_TFQHM -REALITY_PUBLIC_KEY=51H_ikqYdDRgCpjq3pvMYNbqrX8S3zuow1UEjqTN-nI -REALITY_SHORT_ID=e126b4ef9d36adfc diff --git a/.gitignore b/.gitignore index facb2af..928fba8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ client/generated/ data/ panel/venv/ + +# 本地环境配置(勿提交密钥) +.env # 临时文件 *.log .DS_Store diff --git a/panel/db.py b/panel/db.py index 4e72476..a34bbc7 100644 --- a/panel/db.py +++ b/panel/db.py @@ -1,16 +1,36 @@ """SQLite 数据库:管理员账号与节点。""" from __future__ import annotations +import hashlib +import hmac import os import secrets import sqlite3 import subprocess from pathlib import Path -from werkzeug.security import check_password_hash, generate_password_hash - ROOT = Path(os.environ.get("JIEDIAN_ROOT", Path(__file__).resolve().parents[1])) DB_FILE = ROOT / "data" / "nodes.db" +_PBKDF2_ITERATIONS = 600000 + + +def _hash_password(password: str) -> str: + salt = secrets.token_hex(16) + digest = hashlib.pbkdf2_hmac( + "sha256", password.encode(), salt.encode(), _PBKDF2_ITERATIONS + ) + return f"pbkdf2:sha256:{_PBKDF2_ITERATIONS}${salt}${digest.hex()}" + + +def _verify_password(stored: str, password: str) -> bool: + if not stored or stored.count("$") < 2: + return False + method, salt, expected = stored.split("$", 2) + if not method.startswith("pbkdf2:sha256:"): + return False + iterations = int(method.rsplit(":", 1)[1]) + digest = hashlib.pbkdf2_hmac("sha256", password.encode(), salt.encode(), iterations) + return hmac.compare_digest(digest.hex(), expected) def connect() -> sqlite3.Connection: @@ -49,7 +69,7 @@ def init_db(env: dict[str, str]) -> None: conn.execute("DELETE FROM admin") conn.execute( "INSERT INTO admin (username, password_hash) VALUES (?, ?)", - (username, generate_password_hash(password)), + (username, _hash_password(password)), ) count = conn.execute("SELECT COUNT(*) AS c FROM nodes").fetchone()["c"] @@ -72,7 +92,7 @@ def verify_admin(username: str, password: str) -> bool: conn.close() if row is None: return False - return check_password_hash(row["password_hash"], password) + return _verify_password(row["password_hash"], password) def list_nodes() -> list[dict]: @@ -117,7 +137,6 @@ def node_count() -> int: def _generate_credentials() -> tuple[str, str]: - sb = "sing-box" - uuid = subprocess.check_output([sb, "generate", "uuid"], text=True).strip() + uuid = subprocess.check_output(["sing-box", "generate", "uuid"], text=True).strip() hy2 = secrets.token_urlsafe(18)[:24] return uuid, hy2 diff --git a/scripts/install.sh b/scripts/install.sh index 06c181e..9f37cdd 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -140,7 +140,10 @@ nginx -t && systemctl enable nginx && systemctl restart nginx log "安装 Python 面板依赖 ..." python3 -m venv "$ROOT_DIR/panel/venv" +"$ROOT_DIR/panel/venv/bin/pip" install -q --upgrade pip "$ROOT_DIR/panel/venv/bin/pip" install -q -r "$ROOT_DIR/panel/requirements.txt" +"$ROOT_DIR/panel/venv/bin/python" -c "import flask" \ + || err "面板依赖安装失败,请检查网络后重试" log "初始化节点数据库 ..." "$ROOT_DIR/panel/venv/bin/python" "$ROOT_DIR/panel/init_db.py"