feat: IPv6 support and multi-IP per node (closes #60)
- maskIp handles IPv6 addresses (masks second and last group) - maskIp handles comma-separated IP strings (masks each address) - Add splitIps() helper to parse comma-separated IP field - Add primaryIp() helper used by status checker (first IP wins) - BaseNode renders each IP on its own line when comma-separated - NodeModal placeholder shows comma-separated example - Backend status_checker uses only first IP for connectivity checks - Expand maskIp test suite: IPv6, comma-separated, splitIps, primaryIp
This commit is contained in:
@@ -1,12 +1,47 @@
|
||||
/**
|
||||
* Mask the last two octets of an IPv4 address.
|
||||
* e.g. "192.168.1.115" → "192.168.XX.XX"
|
||||
* Non-IPv4 strings are returned unchanged.
|
||||
* Mask a single IP address:
|
||||
* - IPv4 "192.168.1.115" → "192.168.XX.XX"
|
||||
* - IPv6 "2001:db8::1" → "2001:XX::XX"
|
||||
* - Other strings returned unchanged.
|
||||
*/
|
||||
function maskSingle(ip: string): string {
|
||||
const trimmed = ip.trim()
|
||||
if (/^[\da-fA-F:]+$/.test(trimmed) && trimmed.includes(':')) {
|
||||
const groups = trimmed.split(':')
|
||||
if (groups.length >= 2) {
|
||||
groups[1] = 'XX'
|
||||
groups[groups.length - 1] = 'XX'
|
||||
return groups.join(':')
|
||||
}
|
||||
}
|
||||
const parts = trimmed.split('.')
|
||||
if (parts.length === 4) return `${parts[0]}.${parts[1]}.XX.XX`
|
||||
return trimmed
|
||||
}
|
||||
|
||||
/**
|
||||
* Mask all IPs in a comma-separated string.
|
||||
* e.g. "192.168.1.1, 2001:db8::1" → "192.168.XX.XX, 2001:XX::XX"
|
||||
*/
|
||||
export function maskIp(ip: string): string {
|
||||
const parts = ip.split('.')
|
||||
if (parts.length === 4) return `${parts[0]}.${parts[1]}.XX.XX`
|
||||
return ip
|
||||
if (!ip) return ip
|
||||
return ip.split(',').map(maskSingle).join(', ')
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a comma-separated IP string into an array of trimmed values.
|
||||
* Empty string returns [].
|
||||
*/
|
||||
export function splitIps(ip: string): string[] {
|
||||
if (!ip?.trim()) return []
|
||||
return ip.split(',').map((s) => s.trim()).filter(Boolean)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first IP from a comma-separated string (used for status checks).
|
||||
*/
|
||||
export function primaryIp(ip: string): string {
|
||||
return splitIps(ip)[0] ?? ''
|
||||
}
|
||||
|
||||
export function primaryIp(ip: string): string {
|
||||
|
||||
Reference in New Issue
Block a user