mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #2016 from asger-semmle/jquery
Add type tracking and type info to jQuery model
This commit is contained in:
@@ -47,7 +47,9 @@ private class ExtendCallWithFlag extends ExtendCall {
|
||||
name = "node.extend"
|
||||
)
|
||||
or
|
||||
this = jquery().getAPropertyRead("extend").getACall()
|
||||
// Match $.extend using the source of `$` only, as ExtendCall should not
|
||||
// depend on type tracking.
|
||||
this = JQuery::dollarSource().getAMemberCall("extend")
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -336,6 +336,7 @@ class JSDocNamedTypeExpr extends @jsdoc_named_type_expr, JSDocTypeExpr {
|
||||
/**
|
||||
* Gets the qualified name of this name by resolving its prefix, if any.
|
||||
*/
|
||||
cached
|
||||
private string resolvedName() {
|
||||
exists(string prefix, string suffix, JSDoc::Environment env |
|
||||
hasNamePartsAndEnv(prefix, suffix, env) and
|
||||
|
||||
@@ -631,11 +631,11 @@ private class RouteParamSource extends RemoteFlowSource {
|
||||
* AngularJS expose a jQuery-like interface through `angular.html(..)`.
|
||||
* The interface may be backed by an actual jQuery implementation.
|
||||
*/
|
||||
private class JQLiteObject extends JQueryObject {
|
||||
private class JQLiteObject extends JQuery::ObjectSource::Range {
|
||||
JQLiteObject() {
|
||||
this = angular().getAMemberCall("element").asExpr()
|
||||
this = angular().getAMemberCall("element")
|
||||
or
|
||||
exists(SimpleParameter param |
|
||||
exists(Parameter param | this = DataFlow::parameterNode(param) |
|
||||
// element parameters to user-functions invoked by AngularJS
|
||||
param = any(LinkFunction link).getElementParameter()
|
||||
or
|
||||
@@ -652,15 +652,13 @@ private class JQLiteObject extends JQueryObject {
|
||||
param = f.getAstNode().(Function).getParameter(i)
|
||||
)
|
||||
)
|
||||
|
|
||||
this = param.getAnInitialUse()
|
||||
)
|
||||
or
|
||||
exists(ServiceReference element |
|
||||
element.getName() = "$rootElement" or
|
||||
element.getName() = "$document"
|
||||
|
|
||||
this = element.getAnAccess()
|
||||
this = element.getAReference()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,13 @@ abstract class ServiceReference extends TServiceReference {
|
||||
*/
|
||||
abstract string getName();
|
||||
|
||||
/**
|
||||
* Gets a data flow node that may refer to this service.
|
||||
*/
|
||||
DataFlow::SourceNode getAReference() {
|
||||
result = DataFlow::parameterNode(any(ServiceRequest request).getDependencyParameter(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an access to the referenced service.
|
||||
*/
|
||||
|
||||
@@ -7,29 +7,36 @@ import javascript
|
||||
/**
|
||||
* Gets a data flow node that may refer to the jQuery `$` function.
|
||||
*/
|
||||
DataFlow::SourceNode jquery() {
|
||||
// either a reference to a global variable `$` or `jQuery`
|
||||
result = DataFlow::globalVarRef(any(string jq | jq = "$" or jq = "jQuery"))
|
||||
or
|
||||
// or imported from a module named `jquery`
|
||||
result = DataFlow::moduleImport("jquery")
|
||||
}
|
||||
predicate jquery = JQuery::dollar/0;
|
||||
|
||||
/**
|
||||
* DEPRECATED. In most cases, `JQuery::Object` should be used instead.
|
||||
* Alternatively, if used as a base class, and the intent is to extend the model of
|
||||
* jQuery objects with more nodes, extend `JQuery::ObjectSource::Range` instead.
|
||||
*
|
||||
* An expression that may refer to a jQuery object.
|
||||
*
|
||||
* Note that this class is an over-approximation: `nd instanceof JQueryObject`
|
||||
* may hold for nodes `nd` that cannot, in fact, refer to a jQuery object.
|
||||
*/
|
||||
abstract class JQueryObject extends Expr { }
|
||||
deprecated class JQueryObject = JQueryObjectInternal;
|
||||
|
||||
/**
|
||||
* An internal version of `JQueryObject` that may be used to retain
|
||||
* backwards compatibility without triggering a deprecation warning.
|
||||
*/
|
||||
abstract private class JQueryObjectInternal extends Expr { }
|
||||
|
||||
/**
|
||||
* A jQuery object created from a jQuery method.
|
||||
*
|
||||
* This class is defined using the legacy API in order to retain the
|
||||
* behavior of `JQueryObject`.
|
||||
*/
|
||||
private class OrdinaryJQueryObject extends JQueryObject {
|
||||
private class OrdinaryJQueryObject extends JQueryObjectInternal {
|
||||
OrdinaryJQueryObject() {
|
||||
exists(JQueryMethodCall jq |
|
||||
this.flow().getALocalSource().asExpr() = jq and
|
||||
exists(JQuery::MethodCall jq |
|
||||
this.flow().getALocalSource() = jq and
|
||||
// `jQuery.val()` does _not_ return a jQuery object
|
||||
jq.getMethodName() != "val"
|
||||
)
|
||||
@@ -37,20 +44,14 @@ private class OrdinaryJQueryObject extends JQueryObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `JQuery::MethodCall` instead.
|
||||
*
|
||||
* A (possibly chained) call to a jQuery method.
|
||||
*/
|
||||
class JQueryMethodCall extends CallExpr {
|
||||
deprecated class JQueryMethodCall extends CallExpr {
|
||||
string name;
|
||||
|
||||
JQueryMethodCall() {
|
||||
this = jquery().getACall().asExpr() and name = "$"
|
||||
or
|
||||
// initial call
|
||||
this = jquery().getAMemberCall(name).asExpr()
|
||||
or
|
||||
// chained call
|
||||
this.(MethodCallExpr).calls(any(JQueryObject jq), name)
|
||||
}
|
||||
JQueryMethodCall() { name = this.flow().(JQuery::MethodCall).getMethodName() }
|
||||
|
||||
/**
|
||||
* Gets the name of the jQuery method this call invokes.
|
||||
@@ -65,13 +66,7 @@ class JQueryMethodCall extends CallExpr {
|
||||
* `interpretsArgumentAsSelector` below overlap.
|
||||
*/
|
||||
predicate interpretsArgumentAsHtml(Expr e) {
|
||||
// some methods interpret all their arguments as (potential) HTML
|
||||
JQuery::isMethodArgumentInterpretedAsHtml(name) and
|
||||
e = getAnArgument()
|
||||
or
|
||||
// for `$, it's only the first one
|
||||
name = "$" and
|
||||
e = getArgument(0)
|
||||
this.flow().(JQuery::MethodCall).interpretsArgumentAsHtml(e.flow())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,13 +77,7 @@ class JQueryMethodCall extends CallExpr {
|
||||
* `interpretsArgumentAsHtml` above overlap.
|
||||
*/
|
||||
predicate interpretsArgumentAsSelector(Expr e) {
|
||||
// some methods interpret all their arguments as (potential) selectors
|
||||
JQuery::isMethodArgumentInterpretedAsSelector(name) and
|
||||
e = getAnArgument()
|
||||
or
|
||||
// for `$, it's only the first one
|
||||
name = "$" and
|
||||
e = getArgument(0)
|
||||
this.flow().(JQuery::MethodCall).interpretsArgumentAsSelector(e.flow())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +85,7 @@ class JQueryMethodCall extends CallExpr {
|
||||
* A call to `jQuery.parseXML`.
|
||||
*/
|
||||
private class JQueryParseXmlCall extends XML::ParserInvocation {
|
||||
JQueryParseXmlCall() { this.(JQueryMethodCall).getMethodName() = "parseXML" }
|
||||
JQueryParseXmlCall() { flow().(JQuery::MethodCall).getMethodName() = "parseXML" }
|
||||
|
||||
override Expr getSourceArgument() { result = getArgument(0) }
|
||||
|
||||
@@ -136,7 +125,7 @@ private class JQueryDomElementDefinition extends DOM::ElementDefinition, @callex
|
||||
/**
|
||||
* An attribute defined using jQuery APIs.
|
||||
*/
|
||||
abstract private class JQueryAttributeDefinition extends DOM::AttributeDefinition { }
|
||||
abstract private class JQueryAttributeDefinition extends DOM::AttributeDefinition {}
|
||||
|
||||
/**
|
||||
* An attribute definition supplied when constructing a DOM element using `$(...)`.
|
||||
@@ -160,18 +149,20 @@ private class JQueryAttributeDefinitionInElement extends JQueryAttributeDefiniti
|
||||
override DOM::ElementDefinition getElement() { result = elt }
|
||||
}
|
||||
|
||||
/** Gets the `attr` or `prop` string. */
|
||||
private string attrOrProp() {
|
||||
result = "attr" or result = "prop"
|
||||
}
|
||||
|
||||
/**
|
||||
* An attribute definition using `elt.attr(name, value)` or `elt.prop(name, value)`
|
||||
* where `elt` is a wrapped set.
|
||||
*/
|
||||
private class JQueryAttr2Call extends JQueryAttributeDefinition, @callexpr {
|
||||
JQueryDomElementDefinition elt;
|
||||
|
||||
JQueryAttr2Call() {
|
||||
exists(MethodCallExpr mce | this = mce |
|
||||
mce.getReceiver().(DOM::Element).getDefinition() = elt and
|
||||
(mce.getMethodName() = "attr" or mce.getMethodName() = "prop") and
|
||||
mce.getNumArgument() = 2
|
||||
exists(DataFlow::MethodCallNode call | this = call.asExpr() |
|
||||
call = JQuery::objectRef().getAMethodCall(attrOrProp()) and
|
||||
call.getNumArgument() = 2
|
||||
)
|
||||
}
|
||||
|
||||
@@ -181,34 +172,37 @@ private class JQueryAttr2Call extends JQueryAttributeDefinition, @callexpr {
|
||||
result = DataFlow::valueNode(this.(CallExpr).getArgument(1))
|
||||
}
|
||||
|
||||
override DOM::ElementDefinition getElement() { result = elt }
|
||||
override DOM::ElementDefinition getElement() {
|
||||
exists(DataFlow::MethodCallNode call | this = call.asExpr() |
|
||||
result = call.getReceiver().getALocalSource().asExpr().(DOM::Element).getDefinition()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `mce` is a call to `elt.attr(attributes)` or `elt.prop(attributes)`.
|
||||
*/
|
||||
private predicate bulkAttributeInit(
|
||||
MethodCallExpr mce, JQueryDomElementDefinition elt, DataFlow::SourceNode attributes
|
||||
) {
|
||||
mce.getReceiver().(DOM::Element).getDefinition() = elt and
|
||||
(mce.getMethodName() = "attr" or mce.getMethodName() = "prop") and
|
||||
private predicate bulkAttributeInit(DataFlow::MethodCallNode mce, DataFlow::SourceNode attributes) {
|
||||
mce = JQuery::objectRef().getAMethodCall(attrOrProp()) and
|
||||
mce.getNumArgument() = 1 and
|
||||
attributes.flowsToExpr(mce.getArgument(0))
|
||||
attributes.flowsTo(mce.getArgument(0))
|
||||
}
|
||||
|
||||
/**
|
||||
* An attribute definition using `elt.attr(attributes)` or `elt.prop(attributes)`
|
||||
* where `elt` is a wrapped set and `attributes` is an object of attribute-value pairs
|
||||
* to set.
|
||||
* A property stored on an object flowing to `elt.attr(attributes)` or `elt.prop(attributes)`
|
||||
* where `elt` is a wrapped set.
|
||||
*
|
||||
* To avoid spurious combinations of `getName()` and `getValueNode()`,
|
||||
* this class is tied to an individual property write, as opposed to the call itself.
|
||||
*/
|
||||
private class JQueryAttrCall extends JQueryAttributeDefinition, @callexpr {
|
||||
JQueryDomElementDefinition elt;
|
||||
private class JQueryBulkAttributeProp extends JQueryAttributeDefinition {
|
||||
DataFlow::PropWrite pwn;
|
||||
|
||||
JQueryAttrCall() {
|
||||
JQueryBulkAttributeProp() {
|
||||
exists(DataFlow::SourceNode attributes |
|
||||
bulkAttributeInit(this, elt, attributes) and
|
||||
attributes.flowsTo(pwn.getBase())
|
||||
bulkAttributeInit(_, attributes) and
|
||||
pwn = attributes.getAPropertyWrite() and
|
||||
this = pwn.getAstNode()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -216,7 +210,12 @@ private class JQueryAttrCall extends JQueryAttributeDefinition, @callexpr {
|
||||
|
||||
override DataFlow::Node getValueNode() { result = pwn.getRhs() }
|
||||
|
||||
override DOM::ElementDefinition getElement() { result = elt }
|
||||
override DOM::ElementDefinition getElement() {
|
||||
exists(DataFlow::MethodCallNode mce |
|
||||
bulkAttributeInit(mce, pwn.getBase().getALocalSource()) and
|
||||
result = mce.getReceiver().asExpr().(DOM::Element).getDefinition()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,14 +223,12 @@ private class JQueryAttrCall extends JQueryAttributeDefinition, @callexpr {
|
||||
* where `elt` is a wrapped set or a plain DOM element.
|
||||
*/
|
||||
private class JQueryAttr3Call extends JQueryAttributeDefinition, @callexpr {
|
||||
DOM::ElementDefinition elt;
|
||||
MethodCallExpr mce;
|
||||
|
||||
JQueryAttr3Call() {
|
||||
exists(MethodCallExpr mce | this = mce |
|
||||
mce = jquery().getAMemberCall(any(string m | m = "attr" or m = "prop")).asExpr() and
|
||||
mce.getArgument(0).(DOM::Element).getDefinition() = elt and
|
||||
mce.getNumArgument() = 3
|
||||
)
|
||||
this = mce and
|
||||
mce = jquery().getAMemberCall(attrOrProp()).asExpr() and
|
||||
mce.getNumArgument() = 3
|
||||
}
|
||||
|
||||
override string getName() { result = this.(CallExpr).getArgument(1).getStringValue() }
|
||||
@@ -240,7 +237,9 @@ private class JQueryAttr3Call extends JQueryAttributeDefinition, @callexpr {
|
||||
result = DataFlow::valueNode(this.(CallExpr).getArgument(2))
|
||||
}
|
||||
|
||||
override DOM::ElementDefinition getElement() { result = elt }
|
||||
override DOM::ElementDefinition getElement() {
|
||||
result = mce.getArgument(0).(DOM::Element).getDefinition()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,13 +248,12 @@ private class JQueryAttr3Call extends JQueryAttributeDefinition, @callexpr {
|
||||
* For example, the call `$("<script/>").attr("src", mySource)` returns
|
||||
* the DOM element constructed by `$("<script/>")`.
|
||||
*/
|
||||
private class JQueryChainedElement extends DOM::Element {
|
||||
private class JQueryChainedElement extends DOM::Element, InvokeExpr {
|
||||
DOM::Element inner;
|
||||
|
||||
JQueryChainedElement() {
|
||||
exists(JQueryMethodCall jqmc | this = jqmc |
|
||||
jqmc.(MethodCallExpr).getReceiver() = inner and
|
||||
this instanceof JQueryObject and
|
||||
exists(JQuery::MethodCall call | this = call.asExpr() |
|
||||
call.getReceiver().asExpr() = inner and
|
||||
defn = inner.getDefinition()
|
||||
)
|
||||
}
|
||||
@@ -318,4 +316,159 @@ module JQuery {
|
||||
name = "wrapAll" or
|
||||
name = "wrapInner"
|
||||
}
|
||||
|
||||
module DollarSource {
|
||||
/** A data flow node that may refer to the jQuery `$` function. */
|
||||
abstract class Range extends DataFlow::Node { }
|
||||
|
||||
private class DefaultRange extends Range {
|
||||
DefaultRange() {
|
||||
// either a reference to a global variable `$` or `jQuery`
|
||||
this = DataFlow::globalVarRef(any(string jq | jq = "$" or jq = "jQuery"))
|
||||
or
|
||||
// or imported from a module named `jquery`
|
||||
this = DataFlow::moduleImport("jquery")
|
||||
or
|
||||
this.hasUnderlyingType("JQueryStatic")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node that may refer to the jQuery `$` function.
|
||||
*
|
||||
* This predicate can be extended by subclassing `JQuery::DollarSource::Range`.
|
||||
*/
|
||||
DataFlow::SourceNode dollarSource() { result instanceof DollarSource::Range }
|
||||
|
||||
/** Gets a data flow node referring to the jQuery `$` function. */
|
||||
private DataFlow::SourceNode dollar(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = dollarSource()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = dollar(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node referring to the jQuery `$` function.
|
||||
*
|
||||
* This predicate can be extended by subclassing `JQuery::DollarSource::Range`.
|
||||
*/
|
||||
DataFlow::SourceNode dollar() { result = dollar(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/** Gets an invocation of the jQuery `$` function. */
|
||||
DataFlow::CallNode dollarCall() { result = dollar().getACall() }
|
||||
|
||||
/** A call to the jQuery `$` function. */
|
||||
class DollarCall extends DataFlow::CallNode {
|
||||
DollarCall() { this = dollarCall() }
|
||||
}
|
||||
|
||||
module ObjectSource {
|
||||
/**
|
||||
* A data flow node that should be considered a source of jQuery objects.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node { }
|
||||
|
||||
private class DefaultRange extends Range {
|
||||
DefaultRange() {
|
||||
this.asExpr() instanceof JQueryObjectInternal
|
||||
or
|
||||
hasUnderlyingType("JQuery")
|
||||
or
|
||||
hasUnderlyingType("jQuery")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A source of jQuery objects from the AST-based `JQueryObject` class. */
|
||||
private DataFlow::Node legacyObjectSource() {
|
||||
result = any(JQueryObjectInternal e).flow()
|
||||
}
|
||||
|
||||
/** Gets a source of jQuery objects. */
|
||||
private DataFlow::SourceNode objectSource(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof ObjectSource::Range
|
||||
or
|
||||
exists(DataFlow::TypeTracker init |
|
||||
init.start() and
|
||||
t = init.smallstep(legacyObjectSource(), result)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a data flow node referring to a jQuery object. */
|
||||
private DataFlow::SourceNode objectRef(DataFlow::TypeTracker t) {
|
||||
result = objectSource(t)
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = objectRef(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node referring to a jQuery object.
|
||||
*
|
||||
* This predicate can be extended by subclassing `JQuery::ObjectSource::Range`.
|
||||
*/
|
||||
DataFlow::SourceNode objectRef() { result = objectRef(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/** A data flow node that refers to a jQuery object. */
|
||||
class Object extends DataFlow::SourceNode {
|
||||
Object() { this = objectRef() }
|
||||
}
|
||||
|
||||
/** A call to a method on a jQuery object or the jQuery dollar function. */
|
||||
class MethodCall extends DataFlow::CallNode {
|
||||
string name;
|
||||
|
||||
MethodCall() {
|
||||
this = dollarCall() and name = "$"
|
||||
or
|
||||
this = dollar().getAMemberCall(name)
|
||||
or
|
||||
this = objectRef().getAMethodCall(name)
|
||||
or
|
||||
// Handle contributed JQuery objects that aren't source nodes (usually parameter uses)
|
||||
getReceiver() = legacyObjectSource() and
|
||||
this.(DataFlow::MethodCallNode).getMethodName() = name
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the jQuery method this call invokes.
|
||||
*/
|
||||
string getMethodName() { result = name }
|
||||
|
||||
/**
|
||||
* Holds if `node` is an argument that this method may interpret as HTML.
|
||||
*
|
||||
* Note that some jQuery methods decide whether to interpret an argument
|
||||
* as HTML based on its syntactic shape, so this predicate and
|
||||
* `interpretsArgumentAsSelector` below overlap.
|
||||
*/
|
||||
predicate interpretsArgumentAsHtml(DataFlow::Node node) {
|
||||
// some methods interpret all their arguments as (potential) HTML
|
||||
JQuery::isMethodArgumentInterpretedAsHtml(name) and
|
||||
node = getAnArgument()
|
||||
or
|
||||
// for `$, it's only the first one
|
||||
name = "$" and
|
||||
node = getArgument(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is an argument that this method may interpret as a selector.
|
||||
*
|
||||
* Note that some jQuery methods decide whether to interpret an argument
|
||||
* as a selector based on its syntactic shape, so this predicate and
|
||||
* `interpretsArgumentAsHtml` above overlap.
|
||||
*/
|
||||
predicate interpretsArgumentAsSelector(DataFlow::Node node) {
|
||||
// some methods interpret all their arguments as (potential) selectors
|
||||
JQuery::isMethodArgumentInterpretedAsSelector(name) and
|
||||
node = getAnArgument()
|
||||
or
|
||||
// for `$, it's only the first one
|
||||
name = "$" and
|
||||
node = getArgument(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,14 +59,14 @@ module DomBasedXss {
|
||||
class LibrarySink extends Sink, DataFlow::ValueNode {
|
||||
LibrarySink() {
|
||||
// call to a jQuery method that interprets its argument as HTML
|
||||
exists(JQueryMethodCall call | call.interpretsArgumentAsHtml(astNode) |
|
||||
exists(JQuery::MethodCall call | call.interpretsArgumentAsHtml(this) |
|
||||
// either the argument is always interpreted as HTML
|
||||
not call.interpretsArgumentAsSelector(astNode)
|
||||
not call.interpretsArgumentAsSelector(this)
|
||||
or
|
||||
// or it doesn't start with something other than `<`, and so at least
|
||||
// _may_ be interpreted as HTML
|
||||
not exists(DataFlow::Node prefix, string strval |
|
||||
isPrefixOfJQueryHtmlString(astNode, prefix) and
|
||||
isPrefixOfJQueryHtmlString(this, prefix) and
|
||||
strval = prefix.getStringValue() and
|
||||
not strval.regexpMatch("\\s*<.*")
|
||||
) and
|
||||
@@ -90,9 +90,9 @@ module DomBasedXss {
|
||||
* Holds if `prefix` is a prefix of `htmlString`, which may be intepreted as
|
||||
* HTML by a jQuery method.
|
||||
*/
|
||||
private predicate isPrefixOfJQueryHtmlString(Expr htmlString, DataFlow::Node prefix) {
|
||||
any(JQueryMethodCall call).interpretsArgumentAsHtml(htmlString) and
|
||||
prefix = htmlString.flow()
|
||||
private predicate isPrefixOfJQueryHtmlString(DataFlow::Node htmlString, DataFlow::Node prefix) {
|
||||
any(JQuery::MethodCall call).interpretsArgumentAsHtml(htmlString) and
|
||||
prefix = htmlString
|
||||
or
|
||||
exists(DataFlow::Node pred | isPrefixOfJQueryHtmlString(htmlString, pred) |
|
||||
prefix = StringConcatenation::getFirstOperand(pred)
|
||||
|
||||
@@ -4,9 +4,9 @@ test_AttributeDefinition
|
||||
| tst.js:2:22:2:37 | target: "_blank" |
|
||||
| tst.js:3:11:3:66 | $("<a/> ... e.com") |
|
||||
| tst.js:4:3:4:27 | a.attr( ... pener") |
|
||||
| tst.js:5:3:7:4 | a.attr( ... f"\\n }) |
|
||||
| tst.js:6:5:6:24 | "data-bind": "stuff" |
|
||||
| tst.js:8:3:8:29 | a.prop( ... errer") |
|
||||
| tst.js:9:3:11:4 | a.prop( ... f"\\n }) |
|
||||
| tst.js:10:5:10:29 | "data-b ... rstuff" |
|
||||
| tst.js:12:3:12:41 | $.attr( ... errer") |
|
||||
| tst.js:13:3:13:28 | $.prop( ... d", "") |
|
||||
| tst.jsx:4:14:4:38 | href="h ... le.com" |
|
||||
@@ -38,8 +38,8 @@ test_WebStorageWrite
|
||||
test_ElementDefinition_getAttributeByName
|
||||
| tst.html:3:3:3:57 | <a>...</> | href | tst.html:3:6:3:30 | href=https://semmle.com |
|
||||
| tst.html:3:3:3:57 | <a>...</> | target | tst.html:3:32:3:46 | target=_blank |
|
||||
| tst.js:3:11:3:31 | $("<a/> ... rAttrs) | data-bind | tst.js:5:3:7:4 | a.attr( ... f"\\n }) |
|
||||
| tst.js:3:11:3:31 | $("<a/> ... rAttrs) | data-bind | tst.js:9:3:11:4 | a.prop( ... f"\\n }) |
|
||||
| tst.js:3:11:3:31 | $("<a/> ... rAttrs) | data-bind | tst.js:6:5:6:24 | "data-bind": "stuff" |
|
||||
| tst.js:3:11:3:31 | $("<a/> ... rAttrs) | data-bind | tst.js:10:5:10:29 | "data-b ... rstuff" |
|
||||
| tst.js:3:11:3:31 | $("<a/> ... rAttrs) | data-bind | tst.js:13:3:13:28 | $.prop( ... d", "") |
|
||||
| tst.js:3:11:3:31 | $("<a/> ... rAttrs) | href | tst.js:3:11:3:66 | $("<a/> ... e.com") |
|
||||
| tst.js:3:11:3:31 | $("<a/> ... rAttrs) | rel | tst.js:4:3:4:27 | a.attr( ... pener") |
|
||||
@@ -54,9 +54,9 @@ test_AttributeDefinition_getStringValue
|
||||
| tst.js:2:22:2:37 | target: "_blank" | _blank |
|
||||
| tst.js:3:11:3:66 | $("<a/> ... e.com") | https://semmle.com |
|
||||
| tst.js:4:3:4:27 | a.attr( ... pener") | noopener |
|
||||
| tst.js:5:3:7:4 | a.attr( ... f"\\n }) | stuff |
|
||||
| tst.js:6:5:6:24 | "data-bind": "stuff" | stuff |
|
||||
| tst.js:8:3:8:29 | a.prop( ... errer") | noreferrer |
|
||||
| tst.js:9:3:11:4 | a.prop( ... f"\\n }) | otherstuff |
|
||||
| tst.js:10:5:10:29 | "data-b ... rstuff" | otherstuff |
|
||||
| tst.js:12:3:12:41 | $.attr( ... errer") | noopener noreferrer |
|
||||
| tst.js:13:3:13:28 | $.prop( ... d", "") | |
|
||||
| tst.jsx:4:14:4:38 | href="h ... le.com" | https://semmle.com |
|
||||
@@ -66,9 +66,9 @@ test_AttributeDefinition_getName
|
||||
| tst.js:2:22:2:37 | target: "_blank" | target |
|
||||
| tst.js:3:11:3:66 | $("<a/> ... e.com") | href |
|
||||
| tst.js:4:3:4:27 | a.attr( ... pener") | rel |
|
||||
| tst.js:5:3:7:4 | a.attr( ... f"\\n }) | data-bind |
|
||||
| tst.js:6:5:6:24 | "data-bind": "stuff" | data-bind |
|
||||
| tst.js:8:3:8:29 | a.prop( ... errer") | rel |
|
||||
| tst.js:9:3:11:4 | a.prop( ... f"\\n }) | data-bind |
|
||||
| tst.js:10:5:10:29 | "data-b ... rstuff" | data-bind |
|
||||
| tst.js:12:3:12:41 | $.attr( ... errer") | rel |
|
||||
| tst.js:13:3:13:28 | $.prop( ... d", "") | data-bind |
|
||||
| tst.jsx:4:14:4:38 | href="h ... le.com" | href |
|
||||
@@ -101,9 +101,9 @@ test_AttributeDefinition_getValueNode
|
||||
| tst.js:2:22:2:37 | target: "_blank" | tst.js:2:30:2:37 | "_blank" |
|
||||
| tst.js:3:11:3:66 | $("<a/> ... e.com") | tst.js:3:46:3:65 | "https://semmle.com" |
|
||||
| tst.js:4:3:4:27 | a.attr( ... pener") | tst.js:4:17:4:26 | "noopener" |
|
||||
| tst.js:5:3:7:4 | a.attr( ... f"\\n }) | tst.js:6:18:6:24 | "stuff" |
|
||||
| tst.js:6:5:6:24 | "data-bind": "stuff" | tst.js:6:18:6:24 | "stuff" |
|
||||
| tst.js:8:3:8:29 | a.prop( ... errer") | tst.js:8:17:8:28 | "noreferrer" |
|
||||
| tst.js:9:3:11:4 | a.prop( ... f"\\n }) | tst.js:10:18:10:29 | "otherstuff" |
|
||||
| tst.js:10:5:10:29 | "data-b ... rstuff" | tst.js:10:18:10:29 | "otherstuff" |
|
||||
| tst.js:12:3:12:41 | $.attr( ... errer") | tst.js:12:20:12:40 | "noopen ... ferrer" |
|
||||
| tst.js:13:3:13:28 | $.prop( ... d", "") | tst.js:13:26:13:27 | "" |
|
||||
| tst.jsx:4:14:4:38 | href="h ... le.com" | tst.jsx:4:19:4:38 | "https://semmle.com" |
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
| e1 | tst.js:2:14:2:23 | $("<div>") |
|
||||
| e2 | tst.js:6:18:6:41 | angular ... <div>') |
|
||||
| e3 | tst.js:7:18:7:29 | $rootElement |
|
||||
| e4 | tst.js:8:18:8:26 | $document |
|
||||
| e5 | tst.js:13:26:13:32 | element |
|
||||
| e6 | tst.js:16:26:16:32 | element |
|
||||
| e7 | tst.js:18:30:18:36 | element |
|
||||
| e8 | tst.js:22:26:22:32 | element |
|
||||
| e9 | tst.js:25:26:25:32 | element |
|
||||
| tst.js:2:14:2:23 | $("<div>") |
|
||||
| tst.js:5:36:5:47 | $rootElement |
|
||||
| tst.js:5:50:5:58 | $document |
|
||||
| tst.js:6:18:6:41 | angular ... <div>') |
|
||||
| tst.js:12:35:12:41 | element |
|
||||
| tst.js:15:31:15:37 | element |
|
||||
| tst.js:17:40:17:46 | element |
|
||||
| tst.js:21:32:21:38 | element |
|
||||
| tst.js:24:35:24:41 | element |
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from Variable var, JQueryObject jq
|
||||
where var.getAnAssignedExpr() = jq
|
||||
select var, jq
|
||||
from JQuery::Object jq
|
||||
select jq
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
| tracking.js:15:5:15:26 | e.attr( ... 'foo') | class | tracking.js:15:21:15:25 | 'foo' |
|
||||
| tracking.js:17:7:17:18 | color: 'red' | color | tracking.js:17:14:17:18 | 'red' |
|
||||
| tracking.js:18:7:18:18 | size: '12pt' | size | tracking.js:18:13:18:18 | '12pt' |
|
||||
| tst.js:3:1:3:44 | $("<a/> ... e.com") | href | tst.js:3:24:3:43 | "https://semmle.com" |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DOM::AttributeDefinition def
|
||||
select def, def.getName(), def.getValueNode()
|
||||
@@ -1,3 +1,12 @@
|
||||
WARNING: Type JQueryMethodCall has been deprecated and may be removed in future (JQueryMethodCall.ql:3,6-22)
|
||||
| tracking.js:7:5:7:24 | this.elm.html('foo') | html |
|
||||
| tracking.js:14:5:14:17 | e.html('foo') | html |
|
||||
| tracking.js:15:5:15:26 | e.attr( ... 'foo') | attr |
|
||||
| tracking.js:16:5:19:6 | e.attr( ... \\n }) | attr |
|
||||
| tracking.js:23:7:23:15 | $('#foo') | $ |
|
||||
| ts_global_types.ts:3:5:3:17 | e.html('foo') | html |
|
||||
| ts_global_types.ts:7:1:7:9 | $('#foo') | $ |
|
||||
| ts_import.ts:5:5:5:17 | e.html('foo') | html |
|
||||
| tst2.js:2:1:2:7 | jq("a") | $ |
|
||||
| tst.js:1:1:1:3 | $() | $ |
|
||||
| tst.js:2:1:2:8 | jQuery() | $ |
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
WARNING: Type JQueryMethodCall has been deprecated and may be removed in future (interpretsArgumentAsHtml.ql:3,6-22)
|
||||
| tracking.js:7:5:7:24 | this.elm.html('foo') | tracking.js:7:19:7:23 | 'foo' |
|
||||
| tracking.js:14:5:14:17 | e.html('foo') | tracking.js:14:12:14:16 | 'foo' |
|
||||
| tracking.js:23:7:23:15 | $('#foo') | tracking.js:23:9:23:14 | '#foo' |
|
||||
| ts_global_types.ts:3:5:3:17 | e.html('foo') | ts_global_types.ts:3:12:3:16 | 'foo' |
|
||||
| ts_global_types.ts:7:1:7:9 | $('#foo') | ts_global_types.ts:7:3:7:8 | '#foo' |
|
||||
| ts_import.ts:5:5:5:17 | e.html('foo') | ts_import.ts:5:12:5:16 | 'foo' |
|
||||
| tst2.js:2:1:2:7 | jq("a") | tst2.js:2:4:2:6 | "a" |
|
||||
| tst.js:3:1:3:9 | $("<a/>") | tst.js:3:3:3:8 | "<a/>" |
|
||||
| tst.js:7:1:7:14 | $("<br>", doc) | tst.js:7:3:7:8 | "<br>" |
|
||||
|
||||
5
javascript/ql/test/library-tests/frameworks/jQuery/jquery.d.ts
vendored
Normal file
5
javascript/ql/test/library-tests/frameworks/jQuery/jquery.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
interface JQuery {}
|
||||
|
||||
declare module 'jquery' {
|
||||
export = JQuery;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
class C {
|
||||
constructor(elm) {
|
||||
this.elm = elm;
|
||||
}
|
||||
|
||||
doSomething() {
|
||||
this.elm.html('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {JQuery} e
|
||||
*/
|
||||
doSomethingWithTypes(e) {
|
||||
e.html('foo');
|
||||
e.attr('class', 'foo');
|
||||
e.attr({
|
||||
color: 'red',
|
||||
size: '12pt',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
new C($('#foo'));
|
||||
@@ -0,0 +1,7 @@
|
||||
class MyClass {
|
||||
foo2(e: JQuery) {
|
||||
e.html('foo');
|
||||
}
|
||||
}
|
||||
|
||||
$('#foo');
|
||||
@@ -0,0 +1,7 @@
|
||||
import jQuery = require('jquery');
|
||||
|
||||
class MyClass {
|
||||
foo3(e: jQuery) {
|
||||
e.html('foo');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"include": ["."]}
|
||||
Reference in New Issue
Block a user