V2.0.1: listen override fix, sing-box core fetch, probe settings page + fast report, spx removal, core mem env
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Docs CI / build (push) Waiting to run
Docs Deploy (GitHub Pages) / build (push) Waiting to run
Docs Deploy (GitHub Pages) / deploy (push) Blocked by required conditions
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Docs CI / build (push) Waiting to run
Docs Deploy (GitHub Pages) / build (push) Waiting to run
Docs Deploy (GitHub Pages) / deploy (push) Blocked by required conditions
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
- 0: sing-box gen overrides fragment listen/port from the inbound row (empty listen -> "::"), Update/Add recompute the stored fragment; non-loopback E2E against the real core binary. - 1: agent fetches the sing-box core from the Gitea release when missing, self-checks it, and only then latches the switch. - 2: node list shows the sing-box core version (heartbeat field, persisted on the node row), xray version as fallback. - 3: public-page fallback returns 404 to anonymous visitors when the page is disabled. - 4: settings restart hint bar removed, dead i18n keys cleaned. - 5: two PUT calls missing JSON headers fixed (audit: only those two), batch probe-task creation endpoint + UI. - 6: cf-probe retirement card and coverage pipeline removed. - 7: generated vless links no longer carry spx (panel export + sub); parser still accepts spx; golden fixtures updated. - probe batch: dedicated probe settings tab (public-page settings, tasks, per-node meta), retention_days editable, per-node traffic calibration + stat-interface pinning, runtime metrics split into a lightweight fast report (default 3s, 1-60s adjustable). - 8: sing-box core processes start with GOMEMLIMIT=32MiB, GOGC=50. - 9: dead /getTwoFactorEnable docs entries removed (frontend call and contract entry already gone at base; verified by grep).
This commit is contained in:
@@ -54,7 +54,7 @@ func TestGenVlessLink_TLSParamsMapped(t *testing.T) {
|
||||
}
|
||||
|
||||
// Locks the reality field mapping of applyShareRealityParams; distinct pbk/sid
|
||||
// catch a swap mutant. spx is now a per-client derived value (#5718 / follow-up).
|
||||
// catch a swap mutant. spx must never be emitted (V2.0.1 ⑦).
|
||||
func TestGenVlessLink_RealityParamsMapped(t *testing.T) {
|
||||
stream := `{
|
||||
"network":"tcp","security":"reality",
|
||||
@@ -74,13 +74,15 @@ func TestGenVlessLink_RealityParamsMapped(t *testing.T) {
|
||||
"pbk=PBKvalue",
|
||||
"sid=ab12cd",
|
||||
"fp=firefox",
|
||||
"spx=%2F",
|
||||
}
|
||||
for _, w := range wants {
|
||||
if !strings.Contains(link, w) {
|
||||
t.Fatalf("reality link missing %q\n got: %s", w, link)
|
||||
}
|
||||
}
|
||||
if strings.Contains(link, "spx") {
|
||||
t.Fatalf("reality link must not carry spx (V2.0.1 ⑦): %s", link)
|
||||
}
|
||||
// A pbk<->sid swap must not silently pass: pbk must not carry the shortId.
|
||||
if strings.Contains(link, "pbk=ab12cd") || strings.Contains(link, "sid=PBKvalue") {
|
||||
t.Fatalf("reality pbk/sid mapping crossed: %s", link)
|
||||
@@ -88,7 +90,7 @@ func TestGenVlessLink_RealityParamsMapped(t *testing.T) {
|
||||
}
|
||||
|
||||
// realityTwoClientInbound builds a reality VLESS inbound carrying two clients
|
||||
// with distinct subIds so the per-client spx derivation can be exercised.
|
||||
// with distinct subIds.
|
||||
func realityTwoClientInbound() *model.Inbound {
|
||||
return &model.Inbound{
|
||||
Listen: "203.0.113.1",
|
||||
@@ -111,68 +113,19 @@ func realityTwoClientInbound() *model.Inbound {
|
||||
}
|
||||
}
|
||||
|
||||
func spxParam(t *testing.T, link string) string {
|
||||
t.Helper()
|
||||
u, err := url.Parse(link)
|
||||
if err != nil {
|
||||
t.Fatalf("parse link %q: %v", link, err)
|
||||
}
|
||||
spx := u.Query().Get("spx")
|
||||
if spx == "" || spx[0] != '/' {
|
||||
t.Fatalf("spx missing or not /-prefixed in %q", link)
|
||||
}
|
||||
return spx
|
||||
}
|
||||
|
||||
// spx must be stable for a given client across repeated exports (the #5718
|
||||
// complaint) yet differ between clients so the value can't be fingerprinted.
|
||||
func TestGenVlessLink_RealitySpiderXPerClientStable(t *testing.T) {
|
||||
// V2.0.1 ⑦: generated reality links never carry spx, for any client,
|
||||
// even when the inbound still stores a spiderX seed.
|
||||
func TestGenVlessLink_RealityOmitsSpx(t *testing.T) {
|
||||
s := &SubService{}
|
||||
inbound := realityTwoClientInbound()
|
||||
|
||||
aliceFirst := spxParam(t, s.genVlessLink(inbound, "alice"))
|
||||
aliceSecond := spxParam(t, s.genVlessLink(inbound, "alice"))
|
||||
bob := spxParam(t, s.genVlessLink(inbound, "bob"))
|
||||
|
||||
if aliceFirst != aliceSecond {
|
||||
t.Fatalf("spx not stable for the same client: %q vs %q", aliceFirst, aliceSecond)
|
||||
}
|
||||
if aliceFirst == bob {
|
||||
t.Fatalf("spx identical across clients (fingerprintable): %q", aliceFirst)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveSpiderX(t *testing.T) {
|
||||
if got := deriveSpiderX("seed", "clientA"); got != deriveSpiderX("seed", "clientA") {
|
||||
t.Fatalf("deriveSpiderX not deterministic: %q", got)
|
||||
}
|
||||
if deriveSpiderX("seed", "clientA") == deriveSpiderX("seed", "clientB") {
|
||||
t.Fatal("deriveSpiderX must differ per client")
|
||||
}
|
||||
if deriveSpiderX("seedA", "clientA") == deriveSpiderX("seedB", "clientA") {
|
||||
t.Fatal("rotating the seed must rotate a client's spx")
|
||||
}
|
||||
got := deriveSpiderX("seed", "clientA")
|
||||
if len(got) != 16 || got[0] != '/' {
|
||||
t.Fatalf("deriveSpiderX shape = %q, want /-prefixed 15-char path", got)
|
||||
}
|
||||
if fallback := deriveSpiderX("", ""); len(fallback) != 16 || fallback[0] != '/' {
|
||||
t.Fatalf("empty-input fallback = %q, want /-prefixed path", fallback)
|
||||
}
|
||||
}
|
||||
|
||||
// Cross-language vectors shared with frontend/src/test/spider-x.test.ts: the
|
||||
// panel builds these links in TS, so both derivations must agree byte-for-byte.
|
||||
func TestDeriveSpiderXMatchesFrontendVectors(t *testing.T) {
|
||||
vectors := map[string]struct{ seed, clientKey, want string }{
|
||||
"seed and subId": {"/seed", "subAlice", "/c252fbc3ecd3e3c"},
|
||||
"seed only": {"/", "", "/d08ed99bd9afc60"},
|
||||
}
|
||||
for name, v := range vectors {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if got := deriveSpiderX(v.seed, v.clientKey); got != v.want {
|
||||
t.Fatalf("deriveSpiderX(%q, %q) = %q, want %q (must match frontend/src/lib/xray/spider-x.ts)", v.seed, v.clientKey, got, v.want)
|
||||
}
|
||||
})
|
||||
for _, email := range []string{"alice", "bob"} {
|
||||
link := s.genVlessLink(inbound, email)
|
||||
u, err := url.Parse(link)
|
||||
if err != nil {
|
||||
t.Fatalf("parse link %q: %v", link, err)
|
||||
}
|
||||
if _, ok := u.Query()["spx"]; ok {
|
||||
t.Fatalf("link for %s carries spx: %s", email, link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user