修复订阅无法正常获取的错误
This commit is contained in:
@@ -12,6 +12,5 @@ REDIS_DB=0
|
|||||||
JWT_SECRET=change_me_to_a_long_random_secret
|
JWT_SECRET=change_me_to_a_long_random_secret
|
||||||
APP_PORT=8080
|
APP_PORT=8080
|
||||||
APP_URL=http://127.0.0.1:8080
|
APP_URL=http://127.0.0.1:8080
|
||||||
|
LOG_LEVEL=info
|
||||||
|
|
||||||
# Plugin source reference directory, only needed during development.
|
|
||||||
PLUGIN_ROOT=reference/LDNET-GA-Theme/plugin
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -16,23 +17,42 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
config.LoadConfig()
|
config.LoadConfig()
|
||||||
|
configureRuntimeLogging()
|
||||||
database.InitDB()
|
database.InitDB()
|
||||||
database.InitCache()
|
database.InitCache()
|
||||||
|
|
||||||
router := gin.New()
|
router := gin.New()
|
||||||
router.Use(gin.Logger(), gin.Recovery())
|
if config.IsLogLevelEnabled(config.AppConfig.LogLevel, "info") {
|
||||||
|
router.Use(gin.Logger())
|
||||||
|
}
|
||||||
|
router.Use(gin.Recovery())
|
||||||
|
|
||||||
api := router.Group("/api")
|
api := router.Group("/api")
|
||||||
registerV1(api.Group("/v1"))
|
registerV1(api.Group("/v1"))
|
||||||
registerV2(api.Group("/v2"))
|
registerV2(api.Group("/v2"))
|
||||||
registerWebRoutes(router)
|
registerWebRoutes(router)
|
||||||
|
|
||||||
log.Printf("server starting on port %s", config.AppConfig.AppPort)
|
if config.IsLogLevelEnabled(config.AppConfig.LogLevel, "info") {
|
||||||
|
log.Printf("server starting on port %s", config.AppConfig.AppPort)
|
||||||
|
}
|
||||||
if err := router.Run(":" + config.AppConfig.AppPort); err != nil {
|
if err := router.Run(":" + config.AppConfig.AppPort); err != nil {
|
||||||
log.Fatalf("failed to start server: %v", err)
|
log.Fatalf("failed to start server: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func configureRuntimeLogging() {
|
||||||
|
if config.NormalizeLogLevel(config.AppConfig.LogLevel) == "debug" {
|
||||||
|
gin.SetMode(gin.DebugMode)
|
||||||
|
} else {
|
||||||
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.NormalizeLogLevel(config.AppConfig.LogLevel) == "silent" {
|
||||||
|
gin.DefaultWriter = io.Discard
|
||||||
|
gin.DefaultErrorWriter = io.Discard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func registerV1(v1 *gin.RouterGroup) {
|
func registerV1(v1 *gin.RouterGroup) {
|
||||||
registerPassportRoutes(v1)
|
registerPassportRoutes(v1)
|
||||||
registerGuestRoutes(v1)
|
registerGuestRoutes(v1)
|
||||||
@@ -288,8 +308,10 @@ func registerWebRoutes(router *gin.Engine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
securePath := "/" + service.GetAdminSecurePath()
|
securePath := "/" + service.GetAdminSecurePath()
|
||||||
|
subscribePath := "/" + service.GetSubscribePath()
|
||||||
router.GET("/", handler.UserThemePage)
|
router.GET("/", handler.UserThemePage)
|
||||||
router.GET("/dashboard", handler.UserThemePage)
|
router.GET("/dashboard", handler.UserThemePage)
|
||||||
|
router.GET(subscribePath+"/:token", handler.Subscribe)
|
||||||
router.GET(securePath, handler.AdminAppPage)
|
router.GET(securePath, handler.AdminAppPage)
|
||||||
router.GET(securePath+"/", handler.AdminAppPage)
|
router.GET(securePath+"/", handler.AdminAppPage)
|
||||||
router.GET(securePath+"/plugin-panel/:kind", handler.AdminPluginPanelPage)
|
router.GET(securePath+"/plugin-panel/:kind", handler.AdminPluginPanelPage)
|
||||||
|
|||||||
@@ -4,24 +4,26 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
DBHost string
|
DBHost string
|
||||||
DBPort string
|
DBPort string
|
||||||
DBUser string
|
DBUser string
|
||||||
DBPass string
|
DBPass string
|
||||||
DBName string
|
DBName string
|
||||||
RedisHost string
|
RedisHost string
|
||||||
RedisPort string
|
RedisPort string
|
||||||
RedisPass string
|
RedisPass string
|
||||||
RedisDB int
|
RedisDB int
|
||||||
JWTSecret string
|
JWTSecret string
|
||||||
AppPort string
|
AppPort string
|
||||||
AppURL string
|
AppURL string
|
||||||
PluginRoot string
|
LogLevel string
|
||||||
|
PluginRoot string
|
||||||
}
|
}
|
||||||
|
|
||||||
var AppConfig *Config
|
var AppConfig *Config
|
||||||
@@ -45,10 +47,47 @@ func LoadConfig() {
|
|||||||
JWTSecret: getEnv("JWT_SECRET", "secret"),
|
JWTSecret: getEnv("JWT_SECRET", "secret"),
|
||||||
AppPort: getEnv("APP_PORT", "8080"),
|
AppPort: getEnv("APP_PORT", "8080"),
|
||||||
AppURL: getEnv("APP_URL", ""),
|
AppURL: getEnv("APP_URL", ""),
|
||||||
|
LogLevel: NormalizeLogLevel(getEnv("LOG_LEVEL", "info")),
|
||||||
PluginRoot: getEnv("PLUGIN_ROOT", "reference\\LDNET-GA-Theme\\plugin"),
|
PluginRoot: getEnv("PLUGIN_ROOT", "reference\\LDNET-GA-Theme\\plugin"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NormalizeLogLevel(value string) string {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||||
|
case "debug":
|
||||||
|
return "debug"
|
||||||
|
case "warn", "warning":
|
||||||
|
return "warn"
|
||||||
|
case "error":
|
||||||
|
return "error"
|
||||||
|
case "silent":
|
||||||
|
return "silent"
|
||||||
|
default:
|
||||||
|
return "info"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsLogLevelEnabled(currentLevel, targetLevel string) bool {
|
||||||
|
logLevelOrder := map[string]int{
|
||||||
|
"debug": 0,
|
||||||
|
"info": 1,
|
||||||
|
"warn": 2,
|
||||||
|
"error": 3,
|
||||||
|
"silent": 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRank, ok := logLevelOrder[NormalizeLogLevel(currentLevel)]
|
||||||
|
if !ok {
|
||||||
|
currentRank = logLevelOrder["info"]
|
||||||
|
}
|
||||||
|
targetRank, ok := logLevelOrder[NormalizeLogLevel(targetLevel)]
|
||||||
|
if !ok {
|
||||||
|
targetRank = logLevelOrder["info"]
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentRank <= targetRank
|
||||||
|
}
|
||||||
|
|
||||||
func getEnv(key, defaultValue string) string {
|
func getEnv(key, defaultValue string) string {
|
||||||
if value, exists := os.LookupEnv(key); exists {
|
if value, exists := os.LookupEnv(key); exists {
|
||||||
return value
|
return value
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ var fallbackCache = &memoryCache{
|
|||||||
|
|
||||||
func InitCache() {
|
func InitCache() {
|
||||||
if config.AppConfig.RedisHost == "" {
|
if config.AppConfig.RedisHost == "" {
|
||||||
log.Printf("Redis host not configured, using in-memory cache")
|
if config.IsLogLevelEnabled(config.AppConfig.LogLevel, "warn") {
|
||||||
|
log.Printf("Redis host not configured, using in-memory cache")
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,12 +48,16 @@ func InitCache() {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := client.Ping(ctx).Err(); err != nil {
|
if err := client.Ping(ctx).Err(); err != nil {
|
||||||
log.Printf("Redis unavailable at %s, falling back to in-memory: %v", addr, err)
|
if config.IsLogLevelEnabled(config.AppConfig.LogLevel, "warn") {
|
||||||
|
log.Printf("Redis unavailable at %s, falling back to in-memory: %v", addr, err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Redis = client
|
Redis = client
|
||||||
log.Printf("Redis connection established at %s", addr)
|
if config.IsLogLevelEnabled(config.AppConfig.LogLevel, "info") {
|
||||||
|
log.Printf("Redis connection established at %s", addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CacheSet(key string, value any, ttl time.Duration) error {
|
func CacheSet(key string, value any, ttl time.Duration) error {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func InitDB() {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
|
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
|
||||||
Logger: logger.Default.LogMode(logger.Info),
|
Logger: logger.Default.LogMode(gormLogLevel(config.AppConfig.LogLevel)),
|
||||||
DisableForeignKeyConstraintWhenMigrating: true,
|
DisableForeignKeyConstraintWhenMigrating: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -40,5 +40,22 @@ func InitDB() {
|
|||||||
log.Fatalf("Failed to migrate database tables: %v", err)
|
log.Fatalf("Failed to migrate database tables: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Database connection established")
|
if config.IsLogLevelEnabled(config.AppConfig.LogLevel, "info") {
|
||||||
|
log.Println("Database connection established")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gormLogLevel(level string) logger.LogLevel {
|
||||||
|
switch config.NormalizeLogLevel(level) {
|
||||||
|
case "debug", "info":
|
||||||
|
return logger.Info
|
||||||
|
case "warn":
|
||||||
|
return logger.Warn
|
||||||
|
case "error":
|
||||||
|
return logger.Error
|
||||||
|
case "silent":
|
||||||
|
return logger.Silent
|
||||||
|
default:
|
||||||
|
return logger.Info
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ func getAllConfigMappings() gin.H {
|
|||||||
"show_protocol_to_server_enable": service.MustGetBool("show_protocol_to_server_enable", false),
|
"show_protocol_to_server_enable": service.MustGetBool("show_protocol_to_server_enable", false),
|
||||||
"default_remind_expire": service.MustGetBool("default_remind_expire", true),
|
"default_remind_expire": service.MustGetBool("default_remind_expire", true),
|
||||||
"default_remind_traffic": service.MustGetBool("default_remind_traffic", true),
|
"default_remind_traffic": service.MustGetBool("default_remind_traffic", true),
|
||||||
"subscribe_path": service.MustGetString("subscribe_path", "s"),
|
"subscribe_path": service.GetSubscribePath(),
|
||||||
},
|
},
|
||||||
"subscribe_template": service.GetAllSubscribeTemplates(),
|
"subscribe_template": service.GetAllSubscribeTemplates(),
|
||||||
"frontend": gin.H{
|
"frontend": gin.H{
|
||||||
|
|||||||
147
internal/handler/request_url.go
Normal file
147
internal/handler/request_url.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"xboard-go/internal/service"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func requestBaseURL(c *gin.Context) string {
|
||||||
|
if c != nil {
|
||||||
|
if origin := requestOrigin(c.Request); origin != "" {
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if appURL := service.GetAppURL(); appURL != "" {
|
||||||
|
return strings.TrimRight(appURL, "/")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestOrigin(r *http.Request) string {
|
||||||
|
if r == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
scheme, host := forwardedOrigin(r)
|
||||||
|
if scheme != "" && host != "" {
|
||||||
|
return scheme + "://" + host
|
||||||
|
}
|
||||||
|
|
||||||
|
if host == "" {
|
||||||
|
host = firstHeaderValue(r.Header.Get("X-Forwarded-Host"))
|
||||||
|
}
|
||||||
|
if host == "" {
|
||||||
|
host = strings.TrimSpace(r.Host)
|
||||||
|
}
|
||||||
|
if host == "" {
|
||||||
|
host = originHostFallback(r)
|
||||||
|
}
|
||||||
|
if host == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if scheme == "" {
|
||||||
|
scheme = firstHeaderValue(r.Header.Get("X-Forwarded-Proto"))
|
||||||
|
}
|
||||||
|
if scheme == "" {
|
||||||
|
scheme = firstHeaderValue(r.Header.Get("X-Forwarded-Scheme"))
|
||||||
|
}
|
||||||
|
if scheme == "" {
|
||||||
|
scheme = firstHeaderValue(r.Header.Get("X-Scheme"))
|
||||||
|
}
|
||||||
|
if scheme == "" && strings.EqualFold(strings.TrimSpace(r.Header.Get("Front-End-Https")), "on") {
|
||||||
|
scheme = "https"
|
||||||
|
}
|
||||||
|
if scheme == "" && strings.EqualFold(strings.TrimSpace(r.Header.Get("X-Forwarded-Ssl")), "on") {
|
||||||
|
scheme = "https"
|
||||||
|
}
|
||||||
|
if scheme == "" {
|
||||||
|
switch strings.TrimSpace(firstHeaderValue(r.Header.Get("X-Forwarded-Port"))) {
|
||||||
|
case "443":
|
||||||
|
scheme = "https"
|
||||||
|
case "80":
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if scheme == "" {
|
||||||
|
scheme = originSchemeFallback(r)
|
||||||
|
}
|
||||||
|
if scheme == "" {
|
||||||
|
if r.TLS != nil {
|
||||||
|
scheme = "https"
|
||||||
|
} else {
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if forwardedPort := strings.TrimSpace(firstHeaderValue(r.Header.Get("X-Forwarded-Port"))); forwardedPort != "" && !strings.Contains(host, ":") {
|
||||||
|
defaultPort := map[string]string{
|
||||||
|
"http": "80",
|
||||||
|
"https": "443",
|
||||||
|
}[scheme]
|
||||||
|
if forwardedPort != defaultPort {
|
||||||
|
host = net.JoinHostPort(host, forwardedPort)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scheme + "://" + host
|
||||||
|
}
|
||||||
|
|
||||||
|
func forwardedOrigin(r *http.Request) (scheme string, host string) {
|
||||||
|
forwarded := strings.TrimSpace(firstHeaderValue(r.Header.Get("Forwarded")))
|
||||||
|
if forwarded == "" {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, segment := range strings.Split(forwarded, ";") {
|
||||||
|
parts := strings.SplitN(strings.TrimSpace(segment), "=", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key := strings.ToLower(strings.TrimSpace(parts[0]))
|
||||||
|
value := strings.Trim(strings.TrimSpace(parts[1]), "\"")
|
||||||
|
switch key {
|
||||||
|
case "proto":
|
||||||
|
if value != "" {
|
||||||
|
scheme = value
|
||||||
|
}
|
||||||
|
case "host":
|
||||||
|
if value != "" {
|
||||||
|
host = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scheme, host
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstHeaderValue(value string) string {
|
||||||
|
if value == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
parts := strings.Split(value, ",")
|
||||||
|
return strings.TrimSpace(parts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func originHostFallback(r *http.Request) string {
|
||||||
|
for _, raw := range []string{r.Header.Get("Origin"), r.Header.Get("Referer")} {
|
||||||
|
if parsed, err := url.Parse(strings.TrimSpace(raw)); err == nil && parsed.Host != "" {
|
||||||
|
return parsed.Host
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func originSchemeFallback(r *http.Request) string {
|
||||||
|
for _, raw := range []string{r.Header.Get("Origin"), r.Header.Get("Referer")} {
|
||||||
|
if parsed, err := url.Parse(strings.TrimSpace(raw)); err == nil && parsed.Scheme != "" {
|
||||||
|
return parsed.Scheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -74,14 +74,8 @@ func UserGetSubscribe(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
baseURL := strings.TrimRight(service.GetAppURL(), "/")
|
baseURL := requestBaseURL(c)
|
||||||
if baseURL == "" {
|
subscribePath := service.GetSubscribePath()
|
||||||
scheme := "http"
|
|
||||||
if c.Request.TLS != nil {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
baseURL = scheme + "://" + c.Request.Host
|
|
||||||
}
|
|
||||||
|
|
||||||
Success(c, gin.H{
|
Success(c, gin.H{
|
||||||
"plan_id": user.PlanID,
|
"plan_id": user.PlanID,
|
||||||
@@ -96,7 +90,7 @@ func UserGetSubscribe(c *gin.Context) {
|
|||||||
"speed_limit": user.SpeedLimit,
|
"speed_limit": user.SpeedLimit,
|
||||||
"next_reset_at": user.NextResetAt,
|
"next_reset_at": user.NextResetAt,
|
||||||
"plan": user.Plan,
|
"plan": user.Plan,
|
||||||
"subscribe_url": strings.TrimRight(baseURL, "/") + "/s/" + user.Token,
|
"subscribe_url": strings.TrimRight(baseURL, "/") + "/" + subscribePath + "/" + user.Token,
|
||||||
"reset_day": nil,
|
"reset_day": nil,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -129,15 +123,8 @@ func UserResetSecurity(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
baseURL := strings.TrimRight(service.GetAppURL(), "/")
|
baseURL := requestBaseURL(c)
|
||||||
if baseURL == "" {
|
Success(c, strings.TrimRight(baseURL, "/")+"/"+service.GetSubscribePath()+"/"+newToken)
|
||||||
scheme := "http"
|
|
||||||
if c.Request.TLS != nil {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
baseURL = scheme + "://" + c.Request.Host
|
|
||||||
}
|
|
||||||
Success(c, strings.TrimRight(baseURL, "/")+"/s/"+newToken)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func UserUpdate(c *gin.Context) {
|
func UserUpdate(c *gin.Context) {
|
||||||
|
|||||||
@@ -206,10 +206,10 @@ func UserTrafficLog(c *gin.Context) {
|
|||||||
items := make([]gin.H, 0, len(records))
|
items := make([]gin.H, 0, len(records))
|
||||||
for _, record := range records {
|
for _, record := range records {
|
||||||
items = append(items, gin.H{
|
items = append(items, gin.H{
|
||||||
"user_id": record.UserID,
|
"user_id": record.UserID,
|
||||||
"u": record.U,
|
"u": record.U,
|
||||||
"d": record.D,
|
"d": record.D,
|
||||||
"record_at": record.RecordAt,
|
"record_at": record.RecordAt,
|
||||||
"server_rate": 1,
|
"server_rate": 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -726,14 +726,10 @@ func quickLoginURL(c *gin.Context, userID int, redirectValues ...string) string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func baseURL(c *gin.Context) string {
|
func baseURL(c *gin.Context) string {
|
||||||
if appURL := service.GetAppURL(); appURL != "" {
|
if baseURL := requestBaseURL(c); baseURL != "" {
|
||||||
return strings.TrimRight(appURL, "/")
|
return baseURL
|
||||||
}
|
}
|
||||||
scheme := "http"
|
return ""
|
||||||
if c.Request.TLS != nil {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
return scheme + "://" + c.Request.Host
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateTradeNo() string {
|
func generateTradeNo() string {
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
"xboard-go/internal/service"
|
"xboard-go/internal/service"
|
||||||
|
|
||||||
@@ -65,15 +63,10 @@ func UserThemePage(c *gin.Context) {
|
|||||||
|
|
||||||
func AdminAppPage(c *gin.Context) {
|
func AdminAppPage(c *gin.Context) {
|
||||||
securePath := service.GetAdminSecurePath()
|
securePath := service.GetAdminSecurePath()
|
||||||
baseURL := service.GetAppURL()
|
|
||||||
if origin := requestOrigin(c.Request); origin != "" {
|
|
||||||
baseURL = origin
|
|
||||||
}
|
|
||||||
|
|
||||||
title := service.MustGetString("app_name", "XBoard") + " Admin"
|
title := service.MustGetString("app_name", "XBoard") + " Admin"
|
||||||
|
|
||||||
settings := map[string]string{
|
settings := map[string]string{
|
||||||
"base_url": baseURL,
|
"base_url": requestBaseURL(c),
|
||||||
"title": title,
|
"title": title,
|
||||||
"version": service.MustGetString("app_version", "1.0.0"),
|
"version": service.MustGetString("app_version", "1.0.0"),
|
||||||
"logo": service.MustGetString("logo", ""),
|
"logo": service.MustGetString("logo", ""),
|
||||||
@@ -113,38 +106,3 @@ func mustJSON(value any) template.JS {
|
|||||||
}
|
}
|
||||||
return template.JS(payload)
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -79,6 +79,13 @@ func GetAdminSecurePath() string {
|
|||||||
return "admin"
|
return "admin"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetSubscribePath() string {
|
||||||
|
if subscribePath := strings.Trim(normalizeWrappedString(MustGetString("subscribe_path", "")), "/"); subscribePath != "" {
|
||||||
|
return subscribePath
|
||||||
|
}
|
||||||
|
return "s"
|
||||||
|
}
|
||||||
|
|
||||||
func GetAppURL() string {
|
func GetAppURL() string {
|
||||||
if appURL := normalizeWrappedString(MustGetString("app_url", "")); appURL != "" {
|
if appURL := normalizeWrappedString(MustGetString("app_url", "")); appURL != "" {
|
||||||
return strings.TrimRight(appURL, "/")
|
return strings.TrimRight(appURL, "/")
|
||||||
|
|||||||
Reference in New Issue
Block a user