UNPKG

@locker/eslint-plugin-unsafe-types

Version:
108 lines (92 loc) 3.57 kB
/** * @fileoverview Rule to flag use of $A.util.globalEval() statement * @author Lightning Web Security Team */ 'use strict'; //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ const astUtils = require('../utils/ast-utils'); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ /** * Checks a given node is a MemberExpression node which has the specified name's * property. * @param {ASTNode} node A node to check. * @param {string} name A name to check. * @returns {boolean} `true` if the node is a MemberExpression node which has * the specified name's property */ function isMember(node, name) { return astUtils.isSpecificMemberAccess(node, null, name); } //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ /** @type {import('../shared/types').Rule} */ module.exports = { meta: { type: 'suggestion', docs: { description: 'Disallow the use of unsigned `$A.util.globalEval()`', recommended: true, url: './docs/rules/unsafe-aura-globalEval', }, messages: { unexpected: 'eval can be harmful.', }, }, create(context) { /** * Reports a given node. * * `node` is `Identifier` or `MemberExpression`. * The parent of `node` might be `CallExpression`. * * The location of the report is always `eval` `Identifier` (or possibly * `Literal`). The type of the report is `CallExpression` if the parent is * `CallExpression`. Otherwise, it's the given node type. * @param {ASTNode} node A node to report. * @returns {void} */ function report(node) { const parent = node.parent; const locationNode = node.type === 'MemberExpression' ? node.property : node; const reportNode = parent.type === 'CallExpression' && parent.callee === node ? parent : node; context.report({ node: reportNode, loc: locationNode.loc, messageId: 'unexpected', }); } function isAuraGlobalEval(node) { if (isMember(node, 'globalEval') || isMember(node, '$globalEval$')) { const parent = node.object; if (isMember(parent, 'util') || isMember(parent, '$util$')) { if (parent.object.type === 'MemberExpression') { if (isMember(parent.object, '$A')) { return true; } } else if (parent.object.name === '$A') { return true; } } } return false; } return { 'CallExpression:exit'(node) { const callee = node.callee; // LWS BEGIN if (callee.type === 'MemberExpression') { const [argument] = node.arguments; if (isAuraGlobalEval(callee) && !astUtils.isSignatureCall(argument)) { report(callee); } } }, }; }, };