Files
Netcatty/domain/host.ts
T
陈大猫 5d29c8d91a fix: support IPv6 addresses in quick connect and fix display formatting (#472)
* fix: support bare IPv6 addresses in quick connect and fix IPv6 display

- Accept un-bracketed IPv6 addresses (e.g. 2607:f130::4f06) in quick
  connect input. The main regex requires brackets for IPv6+port, but now
  falls back to detecting bare IPv6 (2+ colons, hex-only) when the
  primary pattern fails.
- Add formatHostPort() helper that wraps IPv6 addresses in brackets
  when appending a port, preventing ambiguous displays like
  "2607:f130::4f06:22"
- Apply formatHostPort in QuickConnectWizard, TerminalConnectionDialog,
  and SftpSidePanel
- Fix hop label formatting in sshBridge and sftpBridge for IPv6 jump
  hosts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: truncate long hostnames in connection dialog

Add truncate to the host label and protocol subtitle in the connection
dialog so long IPv6 addresses don't overflow into the action buttons.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: constrain connection dialog header so truncate works correctly

Add min-w-0/flex-1 to the left side of the header flex container and
shrink-0 to the avatar so long hostnames truncate instead of pushing
into the Show logs / close buttons.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent action buttons from being squeezed by long hostname

Add shrink-0 and left margin to the right-side button group so truncated
text doesn't crowd into Show logs / close buttons.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: tighten bare IPv6 detection to avoid MAC address false positives

Only accept bare (un-bracketed) hex:colon strings as IPv6 if they
contain '::' (unambiguously IPv6) or have exactly 7 colons (full
8-group notation). This rejects MAC addresses like aa:bb:cc:dd:ee:ff
(5 colons) which would otherwise trigger quick-connect mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: avoid double-wrapping already-bracketed IPv6 hop labels

Add !startsWith('[') guard so hostnames that are already bracketed
(e.g. from URL-imported hosts) don't produce malformed labels like
[[2607:f130::4f06]]:22.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 23:13:58 +08:00

77 lines
2.4 KiB
TypeScript

import { Host } from './models';
export const LINUX_DISTRO_OPTIONS = [
'linux',
'ubuntu',
'debian',
'centos',
'rocky',
'fedora',
'arch',
'alpine',
'amazon',
'opensuse',
'redhat',
'almalinux',
'oracle',
'kali',
] as const;
export const normalizeDistroId = (value?: string) => {
const v = (value || '').toLowerCase().trim();
if (!v) return '';
if (v.includes('ubuntu')) return 'ubuntu';
if (v.includes('debian')) return 'debian';
if (v.includes('centos')) return 'centos';
if (v.includes('rocky')) return 'rocky';
if (v.includes('fedora')) return 'fedora';
if (v.includes('arch') || v.includes('manjaro')) return 'arch';
if (v.includes('alpine')) return 'alpine';
if (v.includes('amzn') || v.includes('amazon') || v.includes('aws')) return 'amazon';
if (v.includes('opensuse') || v.includes('suse') || v.includes('sles')) return 'opensuse';
if (v.includes('red hat') || v.includes('redhat') || v.includes('rhel')) return 'redhat';
if (v.includes('almalinux')) return 'almalinux';
if (v.includes('oracle')) return 'oracle';
if (v.includes('kali')) return 'kali';
if (v === 'linux' || v.includes('linux')) return 'linux';
return '';
};
export const getEffectiveHostDistro = (
host?: Pick<Host, 'distro' | 'manualDistro' | 'distroMode'> | null,
) => {
if (!host) return '';
const detected = normalizeDistroId(host.distro);
const manual = normalizeDistroId(host.manualDistro);
if (host.distroMode === 'manual') return manual || detected;
if (host.distroMode === 'auto') return detected;
return detected;
};
/** Format hostname:port for display, wrapping IPv6 addresses in brackets. */
export const formatHostPort = (hostname: string, port?: number | null): string => {
if (port == null) return hostname;
const isIPv6 = hostname.includes(':') && !hostname.startsWith('[');
const display = isIPv6 ? `[${hostname}]` : hostname;
return `${display}:${port}`;
};
export const sanitizeHost = (host: Host): Host => {
const cleanHostname = (host.hostname || '').split(/\s+/)[0];
const cleanDistro = normalizeDistroId(host.distro);
const cleanManualDistro = normalizeDistroId(host.manualDistro);
const cleanDistroMode =
host.distroMode === 'manual'
? 'manual'
: host.distroMode === 'auto'
? 'auto'
: undefined;
return {
...host,
hostname: cleanHostname,
distro: cleanDistro,
distroMode: cleanDistroMode,
manualDistro: cleanManualDistro || undefined,
};
};