mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-16 09:36:07 +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>
45 lines
1.9 KiB
TypeScript
45 lines
1.9 KiB
TypeScript
import { formatInboundLabel } from '@/lib/inbounds/label';
|
|
import { preferPublicHost, resolveShareHost } from '@/lib/xray/inbound-link';
|
|
import type { ClientRecord, InboundOption } from '@/hooks/useClients';
|
|
|
|
export function isWireguardClient(client: ClientRecord | null | undefined): boolean {
|
|
if (!client) return false;
|
|
return !!(client.privateKey || client.publicKey || client.allowedIPs || client.preSharedKey || client.keepAlive);
|
|
}
|
|
|
|
export function findWireguardInbound(
|
|
client: ClientRecord | null | undefined,
|
|
inboundsById: Record<number, InboundOption>,
|
|
): InboundOption | undefined {
|
|
return (client?.inboundIds || [])
|
|
.map((id) => inboundsById[id])
|
|
.find((ib) => ib?.protocol === 'wireguard');
|
|
}
|
|
|
|
export function buildWireguardClientConfig(
|
|
client: ClientRecord,
|
|
inbound: InboundOption | undefined,
|
|
host = window.location.hostname,
|
|
publicHost = '',
|
|
): string {
|
|
const endpointHost = resolveShareHost(inbound ?? {}, inbound?.nodeAddress ?? '', preferPublicHost(host, publicHost));
|
|
const address = client.allowedIPs || '10.0.0.2/32';
|
|
const endpoint = `${endpointHost}:${inbound?.port || ''}`;
|
|
const inboundName = inbound ? formatInboundLabel(inbound.tag, inbound.remark) : '';
|
|
const remark = [inboundName, client.email, client.comment].filter(Boolean).join(' - ');
|
|
const lines = [
|
|
'[Interface]',
|
|
`PrivateKey = ${client.privateKey || client.password || ''}`,
|
|
`Address = ${address}`,
|
|
`DNS = ${inbound?.wgDns || '1.1.1.1, 1.0.0.1'}`,
|
|
];
|
|
if (inbound?.wgMtu && inbound.wgMtu > 0) lines.push(`MTU = ${inbound.wgMtu}`);
|
|
lines.push('');
|
|
if (remark) lines.push(`# ${remark}`);
|
|
lines.push('[Peer]', `PublicKey = ${inbound?.wgPublicKey || ''}`);
|
|
if (client.preSharedKey) lines.push(`PresharedKey = ${client.preSharedKey}`);
|
|
lines.push('AllowedIPs = 0.0.0.0/0, ::/0', `Endpoint = ${endpoint}`);
|
|
if (client.keepAlive && client.keepAlive > 0) lines.push(`PersistentKeepalive = ${client.keepAlive}`);
|
|
return lines.join('\n');
|
|
}
|