1+ import { validateAclValue } from '../utils/validators' ;
2+
13/**
24 * DTO for updating ACL rule
35 */
@@ -17,34 +19,78 @@ export interface UpdateAclRuleDto {
1719export function validateUpdateAclRuleDto ( data : any ) : { isValid : boolean ; errors : string [ ] } {
1820 const errors : string [ ] = [ ] ;
1921
22+ // Validate name
2023 if ( data . name !== undefined && ( typeof data . name !== 'string' || ! data . name . trim ( ) ) ) {
2124 errors . push ( 'Name must be a non-empty string' ) ;
25+ } else if ( data . name && data . name . length > 100 ) {
26+ errors . push ( 'Name must not exceed 100 characters' ) ;
2227 }
2328
29+ // Validate type
30+ const validTypes = [ 'whitelist' , 'blacklist' ] ;
2431 if ( data . type !== undefined && typeof data . type !== 'string' ) {
2532 errors . push ( 'Type must be a string' ) ;
33+ } else if ( data . type && ! validTypes . includes ( data . type ) ) {
34+ errors . push ( `Type must be one of: ${ validTypes . join ( ', ' ) } ` ) ;
2635 }
2736
37+ // Validate condition field
38+ const validFields = [ 'ip' , 'geoip' , 'user_agent' , 'url' , 'method' , 'header' ] ;
2839 if ( data . conditionField !== undefined && typeof data . conditionField !== 'string' ) {
2940 errors . push ( 'Condition field must be a string' ) ;
41+ } else if ( data . conditionField && ! validFields . includes ( data . conditionField ) ) {
42+ errors . push ( `Condition field must be one of: ${ validFields . join ( ', ' ) } ` ) ;
3043 }
3144
45+ // Validate condition operator
46+ const validOperators = [ 'equals' , 'contains' , 'regex' ] ;
3247 if ( data . conditionOperator !== undefined && typeof data . conditionOperator !== 'string' ) {
3348 errors . push ( 'Condition operator must be a string' ) ;
49+ } else if ( data . conditionOperator && ! validOperators . includes ( data . conditionOperator ) ) {
50+ errors . push ( `Condition operator must be one of: ${ validOperators . join ( ', ' ) } ` ) ;
3451 }
3552
36- if ( data . conditionValue !== undefined && typeof data . conditionValue !== 'string' ) {
37- errors . push ( 'Condition value must be a string' ) ;
53+ // Validate condition value with field-specific validation
54+ if ( data . conditionValue !== undefined ) {
55+ if ( typeof data . conditionValue !== 'string' ) {
56+ errors . push ( 'Condition value must be a string' ) ;
57+ } else if ( data . conditionValue . trim ( ) . length === 0 ) {
58+ errors . push ( 'Condition value cannot be empty' ) ;
59+ } else if ( data . conditionField && data . conditionOperator ) {
60+ // Perform field-specific validation if we have all required fields
61+ const valueValidation = validateAclValue (
62+ data . conditionField ,
63+ data . conditionOperator ,
64+ data . conditionValue
65+ ) ;
66+
67+ if ( ! valueValidation . valid ) {
68+ errors . push ( valueValidation . error || 'Invalid condition value' ) ;
69+ }
70+ }
3871 }
3972
73+ // Validate action
74+ const validActions = [ 'allow' , 'deny' , 'challenge' ] ;
4075 if ( data . action !== undefined && typeof data . action !== 'string' ) {
4176 errors . push ( 'Action must be a string' ) ;
77+ } else if ( data . action && ! validActions . includes ( data . action ) ) {
78+ errors . push ( `Action must be one of: ${ validActions . join ( ', ' ) } ` ) ;
4279 }
4380
81+ // Validate enabled
4482 if ( data . enabled !== undefined && typeof data . enabled !== 'boolean' ) {
4583 errors . push ( 'Enabled must be a boolean' ) ;
4684 }
4785
86+ // Validate type-action combinations
87+ if ( data . type === 'whitelist' && data . action === 'deny' ) {
88+ errors . push ( 'Whitelist rules should use "allow" action, not "deny"' ) ;
89+ }
90+ if ( data . type === 'blacklist' && data . action === 'allow' ) {
91+ errors . push ( 'Blacklist rules should use "deny" action, not "allow"' ) ;
92+ }
93+
4894 return {
4995 isValid : errors . length === 0 ,
5096 errors
0 commit comments