Files
opsx-licence/backend/config/config.go
T
Logan.LiandCursor ac31cc059a fix: 过滤非法 CORS Origin,避免 Docker 启动 panic
gin-contrib/cors 不接受 tauri://,启动时过滤仅保留 http/https。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 12:09:06 +08:00

121 lines
3.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package config
import (
"crypto/rand"
"encoding/base64"
"log"
"os"
"strings"
"github.com/joho/godotenv"
)
// Config 应用配置 // Logan.Li
type Config struct {
// 服务器配置
Port string
Mode string // debug, release
// 数据库配置
DBDriver string
DBHost string
DBPort string
DBUser string
DBPassword string
DBName string
// JWT 配置
JWTSecret string
// CORS 配置
CORSOrigins []string
}
// Load 从环境变量加载配置 // Logan.Li
func Load() *Config {
// 加载 .env:backend/.env 与仓库根 .env 各自尝试(缺文件不中断) // Logan.Li
_ = godotenv.Load(".env")
_ = godotenv.Load("../.env")
_ = godotenv.Load("../../.env")
cfg := &Config{
Port: getEnv("PORT", "9001"),
Mode: getEnv("GIN_MODE", "debug"),
DBDriver: getEnv("DB_DRIVER", "sqlite"),
DBHost: getEnv("DB_HOST", "127.0.0.1"),
DBPort: getEnv("DB_PORT", "3306"),
DBUser: getEnv("DB_USER", "root"),
DBPassword: getEnv("DB_PASSWORD", ""),
DBName: getEnv("DB_NAME", "db.sqlite3"),
JWTSecret: getEnv("JWT_SECRET", ""),
CORSOrigins: defaultCORSOrigins(),
}
if raw := strings.TrimSpace(os.Getenv("CORS_ORIGINS")); raw != "" {
parts := strings.Split(raw, ",")
origins := make([]string, 0, len(parts))
for _, p := range parts {
p = strings.TrimSpace(p)
if p == "" {
continue
}
origins = append(origins, p)
}
if len(origins) > 0 {
cfg.CORSOrigins = origins
}
}
// 安全检查:生产环境拒绝空密钥,开发环境使用进程级随机密钥避免固定后门。 // Logan.Li
if cfg.JWTSecret == "" {
if cfg.Mode == "release" {
log.Fatal("[安全] 生产环境必须设置 JWT_SECRET 环境变量")
}
cfg.JWTSecret = generateEphemeralJWTSecret()
log.Println("[安全] JWT_SECRET 未设置,已生成仅当前开发进程有效的随机密钥")
}
return cfg
}
func defaultCORSOrigins() []string {
return []string{
"http://localhost:5181",
"http://127.0.0.1:5181",
"http://localhost:3000",
"http://127.0.0.1:3000",
// OpsXShell Tauri / Vite dev origins (gin-cors only accepts http/https)
"http://localhost:1420",
"http://127.0.0.1:1420",
"http://tauri.localhost",
"https://tauri.localhost",
}
}
// IsOriginAllowed 判断浏览器 Origin 是否在显式 CORS 白名单中。 // Logan.Li
func (c *Config) IsOriginAllowed(origin string) bool {
for _, allowed := range c.CORSOrigins {
if strings.EqualFold(strings.TrimSpace(origin), strings.TrimSpace(allowed)) {
return true
}
}
return false
}
// generateEphemeralJWTSecret 生成开发环境临时 JWT 密钥。 // Logan.Li
func generateEphemeralJWTSecret() string {
bytes := make([]byte, 32)
if _, err := rand.Read(bytes); err != nil {
log.Fatal("[安全] 生成开发 JWT 密钥失败")
}
return base64.RawURLEncoding.EncodeToString(bytes)
}
// getEnv 读取环境变量,不存在则返回默认值 // Logan.Li
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}