mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-10 13:21:00 +00:00
feat(wireguard): per-peer comments for identifying devices (#5168)
WG peers were only identifiable by their keys. Add an optional panel-side comment per peer: editable in the inbound form (echoed next to "Peer N" in the section header), stored in the settings JSON alongside the panel-only privateKey (xray-core ignores unknown peer fields), and appended to the share link / .conf remark so the device is identifiable in client apps too.
This commit is contained in:
@@ -1079,11 +1079,11 @@ export function genWireguardLinks(input: GenWireguardFanoutInput): string {
|
|||||||
const addr = resolveAddr(inbound, hostOverride, fallbackHostname);
|
const addr = resolveAddr(inbound, hostOverride, fallbackHostname);
|
||||||
const sep = remarkModel.charAt(0);
|
const sep = remarkModel.charAt(0);
|
||||||
return inbound.settings.peers
|
return inbound.settings.peers
|
||||||
.map((_p, i) => genWireguardLink({
|
.map((p, i) => genWireguardLink({
|
||||||
settings: inbound.settings as WireguardInboundSettings,
|
settings: inbound.settings as WireguardInboundSettings,
|
||||||
address: addr,
|
address: addr,
|
||||||
port: inbound.port,
|
port: inbound.port,
|
||||||
remark: `${remark}${sep}${i + 1}`,
|
remark: `${remark}${sep}${i + 1}${wgPeerCommentSuffix(p)}`,
|
||||||
peerIndex: i,
|
peerIndex: i,
|
||||||
}))
|
}))
|
||||||
.join('\r\n');
|
.join('\r\n');
|
||||||
@@ -1095,16 +1095,23 @@ export function genWireguardConfigs(input: GenWireguardFanoutInput): string {
|
|||||||
const addr = resolveAddr(inbound, hostOverride, fallbackHostname);
|
const addr = resolveAddr(inbound, hostOverride, fallbackHostname);
|
||||||
const sep = remarkModel.charAt(0);
|
const sep = remarkModel.charAt(0);
|
||||||
return inbound.settings.peers
|
return inbound.settings.peers
|
||||||
.map((_p, i) => genWireguardConfig({
|
.map((p, i) => genWireguardConfig({
|
||||||
settings: inbound.settings as WireguardInboundSettings,
|
settings: inbound.settings as WireguardInboundSettings,
|
||||||
address: addr,
|
address: addr,
|
||||||
port: inbound.port,
|
port: inbound.port,
|
||||||
remark: `${remark}${sep}${i + 1}`,
|
remark: `${remark}${sep}${i + 1}${wgPeerCommentSuffix(p)}`,
|
||||||
peerIndex: i,
|
peerIndex: i,
|
||||||
}))
|
}))
|
||||||
.join('\r\n');
|
.join('\r\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Peer comments (#5168) are panel-side annotations; when present they ride
|
||||||
|
// along in the share remark so the device is identifiable in client apps.
|
||||||
|
function wgPeerCommentSuffix(peer: unknown): string {
|
||||||
|
const comment = (peer as { comment?: unknown })?.comment;
|
||||||
|
return typeof comment === 'string' && comment.trim() !== '' ? ` (${comment.trim()})` : '';
|
||||||
|
}
|
||||||
|
|
||||||
export function isPostQuantumLink(link: string): boolean {
|
export function isPostQuantumLink(link: string): boolean {
|
||||||
if (/[?&]pqv=/.test(link)) return true;
|
if (/[?&]pqv=/.test(link)) return true;
|
||||||
if (link.includes('mlkem768') || link.includes('mldsa65')) return true;
|
if (link.includes('mlkem768') || link.includes('mldsa65')) return true;
|
||||||
|
|||||||
@@ -102,6 +102,12 @@ export default function WireguardFields({ wgPubKey, regenInboundWg, regenWgPeerK
|
|||||||
<Divider titlePlacement="center">
|
<Divider titlePlacement="center">
|
||||||
<Space>
|
<Space>
|
||||||
<span>{t('pages.inbounds.info.peerNumber', { n: idx + 1 })}</span>
|
<span>{t('pages.inbounds.info.peerNumber', { n: idx + 1 })}</span>
|
||||||
|
<Form.Item noStyle shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
const comment = form.getFieldValue(['settings', 'peers', field.name, 'comment']) as string | undefined;
|
||||||
|
return comment ? <span style={{ opacity: 0.65 }}>— {comment}</span> : null;
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
{fields.length > 1 && (
|
{fields.length > 1 && (
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
@@ -112,6 +118,9 @@ export default function WireguardFields({ wgPubKey, regenInboundWg, regenWgPeerK
|
|||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
</Divider>
|
</Divider>
|
||||||
|
<Form.Item name={[field.name, 'comment']} label={t('comment')}>
|
||||||
|
<Input placeholder="e.g. Alice's laptop" />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item label={t('pages.xray.wireguard.secretKey')}>
|
<Form.Item label={t('pages.xray.wireguard.secretKey')}>
|
||||||
<Space.Compact block>
|
<Space.Compact block>
|
||||||
<Form.Item name={[field.name, 'privateKey']} noStyle>
|
<Form.Item name={[field.name, 'privateKey']} noStyle>
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ export const WireguardInboundPeerSchema = z.object({
|
|||||||
preSharedKey: z.string().optional(),
|
preSharedKey: z.string().optional(),
|
||||||
allowedIPs: z.array(z.string()).default([]),
|
allowedIPs: z.array(z.string()).default([]),
|
||||||
keepAlive: optionalClearedInt(z.number().int().min(0)),
|
keepAlive: optionalClearedInt(z.number().int().min(0)),
|
||||||
|
// Panel-only annotation (#5168): which client/device this peer belongs to.
|
||||||
|
// Rides along in the settings JSON like privateKey does; xray-core ignores
|
||||||
|
// unknown peer fields.
|
||||||
|
comment: z.string().optional(),
|
||||||
});
|
});
|
||||||
export type WireguardInboundPeer = z.infer<typeof WireguardInboundPeerSchema>;
|
export type WireguardInboundPeer = z.infer<typeof WireguardInboundPeerSchema>;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user