mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-13 14:50:59 +00:00
feat(wireguard): client config UX, collapsible config card, configurable DNS
Land the WireGuard client-config UX work on main (the upstream PR #5642 branch could not be pushed to). - Reusable collapsible ConfigBlock (copy/download/QR, actions aligned right) for the client .conf, used by client info and the public sub page. - Correct .conf: canonical PresharedKey casing and DNS sourced from the inbound (configurable per-inbound, default 1.1.1.1, 1.0.0.1). - Configurable per-inbound DNS for WireGuard (schema + form + backend hint via InboundOption.WgDns); inert at the Xray layer. - Public sub page now shows the WireGuard config, rebuilt from the share link; the Go wireguard:// link carries dns/presharedkey/keepalive for completeness. - QR enabled for the wireguard:// link; link rows are compact like other protocols. - Client information order is subscription, copy URL, WireGuard config; the redundant config tab is removed from the add/edit client modal. - Drop the Inbound Information and QR Code row actions for WireGuard inbounds.
This commit is contained in:
@@ -545,6 +545,15 @@ func (s *SubService) genWireguardLink(inbound *model.Inbound, email string) stri
|
||||
if mtu, ok := settings["mtu"].(float64); ok && mtu > 0 {
|
||||
params["mtu"] = strconv.Itoa(int(mtu))
|
||||
}
|
||||
if dns, ok := settings["dns"].(string); ok && dns != "" {
|
||||
params["dns"] = dns
|
||||
}
|
||||
if client.PreSharedKey != "" {
|
||||
params["presharedkey"] = client.PreSharedKey
|
||||
}
|
||||
if client.KeepAlive > 0 {
|
||||
params["keepalive"] = strconv.Itoa(client.KeepAlive)
|
||||
}
|
||||
return buildLinkWithParams(link, params, s.genRemark(inbound, email, "", ""))
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/mtproto"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/util/common"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/util/netsafe"
|
||||
wgutil "github.com/mhsanaei/3x-ui/v3/internal/util/wireguard"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
|
||||
"gorm.io/gorm"
|
||||
@@ -298,6 +299,9 @@ type InboundOption struct {
|
||||
Port int `json:"port" example:"443"`
|
||||
TlsFlowCapable bool `json:"tlsFlowCapable" example:"true"`
|
||||
SsMethod string `json:"ssMethod"`
|
||||
WgPublicKey string `json:"wgPublicKey,omitempty"`
|
||||
WgMtu int `json:"wgMtu,omitempty"`
|
||||
WgDns string `json:"wgDns,omitempty"`
|
||||
// Hosting node; nil for this panel's own inbounds. Lets the clients
|
||||
// page map a node filter onto inbound IDs (#4997).
|
||||
NodeId *int `json:"nodeId,omitempty"`
|
||||
@@ -325,6 +329,7 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
|
||||
}
|
||||
out := make([]InboundOption, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
wgPublicKey, wgMtu, wgDns := inboundWireguardHints(r.Protocol, r.Settings)
|
||||
out = append(out, InboundOption{
|
||||
Id: r.Id,
|
||||
Remark: r.Remark,
|
||||
@@ -333,12 +338,41 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
|
||||
Port: r.Port,
|
||||
TlsFlowCapable: inboundCanEnableTlsFlow(r.Protocol, r.StreamSettings, r.Settings),
|
||||
SsMethod: inboundShadowsocksMethod(r.Protocol, r.Settings),
|
||||
WgPublicKey: wgPublicKey,
|
||||
WgMtu: wgMtu,
|
||||
WgDns: wgDns,
|
||||
NodeId: r.NodeId,
|
||||
})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func inboundWireguardHints(protocol string, settings string) (string, int, string) {
|
||||
if protocol != string(model.WireGuard) || strings.TrimSpace(settings) == "" {
|
||||
return "", 0, ""
|
||||
}
|
||||
var parsed struct {
|
||||
PublicKey string `json:"publicKey"`
|
||||
PubKey string `json:"pubKey"`
|
||||
SecretKey string `json:"secretKey"`
|
||||
MTU int `json:"mtu"`
|
||||
DNS string `json:"dns"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(settings), &parsed); err != nil {
|
||||
return "", 0, ""
|
||||
}
|
||||
publicKey := parsed.PublicKey
|
||||
if publicKey == "" {
|
||||
publicKey = parsed.PubKey
|
||||
}
|
||||
if publicKey == "" && parsed.SecretKey != "" {
|
||||
if derived, err := wgutil.PublicKeyFromPrivate(parsed.SecretKey); err == nil {
|
||||
publicKey = derived
|
||||
}
|
||||
}
|
||||
return publicKey, parsed.MTU, parsed.DNS
|
||||
}
|
||||
|
||||
// GetAllInbounds retrieves all inbounds with client stats.
|
||||
func (s *InboundService) GetAllInbounds() ([]*model.Inbound, error) {
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -718,6 +718,8 @@
|
||||
"tabBasics": "Basics",
|
||||
"tabCredentials": "Credentials",
|
||||
"tabLinks": "Links",
|
||||
"wireguardConfig": "WireGuard config",
|
||||
"conf": "CONF",
|
||||
"linksHint": "Add third-party share links and remote subscription URLs to include in this client's subscription.",
|
||||
"addExternalLink": "Add External Link",
|
||||
"addExternalSubscription": "Add External Subscription",
|
||||
|
||||
Reference in New Issue
Block a user