feat: 客户端授权防护——响应签名/激活令牌/宽限期/换座限制/在线清扫/疑似共享标记

This commit is contained in:
Logan.Li committed 2026-09-14 21:08:39 +08:00
1 parent 37d9e8ca56
commit b76111dfc3
11 files changed
+437 -54

No files matched your search

+46 -11
View File
@@ -5,6 +5,7 @@ import (
"encoding/base64"
"log"
"os"
"strconv"
"strings"
"github.com/joho/godotenv"
@@ -30,6 +31,12 @@ type Config struct {
// 离线许可证 Ed25519 seed(32 字节 hex;生产必须固定,勿轮换除非同步桌面公钥) // Logan.Li
OfflineLicenseSeed string
// 客户端授权防护配置 // Logan.Li
GracePeriodDays int // 过期宽限天数(仅商业过期;吊销/暂停无宽限)
ActivateDailyLimit int // 单序列号 24 小时内新设备激活上限(0 = 不限制)
OnlineTTLMinutes int // 激活记录在线状态有效期(last_seen 超过即视为离线)
DeactivateRequireToken bool // 解绑是否强制校验设备激活令牌
// CORS 配置
CORSOrigins []string
}
@@ -42,17 +49,21 @@ func Load() *Config {
_ = 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(),
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", ""),
GracePeriodDays: getEnvInt("GRACE_PERIOD_DAYS", 15),
ActivateDailyLimit: getEnvInt("ACTIVATE_DAILY_LIMIT", 5),
OnlineTTLMinutes: getEnvInt("ONLINE_TTL_MINUTES", 11520), // 默认 8 天,适配周检节奏
DeactivateRequireToken: getEnvBool("DEACTIVATE_REQUIRE_TOKEN", true),
CORSOrigins: defaultCORSOrigins(),
}
if raw := strings.TrimSpace(os.Getenv("CORS_ORIGINS")); raw != "" {
@@ -122,3 +133,27 @@ func getEnv(key, defaultValue string) string {
}
return defaultValue
}
// getEnvInt 读取整型环境变量,不存在或非法时返回默认值 // Logan.Li
func getEnvInt(key string, defaultValue int) int {
if raw := strings.TrimSpace(os.Getenv(key)); raw != "" {
if v, err := strconv.Atoi(raw); err == nil {
return v
}
log.Printf("[配置] %s 不是合法整数,使用默认值 %d", key, defaultValue)
}
return defaultValue
}
// getEnvBool 读取布尔环境变量(true/false/1/0),不存在或非法时返回默认值 // Logan.Li
func getEnvBool(key string, defaultValue bool) bool {
if raw := strings.TrimSpace(os.Getenv(key)); raw != "" {
switch strings.ToLower(raw) {
case "true", "1", "yes":
return true
case "false", "0", "no":
return false
}
}
return defaultValue
}