Files
opsx-licence/backend/config/config.go
T
Logan.LiandCursor 8cc2c83f9d feat: 通用授权后台、离线证、Waffo 支付页与仪表盘加强
支持多产品计划展示、LICOFF 离线签发、支付独立配置与调试,以及分析看板;同步更新 README 与集成文档。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 20:25:46 +08:00

125 lines
3.2 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
// 离线许可证 Ed25519 seed(32 字节 hex;生产必须固定,勿轮换除非同步桌面公钥) // Logan.Li
OfflineLicenseSeed 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", ""),
OfflineLicenseSeed: getEnv("OFFLINE_LICENSE_SEED", ""),
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
}