diff --git a/CHANGELOG.md b/CHANGELOG.md index dd8a178..84d877e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,21 @@ --- -## v2.1.0(当前) +## v2.1.1(当前) + +### 新增 / 调整 + +- **图片点击放大**:查询/添加预览支持灯箱全屏查看(Esc / 点击遮罩关闭) +- **一键部署改为 curl | bash**(与 crypto_monitor_user 同风格): + ```bash + curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash + ``` +- 部署脚本迁至 `deploy/manage.sh`(支持管道自举、从 `/dev/tty` 读菜单) +- 文档仅保留 **Ubuntu** 说明,移除 Windows 相关内容 + +--- + +## v2.1.0 ### 新增 @@ -15,34 +29,22 @@ - **系统设置 Tab**:账户密码 / 自定义类型 / 备份恢复 - **前端备份恢复**:下载 `.tar.gz`、立即备份、上传恢复(含 `.env`、`data.json`、`settings.json`、`uploads`) - **每日自动备份**:服务内线程(03:00)+ 部署脚本 cron,备份到 `/root/crypto_key_backups/` -- **交互式管理脚本** `scripts/manage.sh`: +- **交互式管理脚本**: 1. 一键部署 2. 更新(**仅 `git pull`,严禁 scp**) 3. 一键卸载 ### 变更 -- `scripts/install-ubuntu.sh` 改为调用 `manage.sh deploy` - 自定义字段类型增加:`textarea`、`image` ### 升级注意 ```bash -cd /opt/crypto_key -sudo bash scripts/manage.sh +curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash # 选择 2) 更新 ``` -或: - -```bash -cd /opt/crypto_key -git pull -source venv/bin/activate -pip install -r requirements.txt -pm2 restart api-key-manager -``` - --- ## v2.0.0 @@ -111,7 +113,7 @@ pm2 restart api-key-manager - PM2 守护进程支持(`ecosystem.config.cjs`) - Ubuntu `/opt/crypto_key` 部署脚本与文档 -- 启动脚本:`pm2-start.sh` / `pm2-start.ps1` +- 启动脚本:`pm2-start.sh` / `pm2-stop.sh` --- diff --git a/DEPLOY.md b/DEPLOY.md index 3c97489..7b752fd 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -1,4 +1,4 @@ -# 部署文档 — crypto_key(Ubuntu /opt) +# 部署文档 — crypto_key(Ubuntu) > 仓库:[https://git.bz121.com/dekun/crypto_key](https://git.bz121.com/dekun/crypto_key.git) > 部署路径:**`/opt/crypto_key`** @@ -14,19 +14,16 @@ → http://:5200 → PM2 (api-key-manager) → venv/python app.py (Flask) - → .env (登录账号 + 加密主密钥) - → data.json (加密后的凭证数据) - → settings.json (自定义类型配置) - → uploads/ (图片附件) + → .env / data.json / settings.json / uploads/ → /root/crypto_key_backups/ (每日自动备份) ``` | 文件 | 说明 | 是否提交 Git | |------|------|----------------| -| `.env` | `SECRET_KEY`、`AUTH_*`、`DATA_ENCRYPTION_KEY` | 否 | +| `.env` | 登录账号 + 加密主密钥 | 否 | | `data.json` | 加密凭证库 | 否 | -| `settings.json` | 自定义类型定义 | 否 | -| `uploads/` | 上传的图片 | 否 | +| `settings.json` | 自定义类型 | 否 | +| `uploads/` | 上传图片 | 否 | | `venv/` | Python 虚拟环境 | 否 | --- @@ -35,28 +32,20 @@ | 项目 | 要求 | |------|------| -| 系统 | Ubuntu 20.04 / 22.04 / 24.04 LTS(Windows 见附录) | +| 系统 | Ubuntu 20.04 / 22.04 / 24.04 LTS | | Python | 3.8+ | -| Node.js | 16+(PM2 守护时需要) | -| 权限 | `sudo`(管理脚本) | +| Node.js | 16+(PM2) | +| 权限 | root | | 磁盘 | ≥ 200MB | --- -## 三、交互式一键部署(推荐) +## 三、一键部署(推荐) -### 3.1 克隆仓库 +**无需预先 clone**,在 Ubuntu 服务器上执行: ```bash -sudo mkdir -p /opt -sudo git clone https://git.bz121.com/dekun/crypto_key.git /opt/crypto_key -cd /opt/crypto_key -``` - -### 3.2 运行管理脚本 - -```bash -sudo bash scripts/manage.sh +curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash ``` 交互菜单: @@ -68,25 +57,28 @@ sudo bash scripts/manage.sh 0) 退出 ``` -也可直接传参: +也可传参直接执行: ```bash -sudo bash scripts/manage.sh deploy # 等同选项 1 -sudo bash scripts/manage.sh update # 等同选项 2 -sudo bash scripts/manage.sh uninstall # 等同选项 3 +curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash -s -- deploy +curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash -s -- update ``` -兼容旧入口:`sudo bash scripts/install-ubuntu.sh`(内部调用 deploy)。 +已安装后本地调用: -### 3.3 部署脚本会做什么 +```bash +bash /opt/crypto_key/deploy/manage.sh +``` + +### 部署脚本会做什么 1. 安装 python3 / venv / git / Node / PM2 2. `git clone` 或 **`git pull`** 到 `/opt/crypto_key` -3. 创建 venv、`pip install -r requirements.txt` +3. 创建 venv、安装依赖 4. 配置每日 03:00 cron 备份到 `/root/crypto_key_backups/` 5. PM2 启动 `api-key-manager` -### 3.4 验证 +### 验证 ```bash pm2 status @@ -102,97 +94,66 @@ curl -s http://127.0.0.1:5200/api/auth/status ## 四、更新升级(仅 git pull) ```bash -cd /opt/crypto_key -sudo bash scripts/manage.sh +curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash # 选择 2) 更新 ``` -脚本流程:更新前自动备份 → `git pull` → 安装依赖 → 刷新 cron → 重启 PM2。 - -**禁止** 使用 scp / rsync 覆盖代码目录;数据文件(`.env`、`data.json`)本来就不在 Git 里,不会被 pull 冲掉。 - -手动更新: +或: ```bash -cd /opt/crypto_key -git pull -source venv/bin/activate -pip install -r requirements.txt -pm2 restart api-key-manager +bash /opt/crypto_key/deploy/manage.sh +# 选择 2 ``` +流程:更新前自动备份 → `git pull` → 安装依赖 → 刷新 cron → 重启 PM2。 + +**禁止** 使用 scp / rsync 覆盖代码目录。 + --- ## 五、一键卸载 ```bash -sudo bash scripts/manage.sh -# 选择 3) 一键卸载,输入 yes 确认 +bash /opt/crypto_key/deploy/manage.sh +# 选择 3,输入 yes 确认 ``` 会停止 PM2、移除 cron、删除 `/opt/crypto_key`;卸载前尽量再打一份包到 `/root/crypto_key_backups/`,**保留备份目录**。 --- -## 六、Windows 本地部署 - -```powershell -cd C:\path\to\crypto_key -python -m venv venv -.\venv\Scripts\activate -pip install -r requirements.txt -copy .env.example .env -python app.py -``` - -自动备份目录回退为项目下 `backups\`(无 `/root` 写权限时)。 - ---- - -## 七、PM2 运维 +## 六、PM2 运维 | 命令 | 说明 | |------|------| | `pm2 status` | 查看状态 | | `pm2 logs api-key-manager` | 查看日志 | | `pm2 restart api-key-manager` | 重启 | -| `./pm2-start.sh` | 启动(Linux) | +| `./pm2-start.sh` | 启动 | +| `./pm2-stop.sh` | 停止 | --- -## 八、备份与恢复 +## 七、备份与恢复 -### 8.1 自动备份 +### 自动备份 - 应用内守护线程:每天 **03:00** -- cron(部署脚本安装):每天 **03:00** -- 目录:`/root/crypto_key_backups/crypto_key_backup_YYYYMMDD_HHMMSS.tar.gz` -- 保留约 30 天,过期自动清理 +- cron:每天 **03:00** +- 目录:`/root/crypto_key_backups/` +- 约保留 30 天 -### 8.2 前端备份恢复 +### 前端备份恢复 -系统设置 → **备份恢复**: - -- 下载备份 -- 立即备份到服务器 -- 上传 `.tar.gz` 恢复 +系统设置 → **备份恢复**:下载备份 / 立即备份 / 上传恢复。 备份内容:`.env`、`data.json`、`settings.json`、`uploads/`。 -### 8.3 命令行恢复 - -```bash -# 解压到项目目录(示例) -cd /opt/crypto_key -tar xzvf /root/crypto_key_backups/某备份.tar.gz -pm2 restart api-key-manager -``` - **`.env` 中 `DATA_ENCRYPTION_KEY` 必须与备份一致。** --- -## 九、防火墙 +## 八、防火墙 ```bash sudo ufw allow from 192.168.0.0/16 to any port 5200 proto tcp @@ -202,7 +163,7 @@ sudo ufw allow from 192.168.0.0/16 to any port 5200 proto tcp --- -## 十、故障排查 +## 九、故障排查 | 现象 | 处理 | |------|------| @@ -210,11 +171,11 @@ sudo ufw allow from 192.168.0.0/16 to any port 5200 proto tcp | 无法登录 | 检查 `.env` 中 `AUTH_*` | | 数据无法解密 | `DATA_ENCRYPTION_KEY` 是否与备份一致 | | 局域网无法访问 | `ss -tlnp \| grep 5200`;检查 ufw | -| 图片 404 | 确认 `uploads/` 存在且备份已含图片文件 | +| 图片 404 | 确认 `uploads/` 存在 | --- -## 十一、目录结构 +## 十、目录结构 ``` /opt/crypto_key/ @@ -225,29 +186,26 @@ sudo ufw allow from 192.168.0.0/16 to any port 5200 proto tcp ├── index.html ├── requirements.txt ├── ecosystem.config.cjs -├── scripts/ -│ ├── manage.sh # 交互式:部署 / 更新 / 卸载 -│ └── install-ubuntu.sh # 兼容入口 → deploy -├── uploads/ # 图片(运行时) +├── deploy/ +│ └── manage.sh # curl | bash 入口 +├── scripts/ # 兼容旧入口 +├── uploads/ ├── logs/ -├── venv/ -└── ... +└── venv/ ``` --- -## 十二、命令速查 +## 十一、命令速查 ```bash -# 首次 -sudo git clone https://git.bz121.com/dekun/crypto_key.git /opt/crypto_key -cd /opt/crypto_key && sudo bash scripts/manage.sh # 选 1 +# 一键(推荐) +curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash -# 更新(git pull only) -sudo bash scripts/manage.sh # 选 2 - -# 卸载 -sudo bash scripts/manage.sh # 选 3 +# 日常 +bash /opt/crypto_key/deploy/manage.sh +pm2 status +pm2 logs api-key-manager --lines 50 ``` 使用细节请参阅 **[USAGE.md](./USAGE.md)**。 diff --git a/README.md b/README.md index fce44bd..6e88698 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # crypto_key — 凭证保险库 -本地 / 局域网 Web 工具,集中管理交易所 API、钱包助记词/密钥、网站、邮箱、机器人、微信/QQ 及自定义类型凭证。数据 **AES 加密** 存储,**用户名密码登录**,浏览器不缓存明文。 +Ubuntu / 局域网 Web 工具,集中管理交易所 API、钱包助记词/密钥、网站、邮箱、机器人、微信/QQ 及自定义类型凭证。数据 **AES 加密** 存储,**用户名密码登录**,浏览器不缓存明文。 | 项目 | 说明 | |------|------| | 仓库 | [git.bz121.com/dekun/crypto_key](https://git.bz121.com/dekun/crypto_key.git) | | 端口 | `5200`(`0.0.0.0`,局域网可访问) | -| Ubuntu 部署 | `/opt/crypto_key` + PM2 | +| 部署路径 | `/opt/crypto_key` + PM2 | --- @@ -15,29 +15,47 @@ | 文档 | 说明 | |------|------| | **[USAGE.md](./USAGE.md)** | 使用说明(登录、添加、查询、系统设置) | -| **[DEPLOY.md](./DEPLOY.md)** | 部署文档(Ubuntu/Windows、PM2、备份、排错) | +| **[DEPLOY.md](./DEPLOY.md)** | Ubuntu 部署、更新、备份、排错 | | **[CHANGELOG.md](./CHANGELOG.md)** | 更新说明与版本升级注意 | --- -## 快速开始 +## 一键部署(Ubuntu) + +```bash +curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash +``` + +交互菜单: + +1. 一键部署 +2. 更新(**仅 git pull**,严禁 scp) +3. 一键卸载 + +已安装后也可: + +```bash +bash /opt/crypto_key/deploy/manage.sh +``` + +详见 [DEPLOY.md](./DEPLOY.md)。 + +--- + +## 本地开发启动 ```bash git clone https://git.bz121.com/dekun/crypto_key.git cd crypto_key python3 -m venv venv -source venv/bin/activate # Windows: venv\Scripts\activate +source venv/bin/activate pip install -r requirements.txt -cp .env.example .env # 可选,首次运行也会自动生成 +cp .env.example .env python app.py ``` -浏览器打开: - -- 本机:http://127.0.0.1:5200 -- 局域网:`http://<本机IP>:5200` - -默认账号(请尽快在系统设置中修改):`admin` / `admin123` +浏览器:http://127.0.0.1:5200 +默认账号(请尽快修改):`admin` / `admin123` --- @@ -45,30 +63,11 @@ python app.py - 登录鉴权(凭据在 `.env`,Session 在服务端) - 内置类型:交易所、**钱包助记词**、**钱包密钥**、网站、邮箱、企微/钉钉机器人、微信、QQ -- **图片上传**:助记词/密钥等可附带截图 -- 自定义类型:系统设置中添加(小红书、抖音等) +- **图片上传**:助记词/密钥等可附带截图,**点击可放大** +- 自定义类型:系统设置中添加 - Tab 界面:添加凭证 / 查询凭证;查询类型为下拉筛选 - 系统设置 Tab:账户密码 / 自定义类型 / **备份恢复** -- 每日自动备份到 `/root/crypto_key_backups/`(无权限时回退到项目 `backups/`) -- 旧版明文 `data.json` 自动迁移加密 - ---- - -## Ubuntu 一键部署(交互式) - -```bash -sudo git clone https://git.bz121.com/dekun/crypto_key.git /opt/crypto_key -cd /opt/crypto_key -sudo bash scripts/manage.sh -``` - -菜单: - -1. 一键部署 -2. 更新(**仅 git pull**,严禁 scp) -3. 一键卸载 - -详见 [DEPLOY.md](./DEPLOY.md)。 +- 每日自动备份到 `/root/crypto_key_backups/` --- @@ -82,7 +81,7 @@ sudo bash scripts/manage.sh | `env_config.py` | `.env` 管理 | | `index.html` | 前端单页 | | `ecosystem.config.cjs` | PM2 配置 | -| `scripts/manage.sh` | 交互式部署/更新/卸载 | +| `deploy/manage.sh` | 交互式一键部署 / 更新 / 卸载 | --- @@ -91,13 +90,3 @@ sudo bash scripts/manage.sh - 仅在可信局域网使用,勿将 5200 映射到公网 - 定期备份 `.env` 与 `data.json`(密钥丢失将无法解密) - 勿将 `.env`、`data.json`、`uploads/` 提交到 Git - ---- - -## 依赖 - -``` -flask, python-dotenv, cryptography, werkzeug -``` - -服务器 PM2 部署另需 Node.js 16+。 diff --git a/USAGE.md b/USAGE.md index b24ef94..3bd20c1 100644 --- a/USAGE.md +++ b/USAGE.md @@ -88,7 +88,7 @@ |------|------| | **隐藏敏感字段** | 勾选后以圆点显示;复制仍为明文 | | **复制** | 字段右侧「复制」 | -| **图片** | 助记词/密钥等记录可预览已上传图片 | +| **图片** | 助记词/密钥等记录可预览已上传图片;**点击图片可放大**,按 Esc 或点遮罩关闭 | | **删除** | 卡片右上角,需确认 | --- @@ -145,7 +145,13 @@ A:仅支持 jpg/png/gif/webp/bmp,单文件不超过约 16MB。 A:确认备份包内 `.env` 的 `DATA_ENCRYPTION_KEY` 完整。 **Q:更新代码怎么做?** -A:服务器上 `sudo bash scripts/manage.sh` → 选 **2 更新**(仅 git pull,不要用 scp)。 +A:服务器执行: + +```bash +curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash +``` + +选择 **2 更新**(仅 git pull,不要用 scp)。 --- diff --git a/deploy/manage.sh b/deploy/manage.sh new file mode 100644 index 0000000..51acc73 --- /dev/null +++ b/deploy/manage.sh @@ -0,0 +1,321 @@ +#!/usr/bin/env bash +# crypto_key 部署管理器 — 一键部署 / 更新 / 卸载 +# +# 新服务器(免预先克隆): +# curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash +# +# 已安装: +# bash /opt/crypto_key/deploy/manage.sh +# +# 更新一律 git pull,严禁 scp。 +# +set -e +if [ -n "${BASH_VERSION:-}" ]; then + set -o pipefail +fi + +INSTALL_ROOT="${INSTALL_ROOT:-/opt/crypto_key}" +GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/crypto_key.git}" +GIT_BRANCH="${GIT_BRANCH:-main}" +APP_NAME="api-key-manager" +BACKUP_ROOT="/root/crypto_key_backups" +CRON_MARKER="# crypto_key-auto-backup" + +# curl | bash 时脚本从 stdin 执行,BASH_SOURCE[0] 为空;须先安全探测再 set -u +_script_src="${BASH_SOURCE[0]:-}" +_from_pipe=0 +if [[ -n "${_script_src}" && -f "${_script_src}" ]]; then + DEPLOY_DIR="$(cd "$(dirname "${_script_src}")" && pwd)" + REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" +else + DEPLOY_DIR="" + REPO_ROOT="" + _from_pipe=1 +fi +unset _script_src + +set -u + +red() { printf '\033[31m%s\033[0m\n' "$*"; } +grn() { printf '\033[32m%s\033[0m\n' "$*"; } +ylw() { printf '\033[33m%s\033[0m\n' "$*"; } +info() { echo "==> $*"; } + +# 从终端读入,兼容 curl | bash(管道 stdin 已 EOF) +cm_read() { + local __var="$1" + local __prompt="${2:-}" + local __val="" + if [[ -r /dev/tty ]]; then + printf "%s" "${__prompt}" > /dev/tty + IFS= read -r __val < /dev/tty || true + else + printf "%s" "${__prompt}" + IFS= read -r __val || true + fi + printf -v "${__var}" '%s' "${__val}" +} + +require_root() { + if [[ "$(id -u)" -ne 0 ]]; then + red "错误: 请使用 root 执行" + echo " curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash" + exit 1 + fi +} + +repo_ready() { + [[ -f "${1}/deploy/manage.sh" && -f "${1}/app.py" ]] +} + +sync_repo_if_present() { + local root="$1" + if [[ -d "${root}/.git" ]] && command -v git >/dev/null 2>&1; then + info "git pull(${root})..." + git -C "${root}" fetch --all --prune 2>/dev/null || true + git -C "${root}" pull --ff-only origin "${GIT_BRANCH}" 2>/dev/null \ + || git -C "${root}" pull --ff-only 2>/dev/null \ + || true + fi +} + +reexec_local() { + exec bash "${INSTALL_ROOT}/deploy/manage.sh" "$@" /dev/null 2>&1; then + if command -v apt-get >/dev/null 2>&1; then + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get install -y git ca-certificates curl + else + red "错误: 未找到 git" + exit 1 + fi + fi + + if [[ -d "${INSTALL_ROOT}" ]]; then + red "错误: ${INSTALL_ROOT} 已存在但不是有效仓库" + echo "请手动处理后再运行,或设置 INSTALL_ROOT 指向其它路径" + exit 1 + fi + + mkdir -p "$(dirname "${INSTALL_ROOT}")" + git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}" + # clone 后用仓库内脚本 + 终端 stdin(管道已 EOF) + reexec_local "$@" +} + +install_deps() { + info "安装系统依赖..." + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get install -y -qq python3 python3-venv python3-pip git curl ca-certificates + + if ! command -v node >/dev/null 2>&1; then + info "安装 Node.js 20(PM2 需要)..." + curl -fsSL https://deb.nodesource.com/setup_20.x | bash - + apt-get install -y -qq nodejs + fi + + if ! command -v pm2 >/dev/null 2>&1; then + info "安装 PM2..." + npm install -g pm2 + fi +} + +setup_python() { + info "创建/更新 Python 虚拟环境..." + cd "${INSTALL_ROOT}" + python3 -m venv venv + # shellcheck disable=SC1091 + source venv/bin/activate + pip install -q --upgrade pip + pip install -q -r requirements.txt + mkdir -p logs uploads + chmod +x pm2-start.sh pm2-stop.sh deploy/manage.sh 2>/dev/null || true +} + +setup_env() { + cd "${INSTALL_ROOT}" + if [[ ! -f .env ]]; then + if [[ -f .env.example ]]; then + cp .env.example .env + ylw "已从 .env.example 生成 .env(首次启动会自动补全密钥)" + else + touch .env + fi + fi +} + +setup_backup_cron() { + mkdir -p "${BACKUP_ROOT}" + local cron_line="0 3 * * * cd ${INSTALL_ROOT} && ./venv/bin/python -c \"from backup import create_backup_archive; create_backup_archive()\" >> ${BACKUP_ROOT}/cron.log 2>&1 ${CRON_MARKER}" + (crontab -l 2>/dev/null | grep -v "${CRON_MARKER}" || true; echo "${cron_line}") | crontab - + info "已配置每日 03:00 自动备份到 ${BACKUP_ROOT}" +} + +remove_backup_cron() { + if crontab -l 2>/dev/null | grep -q "${CRON_MARKER}"; then + crontab -l 2>/dev/null | grep -v "${CRON_MARKER}" | crontab - || true + info "已移除自动备份 cron" + fi +} + +start_pm2() { + cd "${INSTALL_ROOT}" + pm2 delete "${APP_NAME}" 2>/dev/null || true + pm2 start ecosystem.config.cjs + pm2 save +} + +do_deploy() { + require_root + info "一键部署到 ${INSTALL_ROOT}" + install_deps + mkdir -p /opt + if [[ -d "${INSTALL_ROOT}/.git" ]]; then + info "目录已存在,执行 git pull(不用 scp)..." + sync_repo_if_present "${INSTALL_ROOT}" + else + info "git clone ${GIT_URL} ..." + git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}" + fi + setup_env + setup_python + setup_backup_cron + start_pm2 + + local lan_ip + lan_ip="$(hostname -I 2>/dev/null | awk '{print $1}')" + echo "" + grn "========== 部署完成 ==========" + echo " 目录: ${INSTALL_ROOT}" + echo " 本机: http://127.0.0.1:5200" + echo " 局域网: http://${lan_ip:-}:5200" + echo " 自动备份: ${BACKUP_ROOT}" + echo " 状态: pm2 status" + echo " 日志: pm2 logs ${APP_NAME}" + echo "==============================" + echo "" + echo "日常管理: bash ${INSTALL_ROOT}/deploy/manage.sh" + echo "或: curl -fsSL https://git.bz121.com/dekun/crypto_key/raw/branch/main/deploy/manage.sh | bash" + echo "开机自启: pm2 startup (按提示执行后再 pm2 save)" +} + +do_update() { + require_root + if [[ ! -d "${INSTALL_ROOT}/.git" ]]; then + red "未找到 ${INSTALL_ROOT},请先选择「1 一键部署」" + exit 1 + fi + info "更新(仅 git pull,严禁 scp)..." + cd "${INSTALL_ROOT}" + + mkdir -p "${BACKUP_ROOT}" + if [[ -f "${INSTALL_ROOT}/venv/bin/python" ]]; then + "${INSTALL_ROOT}/venv/bin/python" -c "from backup import create_backup_archive; print(create_backup_archive())" \ + && grn "更新前已自动备份" || ylw "更新前备份跳过(可手动备份)" + fi + + sync_repo_if_present "${INSTALL_ROOT}" + setup_python + setup_backup_cron + start_pm2 + grn "更新完成(git pull + 依赖 + PM2 重启)" +} + +do_uninstall() { + require_root + ylw "即将卸载 crypto_key" + echo " - 停止并删除 PM2 进程 ${APP_NAME}" + echo " - 移除自动备份 cron" + echo " - 删除目录 ${INSTALL_ROOT}" + echo " - 保留 ${BACKUP_ROOT}(如存在)" + local confirm="" + cm_read confirm "确认卸载?输入 yes 继续: " + if [[ "${confirm}" != "yes" ]]; then + echo "已取消" + return 0 + fi + + pm2 delete "${APP_NAME}" 2>/dev/null || true + pm2 save 2>/dev/null || true + remove_backup_cron + + if [[ -d "${INSTALL_ROOT}" ]]; then + mkdir -p "${BACKUP_ROOT}" + local stamp + stamp="$(date +%Y%m%d_%H%M%S)" + tar czf "${BACKUP_ROOT}/uninstall_backup_${stamp}.tar.gz" \ + -C "${INSTALL_ROOT}" .env data.json settings.json uploads 2>/dev/null || true + rm -rf "${INSTALL_ROOT}" + grn "已删除 ${INSTALL_ROOT}" + fi + grn "卸载完成。备份目录保留在: ${BACKUP_ROOT}" +} + +show_menu() { + echo "" + echo "========================================" + echo " crypto_key 管理脚本" + echo " 仓库: ${GIT_URL}" + echo " 部署: ${INSTALL_ROOT}" + echo "========================================" + echo " 1) 一键部署" + echo " 2) 更新(git pull,严禁 scp)" + echo " 3) 一键卸载" + echo " 0) 退出" + echo "========================================" +} + +main() { + bootstrap_repo "$@" + + # 非交互参数 + case "${1:-}" in + deploy|1) do_deploy; exit 0 ;; + update|2) do_update; exit 0 ;; + uninstall|3) do_uninstall; exit 0 ;; + esac + + require_root + while true; do + show_menu + local choice="" + cm_read choice "请选择 [0-3]: " + case "${choice}" in + 1) do_deploy ;; + 2) do_update ;; + 3) do_uninstall ;; + 0) echo "再见"; exit 0 ;; + *) red "无效选项" ;; + esac + echo "" + cm_read _ "按 Enter 返回菜单..." + done +} + +main "$@" diff --git a/index.html b/index.html index d7293c5..d4e82da 100644 --- a/index.html +++ b/index.html @@ -79,8 +79,27 @@ } .tab:hover { color: var(--text); } .tab.on { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; } - .img-preview { max-width: 220px; max-height: 160px; border-radius: 6px; border: 1px solid var(--border); margin-top: 8px; display: block; } + .img-preview { + max-width: 220px; max-height: 160px; border-radius: 6px; border: 1px solid var(--border); + margin-top: 8px; display: block; cursor: zoom-in; + } .img-preview.lg { max-width: 320px; max-height: 240px; } + .lightbox { + position: fixed; inset: 0; z-index: 200; background: rgba(0,0,0,.88); + display: flex; align-items: center; justify-content: center; padding: 24px; + cursor: zoom-out; + } + .lightbox.hidden { display: none !important; } + .lightbox img { + max-width: min(96vw, 1200px); max-height: 92vh; object-fit: contain; + border-radius: 8px; box-shadow: 0 8px 40px rgba(0,0,0,.5); cursor: default; + } + .lightbox-close { + position: absolute; top: 16px; right: 16px; background: transparent; + border: 1px solid var(--border); color: var(--text); border-radius: 6px; + padding: 6px 12px; cursor: pointer; font-size: 0.85rem; + } + .lightbox-close:hover { border-color: var(--accent); color: var(--accent); } .backup-info { font-size: 0.82rem; color: var(--muted); line-height: 1.7; margin: 10px 0 16px; } .backup-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; } @@ -232,6 +251,11 @@
+ +