mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-10-31 14:27:23 +00:00
- 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 内嵌与顶层 非法键回归守卫
121 lines
3.5 KiB
Go
121 lines
3.5 KiB
Go
package store
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestLocalRemoteLinkRoundTrip(t *testing.T) {
|
|
dir := t.TempDir()
|
|
st, err := New(filepath.Join(dir, "test.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer st.Close()
|
|
|
|
if err := st.UpsertLocal(Local{Name: "web", IP: "127.0.0.1", Port: 8080, Protocol: "tcp"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.UpsertRemote(Remote{Name: "srv-a", IP: "1.2.3.4", Port: 7000, Token: "tok", Enabled: true}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.ReplaceLinks([]Link{{Local: "web", Remote: "srv-a", RemotePort: 8080}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
locals, _ := st.ListLocals()
|
|
if len(locals) != 1 || locals[0].Name != "web" {
|
|
t.Fatalf("locals = %+v", locals)
|
|
}
|
|
remotes, _ := st.ListRemotes()
|
|
if len(remotes) != 1 || remotes[0].Token != "tok" {
|
|
t.Fatalf("remotes = %+v", remotes)
|
|
}
|
|
fwds, err := st.LinksForRemote("srv-a")
|
|
if err != nil || len(fwds) != 1 {
|
|
t.Fatalf("forwards = %+v err=%v", fwds, err)
|
|
}
|
|
if fwds[0].LocalPort != 8080 || fwds[0].RemotePort != 8080 {
|
|
t.Fatalf("forward = %+v", fwds[0])
|
|
}
|
|
}
|
|
|
|
func TestReplaceLinksClearsOld(t *testing.T) {
|
|
dir := t.TempDir()
|
|
st, _ := New(filepath.Join(dir, "test.db"))
|
|
defer st.Close()
|
|
_ = st.UpsertLocal(Local{Name: "a", IP: "127.0.0.1", Port: 1, Protocol: "tcp"})
|
|
_ = st.UpsertLocal(Local{Name: "b", IP: "127.0.0.1", Port: 2, Protocol: "tcp"})
|
|
_ = st.UpsertRemote(Remote{Name: "r", IP: "1.2.3.4", Port: 7000, Enabled: true})
|
|
if err := st.ReplaceLinks([]Link{{Local: "a", Remote: "r", RemotePort: 1}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.ReplaceLinks([]Link{{Local: "b", Remote: "r", RemotePort: 2}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
links, _ := st.ListLinks()
|
|
if len(links) != 1 || links[0].Local != "b" {
|
|
t.Fatalf("links = %+v", links)
|
|
}
|
|
}
|
|
|
|
// `usr` is a reserved SQL keyword in several dialects, so the remotes column is
|
|
// named `usr`. This guards the mapping in both directions, including the
|
|
// migrate() path that adds the column to pre-existing databases.
|
|
func TestRemoteUserRoundTrip(t *testing.T) {
|
|
st, err := New(filepath.Join(t.TempDir(), "test.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer st.Close()
|
|
|
|
// A remote written without user (existing installs) must read back empty.
|
|
if err := st.UpsertRemote(Remote{Name: "plain", IP: "1.2.3.4", Port: 7000, Enabled: true}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got, ok := st.GetRemote("plain"); !ok || got.User != "" {
|
|
t.Fatalf("plain remote user = %q ok=%v, want empty", got.User, ok)
|
|
}
|
|
|
|
want := Remote{Name: "panel", IP: "103.40.13.126", Port: 59999, Token: "tk", User: "e8f52adfaf0e5c95", Enabled: true}
|
|
if err := st.UpsertRemote(want); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, ok := st.GetRemote("panel")
|
|
if !ok || got.User != want.User {
|
|
t.Fatalf("user not persisted: %+v", got)
|
|
}
|
|
list, err := st.ListRemotes()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var found bool
|
|
for _, r := range list {
|
|
if r.Name == "panel" {
|
|
found = true
|
|
if r.User != want.User {
|
|
t.Fatalf("ListRemotes user = %q, want %q", r.User, want.User)
|
|
}
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatal("panel remote missing from ListRemotes")
|
|
}
|
|
|
|
// Updating in place must not drop the column, and clearing it must work.
|
|
want.Token = "tk2"
|
|
if err := st.UpsertRemote(want); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got, _ := st.GetRemote("panel"); got.User != want.User || got.Token != "tk2" {
|
|
t.Fatalf("upsert lost fields: %+v", got)
|
|
}
|
|
want.User = ""
|
|
if err := st.UpsertRemote(want); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got, _ := st.GetRemote("panel"); got.User != "" {
|
|
t.Fatalf("user not cleared: %q", got.User)
|
|
}
|
|
}
|