mirror of
https://github.com/itdoginfo/podkop.git
synced 2025-12-14 15:36:52 +03:00
feat: implement validateSubnet
This commit is contained in:
@@ -3,3 +3,4 @@ export * from './validateDomain';
|
|||||||
export * from './validateDns';
|
export * from './validateDns';
|
||||||
export * from './validateUrl';
|
export * from './validateUrl';
|
||||||
export * from './validatePath';
|
export * from './validatePath';
|
||||||
|
export * from './validateSubnet';
|
||||||
|
|||||||
41
fe-app-podkop/src/validators/tests/validateSubnet.test.js
Normal file
41
fe-app-podkop/src/validators/tests/validateSubnet.test.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { validateSubnet } from '../validateSubnet';
|
||||||
|
|
||||||
|
export const validSubnets = [
|
||||||
|
['Simple IP', '192.168.1.1'],
|
||||||
|
['With CIDR /24', '192.168.1.1/24'],
|
||||||
|
['CIDR /0', '10.0.0.1/0'],
|
||||||
|
['CIDR /32', '172.16.0.1/32'],
|
||||||
|
['Loopback', '127.0.0.1'],
|
||||||
|
['Broadcast with mask', '255.255.255.255/32'],
|
||||||
|
];
|
||||||
|
|
||||||
|
export const invalidSubnets = [
|
||||||
|
['Empty string', ''],
|
||||||
|
['Bad format letters', 'abc.def.ghi.jkl'],
|
||||||
|
['Octet too large', '300.1.1.1'],
|
||||||
|
['Negative octet', '-1.2.3.4'],
|
||||||
|
['Too many octets', '1.2.3.4.5'],
|
||||||
|
['Not enough octets', '192.168.1'],
|
||||||
|
['Leading zero octet', '01.2.3.4'],
|
||||||
|
['Invalid CIDR (too high)', '192.168.1.1/33'],
|
||||||
|
['Invalid CIDR (negative)', '192.168.1.1/-1'],
|
||||||
|
['CIDR not number', '192.168.1.1/abc'],
|
||||||
|
['Forbidden 0.0.0.0', '0.0.0.0'],
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('validateSubnet', () => {
|
||||||
|
describe.each(validSubnets)('Valid subnet: %s', (_desc, subnet) => {
|
||||||
|
it(`returns {valid:true} for "${subnet}"`, () => {
|
||||||
|
const res = validateSubnet(subnet);
|
||||||
|
expect(res.valid).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.each(invalidSubnets)('Invalid subnet: %s', (_desc, subnet) => {
|
||||||
|
it(`returns {valid:false} for "${subnet}"`, () => {
|
||||||
|
const res = validateSubnet(subnet);
|
||||||
|
expect(res.valid).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
39
fe-app-podkop/src/validators/validateSubnet.ts
Normal file
39
fe-app-podkop/src/validators/validateSubnet.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { ValidationResult } from './types.js';
|
||||||
|
import { validateIPV4 } from './validateIp';
|
||||||
|
|
||||||
|
export function validateSubnet(value: string): ValidationResult {
|
||||||
|
// Must be in form X.X.X.X or X.X.X.X/Y
|
||||||
|
const subnetRegex = /^(\d{1,3}\.){3}\d{1,3}(?:\/\d{1,2})?$/;
|
||||||
|
|
||||||
|
if (!subnetRegex.test(value)) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: 'Invalid format. Use X.X.X.X or X.X.X.X/Y',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ip, cidr] = value.split('/');
|
||||||
|
|
||||||
|
if (ip === '0.0.0.0') {
|
||||||
|
return { valid: false, message: 'IP address 0.0.0.0 is not allowed' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const ipCheck = validateIPV4(ip);
|
||||||
|
if (!ipCheck.valid) {
|
||||||
|
return ipCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate CIDR if present
|
||||||
|
if (cidr) {
|
||||||
|
const cidrNum = parseInt(cidr, 10);
|
||||||
|
|
||||||
|
if (cidrNum < 0 || cidrNum > 32) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: 'CIDR must be between 0 and 32',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { valid: true, message: 'Valid' };
|
||||||
|
}
|
||||||
@@ -508,23 +508,18 @@ function createConfigSection(section, map, network) {
|
|||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.ucisection = s.section;
|
o.ucisection = s.section;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
if (!value || value.length === 0) return true;
|
// Optional
|
||||||
const subnetRegex = /^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/;
|
if (!value || value.length === 0) {
|
||||||
if (!subnetRegex.test(value)) return _('Invalid format. Use format: X.X.X.X or X.X.X.X/Y');
|
return true
|
||||||
const [ip, cidr] = value.split('/');
|
|
||||||
if (ip === "0.0.0.0") {
|
|
||||||
return _('IP address 0.0.0.0 is not allowed');
|
|
||||||
}
|
}
|
||||||
const ipParts = ip.split('.');
|
|
||||||
for (const part of ipParts) {
|
const validation = main.validateSubnet(value);
|
||||||
const num = parseInt(part);
|
|
||||||
if (num < 0 || num > 255) return _('IP address parts must be between 0 and 255');
|
if (validation.valid) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (cidr !== undefined) {
|
|
||||||
const cidrNum = parseInt(cidr);
|
return _(validation.message)
|
||||||
if (cidrNum < 0 || cidrNum > 32) return _('CIDR must be between 0 and 32');
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
o = s.taboption('basic', form.TextValue, 'user_subnets_text', _('User Subnets List'), _('Enter subnets in CIDR notation or single IP addresses, separated by comma, space or newline. You can add comments after //'));
|
o = s.taboption('basic', form.TextValue, 'user_subnets_text', _('User Subnets List'), _('Enter subnets in CIDR notation or single IP addresses, separated by comma, space or newline. You can add comments after //'));
|
||||||
|
|||||||
@@ -80,6 +80,35 @@ function validatePath(value) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/validators/validateSubnet.ts
|
||||||
|
function validateSubnet(value) {
|
||||||
|
const subnetRegex = /^(\d{1,3}\.){3}\d{1,3}(?:\/\d{1,2})?$/;
|
||||||
|
if (!subnetRegex.test(value)) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: "Invalid format. Use X.X.X.X or X.X.X.X/Y"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const [ip, cidr] = value.split("/");
|
||||||
|
if (ip === "0.0.0.0") {
|
||||||
|
return { valid: false, message: "IP address 0.0.0.0 is not allowed" };
|
||||||
|
}
|
||||||
|
const ipCheck = validateIPV4(ip);
|
||||||
|
if (!ipCheck.valid) {
|
||||||
|
return ipCheck;
|
||||||
|
}
|
||||||
|
if (cidr) {
|
||||||
|
const cidrNum = parseInt(cidr, 10);
|
||||||
|
if (cidrNum < 0 || cidrNum > 32) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: "CIDR must be between 0 and 32"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { valid: true, message: "Valid" };
|
||||||
|
}
|
||||||
|
|
||||||
// src/constants.ts
|
// src/constants.ts
|
||||||
var STATUS_COLORS = {
|
var STATUS_COLORS = {
|
||||||
SUCCESS: "#4caf50",
|
SUCCESS: "#4caf50",
|
||||||
@@ -218,5 +247,6 @@ return baseclass.extend({
|
|||||||
validateDomain,
|
validateDomain,
|
||||||
validateIPV4,
|
validateIPV4,
|
||||||
validatePath,
|
validatePath,
|
||||||
|
validateSubnet,
|
||||||
validateUrl
|
validateUrl
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user