mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-11-01 06:47:20 +00:00
fix(render,store): frpc user 支持 + 修正 useEncryption/useCompression 渲染位置
- store.Remote 新增 user 字段(DB 列名 usr,避开保留字;migrate() 自动加列), 渲染为 frpc 全局 user。面板型 frps(如 ChhChongGou 实例)强制要求 user 登录, 缺失时服务端返回 panel authentication unavailable: panel HTTP status 403 - ★ 修复渲染 bug:useEncryption/useCompression/bandwidthLimit 必须内嵌在 proxy 的 transport 对象(frpc ProxyTransport)。此前渲染在 proxy 顶层,frpc 默认 --strict-config 直接拒载:unknown field "useEncryption"。任何启用加密/压缩 的转发都无法启动。poolCount 无 proxy 级表达(官方 ProxyTransport 无此字段), 保留在 store 但不再渲染 - 前端:RemoteNode 画布节点与 StatusView 表单加 user 输入(画布此前会静默 清掉未声明的字段),带『面板型 frps 必填』提示 - 测试:user 往返(含迁移路径)、渲染含/不含 user、transport 内嵌与顶层 非法键回归守卫
This commit is contained in:
@ -74,14 +74,31 @@ func TestRenderTransportAdvanced(t *testing.T) {
|
||||
t.Fatalf("transport.poolCount = %d, want 3", cfg.Transport.PoolCount)
|
||||
}
|
||||
p := cfg.Proxies[0]
|
||||
if !p.UseEncryption || !p.UseCompression || p.PoolCount != 2 {
|
||||
t.Fatalf("proxy advanced fields = %+v", p)
|
||||
// useEncryption/useCompression/bandwidthLimit belong to the proxy's nested
|
||||
// `transport` object. Asserting them on the proxy top level is what let the
|
||||
// old renderer ship a config frpc rejects outright (`unknown field
|
||||
// "useEncryption"` under --strict-config).
|
||||
if p.Transport == nil {
|
||||
t.Fatalf("proxy transport section missing: %+v", p)
|
||||
}
|
||||
if !p.Transport.UseEncryption || !p.Transport.UseCompression || p.Transport.BandwidthLimit != "1MB" {
|
||||
t.Fatalf("proxy transport = %+v", p.Transport)
|
||||
}
|
||||
if p.Metadatas["env"] != "prod" || p.Annotations["owner"] != "ops" {
|
||||
t.Fatalf("proxy metadatas/annotations = %+v", p)
|
||||
}
|
||||
if p.Transport == nil || p.Transport.BandwidthLimit != "1MB" {
|
||||
t.Fatalf("proxy transport.bandwidthLimit = %+v", p.Transport)
|
||||
// Regression guard: the top level must carry no encryption/pool keys, since
|
||||
// frpc runs with --strict-config and rejects unknown fields.
|
||||
var raw struct {
|
||||
Proxies []map[string]any `json:"proxies"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, bad := range []string{"useEncryption", "useCompression", "poolCount"} {
|
||||
if _, ok := raw.Proxies[0][bad]; ok {
|
||||
t.Fatalf("proxy top level must not carry %q: %s", bad, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,8 +117,8 @@ func TestRenderTransportOmittedWhenEmpty(t *testing.T) {
|
||||
if cfg.Transport.Protocol != "" || cfg.Transport.TLS != nil || cfg.Transport.PoolCount != 0 {
|
||||
t.Fatalf("transport should be empty, got %+v", cfg.Transport)
|
||||
}
|
||||
if cfg.Proxies[0].UseEncryption || cfg.Proxies[0].Transport != nil {
|
||||
t.Fatalf("proxy advanced should be empty, got %+v", cfg.Proxies[0])
|
||||
if cfg.Proxies[0].Transport != nil {
|
||||
t.Fatalf("proxy transport should be empty when no proxy-level knobs are set, got %+v", cfg.Proxies[0].Transport)
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,3 +281,47 @@ func TestRenderAdminWebServerOmitted(t *testing.T) {
|
||||
t.Fatalf("webServer should be omitted, got %+v", cfg.WebServer)
|
||||
}
|
||||
}
|
||||
|
||||
// A panel-managed frps refuses logins without `user`, so the rendered config
|
||||
// must carry it verbatim when set.
|
||||
func TestRenderEmitsUserWhenSet(t *testing.T) {
|
||||
remote := store.Remote{Name: "srv", IP: "1.2.3.4", Port: 7000, Token: "tok", User: "e8f52adfaf0e5c95"}
|
||||
data, err := Render(remote, []Proxy{
|
||||
{Name: "club", Type: "tcp", LocalIP: "127.0.0.1", LocalPort: 80, RemotePort: 62962},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var cfg Config
|
||||
if err := json.Unmarshal(data, &cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cfg.User != "e8f52adfaf0e5c95" {
|
||||
t.Fatalf("user = %q, want e8f52adfaf0e5c95", cfg.User)
|
||||
}
|
||||
// The key must be present on the wire, not merely in the parsed struct:
|
||||
// an omitempty regression would silently break panel-type frps again.
|
||||
var raw map[string]any
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := raw["user"]; !ok {
|
||||
t.Fatalf("rendered JSON has no user key: %s", data)
|
||||
}
|
||||
}
|
||||
|
||||
// Plain frps rejects unknown fields, so an empty user must be omitted entirely.
|
||||
func TestRenderOmitsUserWhenEmpty(t *testing.T) {
|
||||
remote := store.Remote{Name: "srv", IP: "1.2.3.4", Port: 7000}
|
||||
data, err := Render(remote, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var raw map[string]any
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := raw["user"]; ok {
|
||||
t.Fatalf("empty user must be omitted, got: %s", data)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user