Development

This commit is contained in:
Matthew Grotke 2026-06-01 09:45:55 -04:00
parent ebda1cd4a6
commit 2d9b9a4862
4 changed files with 18 additions and 11 deletions

View file

@ -145,10 +145,17 @@ function _checkLine(s){
var anyPartial=false,firstMsg=''; var anyPartial=false,firstMsg='';
function _acc(r){if(r.ok)return r;if(r.partial)anyPartial=true;else if(!firstMsg)firstMsg=r.msg;return null;} function _acc(r){if(r.ok)return r;if(r.partial)anyPartial=true;else if(!firstMsg)firstMsg=r.msg;return null;}
var t; var t;
if(validation&1){t=_acc(function(){var rv=_ipv4(s);if(rv==='ok')return _ok();if(rv==='partial'||rv==='empty')return _par('');if(rv==='badchar')return _err('Invalid character');if(rv==='badrange')return _err('Octet out of range');return _err('Invalid format');}());if(t)return t;} var fmtMask=validation&3;
if(validation&2){t=_acc(function(){var rv=_ipv6(s);if(rv==='ok')return _ok();if(rv==='partial'||rv==='empty')return _par('');if(rv==='badchar')return _err('Invalid character');return _err('Invalid format');}());if(t)return t;} if(fmtMask){
if(validation&4){t=_acc(function(){if(!arg1)return _par('');var prefix=parseInt(arg1,10);if(isNaN(prefix)||prefix<1||prefix>30)return _err('Prefix must be 1-30');var rv=_ipv4(s);if(rv!=='ok')return(rv==='partial'||rv==='empty')?_par(''):(rv==='badchar'?_err('Invalid character'):_err('Invalid format'));var mB=prefix===0?0:((0xFFFFFFFF<<(32-prefix))>>>0);var ipN=s.split('.').reduce(function(a,o){return(a<<8|+o)>>>0;},0);return((ipN&(~mB>>>0))!==0)?_err('Host bits must be zero'):_ok();}());if(t)return t;} var fmtPassed=false;
if(validation&8){t=_acc(function(){var rv=_ipv4(s);if(rv!=='ok')return(rv==='partial'||rv==='empty')?_par(''):(rv==='badchar'?_err('Invalid character'):_err('Invalid format'));if(!arg1||!arg2)return _par('');var prefix=parseInt(arg1,10);if(isNaN(prefix)||prefix<1||prefix>30)return _par('');if(_ipv4(arg2)!=='ok')return _par('');var mB=prefix===0?0:((0xFFFFFFFF<<(32-prefix))>>>0);var snN=arg2.split('.').reduce(function(a,o){return(a<<8|+o)>>>0;},0);if((snN&(~mB>>>0))!==0)return _par('');var iPts=s.split('.').map(Number),sPts=arg2.split('.').map(Number);var ipN=((iPts[0]<<24)|(iPts[1]<<16)|(iPts[2]<<8)|iPts[3])>>>0,sN=((sPts[0]<<24)|(sPts[1]<<16)|(sPts[2]<<8)|sPts[3])>>>0;if((ipN&mB)!==(sN&mB))return _err('IP not in VLAN subnet');var hM=(~mB)>>>0,netN=(sN&mB)>>>0;if(ipN===netN)return _err('Network address not allowed');if(ipN===(netN|hM)>>>0)return _err('Broadcast address not allowed');return _ok();}());if(t)return t;} if(fmtMask&1){t=_acc(function(){var rv=_ipv4(s);if(rv==='ok')return _ok();if(rv==='partial'||rv==='empty')return _par('');if(rv==='badchar')return _err('Invalid character');if(rv==='badrange')return _err('Octet out of range');return _err('Invalid format');}());if(t)fmtPassed=true;}
if(!fmtPassed&&(fmtMask&2)){t=_acc(function(){var rv=_ipv6(s);if(rv==='ok')return _ok();if(rv==='partial'||rv==='empty')return _par('');if(rv==='badchar')return _err('Invalid character');return _err('Invalid format');}());if(t)fmtPassed=true;}
if(!fmtPassed)return anyPartial?_par(''):_err(firstMsg||'Invalid format');
if(!(validation&~3))return _ok();
anyPartial=false;firstMsg='';
}
if(validation&4){t=_acc(function(){if(!arg1)return _par('');var prefix=parseInt(arg1,10);if(isNaN(prefix)||prefix<1||prefix>30)return _err('Prefix must be 1-30');if(!fmtMask){var rv=_ipv4(s);if(rv!=='ok')return(rv==='partial'||rv==='empty')?_par(''):(rv==='badchar'?_err('Invalid character'):_err('Invalid format'));}var mB=prefix===0?0:((0xFFFFFFFF<<(32-prefix))>>>0);var ipN=s.split('.').reduce(function(a,o){return(a<<8|+o)>>>0;},0);return((ipN&(~mB>>>0))!==0)?_err('Host bits must be zero'):_ok();}());if(t)return t;}
if(validation&8){t=_acc(function(){if(!fmtMask){var rv=_ipv4(s);if(rv!=='ok')return(rv==='partial'||rv==='empty')?_par(''):(rv==='badchar'?_err('Invalid character'):_err('Invalid format'));}if(!arg1||!arg2)return _par('');var prefix=parseInt(arg1,10);if(isNaN(prefix)||prefix<1||prefix>30)return _par('');if(_ipv4(arg2)!=='ok')return _par('');var mB=prefix===0?0:((0xFFFFFFFF<<(32-prefix))>>>0);var snN=arg2.split('.').reduce(function(a,o){return(a<<8|+o)>>>0;},0);if((snN&(~mB>>>0))!==0)return _par('');var iPts=s.split('.').map(Number),sPts=arg2.split('.').map(Number);var ipN=((iPts[0]<<24)|(iPts[1]<<16)|(iPts[2]<<8)|iPts[3])>>>0,sN=((sPts[0]<<24)|(sPts[1]<<16)|(sPts[2]<<8)|sPts[3])>>>0;if((ipN&mB)!==(sN&mB))return _err('IP not in VLAN subnet');var hM=(~mB)>>>0,netN=(sN&mB)>>>0;if(ipN===netN)return _err('Network address not allowed');if(ipN===(netN|hM)>>>0)return _err('Broadcast address not allowed');return _ok();}());if(t)return t;}
if(validation&16){t=_acc(function(){if(!s)return _par('');if(/[^0-9a-fA-F:]/.test(s))return _err('Invalid character');if(/::/.test(s))return _err('Invalid format');var g=s.split(':');if(g.length>6)return _err('Too many groups');for(var i=0;i<g.length;i++){if(g[i].length>2)return _err('Each group must be exactly 2 hex characters');}return(g.length===6&&g.every(function(x){return x.length===2;}))?_ok():_par('');}());if(t)return t;} if(validation&16){t=_acc(function(){if(!s)return _par('');if(/[^0-9a-fA-F:]/.test(s))return _err('Invalid character');if(/::/.test(s))return _err('Invalid format');var g=s.split(':');if(g.length>6)return _err('Too many groups');for(var i=0;i<g.length;i++){if(g[i].length>2)return _err('Each group must be exactly 2 hex characters');}return(g.length===6&&g.every(function(x){return x.length===2;}))?_ok():_par('');}());if(t)return t;}
if(validation&32){t=_acc(function(){if(!s)return _par('');if(/[^A-Za-z0-9\-._~:/?#\[\]@!$&'()*+,;=%]/.test(s))return _err('Invalid character');var sl=s.toLowerCase();if('https://'.startsWith(sl)||'http://'.startsWith(sl))return _par('');var sep=sl.indexOf('://');if(sep===-1)return _err('Invalid URL format');var scheme=sl.slice(0,sep);if(scheme!=='http'&&scheme!=='https')return _err('Invalid URL format');var after=s.slice(sep+3);if(!after)return _par('');var he=after.search(/[/:?#]/),host=he===-1?after:after.slice(0,he),rest=he===-1?'':after.slice(he);if(!host)return _par('');if(/\.\./.test(host)||host[0]==='.'||host[host.length-1]==='.')return _err('Invalid URL format');var lb=host.split('.');for(var i=0;i<lb.length;i++){if(!/^[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?$/.test(lb[i]))return _err('Invalid URL format');}if(rest[0]===':'){var pm=rest.slice(1).match(/^\d+/);if(!pm)return _par('');if(parseInt(pm[0])<1||parseInt(pm[0])>65535)return _err('Invalid URL format');}return _ok();}());if(t)return t;} if(validation&32){t=_acc(function(){if(!s)return _par('');if(/[^A-Za-z0-9\-._~:/?#\[\]@!$&'()*+,;=%]/.test(s))return _err('Invalid character');var sl=s.toLowerCase();if('https://'.startsWith(sl)||'http://'.startsWith(sl))return _par('');var sep=sl.indexOf('://');if(sep===-1)return _err('Invalid URL format');var scheme=sl.slice(0,sep);if(scheme!=='http'&&scheme!=='https')return _err('Invalid URL format');var after=s.slice(sep+3);if(!after)return _par('');var he=after.search(/[/:?#]/),host=he===-1?after:after.slice(0,he),rest=he===-1?'':after.slice(he);if(!host)return _par('');if(/\.\./.test(host)||host[0]==='.'||host[host.length-1]==='.')return _err('Invalid URL format');var lb=host.split('.');for(var i=0;i<lb.length;i++){if(!/^[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?$/.test(lb[i]))return _err('Invalid URL format');}if(rest[0]===':'){var pm=rest.slice(1).match(/^\d+/);if(!pm)return _par('');if(parseInt(pm[0])<1||parseInt(pm[0])>65535)return _err('Invalid URL format');}return _ok();}());if(t)return t;}
if(validation&64){t=_acc(function(){if(!s)return _par('');if(/[^0-9]/.test(s))return _err('Digits only');var n=parseInt(s,10);return(n>=1&&n<=65535)?_ok():_err('Must be between 1 and 65535');}());if(t)return t;} if(validation&64){t=_acc(function(){if(!s)return _par('');if(/[^0-9]/.test(s))return _err('Digits only');var n=parseInt(s,10);return(n>=1&&n<=65535)?_ok():_err('Must be between 1 and 65535');}());if(t)return t;}

View file

@ -118,7 +118,7 @@
{ {
"col": "ip", "col": "ip",
"input_type": "text", "input_type": "text",
"validate": "VALIDATION_ADDRESS", "validate": "VALIDATION_IPV4_FORMAT|VALIDATION_ADDRESS",
"attrs": { "attrs": {
"data-vlan-subnets": "%VLAN_SUBNET_INFO_JSON%" "data-vlan-subnets": "%VLAN_SUBNET_INFO_JSON%"
} }

View file

@ -181,7 +181,7 @@
{ {
"label": "IP Address", "label": "IP Address",
"name": "ip", "name": "ip",
"validate": "VALIDATION_ADDRESS", "validate": "VALIDATION_IPV4_FORMAT|VALIDATION_ADDRESS",
"attrs": { "attrs": {
"data-dep-subnet": "[name='subnet']", "data-dep-subnet": "[name='subnet']",
"data-dep-mask": ".subnet-prefix-input" "data-dep-mask": ".subnet-prefix-input"
@ -220,7 +220,7 @@
"label": "DNS Server(s)", "label": "DNS Server(s)",
"name": "dns_servers", "name": "dns_servers",
"override_name": "dns_servers_override", "override_name": "dns_servers_override",
"validate": "VALIDATION_ADDRESS", "validate": "VALIDATION_IPV4_FORMAT|VALIDATION_ADDRESS",
"hint": "DNS server(s) advertised to clients via DHCP." "hint": "DNS server(s) advertised to clients via DHCP."
}, },
{ {
@ -228,7 +228,7 @@
"label": "NTP Server(s)", "label": "NTP Server(s)",
"name": "ntp_servers", "name": "ntp_servers",
"override_name": "ntp_servers_override", "override_name": "ntp_servers_override",
"validate": "VALIDATION_ADDRESS", "validate": "VALIDATION_IPV4_FORMAT",
"hint": "NTP server(s) advertised to clients via DHCP." "hint": "NTP server(s) advertised to clients via DHCP."
}, },
{ {
@ -254,7 +254,7 @@
"label": "DHCP Dynamic Pool Start", "label": "DHCP Dynamic Pool Start",
"name": "dhcp_pool_start", "name": "dhcp_pool_start",
"input_type": "text", "input_type": "text",
"validate": "VALIDATION_ADDRESS", "validate": "VALIDATION_IPV4_FORMAT|VALIDATION_ADDRESS",
"attrs": { "attrs": {
"data-dep-subnet": "[name='subnet']", "data-dep-subnet": "[name='subnet']",
"data-dep-mask": ".subnet-prefix-input" "data-dep-mask": ".subnet-prefix-input"
@ -265,7 +265,7 @@
"label": "DHCP Dynamic Pool End", "label": "DHCP Dynamic Pool End",
"name": "dhcp_pool_end", "name": "dhcp_pool_end",
"input_type": "text", "input_type": "text",
"validate": "VALIDATION_ADDRESS", "validate": "VALIDATION_IPV4_FORMAT|VALIDATION_ADDRESS",
"attrs": { "attrs": {
"data-dep-subnet": "[name='subnet']", "data-dep-subnet": "[name='subnet']",
"data-dep-mask": ".subnet-prefix-input" "data-dep-mask": ".subnet-prefix-input"

View file

@ -83,7 +83,7 @@
{ {
"col": "redirect_to", "col": "redirect_to",
"input_type": "text", "input_type": "text",
"validate": "VALIDATION_ADDRESS", "validate": "VALIDATION_IPV4_FORMAT|VALIDATION_ADDRESS",
"attrs": { "attrs": {
"data-vlan-subnets": "%VLAN_SUBNET_INFO_JSON%" "data-vlan-subnets": "%VLAN_SUBNET_INFO_JSON%"
} }