From 2f75588ed130c3fb61dc8ad509b9061b34b18075 Mon Sep 17 00:00:00 2001 From: chenchen Date: Fri, 8 May 2026 17:40:40 +0800 Subject: [PATCH] feat(server): expose desktop-downloads file route to TokenOrUserAuth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add userRoute.GET /api/user/desktop-downloads/file/:platform with TokenOrUserAuth middleware. A plain browser can hit this with just the session cookie; New-Api-User header isn't required (the SPA's axios layer still injects it for the metadata endpoint on selfRoute). Closes the 401 "无权进行此操作,未提供 New-Api-User" case from the Heicode Manager desktop installer download path. Co-Authored-By: Claude Opus 4.7 (1M context) --- heicode/router/api-router.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/heicode/router/api-router.go b/heicode/router/api-router.go index 00d1010..eac5cd3 100644 --- a/heicode/router/api-router.go +++ b/heicode/router/api-router.go @@ -68,6 +68,12 @@ func SetApiRouter(router *gin.Engine) { userRoute.GET("/epay/notify", controller.EpayNotify) userRoute.GET("/groups", controller.GetUserGroups) + // Heicode desktop installer file streaming — uses TokenOrUserAuth so a plain + // browser download (cookie only, no New-Api-User header) works. + // The metadata endpoint stays on selfRoute since the SPA's axios layer + // already injects the required header. + userRoute.GET("/desktop-downloads/file/:platform", middleware.TokenOrUserAuth(), controller.DownloadDesktopFile) + selfRoute := userRoute.Group("/") selfRoute.Use(middleware.UserAuth()) { @@ -77,9 +83,8 @@ func SetApiRouter(router *gin.Engine) { selfRoute.PUT("/self", controller.UpdateSelf) selfRoute.DELETE("/self", controller.DeleteSelf) selfRoute.GET("/token", controller.GenerateAccessToken) - // Heicode desktop client installers (paths from env, login required) + // Heicode desktop client installers metadata (login required) selfRoute.GET("/desktop-downloads", controller.GetDesktopDownloads) - selfRoute.GET("/desktop-downloads/file/:platform", controller.DownloadDesktopFile) selfRoute.GET("/passkey", controller.PasskeyStatus) selfRoute.POST("/passkey/register/begin", controller.PasskeyRegisterBegin)