Skip to content

Commit 9964902

Browse files
committed
JS: introduce HTTP::RouteHandlerCandidateContainer
1 parent 606f827 commit 9964902

File tree

1 file changed

+115
-0
lines changed
  • javascript/ql/src/semmle/javascript/frameworks

1 file changed

+115
-0
lines changed

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

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44

55
import javascript
6+
private import semmle.javascript.DynamicPropertyAccess
67

78
module HTTP {
89
/**
@@ -496,4 +497,118 @@ module HTTP {
496497
class CookieCryptographicKey extends CryptographicKey {
497498
CookieCryptographicKey() { this = any(CookieMiddlewareInstance instance).getASecretKey() }
498499
}
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+
}
499614
}

0 commit comments

Comments
 (0)