| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 | /** * @fileoverview ESLint rule to disallow unsanitized method calls * @author Frederik Braun et al. * @copyright 2015-2017 Mozilla Corporation. All rights reserved. */"use strict";const RuleHelper = require("../ruleHelper");//------------------------------------------------------------------------------// Rule Definition//------------------------------------------------------------------------------const defaultRuleChecks = {    // check second parameter to .insertAdjacentHTML()    insertAdjacentHTML: {        properties: [1]    },    // check first parameter of import()    import: {        properties: [0]    },    // check first parameter to createContextualFragment()    createContextualFragment: {        properties: [0]    },    // check first parameter to .write(), as long as the preceeding object matches the regex "document"    write: {        objectMatches: [            "document"        ],        properties: [0]    },    // check first parameter to .writeLn(), as long as the preceeding object matches the regex "document"    writeln: {        objectMatches: [            "document"        ],        properties: [0]    }};/** * On newer parsers, `import(foo)` gets parsed as a keyword. * @param {Object} ruleHelper a RuleHelper instance * @param {Object} importExpr The ImportExpression we triggered on * @returns {undefined} Does not return */function checkImport(ruleHelper, importExpr) {    const fakeCall = {callee: {type: "Import"}, arguments: [importExpr.source]};    Object.assign(fakeCall, importExpr);    ruleHelper.checkMethod(fakeCall);}/** * Run ruleHelper.checkMethod for all but irrelevant callees (FunctionExpression, etc.) * @param {Object} ruleHelper a RuleHelper instance * @param {Object} callExpr The CallExpression we triggered on * @param {Object} node The callee node * @returns {undefined} Does not return */function checkCallExpression(ruleHelper, callExpr, node) {    switch(node.type) {    case "Identifier":    case "MemberExpression":        if (callExpr.arguments && callExpr.arguments.length > 0) {            ruleHelper.checkMethod(callExpr);        }        break;    case "TSNonNullExpression": {        const newCallExpr = Object.assign({}, callExpr);        newCallExpr.callee = node.expression;        checkCallExpression(ruleHelper, newCallExpr, node.expression);        break;    }    case "TaggedTemplateExpression": {        const newCallExpr = Object.assign({}, callExpr);        newCallExpr.callee = node.tag;        const expressions = node.quasi.expressions;        const strings = node.quasi.quasis;        newCallExpr.arguments = [strings, ...expressions];        checkCallExpression(ruleHelper, newCallExpr, node.tag);        break;    }            case "TypeCastExpression": {        const newCallExpr = Object.assign({}, callExpr);        newCallExpr.callee = node.expression;        checkCallExpression(ruleHelper, newCallExpr, node.expression);        break;    }    case "AssignmentExpression":        if (node.right.type === "MemberExpression") {            const newCallExpr = Object.assign({}, callExpr);            newCallExpr.callee = node.right;            checkCallExpression(ruleHelper, newCallExpr, node.right);            break;        }        checkCallExpression(ruleHelper, callExpr, node.right);        break;    case "Import":        ruleHelper.checkMethod(callExpr);        break;    case "SequenceExpression": {        // the return value of a SequenceExpression is the last expression.        // So, we create a new mock CallExpression with the actually called        // ... expression as the callee node and pass it to checkMethod()        const newCallExpr = Object.assign({}, callExpr);        const idx = node.expressions.length - 1;        const called = node.expressions[idx];        newCallExpr.callee = called;        ruleHelper.checkMethod(newCallExpr);        break;    }    case "TSAsExpression":        break;    // those are fine:    case "LogicalExpression": // Should we scan these? issue #62.    case "ConditionalExpression":    case "ArrowFunctionExpression":    case "FunctionExpression":    case "Super":    case "CallExpression":    case "ThisExpression":    case "NewExpression":    case "TSTypeAssertion":    case "AwaitExpression": // see issue #122        break;    // If we don't cater for this expression throw an error    default:        ruleHelper.reportUnsupported(node, "Unexpected Callee", `Unsupported Callee of type ${node.type} for CallExpression`);    }}module.exports = {    meta: {        type: "problem",        docs: {            description: "ESLint rule to disallow unsanitized method calls",            category: "possible-errors",            url: "https://github.com/mozilla/eslint-plugin-no-unsanitized/tree/master/docs/rules/method.md"        },        /* schema statement TBD until we have options        schema: [            {                type: array            }        ]*/    },    create(context) {        const ruleHelper = new RuleHelper(context, defaultRuleChecks);        return {            CallExpression(node) {                checkCallExpression(ruleHelper, node, node.callee);            },            ImportExpression(node) {                checkImport(ruleHelper, node);            },            // Tagged template expressions pass arguments in a special format we need to            // map to our existing function call logic            // foo`bar${var1}${var2}` will run as foo(['bar', ''], var1, var2)            TaggedTemplateExpression(node) {                const newCallExpr = Object.assign({}, node);                newCallExpr.callee = node.tag;                const expressions = node.quasi.expressions;                const strings = node.quasi.quasis;                newCallExpr.arguments = [strings, ...expressions];                checkCallExpression(ruleHelper, newCallExpr, node.tag);            },        };    }};
 |