mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-17 23:57:15 +00:00
feat(wireguard): multi-client support
WireGuard inbounds now manage per-client peers using xray-core's native WireGuard users (AddUser/RemoveUser). Each client lives in settings.clients (canonical, like every other protocol) and is projected to peers[] only when emitting the xray config, at level 0 so the dispatcher's per-user traffic/online counters work with no extra plumbing. Backend: internal/util/wireguard gains KeyToHex (base64 to hex for the gRPC path), PublicKeyFromPrivate and GenerateWireguardPSK; xray/api.go builds a wireguard account in AddUser with hex keys (RemoveUser already worked); client CRUD generates a keypair and allocates a unique tunnel address per client and never rotates keys on edit; an idempotent migration converts legacy settings.peers into managed clients; WireGuard is included in the raw subscription. Frontend: WireGuard in the add-client modal with keys on the credential tab, client schema, per-client QR/link/.conf, inbound form reduced to server settings; i18n added across 13 locales. Fix: guard the settings[clients] assertion in add/update so a legacy WireGuard inbound stored without a clients key no longer panics.
This commit is contained in:
@@ -1126,14 +1126,30 @@ export interface GenWireguardFanoutInput {
|
||||
fallbackHostname: string;
|
||||
}
|
||||
|
||||
// WireGuard is multi-client: each client is one accepted peer. The canonical
|
||||
// store is settings.clients; legacy single-config inbounds (pre-migration) are
|
||||
// still rendered from settings.peers. Both carry the privateKey/allowedIPs/
|
||||
// preSharedKey/keepAlive the link and .conf need, so they project to the same
|
||||
// peer shape and reuse genWireguardLink/genWireguardConfig unchanged.
|
||||
function wgRenderPeers(settings: WireguardInboundSettings): WireguardInboundPeer[] {
|
||||
const clients = settings.clients ?? [];
|
||||
if (clients.length > 0) {
|
||||
return clients.map((c) => ({ ...c, publicKey: c.publicKey ?? '' }));
|
||||
}
|
||||
return settings.peers;
|
||||
}
|
||||
|
||||
export function genWireguardLinks(input: GenWireguardFanoutInput): string {
|
||||
const { inbound, remark = '', hostOverride = '', fallbackHostname } = input;
|
||||
if (inbound.protocol !== 'wireguard') return '';
|
||||
const addr = resolveAddr(inbound, hostOverride, fallbackHostname);
|
||||
const sep = '-';
|
||||
return inbound.settings.peers
|
||||
const baseSettings = inbound.settings as WireguardInboundSettings;
|
||||
const peers = wgRenderPeers(baseSettings);
|
||||
const settings: WireguardInboundSettings = { ...baseSettings, peers };
|
||||
return peers
|
||||
.map((p, i) => genWireguardLink({
|
||||
settings: inbound.settings as WireguardInboundSettings,
|
||||
settings,
|
||||
address: addr,
|
||||
port: inbound.port,
|
||||
remark: `${remark}${sep}${i + 1}${wgPeerCommentSuffix(p)}`,
|
||||
@@ -1147,9 +1163,12 @@ export function genWireguardConfigs(input: GenWireguardFanoutInput): string {
|
||||
if (inbound.protocol !== 'wireguard') return '';
|
||||
const addr = resolveAddr(inbound, hostOverride, fallbackHostname);
|
||||
const sep = '-';
|
||||
return inbound.settings.peers
|
||||
const baseSettings = inbound.settings as WireguardInboundSettings;
|
||||
const peers = wgRenderPeers(baseSettings);
|
||||
const settings: WireguardInboundSettings = { ...baseSettings, peers };
|
||||
return peers
|
||||
.map((p, i) => genWireguardConfig({
|
||||
settings: inbound.settings as WireguardInboundSettings,
|
||||
settings,
|
||||
address: addr,
|
||||
port: inbound.port,
|
||||
remark: `${remark}${sep}${i + 1}${wgPeerCommentSuffix(p)}`,
|
||||
|
||||
Reference in New Issue
Block a user