Repository: eslint/eslint (js)

Issue:
Rule proposal: no-buffer-constructor
In the upcoming Node.js v6 release, the existing `Buffer()` constructors are being soft-deprecated (docs-only deprecation) and replaced with new `Buffer.alloc()`, `Buffer.allocUnsafe()` and `Buffer.from()` alternatives. I am adding a rule to Node.js' own eslint configuration to flag uses of the deprecated constructors (see: https://github.com/nodejs/node/pull/5740). The point has been raised that it may be worthwhile upstreaming this rule so that it can be of benefit to the ecosystem as a whole. Currently the rule is pretty simplistic and can be made a bit more robust if necessary.

The rule catches uses of the `Buffer()` constructor either as `new Buffer(...)` or simply `Buffer(...)` (without the new) and suggests using one of the new constructors instead.

If it is worthwhile, I can open a pull request to submit the rule here.


Pull request:
New: no-buffer-constructor rule (fixes #5614)
**What is the purpose of this pull request? (put an "X" next to item)**

[x] New rule (https://github.com/eslint/eslint/issues/5614)

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (http://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**

This adds the `no-buffer-constructor` rule, as described in https://github.com/eslint/eslint/issues/5614.

**Is there anything you'd like reviewers to focus on?**

Nothing in particular

Patch:
diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js
index 72f0833a8..7867e3f23 100755
--- a/conf/eslint-recommended.js
+++ b/conf/eslint-recommended.js
@@ -79,6 +79,7 @@ module.exports = {
         "no-array-constructor": "off",
         "no-await-in-loop": "off",
         "no-bitwise": "off",
+        "no-buffer-constructor": "off",
         "no-caller": "off",
         "no-case-declarations": "error",
         "no-catch-shadow": "off",
diff --git a/docs/rules/no-buffer-constructor.md b/docs/rules/no-buffer-constructor.md
new file mode 100644
index 000000000..f287ce573
--- /dev/null
+++ b/docs/rules/no-buffer-constructor.md
@@ -0,0 +1,41 @@
+# disallow use of the Buffer() constructor (no-buffer-constructor)
+
+In Node.js, the behavior of the `Buffer` constructor is different depending on the type of its argument. Passing an argument from user input to `Buffer()` without validating its type can lead to security vulnerabilities such as remote memory disclosure and denial of service. As a result, the `Buffer` constructor has been deprecated and should not be used. Use the producer methods `Buffer.from`, `Buffer.alloc`, and `Buffer.allocUnsafe` instead.
+
+## Rule Details
+
+This rule disallows calling and constructing the `Buffer()` constructor.
+
+Examples of **incorrect** code for this rule:
+
+```js
+new Buffer(5);
+new Buffer([1, 2, 3]);
+
+Buffer(5);
+Buffer([1, 2, 3]);
+
+new Buffer(res.body.amount);
+new Buffer(res.body.values);
+```
+
+Examples of **correct** code for this rule:
+
+```js
+Buffer.alloc(5);
+Buffer.allocUnsafe(5);
+Buffer.from([1, 2, 3]);
+
+Buffer.alloc(res.body.amount);
+Buffer.from(res.body.values);
+```
+
+## When Not To Use It
+
+If you don't use Node.js, or you still need to support versions of Node.js that lack methods like `Buffer.from`, then you should not enable this rule.
+
+## Further Reading
+
+* [Buffer API documentation](https://nodejs.org/api/buffer.html)
+* [Let's fix Node.js Buffer API](https://github.com/ChALkeR/notes/blob/master/Lets-fix-Buffer-API.md)
+* [Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660)
diff --git a/lib/rules/no-buffer-constructor.js b/lib/rules/no-buffer-constructor.js
new file mode 100644
index 000000000..1521ff284
--- /dev/null
+++ b/lib/rules/no-buffer-constructor.js
@@ -0,0 +1,37 @@
+/**
+ * @fileoverview disallow use of the Buffer() constructor
+ * @author Teddy Katz
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        docs: {
+            description: "disallow use of the Buffer() constructor",
+            category: "Node.js and CommonJS",
+            recommended: false
+        },
+        schema: []
+    },
+
+    create(context) {
+
+        //----------------------------------------------------------------------
+        // Public
+        //----------------------------------------------------------------------
+
+        return {
+            "CallExpression[callee.name='Buffer'], NewExpression[callee.name='Buffer']"(node) {
+                context.report({
+                    node,
+                    message: "{{example}} is deprecated. Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead.",
+                    data: { example: node.type === "CallExpression" ? "Buffer()" : "new Buffer()" }
+                });
+            }
+        };
+    }
+};
diff --git a/lib/rules/space-unary-ops.js b/lib/rules/space-unary-ops.js
index 5b156fac2..d9998370b 100644
--- a/lib/rules/space-unary-ops.js
+++ b/lib/rules/space-unary-ops.js
@@ -288,9 +288,11 @@ module.exports = {
         * @returns {void}
         */
         function checkForSpaces(node) {
-            const tokens = sourceCode.getFirstTokens(node, 2),
-                firstToken = tokens[0],
-                secondToken = tokens[1];
+            const tokens = node.type === "UpdateExpression" && !node.prefix
+                ? sourceCode.getLastTokens(node, 2)
+                : sourceCode.getFirstTokens(node, 2);
+            const firstToken = tokens[0];
+            const secondToken = tokens[1];
 
             if ((node.type === "NewExpression" || node.prefix) && firstToken.type === "Keyword") {
                 checkUnaryWordOperatorForSpaces(node, firstToken, secondToken);


Test patch:
diff --git a/tests/lib/rules/no-buffer-constructor.js b/tests/lib/rules/no-buffer-constructor.js
new file mode 100644
index 000000000..c3540e5e4
--- /dev/null
+++ b/tests/lib/rules/no-buffer-constructor.js
@@ -0,0 +1,68 @@
+/**
+ * @fileoverview disallow use of the Buffer() constructor
+ * @author Teddy Katz
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/no-buffer-constructor");
+const RuleTester = require("../../../lib/testers/rule-tester");
+
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const CALL_ERROR = {
+    message: "Buffer() is deprecated. Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead.",
+    type: "CallExpression"
+};
+const CONSTRUCT_ERROR = {
+    message: "new Buffer() is deprecated. Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead.",
+    type: "NewExpression"
+};
+
+const ruleTester = new RuleTester();
+
+ruleTester.run("no-buffer-constructor", rule, {
+
+    valid: [
+        "Buffer.alloc(5)",
+        "Buffer.allocUnsafe(5)",
+        "new Buffer.Foo()",
+        "Buffer.from([1, 2, 3])",
+        "foo(Buffer)",
+        "Buffer.alloc(res.body.amount)",
+        "Buffer.from(res.body.values)"
+    ],
+
+    invalid: [
+        {
+            code: "Buffer(5)",
+            errors: [CALL_ERROR]
+        },
+        {
+            code: "new Buffer(5)",
+            errors: [CONSTRUCT_ERROR]
+        },
+        {
+            code: "Buffer([1, 2, 3])",
+            errors: [CALL_ERROR]
+        },
+        {
+            code: "new Buffer([1, 2, 3])",
+            errors: [CONSTRUCT_ERROR]
+        },
+        {
+            code: "new Buffer(res.body.amount)",
+            errors: [CONSTRUCT_ERROR]
+        },
+        {
+            code: "new Buffer(res.body.values)",
+            errors: [CONSTRUCT_ERROR]
+        }
+    ]
+});
diff --git a/tests/lib/rules/space-unary-ops.js b/tests/lib/rules/space-unary-ops.js
index 0da1177b6..d5466bff5 100644
--- a/tests/lib/rules/space-unary-ops.js
+++ b/tests/lib/rules/space-unary-ops.js
@@ -36,6 +36,13 @@ ruleTester.run("space-unary-ops", rule, {
             code: "this.a--",
             options: [{ words: true }]
         },
+        {
+            code: "foo .bar++"
+        },
+        {
+            code: "foo.bar --",
+            options: [{ nonwords: true }]
+        },
         {
             code: "delete foo.bar",
             options: [{ words: true }]
@@ -417,6 +424,21 @@ ruleTester.run("space-unary-ops", rule, {
                 message: "Unary operator '++' must be followed by whitespace."
             }]
         },
+        {
+            code: "foo .bar++",
+            output: "foo .bar ++",
+            options: [{ nonwords: true }],
+            errors: [{
+                message: "Space is required before unary expressions '++'."
+            }]
+        },
+        {
+            code: "foo.bar --",
+            output: "foo.bar--",
+            errors: [{
+                message: "Unexpected space before unary operator '--'."
+            }]
+        },
         {
             code: "+ +foo",
             output: null,