Files
SingBox-Gopanel/internal/handler/web_pages.go
CN-JS-HuiBai b3435e5ef8
Some checks failed
build / build (api, amd64, linux) (push) Has been cancelled
build / build (api, arm64, linux) (push) Has been cancelled
build / build (api.exe, amd64, windows) (push) Has been cancelled
基本功能已初步完善
2026-04-17 20:41:47 +08:00

151 lines
4.2 KiB
Go

package handler
import (
"bytes"
"encoding/json"
"html/template"
"net"
"net/http"
"path/filepath"
"strconv"
"strings"
"time"
"xboard-go/internal/service"
"github.com/gin-gonic/gin"
)
type userThemeViewData struct {
Title string
Description string
Version string
Theme string
Logo string
AssetsPath string
CustomHTML template.HTML
ThemeConfigJSON template.JS
}
type adminAppViewData struct {
Title string
SettingsJS template.JS
AssetNonce string
}
func UserThemePage(c *gin.Context) {
config := map[string]any{
"accent": service.MustGetString("nebula_theme_color", "aurora"),
"slogan": service.MustGetString("nebula_hero_slogan", "One control center for login, subscriptions, sessions, and device visibility."),
"backgroundUrl": service.MustGetString("nebula_background_url", ""),
"metricsBaseUrl": service.MustGetString("nebula_metrics_base_url", ""),
"defaultThemeMode": service.MustGetString("nebula_default_theme_mode", "system"),
"lightLogoUrl": service.MustGetString("nebula_light_logo_url", ""),
"darkLogoUrl": service.MustGetString("nebula_dark_logo_url", ""),
"welcomeTarget": service.MustGetString("nebula_welcome_target", service.MustGetString("app_name", "XBoard")),
"registerTitle": service.MustGetString("nebula_register_title", "Create your access."),
"icpNo": service.MustGetString("icp_no", ""),
"psbNo": service.MustGetString("psb_no", ""),
"staticCdnUrl": service.MustGetString("nebula_static_cdn_url", ""),
"isRegisterEnabled": !service.MustGetBool("stop_register", false),
}
payload := userThemeViewData{
Title: service.MustGetString("app_name", "XBoard"),
Description: service.MustGetString("app_description", "Go rebuilt control panel"),
Version: service.MustGetString("app_version", "2.0.0"),
Theme: "Nebula",
Logo: service.MustGetString("logo", ""),
AssetsPath: "/theme/Nebula/assets",
CustomHTML: template.HTML(service.MustGetString("nebula_custom_html", "")),
ThemeConfigJSON: mustJSON(config),
}
renderPageTemplate(c, filepath.Join("frontend", "templates", "user_nebula.html"), payload)
}
func AdminAppPage(c *gin.Context) {
securePath := service.GetAdminSecurePath()
baseURL := service.GetAppURL()
if origin := requestOrigin(c.Request); origin != "" {
baseURL = origin
}
title := service.MustGetString("app_name", "XBoard") + " Admin"
settings := map[string]string{
"base_url": baseURL,
"title": title,
"version": service.MustGetString("app_version", "1.0.0"),
"logo": service.MustGetString("logo", ""),
"secure_path": securePath,
}
settingsJSON, _ := json.Marshal(settings)
payload := adminAppViewData{
Title: title,
SettingsJS: template.JS(settingsJSON),
AssetNonce: strconv.FormatInt(time.Now().UnixNano(), 10),
}
renderPageTemplate(c, filepath.Join("frontend", "templates", "admin_app.html"), payload)
}
func renderPageTemplate(c *gin.Context, templatePath string, data any) {
tpl, err := template.ParseFiles(templatePath)
if err != nil {
c.String(http.StatusInternalServerError, "template parse error: %v", err)
return
}
var buf bytes.Buffer
if err := tpl.Execute(&buf, data); err != nil {
c.String(http.StatusInternalServerError, "template render error: %v", err)
return
}
c.Data(http.StatusOK, "text/html; charset=utf-8", buf.Bytes())
}
func mustJSON(value any) template.JS {
payload, err := json.Marshal(value)
if err != nil {
return template.JS("{}")
}
return template.JS(payload)
}
func requestOrigin(r *http.Request) string {
if r == nil {
return ""
}
scheme := r.Header.Get("X-Forwarded-Proto")
if scheme == "" {
if r.TLS != nil {
scheme = "https"
} else {
scheme = "http"
}
}
host := r.Header.Get("X-Forwarded-Host")
if host == "" {
host = r.Host
}
if host == "" {
return ""
}
if forwardedPort := r.Header.Get("X-Forwarded-Port"); forwardedPort != "" && !strings.Contains(host, ":") {
defaultPort := map[string]string{
"http": "80",
"https": "443",
}[scheme]
if forwardedPort != "" && forwardedPort != defaultPort {
host = net.JoinHostPort(host, forwardedPort)
}
}
return scheme + "://" + host
}