@@ -201,7 +201,18 @@ private class RecursiveReadDir extends FileSystemAccess, FileNameProducer, DataF
201
201
202
202
override DataFlow:: Node getAPathArgument ( ) { result = getArgument ( 0 ) }
203
203
204
- override DataFlow:: Node getAFileName ( ) { result = getCallback ( [ 1 .. 2 ] ) .getParameter ( 1 ) }
204
+ override DataFlow:: Node getAFileName ( ) { result = trackFileSource ( DataFlow:: TypeTracker:: end ( ) ) }
205
+
206
+ private DataFlow:: SourceNode trackFileSource ( DataFlow:: TypeTracker t ) {
207
+ t .start ( ) and result = getCallback ( [ 1 .. 2 ] ) .getParameter ( 1 )
208
+ or
209
+ t .startInPromise ( ) and not exists ( getCallback ( [ 1 .. 2 ] ) ) and result = this
210
+ or
211
+ // Tracking out of a promise
212
+ exists ( DataFlow:: TypeTracker t2 |
213
+ result = PromiseTypeTracking:: promiseStep ( trackFileSource ( t2 ) , t , t2 )
214
+ )
215
+ }
205
216
}
206
217
207
218
/**
@@ -220,10 +231,24 @@ private module JSONFile {
220
231
221
232
override DataFlow:: Node getAPathArgument ( ) { result = getArgument ( 0 ) }
222
233
223
- override DataFlow:: Node getADataNode ( ) {
224
- this .getCalleeName ( ) = "readFile" and result = getCallback ( [ 1 .. 2 ] ) .getParameter ( 1 )
234
+ override DataFlow:: Node getADataNode ( ) { result = trackRead ( DataFlow:: TypeTracker:: end ( ) ) }
235
+
236
+ private DataFlow:: SourceNode trackRead ( DataFlow:: TypeTracker t ) {
237
+ this .getCalleeName ( ) = "readFile" and
238
+ (
239
+ t .start ( ) and result = getCallback ( [ 1 .. 2 ] ) .getParameter ( 1 )
240
+ or
241
+ t .startInPromise ( ) and not exists ( getCallback ( [ 1 .. 2 ] ) ) and result = this
242
+ )
225
243
or
226
- this .getCalleeName ( ) = "readFileSync" and result = this
244
+ t .start ( ) and
245
+ this .getCalleeName ( ) = "readFileSync" and
246
+ result = this
247
+ or
248
+ // Tracking out of a promise
249
+ exists ( DataFlow:: TypeTracker t2 |
250
+ result = PromiseTypeTracking:: promiseStep ( trackRead ( t2 ) , t , t2 )
251
+ )
227
252
}
228
253
}
229
254
@@ -243,6 +268,122 @@ private module JSONFile {
243
268
}
244
269
}
245
270
271
+ /**
272
+ * A call to the library `load-json-file`.
273
+ */
274
+ private class LoadJsonFile extends FileSystemReadAccess , DataFlow:: CallNode {
275
+ LoadJsonFile ( ) {
276
+ this = DataFlow:: moduleImport ( "load-json-file" ) .getACall ( )
277
+ or
278
+ this = DataFlow:: moduleMember ( "load-json-file" , "sync" ) .getACall ( )
279
+ }
280
+
281
+ override DataFlow:: Node getAPathArgument ( ) { result = getArgument ( 0 ) }
282
+
283
+ override DataFlow:: Node getADataNode ( ) { result = trackRead ( DataFlow:: TypeTracker:: end ( ) ) }
284
+
285
+ private DataFlow:: SourceNode trackRead ( DataFlow:: TypeTracker t ) {
286
+ this .getCalleeName ( ) = "sync" and t .start ( ) and result = this
287
+ or
288
+ not this .getCalleeName ( ) = "sync" and t .startInPromise ( ) and result = this
289
+ or
290
+ // Tracking out of a promise
291
+ exists ( DataFlow:: TypeTracker t2 |
292
+ result = PromiseTypeTracking:: promiseStep ( trackRead ( t2 ) , t , t2 )
293
+ )
294
+ }
295
+ }
296
+
297
+ /**
298
+ * A call to the library `write-json-file`.
299
+ */
300
+ private class WriteJsonFile extends FileSystemWriteAccess , DataFlow:: CallNode {
301
+ WriteJsonFile ( ) {
302
+ this = DataFlow:: moduleImport ( "write-json-file" ) .getACall ( )
303
+ or
304
+ this = DataFlow:: moduleMember ( "write-json-file" , "sync" ) .getACall ( )
305
+ }
306
+
307
+ override DataFlow:: Node getAPathArgument ( ) { result = getArgument ( 0 ) }
308
+
309
+ override DataFlow:: Node getADataNode ( ) { result = getArgument ( 1 ) }
310
+ }
311
+
312
+ /**
313
+ * A call to the library `walkdir`.
314
+ */
315
+ private class WalkDir extends FileNameProducer , FileSystemAccess , DataFlow:: CallNode {
316
+ WalkDir ( ) {
317
+ this = DataFlow:: moduleImport ( "walkdir" ) .getACall ( )
318
+ or
319
+ this = DataFlow:: moduleMember ( "walkdir" , "sync" ) .getACall ( )
320
+ or
321
+ this = DataFlow:: moduleMember ( "walkdir" , "async" ) .getACall ( )
322
+ }
323
+
324
+ override DataFlow:: Node getAPathArgument ( ) { result = getArgument ( 0 ) }
325
+
326
+ override DataFlow:: Node getAFileName ( ) { result = trackFileSource ( DataFlow:: TypeTracker:: end ( ) ) }
327
+
328
+ private DataFlow:: SourceNode trackFileSource ( DataFlow:: TypeTracker t ) {
329
+ not this .getCalleeName ( ) = any ( string s | s = "sync" or s = "async" ) and
330
+ t .start ( ) and
331
+ (
332
+ result = getCallback ( getNumArgument ( ) - 1 ) .getParameter ( 0 )
333
+ or
334
+ result = getAMethodCall ( EventEmitter:: on ( ) ) .getCallback ( 1 ) .getParameter ( 0 )
335
+ )
336
+ or
337
+ t .start ( ) and this .getCalleeName ( ) = "sync" and result = this
338
+ or
339
+ t .startInPromise ( ) and this .getCalleeName ( ) = "async" and result = this
340
+ or
341
+ // Tracking out of a promise
342
+ exists ( DataFlow:: TypeTracker t2 |
343
+ result = PromiseTypeTracking:: promiseStep ( trackFileSource ( t2 ) , t , t2 )
344
+ )
345
+ }
346
+ }
347
+
348
+ /**
349
+ * A call to the library `globule`.
350
+ */
351
+ private class Globule extends FileNameProducer , FileSystemAccess , DataFlow:: CallNode {
352
+ Globule ( ) {
353
+ this = DataFlow:: moduleMember ( "globule" , "find" ) .getACall ( )
354
+ or
355
+ this = DataFlow:: moduleMember ( "globule" , "match" ) .getACall ( )
356
+ or
357
+ this = DataFlow:: moduleMember ( "globule" , "isMatch" ) .getACall ( )
358
+ or
359
+ this = DataFlow:: moduleMember ( "globule" , "mapping" ) .getACall ( )
360
+ or
361
+ this = DataFlow:: moduleMember ( "globule" , "findMapping" ) .getACall ( )
362
+ }
363
+
364
+ override DataFlow:: Node getAPathArgument ( ) {
365
+ ( this .getCalleeName ( ) = "match" or this .getCalleeName ( ) = "isMatch" ) and
366
+ result = getArgument ( 1 )
367
+ or
368
+ this .getCalleeName ( ) = "mapping" and
369
+ (
370
+ result = getAnArgument ( ) and not exists ( result .getALocalSource ( ) .getAPropertyWrite ( "src" ) )
371
+ or
372
+ result = getAnArgument ( ) .getALocalSource ( ) .getAPropertyWrite ( "src" ) .getRhs ( )
373
+ )
374
+ }
375
+
376
+ override DataFlow:: Node getAFileName ( ) {
377
+ result = this and
378
+ (
379
+ this .getCalleeName ( ) = "find" or
380
+ this .getCalleeName ( ) = "match" or
381
+ this .getCalleeName ( ) = "findMapping" or
382
+ this .getCalleeName ( ) = "mapping"
383
+ )
384
+ }
385
+ }
386
+
246
387
/**
247
388
* A file system access made by a NodeJS library.
248
389
* This class models multiple NodeJS libraries that access files.
@@ -257,6 +398,10 @@ private class LibraryAccess extends FileSystemAccess, DataFlow::InvokeNode {
257
398
or
258
399
this = DataFlow:: moduleImport ( "rimraf" ) .getACall ( )
259
400
or
401
+ this = DataFlow:: moduleImport ( "readdirp" ) .getACall ( )
402
+ or
403
+ this = DataFlow:: moduleImport ( "walker" ) .getACall ( )
404
+ or
260
405
this =
261
406
DataFlow:: moduleMember ( "node-dir" ,
262
407
any ( string s |
0 commit comments