|
3 | 3 | */
|
4 | 4 |
|
5 | 5 | import javascript
|
| 6 | +private import semmle.javascript.DynamicPropertyAccess |
6 | 7 |
|
7 | 8 | module HTTP {
|
8 | 9 | /**
|
@@ -496,4 +497,118 @@ module HTTP {
|
496 | 497 | class CookieCryptographicKey extends CryptographicKey {
|
497 | 498 | CookieCryptographicKey() { this = any(CookieMiddlewareInstance instance).getASecretKey() }
|
498 | 499 | }
|
| 500 | + |
| 501 | + /** |
| 502 | + * An object that contains one or more potential route handlers. |
| 503 | + */ |
| 504 | + class RouteHandlerCandidateContainer extends DataFlow::Node { |
| 505 | + RouteHandlerCandidateContainer::Range self; |
| 506 | + |
| 507 | + RouteHandlerCandidateContainer() { this = self } |
| 508 | + |
| 509 | + /** |
| 510 | + * Gets the route handler in this container that is accessed at `access`. |
| 511 | + */ |
| 512 | + DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { |
| 513 | + result = self.getRouteHandler(access) |
| 514 | + } |
| 515 | + } |
| 516 | + |
| 517 | + /** |
| 518 | + * Provides classes for working with objects that may contain one or more route handlers. |
| 519 | + */ |
| 520 | + module RouteHandlerCandidateContainer { |
| 521 | + private DataFlow::SourceNode ref(DataFlow::TypeTracker t, RouteHandlerCandidateContainer c) { |
| 522 | + t.start() and result = c |
| 523 | + or |
| 524 | + exists(DataFlow::TypeTracker t2 | result = ref(t2, c).track(t2, t)) |
| 525 | + } |
| 526 | + |
| 527 | + private DataFlow::SourceNode ref(RouteHandlerCandidateContainer c) { |
| 528 | + result = ref(DataFlow::TypeTracker::end(), c) |
| 529 | + } |
| 530 | + |
| 531 | + /** |
| 532 | + * A container for one or more potential route handlers. |
| 533 | + * |
| 534 | + * Extend this class and implement its abstract member predicates to model additional |
| 535 | + * containers. |
| 536 | + */ |
| 537 | + abstract class Range extends DataFlow::SourceNode { |
| 538 | + /** |
| 539 | + * Gets the route handler in this container that is accessed at `access`. |
| 540 | + */ |
| 541 | + abstract DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access); |
| 542 | + } |
| 543 | + |
| 544 | + /** |
| 545 | + * An object that contains one or more potential route handlers. |
| 546 | + */ |
| 547 | + private class ContainerObject extends Range { |
| 548 | + ContainerObject() { |
| 549 | + ( |
| 550 | + this instanceof DataFlow::ObjectLiteralNode |
| 551 | + or |
| 552 | + exists(DataFlow::CallNode create | this = create | |
| 553 | + create = DataFlow::globalVarRef("Object").getAMemberCall("create") and |
| 554 | + create.getArgument(0).asExpr() instanceof NullLiteral |
| 555 | + ) |
| 556 | + ) and |
| 557 | + exists(RouteHandlerCandidate candidate | candidate.flowsTo(getAPropertyWrite().getRhs())) |
| 558 | + } |
| 559 | + |
| 560 | + override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { |
| 561 | + result instanceof RouteHandlerCandidate and |
| 562 | + exists(DataFlow::PropWrite write, DataFlow::PropRead read | |
| 563 | + access = read and |
| 564 | + ref(this).getAPropertyRead() = read and |
| 565 | + result.flowsTo(write.getRhs()) and |
| 566 | + write = this.getAPropertyWrite() |
| 567 | + | |
| 568 | + write.getPropertyName() = read.getPropertyName() |
| 569 | + or |
| 570 | + exists(EnumeratedPropName prop | access = prop.getASourceProp()) |
| 571 | + or |
| 572 | + read = DataFlow::lvalueNode(any(ForOfStmt stmt).getLValue()) |
| 573 | + ) |
| 574 | + } |
| 575 | + } |
| 576 | + |
| 577 | + /** |
| 578 | + * A map that contains one or more route potential handlers. |
| 579 | + */ |
| 580 | + private class ContainerMap extends Range { |
| 581 | + ContainerMap() { |
| 582 | + this = DataFlow::globalVarRef("Map").getAnInstantiation() and |
| 583 | + exists(RouteHandlerCandidate candidate | |
| 584 | + candidate.flowsTo(this.getAMethodCall("set").getArgument(1)) |
| 585 | + ) |
| 586 | + } |
| 587 | + |
| 588 | + override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { |
| 589 | + result instanceof RouteHandlerCandidate and |
| 590 | + exists(DataFlow::MethodCallNode set, DataFlow::Node setKey | |
| 591 | + setKey = set.getArgument(0) and |
| 592 | + this.getAMethodCall("set") = set and |
| 593 | + result.flowsTo(set.getArgument(1)) |
| 594 | + | |
| 595 | + exists(DataFlow::MethodCallNode get, DataFlow::Node getKey | |
| 596 | + get = access and |
| 597 | + getKey = get.getArgument(0) and |
| 598 | + ref(this).getAMethodCall("get") = get |
| 599 | + | |
| 600 | + exists(string name | |
| 601 | + getKey.mayHaveStringValue(name) and |
| 602 | + setKey.mayHaveStringValue(name) |
| 603 | + ) |
| 604 | + ) |
| 605 | + or |
| 606 | + exists(DataFlow::MethodCallNode forEach | |
| 607 | + forEach = ref(this).getAMethodCall("forEach") and |
| 608 | + forEach.getCallback(0).getParameter(0) = access |
| 609 | + ) |
| 610 | + ) |
| 611 | + } |
| 612 | + } |
| 613 | + } |
499 | 614 | }
|
0 commit comments