diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml index 8685d7d..a5740a0 100644 --- a/.gitea/workflows/docker.yml +++ b/.gitea/workflows/docker.yml @@ -55,7 +55,7 @@ jobs: elif [ "${{ github.ref_name }}" = "internal" ]; then echo "DOCKER_TAG_SUFFIX=internal" >> $GITHUB_ENV echo "CONTAINER_NAME=ppanel-server-internal" >> $GITHUB_ENV - echo "DEPLOY_PATH=/root/hifast" >> $GITHUB_ENV + echo "DEPLOY_PATH=/root/bindbox" >> $GITHUB_ENV echo "为 internal 分支设置开发环境变量" else echo "DOCKER_TAG_SUFFIX=${{ github.ref_name }}" >> $GITHUB_ENV diff --git a/doc/tapi-file-upload-zh.md b/doc/tapi-file-upload-zh.md new file mode 100644 index 0000000..c257041 --- /dev/null +++ b/doc/tapi-file-upload-zh.md @@ -0,0 +1,184 @@ +# TAPI 文件上传接入说明 + +本文档说明 `https://tapi.hifast.biz/v1/public/file/upload` 相关上传接口的推荐接入方式、签名规则与常见排查方式。 + +## 总览 + +上传能力包含两类接入方式: + +- 推荐方式:`init -> S3 PUT -> complete` +- 兼容方式:`/upload` multipart 直传 + +推荐优先使用预签名三段式,因为: + +- 现有签名串包含 `BODY_SHA256` +- `/upload` 是 `multipart/form-data` +- multipart 原始 body 的签名和调试成本更高 +- `init` 和 `complete` 是 JSON,更适合客户端和 Apifox 调试 + +## 签名生效逻辑 + +项目保持现有旧逻辑,不做强制签名改造: + +- `Signature.EnableSignature = false` 时:不校验签名 +- `Signature.EnableSignature = true` 且未携带 `X-App-Id` 时:不校验签名,兼容老客户端 +- `Signature.EnableSignature = true` 且携带 `X-App-Id` 时:必须同时携带并校验 + - `X-Timestamp` + - `X-Nonce` + - `X-Signature` + +这意味着: + +- 新客户端建议始终带完整签名头 +- 老客户端如果没有 `X-App-Id`,仍可按旧逻辑访问 + +## 签名头定义 + +- `X-App-Id`: 客户端标识,例如 `ios-client` +- `X-Timestamp`: Unix 秒级时间戳 +- `X-Nonce`: 每次请求唯一随机串 +- `X-Signature`: `HMAC-SHA256` 结果的十六进制小写字符串 + +## StringToSign 规则 + +StringToSign 由下面 7 段按换行符 `\n` 拼接: + +```text +METHOD +PATH +CANONICAL_QUERY +BODY_SHA256 +X-App-Id +X-Timestamp +X-Nonce +``` + +说明: + +- `METHOD`:HTTP 方法大写,例如 `POST` +- `PATH`:请求路径,例如 `/v1/public/file/upload/init` +- `CANONICAL_QUERY`:按 key 排序后的 query string,没有 query 则为空字符串 +- `BODY_SHA256`:请求体原始字节的 SHA-256 十六进制小写 +- 其余三项直接使用请求头值 + +签名计算方式: + +```text +signature = hex_lower(HMAC_SHA256(app_secret, string_to_sign)) +``` + +时间窗与防重放: + +- `X-Timestamp` 默认有效时间窗是 300 秒 +- `X-Nonce` 在有效时间窗内不能重复使用 + +## 推荐接入:预签名三段式 + +### 1. 初始化上传 + +请求: + +```bash +curl -X POST 'https://tapi.hifast.biz/v1/public/file/upload/init' \ + -H 'Accept: application/json, text/plain, */*' \ + -H 'Content-Type: application/json' \ + -H 'authorization: your-token' \ + -H 'X-App-Id: ios-client' \ + -H 'X-Timestamp: 1778776400' \ + -H 'X-Nonce: nonce-001' \ + -H 'X-Signature: your-signature' \ + -d '{ + "biz_type": "app-package", + "file_name": "demo.zip", + "content_type": "application/zip", + "size": 123456, + "sha256": "" + }' +``` + +典型返回: + +```json +{ + "code": 200, + "msg": "success", + "data": { + "file_id": "c29274ee26ab5aa211e0396e", + "object_key": "app-upload/app-package/519/2026/05/c29274ee26ab5aa211e0396e_demo.zip", + "upload_url": "https://bucket.s3.ap-east-1.amazonaws.com/...", + "method": "PUT", + "headers": { + "Content-Type": "application/zip" + }, + "expired_at": 1778776715 + } +} +``` + +### 2. 直传 S3 + +这一步是直接上传二进制文件到 S3,不走业务签名中间件。 + +```bash +curl -X PUT 'https://bucket.s3.ap-east-1.amazonaws.com/...' \ + -H 'Content-Type: application/zip' \ + --upload-file '/tmp/demo.zip' +``` + +说明: + +- `Content-Type` 需和 `init` 返回的 `headers.Content-Type` 一致 +- `upload_url` 有过期时间,通常 300 秒 +- 成功时 S3 常见返回 `200` 或 `204` + +### 3. 完成上传 + +```bash +curl -X POST 'https://tapi.hifast.biz/v1/public/file/upload/complete' \ + -H 'Accept: application/json, text/plain, */*' \ + -H 'Content-Type: application/json' \ + -H 'authorization: your-token' \ + -H 'X-App-Id: ios-client' \ + -H 'X-Timestamp: 1778776405' \ + -H 'X-Nonce: nonce-002' \ + -H 'X-Signature: your-signature' \ + -d '{ + "file_id": "c29274ee26ab5aa211e0396e" + }' +``` + +## 兼容接入:单接口 multipart 直传 + +接口: + +- `POST /v1/public/file/upload` + +表单字段: + +- `biz_type` +- `file` + +说明: + +- 该接口继续保留,兼容旧客户端 +- 如果请求带了 `X-App-Id`,就按现有逻辑验签 +- 如果没有 `X-App-Id`,仍按旧逻辑放行 +- 如果要给该接口加签,签名时必须对原始 multipart body 计算 `BODY_SHA256` + +## 常见错误码 + +- `200`: 成功 +- `400`: 参数错误 +- `40008`: 缺少签名头 +- `40009`: 签名已过期 +- `40010`: 签名无效 +- `40011`: nonce 重放 +- `10001`: 上传元数据不存在或对象不存在 + +## 排查建议 + +- `40008`:确认带了 `X-App-Id` 后,也同时带上 `X-Timestamp / X-Nonce / X-Signature` +- `40009`:检查客户端时间是否偏差过大 +- `40010`:确认 `PATH`、query 排序、body 原始字节、secret 是否完全一致 +- `40011`:确保每次请求都生成新的 `X-Nonce` +- `complete` 失败:确认 S3 `PUT` 已成功,且上传大小与 `init.size` 一致 diff --git a/迁移到命令.txt b/迁移到命令.txt new file mode 100644 index 0000000..780fb22 --- /dev/null +++ b/迁移到命令.txt @@ -0,0 +1,44 @@ +导出数据库: +mysqldump --socket=/var/run/mysqld/mysqld.sock -uroot -p --single-transaction --routines --triggers --events --set-gtid-purged=OFF --source-data=2 --no-tablespaces hifast > /root/data/hifast-final-0515.sql + +jpcV41ppanel + +gzip -1 /root/hifast-final-0515.sql + + + + + +导出redis: +redis-cli -a '0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr' BGSAVE +sleep 5 +cp /var/lib/redis/dump.rdb /root/data/redis-backup-0515.rdb + + +导入数据库: +gunzip -c /root/hifast-final-0515.sql.gz | docker exec -i ppanel-mysql mysql -uroot -p'jpcV41ppanel' hifast + + +导入redis: +docker stop ppanel-redis +docker cp /root/data/redis-backup-0515.rdb ppanel-redis:/data/dump.rdb +docker start ppanel-redis +docker exec ppanel-redis redis-cli -a 'hifast67yj' DBSIZE + + + +docker stop ppanel-redis || true +docker rm -f ppanel-redis + +rm -f /root/data/dump.rdb +rm -rf /root/data/appendonlydir +rm -f /root/data/appendonly.aof* +mkdir -p /root/data + +docker pull redis:8.6.3 +docker run -d \ + --name ppanel-redis \ + --restart always \ + -p 6379:6379 \ + redis:8.6.3 \ + redis-server --requirepass 'hifast67yj'