From 8276bef63be615de3bf5eae981abbd8cac9cef85 Mon Sep 17 00:00:00 2001 From: Pine Date: Wed, 9 Sep 2026 09:17:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(desktop-updates):=20=E6=96=B0=E5=A2=9E=20a?= =?UTF-8?q?rtifacts/signature=20=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=9B=B4=E6=96=B0=E5=8C=85=E5=B7=B2=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=90=8E=E4=BB=85=E7=99=BB=E8=AE=B0/=E6=9B=B4=E6=8D=A2=20.sig?= =?UTF-8?q?=20=E7=AD=BE=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 只传签名场景:校验 minisign 签名后仅更新 artifacts[target].signature,保留既有 url/sha256/size - 更新包未上传时返回 400 提示先传更新包 --- app/api/routers/rbac_desktop_updates.py | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/app/api/routers/rbac_desktop_updates.py b/app/api/routers/rbac_desktop_updates.py index 0b8cbe9..5cb5939 100644 --- a/app/api/routers/rbac_desktop_updates.py +++ b/app/api/routers/rbac_desktop_updates.py @@ -88,6 +88,12 @@ class DesktopArtifactConfirmRequest(BaseModel): signature_text: str = Field("", description=".sig 文件内容(明文 minisign 或 Tauri v2 base64)") +class DesktopArtifactSignatureRequest(BaseModel): + """仅登记更新包 minisign 签名(更新包已上传,只补/换 .sig)。""" + target: str + signature_text: str = Field(..., description=".sig 文件内容(明文 minisign 或 Tauri v2 base64)") + + class DesktopInstallerConfirmRequest(BaseModel): """标准安装包直传完成后确认登记(无签名)。""" target: str @@ -581,6 +587,40 @@ async def confirm_desktop_artifact( return updated +@router.post("/desktop-versions/{vid}/artifacts/signature", summary="仅登记更新包 minisign 签名(更新包已上传时补/换 .sig)") +async def set_desktop_artifact_signature( + vid: str, + payload: DesktopArtifactSignatureRequest, + db: Database = Depends(get_db), + actor: dict = Depends(require_permission("menu:admin_desktop_updates")), +): + if payload.target not in DESKTOP_TARGETS: + raise HTTPException(status_code=400, detail=f"target 仅支持 {', '.join(DESKTOP_TARGETS)}") + version = await _get_version(db, vid) + if version["status"] == "archived": + raise HTTPException(status_code=400, detail="已下架版本不可再登记签名") + artifacts = dict(version.get("artifacts") or {}) + art = artifacts.get(payload.target) + if not art or not (art.get("url") or "").strip(): + raise HTTPException( + status_code=400, + detail=f"target {payload.target} 尚未上传更新包,请先上传更新包后再登记签名", + ) + signature = _verify_signature(payload.signature_text) + art = dict(art) + art["signature"] = signature + artifacts[payload.target] = art + updated = await db.desktop_versions.update( + vid, {"artifacts_json": json.dumps(artifacts, ensure_ascii=False)} + ) + await write_audit( + db, action="desktop_version.artifact_signature", resource="desktop_version", resource_id=vid, + detail=f"version={version['version']} target={payload.target} signature=updated", + user=actor, + ) + return updated + + @router.post("/desktop-versions/{vid}/installers/presign", summary="生成标准安装包 OSS 预签名直传链接") async def presign_desktop_installer( vid: str,