| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- import type { HostEndpoint } from '@/lib/hosts/host-link';
- import { formatInboundLabel } from '@/lib/inbounds/label';
- import { preferPublicHost, resolveShareHost } from '@/lib/xray/inbound-link';
- import type { ClientRecord, InboundOption } from '@/hooks/useClients';
- export function isTuicClient(client: ClientRecord | null | undefined): boolean {
- if (!client) return false;
- return !!(client.uuid && client.password);
- }
- export function findTuicInbound(
- client: ClientRecord | null | undefined,
- inboundsById: Record<number, InboundOption>,
- ): InboundOption | undefined {
- return (client?.inboundIds || [])
- .map((id) => inboundsById[id])
- .find((ib) => ib?.protocol === 'tuic');
- }
- export function buildTuicClientConfig(
- client: ClientRecord,
- inbound: InboundOption | undefined,
- host = window.location.hostname,
- publicHost = '',
- hostEndpoint?: HostEndpoint,
- ): string {
- const endpointHost =
- hostEndpoint?.dest ||
- resolveShareHost(inbound ?? {}, inbound?.nodeAddress ?? '', preferPublicHost(host, publicHost));
- const inboundName = inbound ? formatInboundLabel(inbound.tag, inbound.remark) : '';
- const remark =
- [inboundName, hostEndpoint?.remark, client.email].filter(Boolean).join(' - ') || 'tuic-client';
- // A Host's SNI/ALPN/insecure override the inbound's, as the backend buildTuicProxy does.
- const tuicServer = inbound?.tuicServer;
- const alpn = hostEndpoint?.alpn?.length
- ? hostEndpoint.alpn
- : Array.isArray(tuicServer?.alpn) && tuicServer.alpn.length > 0
- ? tuicServer.alpn
- : ['h3', 'spdy/3.1'];
- const sni = hostEndpoint?.sni || tuicServer?.sni || endpointHost;
- const cc = tuicServer?.congestion_control || 'bbr';
- const udpRelay = tuicServer?.udp_relay_mode || 'native';
- const reduceRtt = tuicServer?.zero_rtt_handshake ?? true;
- const yamlQuote = (v: string) => JSON.stringify(v ?? '');
- const lines = [
- `# TUIC v5 Client Configuration (Clash / Mihomo / Clash Verge)`,
- `# ${remark}`,
- `proxies:`,
- ` - name: ${yamlQuote(remark)}`,
- ` type: tuic`,
- ` server: ${endpointHost}`,
- ` port: ${hostEndpoint?.port || inbound?.port || 8443}`,
- ` uuid: ${client.uuid || ''}`,
- ` password: ${yamlQuote(client.password || '')}`,
- ` alpn:`,
- ...alpn.map((a: string) => ` - ${a}`),
- ` sni: ${/["'\\#\s]/.test(sni) ? yamlQuote(sni) : sni}`,
- ` congestion-controller: ${cc}`,
- ` udp-relay-mode: ${udpRelay}`,
- ` reduce-rtt: ${reduceRtt}`,
- ];
- if (hostEndpoint?.allowInsecure) lines.push(' skip-cert-verify: true');
- return lines.join('\n');
- }
|