From 99b2c94219d95b1f99fbcd0ea56e6d663e5eac48 Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Sun, 15 Sep 2024 20:07:40 -0700 Subject: [PATCH 01/30] ESLint 9 upgrade --- lib/ast-utils.js | 8 +++---- lib/rules/no-postmessage-star-origin.js | 2 +- package.json | 9 +++---- tests/lib/rules/no-cookies.js | 9 +++---- tests/lib/rules/no-document-domain.js | 6 ++--- tests/lib/rules/no-document-write.js | 6 ++--- tests/lib/rules/no-html-method.js | 8 +------ tests/lib/rules/no-inner-html.js | 6 ++--- tests/lib/rules/no-insecure-random.js | 24 +++++++------------ tests/lib/rules/no-insecure-url.js | 24 ++++++++----------- tests/lib/rules/no-postmessage-star-origin.js | 6 ++--- .../lib/rules/react-iframe-missing-sandbox.js | 8 ++++--- tests/lib/test-utils.js | 23 +++++++++++------- 13 files changed, 60 insertions(+), 79 deletions(-) diff --git a/lib/ast-utils.js b/lib/ast-utils.js index b0eaf22..4e944b9 100644 --- a/lib/ast-utils.js +++ b/lib/ast-utils.js @@ -20,17 +20,17 @@ module.exports = { hasFullTypeInformation(context) { var hasFullTypeInformation = ( context && - this.isTypeScriptParserServices(context.parserServices) && - context.parserServices.hasFullTypeInformation === true + this.isTypeScriptParserServices(context.sourceCode.parserServices) && + context.sourceCode.parserServices.program ); return hasFullTypeInformation; }, getFullTypeChecker(context) { - return this.hasFullTypeInformation(context) ? context.parserServices.program.getTypeChecker() : null; + return this.hasFullTypeInformation(context) ? context.sourceCode.parserServices.program.getTypeChecker() : null; }, getNodeTypeAsString(fullTypeChecker, node, context) { if (fullTypeChecker && node) { - const tsNode = context.parserServices.esTreeNodeToTSNodeMap.get(node); + const tsNode = context.sourceCode.parserServices.esTreeNodeToTSNodeMap.get(node); const tsType = fullTypeChecker.getTypeAtLocation(tsNode); const type = fullTypeChecker.typeToString(tsType); return type; diff --git a/lib/rules/no-postmessage-star-origin.js b/lib/rules/no-postmessage-star-origin.js index 294343c..d8c5682 100644 --- a/lib/rules/no-postmessage-star-origin.js +++ b/lib/rules/no-postmessage-star-origin.js @@ -37,7 +37,7 @@ module.exports = { // Check that object type is Window when full type information is available if (fullTypeChecker) { - const tsNode = context.parserServices.esTreeNodeToTSNodeMap.get(node.callee.object); + const tsNode = context.sourceCode.parserServices.esTreeNodeToTSNodeMap.get(node.callee.object); const tsType = fullTypeChecker.getTypeAtLocation(tsNode); const type = fullTypeChecker.typeToString(tsType); if (type !== "any" && type !== "Window") { diff --git a/package.json b/package.json index cee4b4a..b015704 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,13 @@ "dependencies": { "eslint-plugin-node": "11.1.0", "eslint-plugin-security": "1.4.0", - "eslint-plugin-react": "7.33.0" + "eslint-plugin-react": "7.36.1" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^3.7.0", - "@typescript-eslint/parser": "^3.7.0", - "eslint": "^7.32.0", + "@typescript-eslint/eslint-plugin": "^8.5.0", + "@typescript-eslint/parser": "^8.5.0", + "@typescript-eslint/rule-tester": "^8.5.0", + "eslint": "^9.10.0", "mocha": "^8.3.2", "typescript": "^3.9.7" }, diff --git a/tests/lib/rules/no-cookies.js b/tests/lib/rules/no-cookies.js index f2e1c8e..a2fd99d 100644 --- a/tests/lib/rules/no-cookies.js +++ b/tests/lib/rules/no-cookies.js @@ -5,7 +5,6 @@ const path = require("path"); const ruleId = path.parse(__filename).name; const rule = require(path.join('../../../lib/rules/', ruleId)); const RuleTester = require("eslint").RuleTester; -const typescriptParserPath = require.resolve("@typescript-eslint/parser"); const testUtils = require("../test-utils"); var ruleTester = new RuleTester(); @@ -24,8 +23,7 @@ document2.cookie = '...'; documentLikeAPIFunction().cookie = '...' `, { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` interface DocumentLikeAPI { cookie: string; @@ -62,8 +60,7 @@ documentLikeAPIFunction().cookie = '...'; errors: [{ messageId: "doNotUseCookies" }] }, { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` function documentFunction(): Document { return window.document; @@ -73,7 +70,7 @@ documentFunction().cookie = '...'; errors: [{ messageId: "doNotUseCookies" }] }, { - parser: typescriptParserPath, + languageOptions: testUtils.tsParserOptions, code: ` namespace Sample { function method() { diff --git a/tests/lib/rules/no-document-domain.js b/tests/lib/rules/no-document-domain.js index 30a997d..8b1f9ad 100644 --- a/tests/lib/rules/no-document-domain.js +++ b/tests/lib/rules/no-document-domain.js @@ -11,8 +11,7 @@ var ruleTester = new RuleTester(); ruleTester.run(ruleId, rule, { valid: [ { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` interface DocumentLikeAPI { domain: string; @@ -29,8 +28,7 @@ function main() { ], invalid: [ { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: "var doc = window.document; doc.domain = 'somevalue';", errors: [{ messageId: "default" }] }, diff --git a/tests/lib/rules/no-document-write.js b/tests/lib/rules/no-document-write.js index 47f13c8..718f573 100644 --- a/tests/lib/rules/no-document-write.js +++ b/tests/lib/rules/no-document-write.js @@ -11,8 +11,7 @@ var ruleTester = new RuleTester(); ruleTester.run(ruleId, rule, { valid: [ { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` interface DocumentLikeAPI { write: ((arg : string) => void); @@ -49,8 +48,7 @@ ruleTester.run(ruleId, rule, { ], invalid: [ { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` var doc = document; doc.write('...'); diff --git a/tests/lib/rules/no-html-method.js b/tests/lib/rules/no-html-method.js index 47ba7d2..9bc88f2 100644 --- a/tests/lib/rules/no-html-method.js +++ b/tests/lib/rules/no-html-method.js @@ -26,13 +26,7 @@ ruleTester.run(ruleId, rule, { errors: [{ messageId: "default", line: 1 }] }, { - parser: testUtils.tsParser, - parserOptions: { - ecmaVersion: 6, - sourceType: "module" - }, - env: { - }, + languageOptions: testUtils.tsParserOptions, code: ` import $ from "jquery"; test.html('XSS'); diff --git a/tests/lib/rules/no-inner-html.js b/tests/lib/rules/no-inner-html.js index 5ad1758..6d7b3f8 100644 --- a/tests/lib/rules/no-inner-html.js +++ b/tests/lib/rules/no-inner-html.js @@ -16,8 +16,7 @@ ruleTester.run(ruleId, rule, { "document.test", "element.insertAdjacentHTML()", { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` class Test { innerHTML: string; @@ -36,8 +35,7 @@ ruleTester.run(ruleId, rule, { invalid: [ // TypeScript with full type information { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` var element = document.getElementById(id); element.innerHTML = 'test'; diff --git a/tests/lib/rules/no-insecure-random.js b/tests/lib/rules/no-insecure-random.js index 59a401c..cdac0e7 100644 --- a/tests/lib/rules/no-insecure-random.js +++ b/tests/lib/rules/no-insecure-random.js @@ -34,7 +34,7 @@ ruleTester.run(ruleId, rule, { ` }, { - parserOptions: testUtils.moduleParserOptions, + languageOptions: testUtils.moduleParserOptions, code:` import './node_modules/untest'; import 'random'; @@ -54,8 +54,7 @@ ruleTester.run(ruleId, rule, { ` }, { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` function random(){} @@ -66,8 +65,7 @@ ruleTester.run(ruleId, rule, { ` }, { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code:` function pseudoRandomBytes(){} function pseudoRandomByte(){} @@ -91,8 +89,7 @@ ruleTester.run(ruleId, rule, { ] }, { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` Math.random(); this.Math.random(); @@ -103,8 +100,7 @@ ruleTester.run(ruleId, rule, { ] }, { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` function notMath() : Math{ return Math; @@ -117,8 +113,7 @@ ruleTester.run(ruleId, rule, { ] }, { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` crypto.pseudoRandomBytes(); `, @@ -127,8 +122,7 @@ ruleTester.run(ruleId, rule, { ] }, { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` function notCrypto() : Crypto{ return crypto; @@ -141,7 +135,7 @@ ruleTester.run(ruleId, rule, { ] }, { - parserOptions: testUtils.moduleParserOptions, + languageOptions: testUtils.moduleParserOptions, code:` import './node_modules/unique-random'; import 'chance'; @@ -160,7 +154,7 @@ ruleTester.run(ruleId, rule, { ] }, { - parserOptions: testUtils.moduleParserOptions, + languageOptions: testUtils.moduleParserOptions, code:` import * as chance1 from 'chance'; import defaultExport from 'chance'; diff --git a/tests/lib/rules/no-insecure-url.js b/tests/lib/rules/no-insecure-url.js index 52f7acf..d066a48 100644 --- a/tests/lib/rules/no-insecure-url.js +++ b/tests/lib/rules/no-insecure-url.js @@ -27,14 +27,14 @@ ruleTester.run(ruleId, rule, { var x = \`https://www.template-examples.com\` var y = \`ftps://www.template-file-examples.com\` `, - parserOptions: testUtils.moduleParserOptions + languageOptions: testUtils.moduleParserOptions }, { // should allow https,ftps multipart template strings in variables code: ` var x = \`https://www.\${multipartExample}.com\` var y = \`ftps://www.\${multipartExample}.com\` `, - parserOptions: testUtils.moduleParserOptions + languageOptions: testUtils.moduleParserOptions }, { // should allow http,ftp in middle of string code: "var x = 'The protocol may be http://, https://, ftp:// or ftps://'" @@ -44,8 +44,7 @@ ruleTester.run(ruleId, rule, { function f(x : string = 'https://www.example.com') {} function f(y : string = 'ftps://www.example.com') {} `, - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, }, { // should allow user-provided exceptions matches, regardless of upper/lower-case code: ` @@ -77,8 +76,7 @@ ruleTester.run(ruleId, rule, { ); }; `, - parser: testUtils.tsParser, - parserOptions: testUtils.tsReactParserOptions, + languageOptions: testUtils.tsReactParserOptions, }, { // should allow localhost @@ -135,7 +133,7 @@ ruleTester.run(ruleId, rule, { { messageId: "doNotUseInsecureUrl", line: 4}, { messageId: "doNotUseInsecureUrl", line: 5} ], - parserOptions: testUtils.moduleParserOptions + languageOptions: testUtils.moduleParserOptions }, { // should ban http,ftp multipart template strings in variables code: ` @@ -150,7 +148,7 @@ ruleTester.run(ruleId, rule, { { messageId: "doNotUseInsecureUrl", line: 2}, { messageId: "doNotUseInsecureUrl", line: 3}, ], - parserOptions: testUtils.moduleParserOptions + languageOptions: testUtils.moduleParserOptions }, { // should ban http,ftp strings in default values code: ` @@ -165,8 +163,7 @@ ruleTester.run(ruleId, rule, { { messageId: "doNotUseInsecureUrl", line: 2}, { messageId: "doNotUseInsecureUrl", line: 3}, ], - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, }, { // should ban user-provided blacklist matches, regardless of upper/lower-case code: ` @@ -212,8 +209,7 @@ ruleTester.run(ruleId, rule, { errors: [ { messageId: "doNotUseInsecureUrl", line: 4}, ], - parser: testUtils.tsParser, - parserOptions: testUtils.tsReactParserOptions, + languageOptions: testUtils.tsReactParserOptions, }, { // should escape the url string correctly @@ -231,7 +227,7 @@ ruleTester.run(ruleId, rule, { { messageId: "doNotUseInsecureUrl", line: 1}, ], - parserOptions: testUtils.moduleParserOptions + languageOptions: testUtils.moduleParserOptions }, { // should escape the string and fix it properly in `` @@ -241,7 +237,7 @@ ruleTester.run(ruleId, rule, { { messageId: "doNotUseInsecureUrl", line: 1}, ], - parserOptions: testUtils.moduleParserOptions + languageOptions: testUtils.moduleParserOptions }, ] }); \ No newline at end of file diff --git a/tests/lib/rules/no-postmessage-star-origin.js b/tests/lib/rules/no-postmessage-star-origin.js index b40c5ec..85aac80 100644 --- a/tests/lib/rules/no-postmessage-star-origin.js +++ b/tests/lib/rules/no-postmessage-star-origin.js @@ -17,8 +17,7 @@ ruleTester.run(ruleId, rule, { "window.postMessage('data', 'https://target.domain')", "window.postMessage('data', 'https://target.domain', 'menubar=yes')", { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` class WindowLike { postMessage(): void { @@ -43,8 +42,7 @@ function main() { ] }, { - parser: testUtils.tsParser, - parserOptions: testUtils.tsParserOptions, + languageOptions: testUtils.tsParserOptions, code: ` window.frames[0].postMessage(message, "*"); var w1 = window.open(url); diff --git a/tests/lib/rules/react-iframe-missing-sandbox.js b/tests/lib/rules/react-iframe-missing-sandbox.js index 377de5b..2715fd0 100644 --- a/tests/lib/rules/react-iframe-missing-sandbox.js +++ b/tests/lib/rules/react-iframe-missing-sandbox.js @@ -9,11 +9,13 @@ const rule = require(path.join('../../../lib/rules/', ruleId)); const RuleTester = require("eslint").RuleTester; var ruleTester = new RuleTester({ - parserOptions: { + languageOptions: { ecmaVersion: 2018, sourceType: 'module', - ecmaFeatures: { - jsx: true + parserOptions: { + ecmaFeatures: { + jsx: true + } } } }); diff --git a/tests/lib/test-utils.js b/tests/lib/test-utils.js index 018a1d9..c352389 100644 --- a/tests/lib/test-utils.js +++ b/tests/lib/test-utils.js @@ -10,10 +10,12 @@ const path = require("path"); module.exports = { - tsParser: require.resolve("@typescript-eslint/parser"), tsParserOptions: { - tsconfigRootDir: path.join(__dirname, '../fixtures'), - project: 'tsconfig.json', + parser: require("@typescript-eslint/parser"), + parserOptions: { + tsconfigRootDir: path.join(__dirname, '../fixtures'), + project: 'tsconfig.json' + }, sourceType: "module" }, moduleParserOptions: { @@ -21,11 +23,14 @@ module.exports = { sourceType: "module" }, tsReactParserOptions: { - tsconfigRootDir: path.join(__dirname, '../fixtures'), - project: 'tsconfig-react.json', - sourceType: "module", - ecmaFeatures: { - jsx: true - } + parser: require("@typescript-eslint/parser"), + parserOptions: { + tsconfigRootDir: path.join(__dirname, '../fixtures'), + project: 'tsconfig-react.json', + ecmaFeatures: { + jsx: true + }, + }, + sourceType: "module" } }; \ No newline at end of file From 260e9b62a149cbd2ae8c822d8ccaa49fad2c2c19 Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Sun, 15 Sep 2024 20:15:06 -0700 Subject: [PATCH 02/30] Remove unnecessary package --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index b015704..768383d 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "devDependencies": { "@typescript-eslint/eslint-plugin": "^8.5.0", "@typescript-eslint/parser": "^8.5.0", - "@typescript-eslint/rule-tester": "^8.5.0", "eslint": "^9.10.0", "mocha": "^8.3.2", "typescript": "^3.9.7" From d9a039a50aeba24d9bbe621e17f88829a5b86409 Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Sun, 15 Sep 2024 20:18:03 -0700 Subject: [PATCH 03/30] Update Node version --- .github/workflows/node-version-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/node-version-integration.yml b/.github/workflows/node-version-integration.yml index e66afb6..034d422 100644 --- a/.github/workflows/node-version-integration.yml +++ b/.github/workflows/node-version-integration.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - node-version: [12.x, 14.x, 16.x] + node-version: [20.x] steps: - uses: actions/checkout@v2 From fcc319ec18b13761e9efc88b7411f767fc3c3a21 Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Sun, 15 Sep 2024 20:19:45 -0700 Subject: [PATCH 04/30] Upgrade deprecated action --- .github/workflows/E2E integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/E2E integration.yml b/.github/workflows/E2E integration.yml index 79cda1b..87a5726 100644 --- a/.github/workflows/E2E integration.yml +++ b/.github/workflows/E2E integration.yml @@ -81,7 +81,7 @@ jobs: continue-on-error: true - name: Upload eslint results as artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: eslint-result path: ${{env.PROJECT}}/eslint-result-${{ matrix.os }}-${{github.run_id}}.sarif From 526667bcc1c16b46f5b14019ce5766d9f8bbb0e9 Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Sun, 15 Sep 2024 23:19:23 -0700 Subject: [PATCH 05/30] Update node --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 466cbd7..12d7023 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 14 + node-version: 20 - run: npm i - run: npm test From 9a8c56fba71e05fee3c6cc53db0c463891c2fdcd Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Sun, 15 Sep 2024 23:25:35 -0700 Subject: [PATCH 06/30] Update --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 12d7023..08ed18e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2.1.4 with: - node-version: 14 + node-version: 20 registry-url: https://registry.npmjs.org/ - run: npm i - run: npm publish From 939e9a4b50a975ac9e336468109223bc5a4b69ad Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Mon, 16 Sep 2024 23:03:17 -0700 Subject: [PATCH 07/30] Add log --- lib/ast-utils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ast-utils.js b/lib/ast-utils.js index 4e944b9..b41f638 100644 --- a/lib/ast-utils.js +++ b/lib/ast-utils.js @@ -39,6 +39,7 @@ module.exports = { }, isDocumentObject(node, context, fullTypeChecker) { if (fullTypeChecker) { + console.log("fullTypeChecker is not null"); const type = this.getNodeTypeAsString(fullTypeChecker, node, context); return (type === "Document"); } From e7b26cb523f35ab8a4a482d070778677f2d511fd Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Mon, 16 Sep 2024 23:15:26 -0700 Subject: [PATCH 08/30] More logging --- lib/ast-utils.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ast-utils.js b/lib/ast-utils.js index b41f638..1ff7660 100644 --- a/lib/ast-utils.js +++ b/lib/ast-utils.js @@ -38,6 +38,9 @@ module.exports = { return "any"; }, isDocumentObject(node, context, fullTypeChecker) { + console.log(`context: ${!!context}`); + console.log(`isTypeScriptParserServices: ${!!this.isTypeScriptParserServices(context.sourceCode.parserServices)}`); + console.log(`program: ${!!context.sourceCode.parserServices.program}`); if (fullTypeChecker) { console.log("fullTypeChecker is not null"); const type = this.getNodeTypeAsString(fullTypeChecker, node, context); From bd52d4bec4bd8f2da768dde48b1c391503657bcc Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Mon, 16 Sep 2024 23:19:26 -0700 Subject: [PATCH 09/30] More --- lib/ast-utils.js | 4 ---- lib/rules/no-cookies.js | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/ast-utils.js b/lib/ast-utils.js index 1ff7660..4e944b9 100644 --- a/lib/ast-utils.js +++ b/lib/ast-utils.js @@ -38,11 +38,7 @@ module.exports = { return "any"; }, isDocumentObject(node, context, fullTypeChecker) { - console.log(`context: ${!!context}`); - console.log(`isTypeScriptParserServices: ${!!this.isTypeScriptParserServices(context.sourceCode.parserServices)}`); - console.log(`program: ${!!context.sourceCode.parserServices.program}`); if (fullTypeChecker) { - console.log("fullTypeChecker is not null"); const type = this.getNodeTypeAsString(fullTypeChecker, node, context); return (type === "Document"); } diff --git a/lib/rules/no-cookies.js b/lib/rules/no-cookies.js index 19fc215..f350ae4 100644 --- a/lib/rules/no-cookies.js +++ b/lib/rules/no-cookies.js @@ -31,6 +31,7 @@ module.exports = { const fullTypeChecker = astUtils.getFullTypeChecker(context); return { "MemberExpression[property.name='cookie']"(node) { + console.log("cookie method hit"); if (astUtils.isDocumentObject(node.object, context, fullTypeChecker)) { context.report({ node: node, From db92c447b21dd8ac399ecd1434de0d8833355285 Mon Sep 17 00:00:00 2001 From: Jesse Parsons Date: Mon, 16 Sep 2024 23:32:17 -0700 Subject: [PATCH 10/30] Log package-log.json --- .../workflows/node-version-integration.yml | 3 +- out.log | 572 ++++++++++++++++++ 2 files changed, 574 insertions(+), 1 deletion(-) create mode 100644 out.log diff --git a/.github/workflows/node-version-integration.yml b/.github/workflows/node-version-integration.yml index 034d422..f357b63 100644 --- a/.github/workflows/node-version-integration.yml +++ b/.github/workflows/node-version-integration.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest] node-version: [20.x] steps: @@ -26,5 +26,6 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: npm i + - run: cat package-log.json - run: npm run build --if-present - run: npm test diff --git a/out.log b/out.log new file mode 100644 index 0000000..95037d2 --- /dev/null +++ b/out.log @@ -0,0 +1,572 @@ + +> @microsoft/eslint-plugin-sdl@0.2.2 test +> mocha tests --recursive + + + + no-angular-bypass-sanitizer + valid + √ bypassSecurityTrustHtml('XSS') + √ x.bypassSecurityTrustHtml() + √ x.BypassSecurityTrustHtml('XSS') + invalid + √ $('p').bypassSecurityTrustHtml('XSS'); + √ $('p').bypassSecurityTrustResourceUrl('XSS') + √ $('p').bypassSecurityTrustScript('XSS') + √ $('p').bypassSecurityTrustStyle('XSS') + √ $('p').bypassSecurityTrustUrl('XSS') + + no-angular-sanitization-trusted-urls + valid + √ aHrefSanitizationTrustedUrlList ('.*') + √ x.aHrefSanitizationTrustedUrlList ('.*') + √ $compileProvider.aHrefSanitizationTrustedUrlList () + √ $compileProvider.AHrefSanitizationTrustedUrlList ('.*') + invalid + √ $compileProvider.aHrefSanitizationTrustedUrlList ('.*'); + √ $compileProvider.imgSrcSanitizationTrustedUrlList('.*'); + + no-angularjs-bypass-sce + valid + √ trustAsHtml() + √ $sce.trustAsHtml() + √ $sce.trustAsHtml('') + √ $sce.TrustAsHtml('XSS') + √ x.trustAsHtml('XSS') + √ $sceProvider.enabled() + √ $sceProvider.enabled(true) + √ $sceProvider.enabled(1) + invalid + √ $sceDelegate.trustAs($sce.HTML, 'XSS') + √ $sce.trustAs($sce.HTML, 'XSS') + √ $sce.trustAsCss('XSS') + √ $sce.trustAsHtml('XSS') + √ $sce.trustAsJs('XSS') + √ $sce.trustAsResourceUrl('XSS') + √ $sce.trustAsUrl('XSS') + √ $sceProvider.enabled(false) + √ $sceProvider.enabled(0) + √ $sceProvider.enabled(true != true) + + no-angularjs-enable-svg + valid + √ enableSvg() + √ enableSvg(true) + √ $sanitizeProvider.enableSvg() + √ $sanitizeProvider.enableSvg(false) + √ $sanitizeProvider.enableSvg(0) + √ $sanitizeProvider.EnableSvg(0) + invalid + √ $sanitizeProvider.enableSvg(true) + √ $sanitizeProvider.enableSvg(1) + + no-angularjs-sanitization-whitelist + valid + √ aHrefSanitizationWhitelist('.*') + √ x.aHrefSanitizationWhitelist('.*') + √ $compileProvider.aHrefSanitizationWhitelist() + √ $compileProvider.AHrefSanitizationWhitelist('.*') + invalid + √ $compileProvider.aHrefSanitizationWhitelist('.*'); + √ $compileProvider.imgSrcSanitizationWhitelist('.*'); + + no-cookies + valid +cookie method hit +cookie method hit +cookie method hit + √ +function documentLikeAPIFunction(){ + return { + cookie:'fake.cookie' + } +} +var document2 = documentLikeAPIFunction(); +document2.cookie = '...'; +document2.cookie = '...'; +documentLikeAPIFunction().cookie = '...' + +cookie method hit +cookie method hit +cookie method hit + √ +interface DocumentLikeAPI { + cookie: string; +} +function documentLikeAPIFunction(): DocumentLikeAPI { + return null; +} +function X() { + // These usages are OK because they are not on the DOM document + var document: DocumentLikeAPI = documentLikeAPIFunction(); + document.cookie = '...'; + document.cookie = '...'; +} + +documentLikeAPIFunction().cookie = '...'; + (359ms) + invalid +cookie method hit + √ document.cookie = '...' +cookie method hit + √ window.document.cookie = '...' +cookie method hit + √ this.window.document.cookie = '...' +cookie method hit + √ globalThis.window.document.cookie = '...' +cookie method hit + √ +function documentFunction(): Document { + return window.document; +} +documentFunction().cookie = '...'; + +cookie method hit + √ +namespace Sample { + function method() { + return document.cookie; + } +} + + + no-document-domain + valid + √ +interface DocumentLikeAPI { + domain: string; +} +function documentLikeAPIFunction(): DocumentLikeAPI { + return null; +} +function main() { + var document: DocumentLikeAPI = documentLikeAPIFunction(); + document.domain = 'somevalue'; +} + + invalid + √ var doc = window.document; doc.domain = 'somevalue'; + √ document.domain = 'somevalue' + √ window.document.domain = 'somevalue' + √ +var somevalue = 'somevalue'; +document.domain = somevalue; +window.document.domain = somevalue; +newWindow.document.domain = somevalue; + + + no-document-write + valid + √ + interface DocumentLikeAPI { + write: ((arg : string) => void); + writeln: ((arg : string) => void); + } + function documentLikeAPIFunction() : DocumentLikeAPI { + return { + write: () => {}, + writeln: () => {}, + }; + } + + √ + function documentLikeAPIFunction() { + return { + write: function(){}, + writeln: function(){} + }; + } + var documentAPI = documentLikeAPIFunction(); + documentAPI.write('...'); + documentAPI.writeln('...'); + documentLikeAPIFunction().write('...'); + documentLikeAPIFunction().writeln('...'); + // wrong # of args + document.write(); + document.write('', ''); + document.writeln(); + document.writeln('', ''); + + invalid + √ + var doc = document; + doc.write('...'); + doc.writeln('...'); + function documentFunction() : Document { + return window.document; + } + documentFunction().write('...'); + documentFunction().writeln('...'); + + √ + document.write('...'); + document.writeln('...'); + window.document.write('...'); + window.document.writeln('...'); + newWindow.document.write('...'); + newWindow.document.writeln('...'); + + + no-electron-node-integration + valid + √ + var mainWindow = new BrowserWindow({ + webPreferences: { + nodeIntegration: false, + nodeIntegrationInWorker: false, + nodeIntegrationInSubFrames: false + } + }); + var view = new BrowserView({ + webPreferences: { + nodeIntegration: false + } + }); + + invalid + √ + var mainWindow = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + nodeIntegrationInWorker: true, + nodeIntegrationInSubFrames: true + } + }); + + √ + var view = new BrowserView({ + webPreferences: { + nodeIntegration: true, + nodeIntegrationInWorker: true, + nodeIntegrationInSubFrames: true + } + }); + + + no-html-method + valid + √ test.html = 'test' + √ test.html() + √ test.html('','') + √ element.html(''); + √ element.html(null); + invalid + √ $('p').html('XSS') + √ $(selector).html(sample_function()) + √ + import $ from "jquery"; + test.html('XSS'); + + + no-inner-html + valid + √ var test = element.innerHTML + √ var test = element.outerHTML + √ document.body.innerHTML = '' + √ document.test + √ element.insertAdjacentHTML() + √ + class Test { + innerHTML: string; + outerHTML: string; + constructor(test: string) { + this.innerHTML = test; + this.outerHTML = test; + } + }; + let test = new Test("test"); + test.innerHTML = test; + test.outerHTML = test; + + invalid + √ + var element = document.getElementById(id); + element.innerHTML = 'test'; + element.outerHTML = 'test'; + element.insertAdjacentHTML('beforebegin', 'foo'); + + √ + element.innerHTML = 'test'; + parent.child.innerHTML += 'test'; + + √ + element.outerHTML = 'test'; + parent.child.outerHTML += 'test'; + + √ element.insertAdjacentHTML('beforebegin', 'foo') + + no-insecure-random + valid + √ Math.Random; + √ Math.random; + √ math.random(); + √ random(); + √ + Math.Random; + Math.random; + math.random(); + random(); + + √ + require('./node_modules/not-unsafe-random'); + require('eslint'); + require('test'); + require('random-package'); + require('random-float2'); + require('random2-seed'); + + √ + import './node_modules/untest'; + import 'random'; + import 'random-3'; + import 'eslint'; + import 'eslint-plugin-sdl'; + import 'testing'; + + √ + cryptos.pseudoRandomBytes(); + pseudoRandomBytes(); + pseudoRandomByte(); + cryptos.pseudoRondomBytes(); + + √ + function random(){} + + random(); + + Math.Random; + Math.random; + + √ + function pseudoRandomBytes(){} + function pseudoRandomByte(){} + + pseudoRandomBytes(); + pseudoRandomByte(); + cryptos.pseudoRondomBytes(); + cryptos.pseudoRondomBytes(); + + invalid + √ + Math.random(); + crypto.pseudoRandomBytes(); + + √ + Math.random(); + this.Math.random(); + + √ + function notMath() : Math{ + return Math; + } + + notMath().random(); + + √ + crypto.pseudoRandomBytes(); + + √ + function notCrypto() : Crypto{ + return crypto; + } + + notCrypto().pseudoRandomBytes(); + + √ + import './node_modules/unique-random'; + import 'chance'; + import 'random-number'; + import 'random-int'; + import 'random-float'; + import 'random-seed'; + + √ + import * as chance1 from 'chance'; + import defaultExport from 'chance'; + import { chance } from 'chance'; + import { chance as chance2 } from 'chance'; + import { chance3, chance4 } from 'chance'; + + √ + require('./node_modules/unique-random'); + require('**/chance.js'); + require('random-number'); + require('random-int'); + require('random-float'); + require('random-seed'); + + + no-insecure-url + valid + √ + var x = 'https://www.example.com' + var y = 'ftps://www.example.com' + + √ + var x = `https://www.template-examples.com` + var y = `ftps://www.template-file-examples.com` + + √ + var x = `https://www.${multipartExample}.com` + var y = `ftps://www.${multipartExample}.com` + + √ var x = 'The protocol may be http://, https://, ftp:// or ftps://' + √ + function f(x : string = 'https://www.example.com') {} + function f(y : string = 'ftps://www.example.com') {} + + √ + var a1 = 'http://www.allow-example.com' + var a2 = 'HtTp://www.allow-example.com/path' + var b1 = 'FTP://www.allow-file-example.com' + var c1 = 'LDaP://www.allow-ldap-example.com' + + √ + var insecureURL = 'http://www.allow-example.com' + var InSeCuReURL = 'ftp://www.allow-example.com/path' + + √ + const someSvg: React.FC = () => { + return ( + + + ); + }; + (260ms) + √ + var x = "http://localhost/test"; + var y = "http://localhost"; + + √ + var x = "http://www.w3.org/1999/xhtml"; + var y = "http://www.w3.org/2000/svg"; + + invalid + √ + var x1 = 'http://www.examples.com' + var x2 = 'HTTP://www.examples.com' + var y1 = 'ftp://www.file-examples.com' + var y2 = 'FTP://www.file-examples.com' + + √ + var x1 = `http://www.template-examples.com` + var x2 = `HTTP://www.template-examples.com` + var y1 = `ftp://www.file-examples.com` + var y2 = `FTP://www.file-examples.com` + + √ + var x1 = `http://www.${multipartExample}.com`; + var y1 = `ftp://www.${multipartExample}.com`; + + √ + function f(x : string = 'http://www.example.com') {} + function f(y : string = 'ftp://www.example.com') {} + + √ + var a1 = 'http://www.ban-example.com' + var a2 = 'HTTP://www.ban-example.com/path' + var b1 = 'FtP://www.ban-file-example.com' + var c1 = 'LDAp://www.ban-ldap-example.com' + + √ + const someSvg: React.FC = () => { + return ( + + + ); + }; + + √ var a1 = "http://moz\u0009i\u0009lla.org"; + √ var x1 = `http://foo${multipartExample} http://${multipartExample}.com`; + √ var a1 = `http://moz\u0009i\u0009lla.org`; + + no-msapp-exec-unsafe + valid + √ test.execUnsafeLocalFunction = 'test' + √ MSApp.execUnsafeLocalFunction() + invalid + √ MSApp.execUnsafeLocalFunction(testfunc) + + no-postmessage-star-origin + valid + √ window.postMessage() + √ window.postMessage = '' + √ window.postMessage(1) + √ window.postMessage(1, 2, 3, 4) + √ window.postMessage('data', 'https://target.domain') + √ window.postMessage('data', 'https://target.domain', 'menubar=yes') + √ +class WindowLike { + postMessage(): void { + }; +} +function main() { + var w: WindowLike = new WindowLike(); + w.postMessage('test', '*'); +} + + invalid + √ + any.postMessage(message, "*"); + any.postMessage(message, "*", "menubar=yes"); + + √ + window.frames[0].postMessage(message, "*"); + var w1 = window.open(url); + w1.postMessage(message, "*"); + + + no-unsafe-alloc + valid + √ foo.allocUnsafe + √ Buffer.allocUnsafe(0) + √ Buffer.allocUnsafeSlow(0) + invalid + √ + var buf1 = Buffer.allocUnsafe(10); + var buf2 = Buffer.allocUnsafeSlow(10) + + + no-winjs-html-unsafe + valid + √ element.insertAdjacentHTMLUnsafe = "test"; + invalid + √ + WinJS.Utilities.insertAdjacentHTMLUnsafe(element, position, text); + WinJS.Utilities.setInnerHTMLUnsafe(element, text); + WinJS.Utilities.setOuterHTMLUnsafe(element, text); + + + react-iframe-missing-sandbox + valid + √
; + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + invalid + √ ; + √ + √ ; + √ - √ - √ - √ - √ - √ - √ - √ - √ - √ - √ - √ - √ - √ - √ - invalid - √ ; - √ - √ ; - √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + √ + invalid + √ ; + √ + √ ; + √