@locker/eslint-plugin-unsafe-types
Version:
Detect usage of unsigned unsafe types.
257 lines (226 loc) • 9.35 kB
JavaScript
/**
* @fileoverview Tests for no-implied-eval rule.
* Original source code https://github.com/eslint/eslint/blob/main/tests/lib/rules/no-implied-eval.js
* @author Lightning Web Security Team
*/
'use strict';
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const RuleTester = require('eslint').RuleTester;
const rule = require('../../../lib/rules/unsafe-implied-eval');
const env = { browser: true, commonjs: true, es2024: true, jquery: true };
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
const ruleTester = new RuleTester();
ruleTester.run('no-implied-eval', rule, {
valid: [
'setTimeout();',
'setTimeout;',
'setTimeout = foo;',
'window.setTimeout;',
'window.setTimeout = foo;',
"window['setTimeout'];",
"window['setTimeout'] = foo;",
'global.setTimeout;',
'global.setTimeout = foo;',
"global['setTimeout'];",
"global['setTimeout'] = foo;",
"globalThis['setTimeout'] = foo;",
"window.setTimeout($A.lockerService.restricted.createScript('foo'))",
"window.setInterval($A.lockerService.restricted.createScript('foo'))",
"window['setTimeout']($A.lockerService.restricted.createScript('foo'))",
"window['setInterval']($A.lockerService.restricted.createScript('foo'))",
"window.setTimeout($A.lockerService.restricted.createScript('foo'))",
"window.setInterval($A.lockerService.restricted.createScript('foo'))",
"window['setTimeout']($A.lockerService.restricted.createScript('foo'))",
"window['setInterval']($A.lockerService.restricted.createScript('foo'))",
"global.setTimeout($A.lockerService.restricted.createScript('foo'))",
"global.setInterval($A.lockerService.restricted.createScript('foo'))",
"global['setTimeout']($A.lockerService.restricted.createScript('foo'))",
"global['setInterval']($A.lockerService.restricted.createScript('foo'))",
"globalThis.setTimeout($A.lockerService.restricted.createScript('foo'))",
"globalThis['setInterval']($A.lockerService.restricted.createScript('foo'))",
"window[`SetTimeOut`]('foo', 100);",
"global[`SetTimeOut`]('foo', 100);",
// eslint-disable-next-line no-template-curly-in-string
"global[`setTimeout${foo}`]('foo', 100);",
// eslint-disable-next-line no-template-curly-in-string
"global[`setTimeout${foo}`]('foo', 100);",
// eslint-disable-next-line no-template-curly-in-string
"globalThis[`setTimeout${foo}`]('foo', 100);",
// normal usage
'setTimeout(function() { x = 1; }, 100);',
'setInterval(function() { x = 1; }, 100)',
'execScript(function() { x = 1; }, 100)',
'window.setTimeout(function() { x = 1; }, 100);',
'window.setInterval(function() { x = 1; }, 100);',
'window.execScript(function() { x = 1; }, 100);',
'window.setTimeout(foo, 100);',
'window.setInterval(foo, 100);',
'window.execScript(foo, 100);',
'global.setTimeout(function() { x = 1; }, 100);',
'global.setInterval(function() { x = 1; }, 100);',
'global.execScript(function() { x = 1; }, 100);',
'global.setTimeout(foo, 100);',
'global.setInterval(foo, 100);',
'global.execScript(foo, 100);',
'globalThis.setTimeout(foo, 100);',
// only checks on top-level statements or window.*
"foo.setTimeout('hi')",
// identifiers are fine
'setTimeout(foo, 10)',
'setInterval(1, 10)',
'execScript(2)',
// as are function expressions
'setTimeout(function() {}, 10)',
// setInterval
"foo.setInterval('hi')",
'setInterval(foo, 10)',
'setInterval(function() {}, 10)',
// execScript
"foo.execScript('hi')",
'execScript(foo)',
'execScript(function() {})',
// a binary plus on non-strings doesn't guarantee a string
'setTimeout(foo + bar, 10)',
// doesn't check anything but the first argument
"setTimeout(foobar, 'buzz')",
"setTimeout(foobar, foo + 'bar')",
// only checks immediate subtrees of the argument
"setTimeout(function() { return 'foobar'; }, 10)",
// https://github.com/eslint/eslint/issues/7821
"setTimeoutFooBar('Foo Bar')",
"foo.window.setTimeout('foo', 100);",
"foo.global.setTimeout('foo', 100);",
"var window; window.setTimeout('foo', 100);",
"var global; global.setTimeout('foo', 100);",
"function foo(window) { window.setTimeout('foo', 100); }",
"function foo(global) { global.setTimeout('foo', 100); }",
"foo('', window.setTimeout);",
"foo('', global.setTimeout);",
].map((code) => ({ code, env })),
invalid: [
"globalThis['setInterval']('foo')",
'setTimeout("x = 1;");',
'setTimeout("x = 1;", 100);',
'setInterval("x = 1;");',
'execScript("x = 1;");',
"const s = 'x=1'; setTimeout(s, 100);",
"setTimeout(String('x=1'), 100);",
// member expressions
"window.setTimeout('foo')",
"window.setInterval('foo')",
"window['setTimeout']('foo')",
"window['setInterval']('foo')",
"window[`setInterval`]('foo')",
"window.window['setInterval']('foo')",
"global.setTimeout('foo')",
"global.setInterval('foo')",
"global['setTimeout']('foo')",
"global['setInterval']('foo')",
"global[`setInterval`]('foo')",
"global.global['setInterval']('foo')",
"globalThis.setTimeout('foo')",
"globalThis.setInterval('foo')",
// template literals
// eslint-disable-next-line no-template-curly-in-string
'setTimeout(`foo${bar}`)',
// eslint-disable-next-line no-template-curly-in-string
'window.setTimeout(`foo${bar}`)',
// eslint-disable-next-line no-template-curly-in-string
'window.window.setTimeout(`foo${bar}`)',
// eslint-disable-next-line no-template-curly-in-string
'global.global.setTimeout(`foo${bar}`)',
// string concatenation
"setTimeout('foo' + bar)",
"setTimeout(foo + 'bar')",
'setTimeout(`foo` + bar)',
"setTimeout(1 + ';' + 1)",
"window.setTimeout('foo' + bar)",
"window.setTimeout(foo + 'bar')",
'window.setTimeout(`foo` + bar)',
"window.setTimeout(1 + ';' + 1)",
"global.setTimeout('foo' + bar)",
"global.setTimeout(foo + 'bar')",
'global.setTimeout(`foo` + bar)',
"global.setTimeout(1 + ';' + 1)",
"global.global.setTimeout(1 + ';' + 1)",
"globalThis.setTimeout('foo' + bar)",
// gives the correct node when dealing with nesting
{
code:
"setTimeout('foo' + (function() {\n" +
' setTimeout(helper);\n' +
" execScript('str');\n" +
" return 'bar';\n" +
'})())',
errors: [
{
messageId: 'impliedEval',
type: 'CallExpression',
line: 1,
},
// no error on line 2
{
messageId: 'impliedEval',
type: 'CallExpression',
line: 3,
},
],
},
{
code:
"window.setTimeout('foo' + (function() {\n" +
' setTimeout(helper);\n' +
" window.execScript('str');\n" +
" return 'bar';\n" +
'})())',
errors: [
{
messageId: 'impliedEval',
type: 'CallExpression',
line: 1,
},
// no error on line 2
{
messageId: 'impliedEval',
type: 'CallExpression',
line: 3,
},
],
},
{
code:
"global.setTimeout('foo' + (function() {\n" +
' setTimeout(helper);\n' +
" global.execScript('str');\n" +
" return 'bar';\n" +
'})())',
errors: [
{
messageId: 'impliedEval',
type: 'CallExpression',
line: 1,
},
// no error on line 2
{
messageId: 'impliedEval',
type: 'CallExpression',
line: 3,
},
],
},
// Optional chaining
"window?.setTimeout('code', 0)",
"(window?.setTimeout)('code', 0)",
].map((code) => {
if (typeof code === 'object') {
code.env = env;
} else {
code = { code, env, errors: [{ messageId: 'impliedEval' }] };
}
return code;
}),
});