Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2f3cef1

Browse files
committed
JS: More steps in Angular2 model
1 parent c8901b6 commit 2f3cef1

1 file changed

Lines changed: 132 additions & 6 deletions

File tree

javascript/ql/src/semmle/javascript/frameworks/Angular2.qll

Lines changed: 132 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,23 @@ module Angular2 {
241241
}
242242
}
243243

244+
/**
245+
* A call derived from a pipe expression.
246+
*
247+
* For example, the expression `x | f: y` is desugared to `f(x, y)` where
248+
* `f` is a `PipeRefExpr` and the call itself is a `PipeCallExpr`.
249+
*/
250+
class PipeCallExpr extends CallExpr {
251+
PipeCallExpr() {
252+
getCallee() instanceof PipeRefExpr
253+
}
254+
255+
/** Gets the name of the pipe being invoked, such as `f` in `x | f`. */
256+
string getPipeName() {
257+
result = getCallee().(PipeRefExpr).getName()
258+
}
259+
}
260+
244261
/**
245262
* A reference to a variable in a template expression, corresponding
246263
* to a property on the component class.
@@ -263,6 +280,7 @@ module Angular2 {
263280
result = DataFlow::ssaDefinitionNode(SSA::implicitInit(getScope().getVariable(name)))
264281
}
265282

283+
/** Gets a data flow node corresponding to a use of the given template variable within this top-level. */
266284
DataFlow::SourceNode getAVariableUse(string name) {
267285
result = getScope().getVariable(name).getAnAccess().flow()
268286
}
@@ -375,9 +393,9 @@ module Angular2 {
375393
}
376394

377395
/**
378-
* Gets an access to the variable `name` in the template body.
396+
* Gets an access to the given template variable within the template body of this component.
379397
*/
380-
DataFlow::Node getATemplateVarAccess(string name) {
398+
DataFlow::SourceNode getATemplateVarAccess(string name) {
381399
result = getATemplateElement().getAnAttribute().getCodeInAttribute().(TemplateTopLevel).getAVariableUse(name)
382400
}
383401
}
@@ -453,7 +471,7 @@ module Angular2 {
453471

454472
/** Gets the name of the variable holding the element of the current iteration. */
455473
string getIteratorName() {
456-
result = getValue().regexpCapture("^ *let (\\w+) .*", 1)
474+
result = getValue().regexpCapture(" *let +(\\w+).*", 1)
457475
}
458476

459477
/** Gets an HTML element in which the iterator variable is in scope. */
@@ -484,11 +502,119 @@ module Angular2 {
484502
}
485503
}
486504

487-
private class AnyCastStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
488-
AnyCastStep() { this = any(TemplateTopLevel tl).getAVariableUse("$any").getACall() }
505+
private class AnyCastStep extends PreCallGraphStep {
506+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
507+
exists(DataFlow::CallNode call |
508+
call = any(TemplateTopLevel tl).getAVariableUse("$any").getACall() and
509+
pred = call.getArgument(0) and
510+
succ = call
511+
)
512+
}
513+
}
514+
515+
/**
516+
* Gets an invocation of the pipe of the given name.
517+
*
518+
* For example, the call generated from `items | async` would be found by `getAPipeCall("async")`.
519+
*/
520+
DataFlow::CallNode getAPipeCall(string name) {
521+
result.getCalleeNode().asExpr().(PipeRefExpr).getName() = name
522+
}
523+
524+
private class BuiltinPipeStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
525+
string name;
526+
527+
BuiltinPipeStep() {
528+
this = getAPipeCall(name)
529+
}
530+
531+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
532+
succ = this and
533+
exists(int i | pred = getArgument(i) |
534+
i = 0 and name = ["async", "i18nPlural", "json", "keyvalue", "lowercase", "uppercase", "titlecase", "slice"]
535+
or
536+
i = 1 and name = "date" // date format string
537+
)
538+
or
539+
// Arguments to translate are assumed to be included in the result somewhere
540+
name = "translate" and
541+
succ = this and
542+
pred = [getArgument(1), getOptionArgument(1, _)]
543+
}
544+
}
545+
546+
/**
547+
* A `<mat-table>` element.
548+
*/
549+
class MatTableElement extends HTML::Element {
550+
MatTableElement() {
551+
getName() = "mat-table"
552+
}
553+
554+
/** Gets the data flow node corresponding to the `[dataSource]` attribute. */
555+
DataFlow::Node getDataSourceNode() {
556+
result = getAttributeValueAsNode(getAttributeByName("[dataSource]"))
557+
}
558+
559+
/**
560+
* Gets an element of form `<mat-cell *matCellDef="let rowBinding">` in this table.
561+
*/
562+
HTML::Element getATableCell(string rowBinding) {
563+
result.getName() = "mat-cell" and
564+
result.getParent+() = this and
565+
rowBinding = result.getAttributeByName("*matCellDef").getValue().regexpCapture(" *let +(\\w+).*", 1)
566+
}
567+
568+
/** Gets a data flow node that refers to one of the rows from the data source. */
569+
DataFlow::Node getARowRef() {
570+
exists(string rowBinding |
571+
result = getATableCell(rowBinding).getChild*().getAnAttribute().getCodeInAttribute().(TemplateTopLevel).getAVariableUse(rowBinding)
572+
)
573+
}
574+
}
575+
576+
/**
577+
* A taint step from `x -> y` in code of form:
578+
* ```
579+
* <mat-table [dataSource]="x">
580+
* <mat-cell *matCellDef="let y">
581+
* <foo [prop]="y"/>
582+
* </mat-cell>
583+
* </mat-table>
584+
* ```
585+
*/
586+
private class MatTableTaintStep extends TaintTracking::AdditionalTaintStep {
587+
MatTableElement table;
588+
589+
MatTableTaintStep() {
590+
this = table.getDataSourceNode()
591+
}
592+
593+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
594+
pred = this and
595+
succ = table.getARowRef()
596+
}
597+
}
598+
599+
/** Like `MatTableTaintStep` but as a value-preserving load step. */
600+
private class MatTableLoadStep extends PreCallGraphStep {
601+
override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
602+
exists(MatTableElement table |
603+
pred = table.getDataSourceNode() and
604+
succ = table.getARowRef() and
605+
prop = DataFlow::PseudoProperties::arrayElement()
606+
)
607+
}
608+
}
609+
610+
/** A taint step into the data array of a `MatTableDataSource` instance. */
611+
private class MatTableDataSourceStep extends TaintTracking::AdditionalTaintStep, DataFlow::NewNode {
612+
MatTableDataSourceStep() {
613+
this = DataFlow::moduleMember("@angular/material/table", "MatTableDataSource").getAnInstantiation()
614+
}
489615

490616
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
491-
pred = getArgument(0) and
617+
pred = [getArgument(0), getAPropertyWrite("data").getRhs()] and
492618
succ = this
493619
}
494620
}

0 commit comments

Comments
 (0)