mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-07 05:14:27 +00:00
f90e4a6962
* fix(panel): use the hosting node address for WireGuard client configs The clients page rendered a node-managed WireGuard inbound's config with the master panel's host in Endpoint instead of the hosting node's address, so the copied/QR config pointed at the wrong server. The subscription path already resolves this via resolveInboundAddress; the UI generator did not. Expose the share-host resolution inputs (node address, listen, share-address strategy/address) on InboundOption and route buildWireguardClientConfig through the same canonical resolver the inbounds-page share links use, extracted as resolveShareHost. This also brings local inbounds with a shareable listen or a listen/custom share strategy into parity with the subscription Endpoint; the common listen=0.0.0.0 case still falls back to the panel host. * fix(frontend): keep a raw fallback host and refresh node-fed inbound options Code review of the WireGuard node-endpoint change surfaced two gaps. resolveShareHost normalized its last-resort fallbackHostname, so a panel reached via a hostname the share-host grammar rejects (underscore label, trailing-dot FQDN) emitted a broken 'Endpoint = :51820'; the fallback now stays verbatim when normalization empties it. Node mutations only invalidated the nodes query, leaving the staleTime-Infinity inbound options cache serving an edited node address until the sync job broadcast (never, for disabled/offline nodes); they now invalidate the options key too. Also folds the ShareHostFields projections into direct structural passes, elides the default node shareAddrStrategy so omitempty drops it, and replaces the nullable node-address scan with COALESCE. --------- Co-authored-by: STRENCH0 <17428017+STRENCH0@users.noreply.github.com> Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
90 lines
2.8 KiB
Go
90 lines
2.8 KiB
Go
package service
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
)
|
|
|
|
// TestGetInboundOptions_NodeAddress verifies that a node-managed inbound carries
|
|
// its hosting node's externally reachable address, while this panel's own
|
|
// inbounds report an empty NodeAddress. The clients page uses it as the
|
|
// WireGuard endpoint host so a copied config points at the node, not the master.
|
|
func TestGetInboundOptions_NodeAddress(t *testing.T) {
|
|
setupConflictDB(t)
|
|
|
|
node := &model.Node{Name: "de-fra-1", Address: "node.example.net", Port: 2053, Enable: true}
|
|
if err := database.GetDB().Create(node).Error; err != nil {
|
|
t.Fatalf("create node: %v", err)
|
|
}
|
|
|
|
nodeInbound := &model.Inbound{
|
|
UserId: 1,
|
|
Tag: "in-51820-udp",
|
|
Enable: true,
|
|
Listen: "0.0.0.0",
|
|
Port: 51820,
|
|
Protocol: model.WireGuard,
|
|
Settings: `{"clients":[],"secretKey":"QGVlb2dXc1ZTWGw0ZXBzZndsWmtMaUM5MUlNYjBHWFdYbz0="}`,
|
|
NodeID: &node.Id,
|
|
}
|
|
localInbound := &model.Inbound{
|
|
UserId: 1,
|
|
Tag: "in-443-tcp",
|
|
Enable: true,
|
|
Listen: "0.0.0.0",
|
|
Port: 443,
|
|
Protocol: model.VLESS,
|
|
StreamSettings: `{"network":"tcp"}`,
|
|
Settings: `{"clients":[]}`,
|
|
ShareAddrStrategy: "custom",
|
|
ShareAddr: "vpn.example.com",
|
|
}
|
|
if err := database.GetDB().Create(nodeInbound).Error; err != nil {
|
|
t.Fatalf("create node inbound: %v", err)
|
|
}
|
|
if err := database.GetDB().Create(localInbound).Error; err != nil {
|
|
t.Fatalf("create local inbound: %v", err)
|
|
}
|
|
|
|
svc := &InboundService{}
|
|
options, err := svc.GetInboundOptions(1)
|
|
if err != nil {
|
|
t.Fatalf("GetInboundOptions: %v", err)
|
|
}
|
|
|
|
byID := make(map[int]InboundOption, len(options))
|
|
for _, o := range options {
|
|
byID[o.Id] = o
|
|
}
|
|
|
|
got, ok := byID[nodeInbound.Id]
|
|
if !ok {
|
|
t.Fatalf("node inbound %d missing from options", nodeInbound.Id)
|
|
}
|
|
if got.NodeAddress != "node.example.net" {
|
|
t.Fatalf("node inbound NodeAddress = %q, want node.example.net", got.NodeAddress)
|
|
}
|
|
if got.Listen != "0.0.0.0" {
|
|
t.Fatalf("node inbound Listen = %q, want 0.0.0.0", got.Listen)
|
|
}
|
|
if got.ShareAddrStrategy != "" {
|
|
t.Fatalf("node inbound ShareAddrStrategy = %q, want empty (the default node strategy is elided so omitempty drops it)", got.ShareAddrStrategy)
|
|
}
|
|
|
|
local, ok := byID[localInbound.Id]
|
|
if !ok {
|
|
t.Fatalf("local inbound %d missing from options", localInbound.Id)
|
|
}
|
|
if local.NodeAddress != "" {
|
|
t.Fatalf("local inbound NodeAddress = %q, want empty", local.NodeAddress)
|
|
}
|
|
if local.ShareAddrStrategy != "custom" {
|
|
t.Fatalf("local inbound ShareAddrStrategy = %q, want custom", local.ShareAddrStrategy)
|
|
}
|
|
if local.ShareAddr != "vpn.example.com" {
|
|
t.Fatalf("local inbound ShareAddr = %q, want vpn.example.com", local.ShareAddr)
|
|
}
|
|
}
|