Smail/backend/config/public_https_test.go
smail d193324e6d
Some checks are pending
Security Checks / security (push) Waiting to run
整改基线:封存公网端口分离与远程后端回归候选
2026-09-18 01:05:50 +08:00

102 lines
3.7 KiB
Go
Raw Permalink 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 (
"encoding/json"
"testing"
)
func TestResolvePublicHTTPSPort(t *testing.T) {
t.Setenv("SMAIL_HTTP_TLS_MODE_OVERRIDE", "")
t.Setenv("SMAIL_HTTPS_PORT", "")
cases := []struct {
name string
config HTTPConfig
want int
}{
{"default direct", HTTPConfig{}, 443},
{"custom direct", HTTPConfig{HTTPSPort: 8443}, 8443},
{"https upstream", HTTPConfig{HTTPSPort: 8002, PublicHTTPSPort: 443}, 443},
{"custom public", HTTPConfig{HTTPSPort: 8002, PublicHTTPSPort: 9443}, 9443},
{"http upstream", HTTPConfig{TLSMode: HTTPSTLSModeProxy}, 443},
{"custom http upstream", HTTPConfig{TLSMode: HTTPSTLSModeProxy, PublicHTTPSPort: 9443}, 9443},
{"invalid negative", HTTPConfig{PublicHTTPSPort: -1}, -1},
{"invalid upper bound", HTTPConfig{PublicHTTPSPort: 65536}, 65536},
}
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
if got := ResolvePublicHTTPSPort(test.config); got != test.want {
t.Fatalf("公网端口为 %d,预期 %d", got, test.want)
}
})
}
}
func TestPublicHTTPSPortValidationAndSerialization(t *testing.T) {
for _, port := range []int{0, 1, 443, 8002, 65535} {
value := HTTPConfig{Port: 8001, HTTPSPort: 8002, HTTPSEnabled: true, PublicHTTPSPort: port}
if err := validateHTTP(value); err != nil {
t.Fatal(err)
}
// 公网端口不是当前进程监听端口,不能参与本机端口冲突检查。
if err := validateRuntimePorts(value, MailPorts{}); err != nil {
t.Fatal(err)
}
data, err := json.Marshal(value)
if err != nil {
t.Fatal(err)
}
var restored HTTPConfig
if err := ParseStrict(data, &restored); err != nil {
t.Fatal(err)
}
if restored.PublicHTTPSPort != port || restored.HTTPSPort != 8002 {
t.Fatalf("序列化丢失公网或内部端口:%s", data)
}
}
for _, port := range []int{-1, 65536} {
if validateHTTP(HTTPConfig{PublicHTTPSPort: port}) == nil {
t.Fatalf("接受了非法公网端口 %d", port)
}
}
}
func TestPublicHTTPSPortRuntimeAccess(t *testing.T) {
oldInstance, oldSnapshot, oldManager := Instance, CurrentConfig(), CurrentManager()
t.Cleanup(func() {
Instance = oldInstance
PublishConfigSnapshot(oldSnapshot)
SetRuntimeManager(oldManager)
})
SetRuntimeManager(nil)
PublishConfigSnapshot(&Config{HttpPort: 8001, HttpsPort: 8002, PublicHTTPSPort: 443})
if got := CurrentHTTPConfig(); got.PublicHTTPSPort != 443 || got.HTTPSPort != 8002 {
t.Fatalf("旧配置运行时映射丢失端口:%+v", got)
}
runtime := validRuntimeConfig()
runtime.Root.HTTP = HTTPConfig{Port: 8001, HTTPSPort: 8002, HTTPSEnabled: true, PublicHTTPSPort: 9443}
SetRuntimeManager(&ConfigManager{snapshots: runtimeAccessSnapshotStore{runtime: runtime}})
if got := CurrentHTTPConfig(); got.PublicHTTPSPort != 9443 || got.HTTPSPort != 8002 {
t.Fatalf("分区配置运行时映射丢失端口:%+v", got)
}
}
func TestWebAuthnUsesPublicHTTPSPort(t *testing.T) {
root := RootConfig{Domains: DomainConfig{Web: "mail.example.com"}, HTTP: HTTPConfig{HTTPSPort: 8002, PublicHTTPSPort: 443}}
for _, test := range []struct {
port int
want string
}{{443, "https://mail.example.com"}, {9443, "https://mail.example.com:9443"}, {0, "https://mail.example.com:8002"}} {
root.HTTP.PublicHTTPSPort = test.port
security, err := ResolveWebAuthnSecurity(root)
if err != nil || len(security.WebAuthnRPOrigins) != 1 || security.WebAuthnRPOrigins[0] != test.want {
t.Fatalf("安全密钥默认来源不匹配:%+v,%v", security, err)
}
}
root.HTTP.PublicHTTPSPort = 443
root.Security.WebAuthnRPOrigins = []string{"https://mail.example.com:9443"}
security, err := ResolveWebAuthnSecurity(root)
if err != nil || security.WebAuthnRPOrigins[0] != root.Security.WebAuthnRPOrigins[0] {
t.Fatal("公网端口覆盖了显式配置的安全密钥来源")
}
}