@@ -617,41 +617,12 @@ Ext.define("NOC.pm.metricaction.Application", {
617617 //
618618 saveRecord : function ( data ) {
619619 var me = this ,
620- save = { } ,
621620 inputs = Ext . Array . push ( [ ] , {
622621 metric_type : data . metric_type0 ,
623622 } , Ext . Array . map ( me . query ( "[name=metric_type]" ) , function ( input ) {
624623 return { metric_type : input . getValue ( ) }
625624 } ) ) ,
626- set = function ( path , value ) {
627- let keys = path . split ( "." ) ,
628- curStep = save ,
629- keysForSkipping = [ "__proto__" , "constructor" , "prototype" , "__label" ] ,
630- isKeyForSkipping = keysForSkipping . some ( function ( key ) {
631- return path . indexOf ( key ) !== - 1 ;
632- } ) ;
633-
634- if ( isKeyForSkipping ) {
635- return ;
636- }
637- for ( var i = 0 ; i < keys . length - 1 ; i ++ ) {
638- var key = keys [ i ] ;
639-
640- if ( ! curStep [ key ] && ! Object . hasOwn ( curStep , key ) ) {
641- var nextKey = keys [ i + 1 ] ;
642- var useArray = / ^ \+ ? ( 0 | [ 1 - 9 ] \d * ) $ / . test ( nextKey ) ;
643- curStep [ key ] = useArray ? [ ] : { } ;
644- }
645- curStep = curStep [ key ] ;
646- }
647- var finalStep = keys [ keys . length - 1 ] ;
648- curStep [ finalStep ] = value ;
649- } ;
650-
651- Ext . Object . each ( data , set ) ;
652- // set(key, value);
653- // });
654-
625+ save = me . transferFlatToNested ( data ) ;
655626 save [ "compose_inputs" ] = inputs ;
656627
657628 me . mask ( "Saving ..." ) ;
@@ -660,7 +631,7 @@ Ext.define("NOC.pm.metricaction.Application", {
660631 url : me . base_url + ( me . currentRecord ? me . currentRecord . id + "/" : "" ) ,
661632 method : me . currentRecord ? "PUT" : "POST" ,
662633 scope : me ,
663- jsonData : save ,
634+ jsonData : JSON . stringify ( save ) ,
664635 success : function ( response ) {
665636 // Process result
666637 var data = Ext . decode ( response . responseText ) ;
@@ -694,6 +665,114 @@ Ext.define("NOC.pm.metricaction.Application", {
694665 } ) ;
695666 } ,
696667 //
668+ transferFlatToNested : function ( flatData ) {
669+ const result = Object . create ( null ) ,
670+ DANGEROUS_KEYS = new Set ( [
671+ "__proto__" ,
672+ "constructor" ,
673+ "prototype" ,
674+ "__defineGetter__" ,
675+ "__defineSetter__" ,
676+ "__lookupGetter__" ,
677+ "__lookupSetter__" ,
678+ "hasOwnProperty" ,
679+ "isPrototypeOf" ,
680+ "propertyIsEnumerable" ,
681+ "toString" ,
682+ "valueOf" ,
683+ ] ) ;
684+ let isSafeKey = function ( key ) {
685+ return ! DANGEROUS_KEYS . has ( key ) &&
686+ typeof key === "string" &&
687+ key . length > 0 ;
688+ } ,
689+ isSafePath = function ( path ) {
690+ if ( typeof path !== "string" || path . length === 0 ) {
691+ return false ;
692+ }
693+
694+ const segments = path . split ( "." ) ;
695+ return segments . every ( segment => {
696+ if ( DANGEROUS_KEYS . has ( segment ) ) {
697+ return false ;
698+ }
699+
700+ if ( segment . includes ( "__" ) ) { // Prevent double underscore in segment names
701+ return false ;
702+ }
703+
704+ return true ;
705+ } ) ;
706+ } ,
707+ safeSetProperty = function ( obj , key , value ) {
708+ if ( ! isSafeKey ( key ) ) {
709+ console . warn ( `Attempted to set dangerous property: ${ key } ` ) ;
710+ return ;
711+ }
712+
713+ // Используем Object.defineProperty для большей безопасности
714+ Object . defineProperty ( obj , key , {
715+ value : value ,
716+ writable : true ,
717+ enumerable : true ,
718+ configurable : true ,
719+ } ) ;
720+ } ,
721+ setNestedValue = function ( path , value , target ) {
722+ if ( ! isSafePath ( path ) ) { // Dangerous path detected and ignored
723+ return ;
724+ }
725+
726+ const segments = path . split ( "." ) ;
727+ let current = target ;
728+
729+ for ( let i = 0 ; i < segments . length - 1 ; i ++ ) {
730+ const segment = segments [ i ] ;
731+
732+ if ( ! isSafeKey ( segment ) ) { // Dangerous segment in path detected and ignored
733+ return ;
734+ }
735+
736+ if ( ! Object . hasOwn ( current , segment ) ) {
737+ const nextSegment = segments [ i + 1 ] ,
738+ isNumericIndex = / ^ \d + $ / . test ( nextSegment ) ,
739+ newContainer = isNumericIndex ?
740+ [ ] :
741+ Object . create ( null ) ;
742+
743+ safeSetProperty ( current , segment , newContainer ) ;
744+ }
745+
746+ current = current [ segment ] ;
747+ if ( current === null || typeof current !== "object" ) {
748+ console . warn ( `Invalid intermediate object at path: ${ path } ` ) ;
749+ return ;
750+ }
751+ }
752+
753+ const finalSegment = segments [ segments . length - 1 ] ;
754+ if ( isSafeKey ( finalSegment ) ) {
755+ safeSetProperty ( current , finalSegment , value ) ;
756+ }
757+ } ;
758+ if ( ! flatData || typeof flatData !== "object" ) {
759+ return result ;
760+ }
761+
762+ for ( const [ key , value ] of Object . entries ( flatData ) ) {
763+ if ( ! isSafeKey ( key ) || key . endsWith ( "__label" ) ) {
764+ continue ;
765+ }
766+
767+ if ( key . includes ( "." ) ) {
768+ setNestedValue ( key , value , result ) ;
769+ } else {
770+ safeSetProperty ( result , key , value ) ;
771+ }
772+ }
773+ return result ;
774+ } ,
775+ //
697776 addInput : function ( value ) {
698777 var me = this ,
699778 inputsContainer = me . down ( "[itemId=input-container]" ) ,
0 commit comments