Files
SingBox-Gopanel/internal/handler/client_api.go
CN-JS-HuiBai 1ed31b9292
All checks were successful
build / build (api, amd64, linux) (push) Successful in -47s
build / build (api, arm64, linux) (push) Successful in -48s
build / build (api.exe, amd64, windows) (push) Successful in -47s
first commit
2026-04-17 09:49:16 +08:00

145 lines
4.8 KiB
Go

package handler
import (
"encoding/base64"
"net/http"
"strconv"
"strings"
"xboard-go/internal/model"
"xboard-go/internal/protocol"
"xboard-go/internal/service"
"github.com/gin-gonic/gin"
)
func ClientSubscribe(c *gin.Context) {
user, ok := currentUser(c)
if !ok {
Fail(c, http.StatusForbidden, "invalid token")
return
}
servers, err := service.AvailableServersForUser(user)
if err != nil {
Fail(c, 500, "failed to fetch servers")
return
}
ua := c.GetHeader("User-Agent")
flag := c.Query("flag")
if strings.Contains(ua, "Clash") || flag == "clash" {
config, _ := protocol.GenerateClash(servers, *user)
c.Header("Content-Type", "application/octet-stream")
c.String(http.StatusOK, config)
return
}
if strings.Contains(strings.ToLower(ua), "sing-box") || flag == "sing-box" {
config, _ := protocol.GenerateSingBox(servers, *user)
c.Header("Content-Type", "application/json; charset=utf-8")
c.String(http.StatusOK, config)
return
}
links := make([]string, 0, len(servers))
for _, server := range servers {
links = append(links, "vmess://"+server.Name)
}
c.Header("Content-Type", "text/plain; charset=utf-8")
c.Header("Subscription-Userinfo", subscriptionUserInfo(*user))
c.String(http.StatusOK, base64.StdEncoding.EncodeToString([]byte(strings.Join(links, "\n"))))
}
func ClientAppConfigV1(c *gin.Context) {
user, ok := currentUser(c)
if !ok {
Fail(c, http.StatusForbidden, "invalid token")
return
}
servers, err := service.AvailableServersForUser(user)
if err != nil {
Fail(c, 500, "failed to fetch servers")
return
}
config, _ := protocol.GenerateClash(servers, *user)
c.Header("Content-Type", "text/yaml; charset=utf-8")
c.String(http.StatusOK, config)
}
func ClientAppConfigV2(c *gin.Context) {
config := gin.H{
"app_info": gin.H{
"app_name": service.MustGetString("app_name", "XBoard"),
"app_description": service.MustGetString("app_description", ""),
"app_url": service.GetAppURL(),
"logo": service.MustGetString("logo", ""),
"version": service.MustGetString("app_version", "1.0.0"),
},
"features": gin.H{
"enable_register": service.MustGetBool("app_enable_register", true),
"enable_invite_system": service.MustGetBool("app_enable_invite_system", true),
"enable_telegram_bot": service.MustGetBool("telegram_bot_enable", false),
"enable_ticket_system": service.MustGetBool("app_enable_ticket_system", true),
"enable_commission_system": service.MustGetBool("app_enable_commission_system", true),
"enable_traffic_log": service.MustGetBool("app_enable_traffic_log", true),
"enable_knowledge_base": service.MustGetBool("app_enable_knowledge_base", true),
"enable_announcements": service.MustGetBool("app_enable_announcements", true),
},
"security_config": gin.H{
"tos_url": service.MustGetString("tos_url", ""),
"privacy_policy_url": service.MustGetString("app_privacy_policy_url", ""),
"is_email_verify": service.MustGetInt("email_verify", 0),
"is_invite_force": service.MustGetInt("invite_force", 0),
"email_whitelist_suffix": service.MustGetString("email_whitelist_suffix", ""),
"is_captcha": service.MustGetInt("captcha_enable", 0),
"captcha_type": service.MustGetString("captcha_type", "recaptcha"),
"recaptcha_site_key": service.MustGetString("recaptcha_site_key", ""),
"turnstile_site_key": service.MustGetString("turnstile_site_key", ""),
},
}
Success(c, config)
}
func ClientAppVersion(c *gin.Context) {
ua := strings.ToLower(c.GetHeader("User-Agent"))
if strings.Contains(ua, "tidalab/4.0.0") || strings.Contains(ua, "tunnelab/4.0.0") {
if strings.Contains(ua, "win64") {
Success(c, gin.H{
"version": service.MustGetString("windows_version", ""),
"download_url": service.MustGetString("windows_download_url", ""),
})
return
}
Success(c, gin.H{
"version": service.MustGetString("macos_version", ""),
"download_url": service.MustGetString("macos_download_url", ""),
})
return
}
Success(c, gin.H{
"windows_version": service.MustGetString("windows_version", ""),
"windows_download_url": service.MustGetString("windows_download_url", ""),
"macos_version": service.MustGetString("macos_version", ""),
"macos_download_url": service.MustGetString("macos_download_url", ""),
"android_version": service.MustGetString("android_version", ""),
"android_download_url": service.MustGetString("android_download_url", ""),
})
}
func subscriptionUserInfo(user model.User) string {
expire := int64(0)
if user.ExpiredAt != nil {
expire = *user.ExpiredAt
}
return "upload=" + strconv.FormatInt(int64(user.U), 10) +
"; download=" + strconv.FormatInt(int64(user.D), 10) +
"; total=" + strconv.FormatInt(int64(user.TransferEnable), 10) +
"; expire=" + strconv.FormatInt(expire, 10)
}