mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 19:25:05 +03:00
fix(wireguard): check every line of generated client configs
The WireGuard and AmneziaWG .conf builders (subscription service, clients page, inbound modal and subscription page) checked only a few of the values they write. Each builder now assembles the file line by line and renders nothing when a line holds a control character, so every value is covered whatever stored it. A decoded vpn:// payload is refused when it carries a wg-quick hook directive, which no panel builder writes, and the subscription page hides a config block that rendered nothing. The inbound form now validates a WireGuard/AmneziaWG client's allowedIPs on create and on update, including the stored clients a protocol switch keeps, as the client endpoints already did.
This commit is contained in:
@@ -2,6 +2,7 @@ import type { HostEndpoint } from '@/lib/hosts/host-link';
|
||||
import { formatInboundLabel } from '@/lib/inbounds/label';
|
||||
import { preferPublicHost, resolveShareHost } from '@/lib/xray/inbound-link';
|
||||
import { effectiveMtu } from '@/lib/xray/amneziawg-obfuscation';
|
||||
import { joinConfLines } from '@/lib/xray/conf-lines';
|
||||
import type { ClientRecord, InboundOption } from '@/hooks/useClients';
|
||||
|
||||
// AmneziaWG clients are wire-identical to WireGuard clients (same
|
||||
@@ -58,13 +59,7 @@ export function buildAmneziaWGClientConfig(
|
||||
.filter(Boolean)
|
||||
.join(' - ');
|
||||
|
||||
// These land unescaped in [Interface]; a newline here would inject a
|
||||
// config line (e.g. a rogue PostUp) into the downloaded .conf.
|
||||
const privateKey = client.privateKey || client.password || '';
|
||||
for (const v of [privateKey, server?.primaryDns ?? '', server?.secondaryDns ?? '', remark]) {
|
||||
if (/[\r\n]/.test(v)) return '';
|
||||
}
|
||||
|
||||
const dnsParts = [server?.primaryDns, server?.secondaryDns].filter((v) => !!v && v.trim() !== '');
|
||||
const lines = ['[Interface]', `PrivateKey = ${privateKey}`, `Address = ${address}`];
|
||||
if (dnsParts.length > 0) lines.push(`DNS = ${dnsParts.join(', ')}`);
|
||||
@@ -109,5 +104,5 @@ export function buildAmneziaWGClientConfig(
|
||||
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');
|
||||
return joinConfLines(lines);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { HostEndpoint } from '@/lib/hosts/host-link';
|
||||
import { formatInboundLabel } from '@/lib/inbounds/label';
|
||||
import { joinConfLines } from '@/lib/xray/conf-lines';
|
||||
import { preferPublicHost, resolveShareHost } from '@/lib/xray/inbound-link';
|
||||
import type { ClientRecord, InboundOption } from '@/hooks/useClients';
|
||||
|
||||
@@ -54,5 +55,5 @@ export function buildWireguardClientConfig(
|
||||
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');
|
||||
return joinConfLines(lines);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ export default function SubConfigsTab({ links, onCopy }: SubConfigsTabProps) {
|
||||
const parts = parseLinkParts(link);
|
||||
const rowTitle = parts?.remark || `Link ${idx + 1}`;
|
||||
const isWireguardLink = link.startsWith('wireguard://') || link.startsWith('wg://');
|
||||
const isAmneziawgLink = link.startsWith('vpn://');
|
||||
const wireguardConfig = isWireguardLink ? wireguardConfigFromLink(link, rowTitle) : '';
|
||||
const amneziawgConfig = link.startsWith('vpn://') ? amneziawgConfigFromLink(link) : '';
|
||||
return (
|
||||
<Fragment key={link}>
|
||||
<div className="sub-row">
|
||||
@@ -54,19 +55,19 @@ export default function SubConfigsTab({ links, onCopy }: SubConfigsTabProps) {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{isWireguardLink && (
|
||||
{wireguardConfig && (
|
||||
<ConfigBlock
|
||||
label={t('pages.clients.wireguardConfig')}
|
||||
text={wireguardConfigFromLink(link, rowTitle)}
|
||||
text={wireguardConfig}
|
||||
fileName={`${rowTitle || 'peer'}.conf`}
|
||||
qrRemark={rowTitle}
|
||||
tagColor="cyan"
|
||||
/>
|
||||
)}
|
||||
{isAmneziawgLink && (
|
||||
{amneziawgConfig && (
|
||||
<ConfigBlock
|
||||
label={t('pages.clients.amneziaWgConfig')}
|
||||
text={amneziawgConfigFromLink(link)}
|
||||
text={amneziawgConfig}
|
||||
fileName={`${rowTitle || 'peer'}.conf`}
|
||||
qrRemark={rowTitle}
|
||||
tagColor="purple"
|
||||
|
||||
Reference in New Issue
Block a user