mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-07 05:34:17 +00:00
feat(clients): hide QR for post-quantum links in client info modal
Post-quantum keys (mldsa65 / ML-KEM-768) blow the encoded URL past what a single QR can hold. Detect them by the markers VLESS share links actually carry — `pqv=<base64>` for mldsa65Verify and `encryption=mlkem768x25519plus.*` for ML-KEM-768 — and drop the QR button for those rows. Copy still works.
This commit is contained in:
parent
e7ac1fadaa
commit
1752702f74
1 changed files with 27 additions and 10 deletions
|
|
@ -33,6 +33,20 @@ const INBOUND_PROTOCOL_COLORS: Record<string, string> = {
|
||||||
|
|
||||||
const INBOUND_CHIP_LIMIT = 1;
|
const INBOUND_CHIP_LIMIT = 1;
|
||||||
|
|
||||||
|
// Post-quantum keys blow up the encoded URL past what a single QR can
|
||||||
|
// hold. In VLESS share links the algorithm names don't appear as plain
|
||||||
|
// text — they ride inside query params:
|
||||||
|
// - mldsa65Verify becomes `pqv=<base64>` (sub/subService.go:841)
|
||||||
|
// - ML-KEM-768 becomes `encryption=mlkem768x25519plus.<...>`
|
||||||
|
// We also keep the literal substrings so configs that DO embed them
|
||||||
|
// directly (e.g. wireguard config text) still match.
|
||||||
|
function isPostQuantumLink(link: string): boolean {
|
||||||
|
if (/[?&]pqv=/.test(link)) return true;
|
||||||
|
if (link.includes('mlkem768') || link.includes('mldsa65')) return true;
|
||||||
|
if (link.includes('ML-KEM-768')) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 3x-ui's genRemark concatenates inbound remark + client email (and an
|
// 3x-ui's genRemark concatenates inbound remark + client email (and an
|
||||||
// optional extra) using a configurable separator. The email half is
|
// optional extra) using a configurable separator. The email half is
|
||||||
// redundant in the row title — the modal already names the client by
|
// redundant in the row title — the modal already names the client by
|
||||||
|
|
@ -356,6 +370,7 @@ export default function ClientInfoModal({
|
||||||
const qrRemark = meta.remark || `${t('pages.clients.link')} ${idx + 1}`;
|
const qrRemark = meta.remark || `${t('pages.clients.link')} ${idx + 1}`;
|
||||||
const rowTitle = trimEmail(meta.remark, client.email)
|
const rowTitle = trimEmail(meta.remark, client.email)
|
||||||
|| `${t('pages.clients.link')} ${idx + 1}`;
|
|| `${t('pages.clients.link')} ${idx + 1}`;
|
||||||
|
const canQr = !isPostQuantumLink(link);
|
||||||
return (
|
return (
|
||||||
<div key={idx} className="link-row">
|
<div key={idx} className="link-row">
|
||||||
<Tag color={PROTOCOL_COLORS[meta.protocol] ?? 'default'} className="link-row-tag">
|
<Tag color={PROTOCOL_COLORS[meta.protocol] ?? 'default'} className="link-row-tag">
|
||||||
|
|
@ -366,16 +381,18 @@ export default function ClientInfoModal({
|
||||||
<Tooltip title={t('copy')}>
|
<Tooltip title={t('copy')}>
|
||||||
<Button size="small" icon={<CopyOutlined />} onClick={() => copyValue(link)} />
|
<Button size="small" icon={<CopyOutlined />} onClick={() => copyValue(link)} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Popover
|
{canQr && (
|
||||||
trigger="click"
|
<Popover
|
||||||
placement="left"
|
trigger="click"
|
||||||
destroyOnHidden
|
placement="left"
|
||||||
content={<QrPanel value={link} remark={qrRemark} size={220} />}
|
destroyOnHidden
|
||||||
>
|
content={<QrPanel value={link} remark={qrRemark} size={220} />}
|
||||||
<Tooltip title={t('pages.clients.qrCode')}>
|
>
|
||||||
<Button size="small" icon={<QrcodeOutlined />} />
|
<Tooltip title={t('pages.clients.qrCode')}>
|
||||||
</Tooltip>
|
<Button size="small" icon={<QrcodeOutlined />} />
|
||||||
</Popover>
|
</Tooltip>
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue