Go 1.27.1 (Gin+GORM) + Vue 3 文件快传服务: - 安全审计全部修复(docs/security-audit-2026-09-05.md): bcrypt 密码哈希与自动升级、presign 直传服务端大小/内容校验、 全局请求体上限、依赖升级(govulncheck 0 命中)、janitor 后台清理、 管理端审计动作落库、/admin CORS 收紧、通知内容白名单净化、 会话默认 7 天、限流缓存故障降级、robots.txt 端点等 - 前端:取件链接复制修复(不再重复拼接提取码)、markdown 净化器加固 - Redis 支持库号(FCB_REDIS_DB / redis://…/db URL) - 文档:docs/api/* 与 openapi.yaml 同步最新行为(robots.txt、 提码 5 位起、chunk 32MiB 上限、admin 审计动作等) 验证:gofmt/go vet/go test 全绿;二进制端到端冒烟通过
161 lines
4.6 KiB
Go
161 lines
4.6 KiB
Go
package config
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestNewDefaultsToSQLite(t *testing.T) {
|
|
t.Setenv("FCB_DB_DRIVER", "")
|
|
t.Setenv("FCB_DB_DSN", "")
|
|
t.Setenv("FCB_REDIS_ADDR", "")
|
|
t.Setenv("FCB_LISTEN", "")
|
|
t.Setenv("FCB_STORAGE_ENGINE", "")
|
|
c, err := New()
|
|
if err != nil {
|
|
t.Fatalf("默认(无 DSN)应可构造: %v", err)
|
|
}
|
|
if c.Env.DBDriver != DBDriverSQLite {
|
|
t.Errorf("默认驱动应为 sqlite,实际 %s", c.Env.DBDriver)
|
|
}
|
|
if c.SQLitePath() != DefaultSQLitePath {
|
|
t.Errorf("SQLite 默认路径 = %s", c.SQLitePath())
|
|
}
|
|
if c.Env.Listen != ":8466" {
|
|
t.Errorf("默认监听地址错误: %s", c.Env.Listen)
|
|
}
|
|
if c.Env.StorageEngine != "local" {
|
|
t.Errorf("默认存储引擎错误: %s", c.Env.StorageEngine)
|
|
}
|
|
if c.Env.RedisAddr != "" {
|
|
t.Errorf("RedisAddr 应为空: %s", c.Env.RedisAddr)
|
|
}
|
|
}
|
|
|
|
func TestNewPostgresRequiresDSN(t *testing.T) {
|
|
t.Setenv("FCB_DB_DRIVER", "postgres")
|
|
t.Setenv("FCB_DB_DSN", "")
|
|
if _, err := New(); err == nil {
|
|
t.Fatal("postgres 模式缺少 FCB_DB_DSN 应报错")
|
|
}
|
|
t.Setenv("FCB_DB_DSN", "postgres://user:pass@localhost:5432/fcb")
|
|
c, err := New()
|
|
if err != nil {
|
|
t.Fatalf("postgres + DSN 应可构造: %v", err)
|
|
}
|
|
if c.Env.DBDriver != DBDriverPostgres {
|
|
t.Errorf("驱动应为 postgres,实际 %s", c.Env.DBDriver)
|
|
}
|
|
if c.SQLitePath() != "" {
|
|
t.Errorf("postgres 模式 SQLitePath 应为空: %s", c.SQLitePath())
|
|
}
|
|
}
|
|
|
|
func TestNewInvalidDriver(t *testing.T) {
|
|
t.Setenv("FCB_DB_DRIVER", "mysql")
|
|
t.Setenv("FCB_DB_DSN", "x")
|
|
if _, err := New(); err == nil {
|
|
t.Fatal("非法驱动应报错")
|
|
}
|
|
}
|
|
|
|
func TestNewInvalidEngine(t *testing.T) {
|
|
t.Setenv("FCB_DB_DSN", "postgres://x")
|
|
t.Setenv("FCB_STORAGE_ENGINE", "onedrive")
|
|
if _, err := New(); err == nil {
|
|
t.Fatal("非法引擎应报错")
|
|
}
|
|
}
|
|
|
|
func TestEnvOverridesAndDefaults(t *testing.T) {
|
|
t.Setenv("FCB_DB_DSN", "postgres://x")
|
|
t.Setenv("FCB_LISTEN", ":9999")
|
|
t.Setenv("FCB_STORAGE_ENGINE", "webdav")
|
|
c, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New 失败: %v", err)
|
|
}
|
|
if c.Env.Listen != ":9999" || c.Env.StorageEngine != "webdav" {
|
|
t.Fatalf("env 覆盖失败: %+v", c.Env)
|
|
}
|
|
// 默认值对齐参考 DEFAULT_CONFIG
|
|
if got := c.GetInt("uploadSize"); got != 1024*1024*10 {
|
|
t.Errorf("uploadSize 默认值 = %d", got)
|
|
}
|
|
if got := c.GetInt("errorCount"); got != 10 {
|
|
t.Errorf("errorCount 默认值 = %d", got)
|
|
}
|
|
if got := c.GetInt("loginCount"); got != 5 {
|
|
t.Errorf("loginCount 默认值 = %d", got)
|
|
}
|
|
if got := c.GetInt("loginMinute"); got != 15 {
|
|
t.Errorf("loginMinute 默认值 = %d", got)
|
|
}
|
|
if got := c.GetBool("openUpload"); !got {
|
|
t.Error("openUpload 默认应为开启")
|
|
}
|
|
if c.EnableChunk() {
|
|
t.Error("enableChunk 默认应关闭")
|
|
}
|
|
// 新增字段(需求 ①)
|
|
if c.LogoURL() != DefaultLogoURL {
|
|
t.Errorf("logo_url 默认值 = %s", c.LogoURL())
|
|
}
|
|
if c.FaviconURL() != DefaultFaviconURL {
|
|
t.Errorf("favicon_url 默认值 = %s", c.FaviconURL())
|
|
}
|
|
if c.SiteName() == "" {
|
|
t.Error("site_name 默认值不应为空")
|
|
}
|
|
// 过期方式与文件类型
|
|
if len(c.ExpireStyle()) != 5 {
|
|
t.Errorf("expireStyle 默认值 = %v", c.ExpireStyle())
|
|
}
|
|
if len(c.AllowedFileTypes()) != 1 || c.AllowedFileTypes()[0] != "*" {
|
|
t.Errorf("allowed_file_types 默认值 = %v", c.AllowedFileTypes())
|
|
}
|
|
}
|
|
|
|
func TestKVOverridesEnvAndDefaults(t *testing.T) {
|
|
t.Setenv("FCB_DB_DSN", "postgres://x")
|
|
c, _ := New()
|
|
c.ApplyKV(map[string]any{
|
|
"uploadSize": 1024,
|
|
"openUpload": 0,
|
|
"site_name": "我的快递柜",
|
|
"logo_url": "https://example.com/logo.svg",
|
|
"internalKey": "x", // 非下划线开头允许;下划线开头被拒
|
|
"_secret": "no",
|
|
})
|
|
if got := c.GetInt("uploadSize"); got != 1024 {
|
|
t.Errorf("KV 覆盖 uploadSize 失败: %d", got)
|
|
}
|
|
if c.OpenUpload() {
|
|
t.Error("KV 覆盖 openUpload 失败")
|
|
}
|
|
if c.SiteName() != "我的快递柜" {
|
|
t.Errorf("site_name KV 覆盖失败: %s", c.SiteName())
|
|
}
|
|
if c.LogoURL() != "https://example.com/logo.svg" {
|
|
t.Errorf("logo_url KV 覆盖失败: %s", c.LogoURL())
|
|
}
|
|
if _, ok := c.Get("_secret"); ok {
|
|
t.Error("下划线内部键不应可通过 ApplyKV 覆盖")
|
|
}
|
|
}
|
|
|
|
func TestAdminSessionExpireClamp(t *testing.T) {
|
|
t.Setenv("FCB_DB_DSN", "postgres://x")
|
|
c, _ := New()
|
|
if got := c.AdminSessionExpireSeconds(); got != AdminSessionExpireDefault {
|
|
t.Errorf("默认会话有效期 = %d", got)
|
|
}
|
|
c.ApplyKV(map[string]any{"adminSessionExpire": 7 * 24 * 60 * 60})
|
|
if got := c.AdminSessionExpireSeconds(); got != 7*24*60*60 {
|
|
t.Errorf("7 天会话有效期 = %d", got)
|
|
}
|
|
c.ApplyKV(map[string]any{"adminSessionExpire": 3600}) // 非整天,回落默认
|
|
if got := c.AdminSessionExpireSeconds(); got != AdminSessionExpireDefault {
|
|
t.Errorf("非法值应回落默认 = %d", got)
|
|
}
|
|
}
|