Browse Source

Fix firewall IPv6 validation and test expectations

Updated validation to correctly handle plain and bracketed IPv6 addresses, and fixed test to expect string from schema instead of object.
pull/2418/head
Ian Foster 5 months ago
parent
commit
146c21d639
  1. 33
      src/server/utils/types.ts
  2. 7
      src/test/unit/firewall.spec.ts

33
src/server/utils/types.ts

@ -103,7 +103,32 @@ const FirewallIpEntrySchema = z
const hasProto = /\/(tcp|udp)$/i.test(entry); const hasProto = /\/(tcp|udp)$/i.test(entry);
const entryWithoutProto = entry.replace(/\/(tcp|udp)$/i, ''); const entryWithoutProto = entry.replace(/\/(tcp|udp)$/i, '');
// Check if it's IP:port format // If protocol was specified without a port, it's invalid
if (hasProto) {
// Protocol requires port, so check for IP:port format
const portMatch = entryWithoutProto.match(/^(.+):(\d+)$/);
if (!portMatch) {
return false;
}
const [, ipPart, portPart] = portMatch;
const port = parseInt(portPart, 10);
const cleanIp = ipPart.replace(/^\[|\]$/g, '');
return (isIP(cleanIp) || isCidr(cleanIp)) && port >= 1 && port <= 65535;
}
// Check if it's just IP or CIDR first (handles IPv6 addresses)
if (isIP(entryWithoutProto) || isCidr(entryWithoutProto)) {
return true;
}
// Check if it's bracketed IPv6 without port: [::1]
const bracketedMatch = entryWithoutProto.match(/^\[(.+)\]$/);
if (bracketedMatch) {
const innerIp = bracketedMatch[1];
return isIP(innerIp) || isCidr(innerIp);
}
// Check if it's IP:port format (IPv4:port or [IPv6]:port)
const portMatch = entryWithoutProto.match(/^(.+):(\d+)$/); const portMatch = entryWithoutProto.match(/^(.+):(\d+)$/);
if (portMatch) { if (portMatch) {
const [, ipPart, portPart] = portMatch; const [, ipPart, portPart] = portMatch;
@ -116,13 +141,7 @@ const FirewallIpEntrySchema = z
return (isIP(cleanIp) || isCidr(cleanIp)) && port >= 1 && port <= 65535; return (isIP(cleanIp) || isCidr(cleanIp)) && port >= 1 && port <= 65535;
} }
// If protocol was specified without a port, it's invalid
if (hasProto) {
return false; return false;
}
// Check if it's just IP or CIDR
return isIP(entryWithoutProto) || isCidr(entryWithoutProto);
}, },
{ {
message: t('zod.client.firewallIpsInvalid'), message: t('zod.client.firewallIpsInvalid'),

7
src/test/unit/firewall.spec.ts

@ -72,8 +72,11 @@ describe('firewall', () => {
expect( expect(
typesTextExports.FirewallIpEntrySchema.parse('2001:db8::1/32') typesTextExports.FirewallIpEntrySchema.parse('2001:db8::1/32')
).toBe('2001:db8::1/32'); ).toBe('2001:db8::1/32');
expect(typesTextExports.FirewallIpEntrySchema.parse('[::1]')).toEqual({ expect(typesTextExports.FirewallIpEntrySchema.parse('[::1]')).toBe(
ip: '[::1]', '[::1]'
);
expect(testExports.parseFirewallEntry('[::1]')).toEqual({
ip: '::1',
}); });
}); });
}); });

Loading…
Cancel
Save