Skip to content

Commit 2b143c8

Browse files
committed
NestJS dependency Injection support useFactory provider
1 parent baf0d3e commit 2b143c8

File tree

6 files changed

+37
-11
lines changed

6 files changed

+37
-11
lines changed

javascript/ql/lib/semmle/javascript/frameworks/Nest.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,12 +519,20 @@ module NestJS {
519519
.(DataFlow::ArrayCreationNode)
520520
.getAnElement()
521521
}
522+
private DataFlow::Node getConcreteClassFromProviderTuple(DataFlow::SourceNode tuple) {
523+
result = tuple.getAPropertyWrite("useClass").getRhs()
524+
or
525+
exists(DataFlow::FunctionNode f |
526+
f = tuple.getAPropertyWrite("useFactory").getRhs().getALocalSource() and
527+
result.getAstNode() = f.getFunction().getAReturnedExpr().getType().(ClassType).getClass()
528+
)
529+
}
522530

523531
private predicate providerPair(DataFlow::Node interface, DataFlow::Node concreteClass) {
524532
exists(DataFlow::SourceNode tuple |
525533
tuple = providerTuple().getALocalSource() and
526534
interface = tuple.getAPropertyWrite("provide").getRhs() and
527-
concreteClass = tuple.getAPropertyWrite("useClass").getRhs()
535+
concreteClass = getConcreteClassFromProviderTuple(tuple)
528536
)
529537
}
530538

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import { Module } from '@nestjs/common';
22
import { Controller } from './validation';
3-
import { Foo } from './foo.interface';
4-
import { FooImpl } from './foo.impl';
3+
import { Foo, Foo2 } from './foo.interface';
4+
import { FooImpl, Foo2Impl } from './foo.impl';
55

66
@Module({
7-
controllers: [Controller],
8-
providers: [{
9-
provide: Foo, useClass: FooImpl
10-
}],
7+
controllers: [Controller],
8+
providers: [
9+
{
10+
provide: Foo,
11+
useClass: FooImpl
12+
},
13+
{
14+
provide: Foo2,
15+
useFactory: () => new Foo2Impl()
16+
}
17+
],
1118
})
1219
export class AppModule { }
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
import { Foo } from "./foo.interface";
1+
import { Foo , Foo2 } from "./foo.interface";
22

33
export class FooImpl extends Foo {
44
fooMethod(x: string) {
55
sink(x); // $ hasValueFlow=x
66
}
77
}
8+
9+
export class Foo2Impl extends Foo2 {
10+
fooMethod(x: string) {
11+
sink(x); // $ hasValueFlow=x
12+
}
13+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
export abstract class Foo {
22
abstract fooMethod(x: string): void;
33
}
4+
5+
export abstract class Foo2 {
6+
abstract fooMethod(x: string): void;
7+
}

javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Get, Query } from '@nestjs/common';
22
import { IsIn } from 'class-validator';
3-
import { Foo } from './foo.interface';
3+
import { Foo, Foo2 } from './foo.interface';
44

55
export class Controller {
66
constructor(
7-
private readonly foo: Foo
7+
private readonly foo: Foo, private readonly foo2: Foo2
88
) { }
99

1010
@Get()
@@ -16,6 +16,7 @@ export class Controller {
1616
@Get()
1717
route2(@Query('x') x: string) {
1818
this.foo.fooMethod(x);
19+
this.foo2.fooMethod(x);
1920
}
2021
}
2122

javascript/ql/test/library-tests/frameworks/Nest/test.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
testFailures
22
routeHandler
33
| global/validation.ts:11:3:14:3 | route1( ... OK\\n } |
4-
| global/validation.ts:17:3:19:3 | route2( ... x);\\n } |
4+
| global/validation.ts:17:3:20:3 | route2( ... x);\\n } |
55
| local/customDecorator.ts:18:3:20:3 | sneaky( ... OK\\n } |
66
| local/customDecorator.ts:23:3:25:3 | safe(@S ... OK\\n } |
77
| local/customPipe.ts:20:5:22:5 | sanitiz ... K\\n } |

0 commit comments

Comments
 (0)