JS: add query js/vue/arrow-method-on-vue-instance

This commit is contained in:
Esben Sparre Andreasen
2019-01-25 12:35:12 +01:00
parent ea175b2a9f
commit a78dd422b6
8 changed files with 111 additions and 0 deletions

View File

@@ -14,6 +14,7 @@
| **Query** | **Tags** | **Purpose** | | **Query** | **Tags** | **Purpose** |
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Arrow method on Vue instance (`js/vue/arrow-method-on-vue-instance`) | reliability, frameworks/vue | Highlights arrow functions that are used as methods on Vue instances. Results are shown on LGTM by default.|
| Double escaping or unescaping (`js/double-escaping`) | correctness, security, external/cwe/cwe-116 | Highlights potential double escaping or unescaping of special characters, indicating a possible violation of [CWE-116](https://cwe.mitre.org/data/definitions/116.html). Results are shown on LGTM by default. | | Double escaping or unescaping (`js/double-escaping`) | correctness, security, external/cwe/cwe-116 | Highlights potential double escaping or unescaping of special characters, indicating a possible violation of [CWE-116](https://cwe.mitre.org/data/definitions/116.html). Results are shown on LGTM by default. |
| Incomplete regular expression for hostnames (`js/incomplete-hostname-regexp`) | correctness, security, external/cwe/cwe-020 | Highlights hostname sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default.| | Incomplete regular expression for hostnames (`js/incomplete-hostname-regexp`) | correctness, security, external/cwe/cwe-020 | Highlights hostname sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default.|
| Incomplete URL substring sanitization | correctness, security, external/cwe/cwe-020 | Highlights URL sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results shown on LGTM by default. | | Incomplete URL substring sanitization | correctness, security, external/cwe/cwe-020 | Highlights URL sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results shown on LGTM by default. |

View File

@@ -23,3 +23,4 @@
+ semmlecode-javascript-queries/React/UnusedOrUndefinedStateProperty.ql: /Frameworks/React + semmlecode-javascript-queries/React/UnusedOrUndefinedStateProperty.ql: /Frameworks/React
+ semmlecode-javascript-queries/Electron/DisablingWebSecurity.ql: /Frameworks/Electron + semmlecode-javascript-queries/Electron/DisablingWebSecurity.ql: /Frameworks/Electron
+ semmlecode-javascript-queries/Electron/AllowRunningInsecureContent.ql: /Frameworks/Electron + semmlecode-javascript-queries/Electron/AllowRunningInsecureContent.ql: /Frameworks/Electron
+ semmlecode-javascript-queries/Vue/ArrowMethodOnVueInstance.ql: /Frameworks/Vue

View File

@@ -0,0 +1,49 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
The Vue framework invokes the methods of a Vue instance with
the instance as the receiver. It is however impossible to perform
this binding of instance and receiver for arrow functions, so the
<code>this</code> variable in an arrow function on a Vue instance may
not have the value that the programmer expects.
</p>
</overview>
<recommendation>
<p>
Ensure that the methods on a Vue instance can have their receiver bound to the instance.
</p>
</recommendation>
<example>
<p>
The following example shows two similar Vue instances, the only
difference is how the <code>created</code> life cycle hook
callback is defined.
The first Vue instance uses an arrow function as the callback.
This means that the <code>this</code> variable will have the global
object as its value, causing <code>this.myProperty</code> to evaluate
to <code>undefined</code>, which may not be intended.
Instead, the second Vue instance uses an ordinary function as the callback,
causing <code>this.myProperty</code> to evaluate to <code>42</code>.
</p>
<sample src="examples/ArrowMethodOnVueInstance.js"/>
</example>
<references>
<li>Vue documentation: <a href="https://vuejs.org/v2/guide/instance.html">The Vue Instance</a></li>
</references>
</qhelp>

View File

@@ -0,0 +1,19 @@
/**
* @name Arrow method on Vue instance
* @description An arrow method on a Vue instance doesn't have its `this` variable bound to the Vue instance.
* @kind problem
* @problem.severity warning
* @id js/vue/arrow-method-on-vue-instance
* @tags reliability
* frameworks/vue
* @precision high
*/
import javascript
from Vue::Instance instance, DataFlow::Node def, DataFlow::FunctionNode arrow, ThisExpr dis
where instance.getABoundFunction() = def and
arrow.flowsTo(def) and
arrow.asExpr() instanceof ArrowFunctionExpr and
arrow.asExpr() = dis.getEnclosingFunction()
select def, "The $@ of this $@ it will not be bound to the Vue instance.", dis, "`this` variable", arrow, "arrow function"

View File

@@ -0,0 +1,19 @@
new Vue({
data: {
myProperty: 42
},
created: () => {
// BAD: prints: "myProperty is: undefined"
console.log('myProperty is: ' + this.myProperty);
}
});
new Vue({
data: {
myProperty: 42
},
created: function () {
// GOOD: prints: "myProperty is: 1"
console.log('myProperty is: ' + this.myProperty);
}
});

View File

@@ -0,0 +1,5 @@
| tst.js:4:11:4:20 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:4:17:4:20 | this | `this` variable | tst.js:4:11:4:20 | () => this | arrow function |
| tst.js:6:6:6:15 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:6:12:6:15 | this | `this` variable | tst.js:6:6:6:15 | () => this | arrow function |
| tst.js:7:13:7:22 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:7:19:7:22 | this | `this` variable | tst.js:7:13:7:22 | () => this | arrow function |
| tst.js:8:13:8:22 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:8:19:8:22 | this | `this` variable | tst.js:8:13:8:22 | () => this | arrow function |
| tst.js:11:10:11:19 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:11:16:11:19 | this | `this` variable | tst.js:11:10:11:19 | () => this | arrow function |

View File

@@ -0,0 +1 @@
Vue/ArrowMethodOnVueInstance.ql

View File

@@ -0,0 +1,16 @@
let Vue = require('vue');
new Vue( {
created: () => this, // NOT OK
computed: {
x: () => this, // NOT OK
y: { get: () => this }, // NOT OK
z: { set: () => this } // NOT OK
},
methods: {
arrow: () => this, // NOT OK
nonArrow: function() { this; }, // OK
arrowWithoutThis: () => 42, // OK
arrowWithNestedThis: () => (() => this) // OK
}
});