@@ -369,22 +369,118 @@ describe('Script Generation', () => {
369369 name : createFieldMapping ( 'person.fullName' ) ,
370370 } ;
371371
372- const result = generateScript ( schema , {
372+ // Test various special characters: quotes, newlines, tabs
373+ const result1 = generateScript ( schema , {
373374 databaseName : 'test\'db`with"quotes' ,
374375 collectionName : 'coll\nwith\ttabs' ,
375376 documentCount : 1 ,
376377 } ) ;
377378
379+ expect ( result1 . success ) . to . equal ( true ) ;
380+ if ( result1 . success ) {
381+ expect ( result1 . script ) . to . contain ( 'use("test\'db`with\\"quotes")' ) ;
382+ expect ( result1 . script ) . to . contain (
383+ 'getCollection("coll\\nwith\\ttabs")'
384+ ) ;
385+ // Should not contain unescaped special characters that could break JS
386+ expect ( result1 . script ) . not . to . contain ( "use('test'db" ) ;
387+ expect ( result1 . script ) . not . to . contain ( "getCollection('coll\nwith" ) ;
388+
389+ // Test that the generated document code is executable
390+ testDocumentCodeExecution ( result1 . script ) ;
391+ }
392+
393+ // Test backticks and dollar signs (template literal characters)
394+ const result2 = generateScript ( schema , {
395+ databaseName : 'test`${}' ,
396+ collectionName : 'collection`${}' ,
397+ documentCount : 1 ,
398+ } ) ;
399+
400+ expect ( result2 . success ) . to . equal ( true ) ;
401+ if ( result2 . success ) {
402+ // Verify the script is syntactically valid
403+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
404+ expect ( ( ) => new Function ( result2 . script ) ) . to . not . throw ( ) ;
405+
406+ // Verify template literal characters are properly escaped in console.log
407+ expect ( result2 . script ) . to . contain ( 'test\\`\\${}' ) ;
408+ expect ( result2 . script ) . to . contain ( 'collection\\`\\${}' ) ;
409+
410+ // Test that the generated document code is executable
411+ testDocumentCodeExecution ( result2 . script ) ;
412+ }
413+ } ) ;
414+
415+ it ( 'should prevent code injection attacks via database and collection names' , ( ) => {
416+ const schema = {
417+ name : {
418+ mongoType : 'String' as const ,
419+ fakerMethod : 'person.firstName' ,
420+ fakerArgs : [ ] ,
421+ } ,
422+ } ;
423+
424+ // Test with potentially dangerous names that could inject malicious code
425+ const result = generateScript ( schema , {
426+ databaseName : 'test`; require("fs").rmSync("/"); //' ,
427+ collectionName : 'my "collection"' ,
428+ documentCount : 1 ,
429+ } ) ;
430+
378431 expect ( result . success ) . to . equal ( true ) ;
379432 if ( result . success ) {
380- // Should use JSON.stringify for safe string insertion
381- expect ( result . script ) . to . contain ( 'use("test\'db`with\\"quotes")' ) ;
433+ // Verify the script is syntactically valid JavaScript
434+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
435+ expect ( ( ) => new Function ( result . script ) ) . to . not . throw ( ) ;
436+
437+ // Verify malicious code is safely contained in string
382438 expect ( result . script ) . to . contain (
383- 'db.getCollection("coll\\nwith\\ttabs")'
439+ 'use(\'test`; require("fs").rmSync("/"); //\')'
440+ ) ;
441+ expect ( result . script ) . to . contain ( 'getCollection(\'my "collection"\')' ) ;
442+
443+ // Verify template literal injection is prevented (backticks are escaped)
444+ expect ( result . script ) . to . contain (
445+ 'test\\`; require("fs").rmSync("/"); //'
446+ ) ;
447+
448+ // Verify malicious code in name is safely contained in code comment
449+ expect ( result . script ) . to . contain (
450+ '// Generated for collection: test`; require("fs").rmSync("/"); //.my "collection"'
384451 ) ;
385- // Should not contain unescaped special characters that could break JS
386- expect ( result . script ) . not . to . contain ( "use('test'db" ) ;
387- expect ( result . script ) . not . to . contain ( "getCollection('coll\nwith" ) ;
452+
453+ // Test that the generated document code is executable
454+ testDocumentCodeExecution ( result . script ) ;
455+ }
456+ } ) ;
457+
458+ it ( 'should sanitize newlines in database and collection names in comments' , ( ) => {
459+ const schema = {
460+ field : {
461+ mongoType : 'String' as const ,
462+ fakerMethod : 'lorem.word' ,
463+ fakerArgs : [ ] ,
464+ } ,
465+ } ;
466+
467+ // Test with names containing actual newlines and carriage returns
468+ const result = generateScript ( schema , {
469+ databaseName : 'test\nwith\nnewlines' ,
470+ collectionName : 'coll\rwith\r\nreturns' ,
471+ documentCount : 1 ,
472+ } ) ;
473+
474+ expect ( result . success ) . to . equal ( true ) ;
475+ if ( result . success ) {
476+ // Verify newlines are replaced with spaces in comments to prevent syntax errors
477+ expect ( result . script ) . to . contain (
478+ '// Generated for collection: test with newlines.coll with returns'
479+ ) ;
480+
481+ // Verify the script is still syntactically valid
482+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
483+ expect ( ( ) => new Function ( result . script ) ) . to . not . throw ( ) ;
388484
389485 // Test that the generated document code is executable
390486 testDocumentCodeExecution ( result . script ) ;
@@ -1028,7 +1124,7 @@ describe('Script Generation', () => {
10281124 color : {
10291125 mongoType : 'String' as const ,
10301126 fakerMethod : 'helpers.arrayElement' ,
1031- fakerArgs : [ { json : "[' red', ' blue', ' green']" } ] ,
1127+ fakerArgs : [ { json : '[" red", " blue", " green"]' } ] ,
10321128 } ,
10331129 } ;
10341130
@@ -1184,12 +1280,6 @@ describe('Script Generation', () => {
11841280 fakerArgs : [ ] ,
11851281 probability : - 0.5 , // Invalid - should default to 1.0
11861282 } ,
1187- field3 : {
1188- mongoType : 'String' as const ,
1189- fakerMethod : 'lorem.word' ,
1190- fakerArgs : [ ] ,
1191- probability : 'invalid' as any , // Invalid - should default to 1.0
1192- } ,
11931283 } ;
11941284
11951285 const result = generateScript ( schema , {
@@ -1203,8 +1293,7 @@ describe('Script Generation', () => {
12031293 // All fields should be treated as probability 1.0 (always present)
12041294 const expectedReturnBlock = `return {
12051295 field1: faker.lorem.word(),
1206- field2: faker.lorem.word(),
1207- field3: faker.lorem.word()
1296+ field2: faker.lorem.word()
12081297 };` ;
12091298 expect ( result . script ) . to . contain ( expectedReturnBlock ) ;
12101299 expect ( result . script ) . not . to . contain ( 'Math.random()' ) ;
0 commit comments