'use client'; import { useCallback, useEffect, useState } from 'react'; import { RefreshCw } from 'lucide-react'; import { generateX25519KeyPair, isX25519Available, randomShortId, randomUuid, realityClientLink, realityServerInbound, type RealityConfig, type X25519KeyPair, } from '@/lib/xray/reality'; import { ToolFrame } from './tool-frame'; import { TextField, SelectField } from './shared/fields'; import { OutputBlock } from './shared/output-block'; import { CopyButton } from './shared/copy-button'; const FINGERPRINTS = ['chrome', 'firefox', 'safari', 'ios', 'android', 'edge', 'random'] as const; export function RealityConfigGenerator() { const [address, setAddress] = useState('your-server.com'); const [port, setPort] = useState('443'); const [dest, setDest] = useState('www.microsoft.com:443'); const [sni, setSni] = useState('www.microsoft.com'); const [fingerprint, setFingerprint] = useState('chrome'); const [uuid, setUuid] = useState(''); const [shortId, setShortId] = useState(''); const [keys, setKeys] = useState(null); const [unavailable, setUnavailable] = useState(false); const regenerate = useCallback(async () => { setUuid(randomUuid()); setShortId(randomShortId(4)); if (!isX25519Available()) { setUnavailable(true); return; } try { setKeys(await generateX25519KeyPair()); setUnavailable(false); } catch { setUnavailable(true); } }, []); // Generate keys/identifiers on the client after hydration. This is a genuine // client-only side effect (WebCrypto + randomness), not derived render state. useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect void regenerate(); }, [regenerate]); const config: RealityConfig | null = keys && uuid ? { address, port: Number(port) || 443, uuid, dest, serverNames: [sni], shortIds: [shortId], privateKey: keys.privateKey, publicKey: keys.publicKey, fingerprint, spiderX: '/', flow: 'xtls-rprx-vision', } : null; const serverJson = config ? JSON.stringify(realityServerInbound(config), null, 2) : ''; const clientLink = config ? realityClientLink(config) : ''; return ( void regenerate()} >
{unavailable ? (
Your browser can't generate X25519 keys here. Generate them on the server instead:
) : ( <>
Generated keys & identifiers
)}
); } function KeyRow({ label, value }: { label: string; value: string }) { return (
{label} {value}
); }