Apply prettier for consistent code formatting
This commit is contained in:
Родитель
5b9b57b04a
Коммит
7a5a085e08
|
@ -1,10 +1,9 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
|
@ -12,6 +11,7 @@ A clear and concise description of what the bug is.
|
|||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
|
@ -24,15 +24,17 @@ A clear and concise description of what you expected to happen.
|
|||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
|
|
|
@ -40,7 +40,7 @@ jobs:
|
|||
npm i typescript
|
||||
npm i @microsoft/eslint-formatter-sarif
|
||||
working-directory: ${{env.TEST_RUN_DIR}}
|
||||
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{env.GITHUB_REPO}}
|
||||
|
@ -55,12 +55,12 @@ jobs:
|
|||
- name: Install plugin dependencies
|
||||
run: npm install --production
|
||||
working-directory: ${{env.PLUGIN_DIR}}
|
||||
|
||||
|
||||
- name: Link plugin
|
||||
run: sudo npm link ../${{env.PLUGIN_DIR}}
|
||||
working-directory: ${{env.TEST_RUN_DIR}}
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
|
||||
- name: Link plugin
|
||||
run: npm link ../${{env.PLUGIN_DIR}}
|
||||
working-directory: ${{env.TEST_RUN_DIR}}
|
||||
|
@ -69,18 +69,18 @@ jobs:
|
|||
- name: Create ESLint config file
|
||||
run: echo 'module.exports = [...require("@microsoft/eslint-plugin-sdl").configs.recommended];' > eslint.config.js
|
||||
working-directory: ${{env.TEST_RUN_DIR}}
|
||||
|
||||
|
||||
- name: Run ESLint
|
||||
run: npx eslint
|
||||
--config eslint.config.js
|
||||
--no-config-lookup
|
||||
${{env.TEST_TARGET_DIR}}/${{env.GITHUB_REPO_ESLINT_GLOB}}
|
||||
--parser-options=project:${{env.TEST_TARGET_DIR}}/${{env.GITHUB_REPO_TSCONFIG}}
|
||||
--format @microsoft/eslint-formatter-sarif
|
||||
--output-file eslint-result-${{ matrix.os }}-${{github.run_id}}.sarif
|
||||
run: npx eslint
|
||||
--config eslint.config.js
|
||||
--no-config-lookup
|
||||
${{env.TEST_TARGET_DIR}}/${{env.GITHUB_REPO_ESLINT_GLOB}}
|
||||
--parser-options=project:${{env.TEST_TARGET_DIR}}/${{env.GITHUB_REPO_TSCONFIG}}
|
||||
--format @microsoft/eslint-formatter-sarif
|
||||
--output-file eslint-result-${{ matrix.os }}-${{github.run_id}}.sarif
|
||||
working-directory: ${{env.TEST_RUN_DIR}}
|
||||
continue-on-error: true
|
||||
|
||||
continue-on-error: true
|
||||
|
||||
- name: Upload ESLint results as artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
|
@ -11,7 +11,6 @@ on:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
|
@ -20,10 +19,10 @@ jobs:
|
|||
node-version: [18.x, 20.x, 22.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm install
|
||||
- run: npm test
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm install
|
||||
- run: npm test
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
SECURITY.md
|
||||
CODE_OF_CONDUCT.md
|
||||
package.json
|
||||
package-lock.json
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"printWidth": 100
|
||||
}
|
68
README.md
68
README.md
|
@ -12,7 +12,9 @@ Plugin is intended as a baseline for projects that follow [Microsoft Security De
|
|||
```sh
|
||||
npm install microsoft/eslint-plugin-sdl
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
yarn add microsoft/eslint-plugin-sdl
|
||||
```
|
||||
|
@ -24,9 +26,7 @@ Including an ESLint configuration file in your project allows you to customize h
|
|||
```js
|
||||
const pluginMicrosoftSdl = require("@microsoft/eslint-plugin-sdl");
|
||||
|
||||
module.exports = [
|
||||
...pluginMicrosoftSdl.configs.recommended
|
||||
];
|
||||
module.exports = [...pluginMicrosoftSdl.configs.recommended];
|
||||
```
|
||||
|
||||
ESLint will then only enforce rules you specify in the rules section of your configuration file at the [severity level](https://eslint.org/docs/latest/use/configure/rules) you designate. For example:
|
||||
|
@ -39,9 +39,9 @@ module.exports = [
|
|||
{
|
||||
rules: {
|
||||
"no-eval": "error",
|
||||
"@microsoft/sdl/no-inner-html": "error"
|
||||
}
|
||||
}
|
||||
"@microsoft/sdl/no-inner-html": "error",
|
||||
},
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
|
@ -65,36 +65,36 @@ Where possible, we leverage existing rules from [ESLint](https://eslint.org/docs
|
|||
|
||||
We also implemented several [custom rules](./lib/rules) where we did not find sufficient alternative in the community.
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
| [no-caller](https://eslint.org/docs/rules/no-caller) | Bans usage of deprecated functions `arguments.caller()` and `arguments.callee` that could potentially allow access to call stack. |
|
||||
| [no-delete-var](https://eslint.org/docs/rules/no-delete-var) | Bans usage of operator `delete` on variables as it can lead to unexpected behavior. |
|
||||
| [no-eval](https://eslint.org/docs/rules/no-eval) | Bans usage of [`eval()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval) that allows code execution from string argument. |
|
||||
| [no-implied-eval](https://eslint.org/docs/rules/no-implied-eval) | Bans usage of `setTimeout()`, `setInterval()` and `execScript()`. These functions are similar to `eval()` and prone to code execution. |
|
||||
| [no-new-func](https://eslint.org/docs/rules/no-new-func) | Bans calling `new Function()` as it's similar to `eval()` and prone to code execution. |
|
||||
| [node/no-deprecated-api](https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-deprecated-api.md) | Bans usage of deprecated APIs in Node. |
|
||||
| [@microsoft/sdl/no-angular-bypass-sanitizer](./docs/rules/no-angular-bypass-sanitizer.md) | Calls to bypassSecurityTrustHtml, bypassSecurityTrustScript and similar methods bypass [DomSanitizer](https://angular.io/api/platform-browser/DomSanitizer#security-risk) in Angular and need to be reviewed. |
|
||||
| [@microsoft/sdl/no-angularjs-bypass-sce](./docs/rules/no-angularjs-bypass-sce.md) | Calls to `$sceProvider.enabled(false)`, `$sceDelegate.trustAs()`, `$sce.trustAs()` and relevant shorthand methods (e.g. `trustAsHtml` or `trustAsJs`) bypass [Strict Contextual Escaping (SCE)](https://docs.angularjs.org/api/ng/service/$sce#strict-contextual-escaping) in AngularJS and need to be reviewed. |
|
||||
| [@microsoft/sdl/no-angularjs-enable-svg](./docs/rules/no-angularjs-enable-svg.md) | Calls to [`$sanitizeProvider.enableSvg(true)`](https://docs.angularjs.org/api/ngSanitize/provider/$sanitizeProvider#enableSvg) increase attack surface of the application by enabling SVG support in AngularJS sanitizer and need to be reviewed. |
|
||||
| [@microsoft/sdl/no-angularjs-sanitization-whitelist](./docs/rules/no-angularjs-sanitization-whitelist.md) | Calls to [`$compileProvider.aHrefSanitizationWhitelist`](https://docs.angularjs.org/api/ng/provider/$compileProvider#aHrefSanitizationWhitelist) or [`$compileProvider.imgSrcSanitizationWhitelist`](https://docs.angularjs.org/api/ng/provider/$compileProvider#imgSrcSanitizationWhitelist) configure whitelists in AngularJS sanitizer and need to be reviewed. |
|
||||
| [@microsoft/sdl/no-cookies](./docs/rules/no-cookies.md) | HTTP cookies are an old client-side storage mechanism with inherent risks and limitations. Use Web Storage, IndexedDB or other modern methods instead. |
|
||||
| [@microsoft/sdl/no-document-domain](./docs/rules/no-document-domain.md) | Writes to [`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain) property must be reviewed to avoid bypass of [same-origin checks](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin). Usage of top level domains such as `azurewebsites.net` is strictly prohibited. |
|
||||
| [@microsoft/sdl/no-document-write](./docs/rules/no-document-write.md) | Calls to document.write or document.writeln manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead. |
|
||||
| [@microsoft/sdl/no-electron-node-integration](./docs/rules/no-electron-node-integration.md) | [Node.js Integration](https://www.electronjs.org/docs/tutorial/security#2-do-not-enable-nodejs-integration-for-remote-content) must not be enabled in any renderer that loads remote content to avoid remote code execution attacks. |
|
||||
| [@microsoft/sdl/no-html-method](./docs/rules/no-html-method.md) | Direct calls to method `html()` often (e.g. in jQuery framework) manipulate DOM without any sanitization and should be avoided. Use document.createElement() or similar methods instead. |
|
||||
| [@microsoft/sdl/no-inner-html](./docs/rules/no-inner-html.md) | Assignments to innerHTML or outerHTML properties manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead. |
|
||||
| [@microsoft/sdl/no-insecure-url](./docs/rules/no-insecure-url.md) | Insecure protocols such as [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) or [FTP](https://en.wikipedia.org/wiki/File_Transfer_Protocol) should be replaced by their encrypted counterparts ([HTTPS](https://en.wikipedia.org/wiki/HTTPS), [FTPS](https://en.wikipedia.org/wiki/FTPS)) to avoid sending potentially sensitive data over untrusted networks in plaintext. |
|
||||
| [@microsoft/sdl/no-msapp-exec-unsafe](./docs/rules/no-msapp-exec-unsafe.md) | Calls to [`MSApp.execUnsafeLocalFunction()`](https://docs.microsoft.com/en-us/previous-versions/hh772324(v=vs.85)) bypass script injection validation and should be avoided. |
|
||||
| [@microsoft/sdl/no-postmessage-star-origin](./docs/rules/no-postmessage-star-origin.md) | Always provide specific target origin, not * when sending data to other windows using [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Security_concerns) to avoid data leakage outside of trust boundary. |
|
||||
| [@microsoft/sdl/no-unsafe-alloc](./docs/rules/no-unsafe-alloc.md) | When calling [`Buffer.allocUnsafe`](https://nodejs.org/api/buffer.html#buffer_static_method_buffer_allocunsafe_size) and [`Buffer.allocUnsafeSlow`](https://nodejs.org/api/buffer.html#buffer_static_method_buffer_allocunsafeslow_size), the allocated memory is not wiped-out and can contain old, potentially sensitive data. |
|
||||
| [@microsoft/sdl/no-winjs-html-unsafe](./docs/rules/no-winjs-html-unsafe.md) | Calls to [`WinJS.Utilities.setInnerHTMLUnsafe()`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211696(v=win.10)) and similar methods do not perform any input validation and should be avoided. Use [`WinJS.Utilities.setInnerHTML()`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211697(v=win.10)) instead. |
|
||||
| [@microsoft/sdl/react-iframe-missing-sandbox](./docs/rules/react-iframe-missing-sandbox.md) | The [sandbox](https://www.w3schools.com/tags/att_iframe_sandbox.asp) attribute enables an extra set of restrictions for the content in the iframe and should always be specified. |
|
||||
| [react/no-danger](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md) | Bans usage of `dangerouslySetInnerHTML` property in React as it allows passing unsanitized HTML in DOM. |
|
||||
| [@typescript-eslint/no-implied-eval](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-implied-eval.md) | Similar to built-in ESLint rule `no-implied-eval`. Bans usage of `setTimeout()`, `setInterval()`, `setImmediate()`, `execScript()` or `new Function()` as they are similar to `eval()` and allow code execution from string arguments. |
|
||||
| Name | Description |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [no-caller](https://eslint.org/docs/rules/no-caller) | Bans usage of deprecated functions `arguments.caller()` and `arguments.callee` that could potentially allow access to call stack. |
|
||||
| [no-delete-var](https://eslint.org/docs/rules/no-delete-var) | Bans usage of operator `delete` on variables as it can lead to unexpected behavior. |
|
||||
| [no-eval](https://eslint.org/docs/rules/no-eval) | Bans usage of [`eval()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval) that allows code execution from string argument. |
|
||||
| [no-implied-eval](https://eslint.org/docs/rules/no-implied-eval) | Bans usage of `setTimeout()`, `setInterval()` and `execScript()`. These functions are similar to `eval()` and prone to code execution. |
|
||||
| [no-new-func](https://eslint.org/docs/rules/no-new-func) | Bans calling `new Function()` as it's similar to `eval()` and prone to code execution. |
|
||||
| [node/no-deprecated-api](https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-deprecated-api.md) | Bans usage of deprecated APIs in Node. |
|
||||
| [@microsoft/sdl/no-angular-bypass-sanitizer](./docs/rules/no-angular-bypass-sanitizer.md) | Calls to bypassSecurityTrustHtml, bypassSecurityTrustScript and similar methods bypass [DomSanitizer](https://angular.io/api/platform-browser/DomSanitizer#security-risk) in Angular and need to be reviewed. |
|
||||
| [@microsoft/sdl/no-angularjs-bypass-sce](./docs/rules/no-angularjs-bypass-sce.md) | Calls to `$sceProvider.enabled(false)`, `$sceDelegate.trustAs()`, `$sce.trustAs()` and relevant shorthand methods (e.g. `trustAsHtml` or `trustAsJs`) bypass [Strict Contextual Escaping (SCE)](https://docs.angularjs.org/api/ng/service/$sce#strict-contextual-escaping) in AngularJS and need to be reviewed. |
|
||||
| [@microsoft/sdl/no-angularjs-enable-svg](./docs/rules/no-angularjs-enable-svg.md) | Calls to [`$sanitizeProvider.enableSvg(true)`](https://docs.angularjs.org/api/ngSanitize/provider/$sanitizeProvider#enableSvg) increase attack surface of the application by enabling SVG support in AngularJS sanitizer and need to be reviewed. |
|
||||
| [@microsoft/sdl/no-angularjs-sanitization-whitelist](./docs/rules/no-angularjs-sanitization-whitelist.md) | Calls to [`$compileProvider.aHrefSanitizationWhitelist`](https://docs.angularjs.org/api/ng/provider/$compileProvider#aHrefSanitizationWhitelist) or [`$compileProvider.imgSrcSanitizationWhitelist`](https://docs.angularjs.org/api/ng/provider/$compileProvider#imgSrcSanitizationWhitelist) configure whitelists in AngularJS sanitizer and need to be reviewed. |
|
||||
| [@microsoft/sdl/no-cookies](./docs/rules/no-cookies.md) | HTTP cookies are an old client-side storage mechanism with inherent risks and limitations. Use Web Storage, IndexedDB or other modern methods instead. |
|
||||
| [@microsoft/sdl/no-document-domain](./docs/rules/no-document-domain.md) | Writes to [`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain) property must be reviewed to avoid bypass of [same-origin checks](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin). Usage of top level domains such as `azurewebsites.net` is strictly prohibited. |
|
||||
| [@microsoft/sdl/no-document-write](./docs/rules/no-document-write.md) | Calls to document.write or document.writeln manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead. |
|
||||
| [@microsoft/sdl/no-electron-node-integration](./docs/rules/no-electron-node-integration.md) | [Node.js Integration](https://www.electronjs.org/docs/tutorial/security#2-do-not-enable-nodejs-integration-for-remote-content) must not be enabled in any renderer that loads remote content to avoid remote code execution attacks. |
|
||||
| [@microsoft/sdl/no-html-method](./docs/rules/no-html-method.md) | Direct calls to method `html()` often (e.g. in jQuery framework) manipulate DOM without any sanitization and should be avoided. Use document.createElement() or similar methods instead. |
|
||||
| [@microsoft/sdl/no-inner-html](./docs/rules/no-inner-html.md) | Assignments to innerHTML or outerHTML properties manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead. |
|
||||
| [@microsoft/sdl/no-insecure-url](./docs/rules/no-insecure-url.md) | Insecure protocols such as [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) or [FTP](https://en.wikipedia.org/wiki/File_Transfer_Protocol) should be replaced by their encrypted counterparts ([HTTPS](https://en.wikipedia.org/wiki/HTTPS), [FTPS](https://en.wikipedia.org/wiki/FTPS)) to avoid sending potentially sensitive data over untrusted networks in plaintext. |
|
||||
| [@microsoft/sdl/no-msapp-exec-unsafe](./docs/rules/no-msapp-exec-unsafe.md) | Calls to [`MSApp.execUnsafeLocalFunction()`](<https://docs.microsoft.com/en-us/previous-versions/hh772324(v=vs.85)>) bypass script injection validation and should be avoided. |
|
||||
| [@microsoft/sdl/no-postmessage-star-origin](./docs/rules/no-postmessage-star-origin.md) | Always provide specific target origin, not \* when sending data to other windows using [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Security_concerns) to avoid data leakage outside of trust boundary. |
|
||||
| [@microsoft/sdl/no-unsafe-alloc](./docs/rules/no-unsafe-alloc.md) | When calling [`Buffer.allocUnsafe`](https://nodejs.org/api/buffer.html#buffer_static_method_buffer_allocunsafe_size) and [`Buffer.allocUnsafeSlow`](https://nodejs.org/api/buffer.html#buffer_static_method_buffer_allocunsafeslow_size), the allocated memory is not wiped-out and can contain old, potentially sensitive data. |
|
||||
| [@microsoft/sdl/no-winjs-html-unsafe](./docs/rules/no-winjs-html-unsafe.md) | Calls to [`WinJS.Utilities.setInnerHTMLUnsafe()`](<https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211696(v=win.10)>) and similar methods do not perform any input validation and should be avoided. Use [`WinJS.Utilities.setInnerHTML()`](<https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211697(v=win.10)>) instead. |
|
||||
| [@microsoft/sdl/react-iframe-missing-sandbox](./docs/rules/react-iframe-missing-sandbox.md) | The [sandbox](https://www.w3schools.com/tags/att_iframe_sandbox.asp) attribute enables an extra set of restrictions for the content in the iframe and should always be specified. |
|
||||
| [react/no-danger](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md) | Bans usage of `dangerouslySetInnerHTML` property in React as it allows passing unsanitized HTML in DOM. |
|
||||
| [@typescript-eslint/no-implied-eval](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-implied-eval.md) | Similar to built-in ESLint rule `no-implied-eval`. Bans usage of `setTimeout()`, `setInterval()`, `setImmediate()`, `execScript()` or `new Function()` as they are similar to `eval()` and allow code execution from string arguments. |
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||
|
||||
|
@ -104,4 +104,4 @@ provided by the bot. You will only need to do this once across all repos using o
|
|||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
// Generates shareable config for modern Angular (https://angular.dev/) apps.
|
||||
// Generates shareable config for modern Angular (https://angular.dev/) apps.
|
||||
module.exports = (pluginSdl) => {
|
||||
return [
|
||||
{
|
||||
plugins: {
|
||||
"@microsoft/sdl": pluginSdl
|
||||
"@microsoft/sdl": pluginSdl,
|
||||
},
|
||||
rules: {
|
||||
"@microsoft/sdl/no-angular-bypass-sanitizer": "error"
|
||||
}
|
||||
}
|
||||
"@microsoft/sdl/no-angular-bypass-sanitizer": "error",
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,18 +3,18 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
// Generates shareable config for legacy AngularJS (https://angularjs.org/) apps.
|
||||
// Generates shareable config for legacy AngularJS (https://angularjs.org/) apps.
|
||||
module.exports = (pluginSdl) => {
|
||||
return [
|
||||
{
|
||||
plugins: {
|
||||
"@microsoft/sdl": pluginSdl
|
||||
"@microsoft/sdl": pluginSdl,
|
||||
},
|
||||
rules: {
|
||||
"@microsoft/sdl/no-angularjs-enable-svg": "error",
|
||||
"@microsoft/sdl/no-angularjs-sanitization-whitelist": "error",
|
||||
"@microsoft/sdl/no-angularjs-bypass-sce": "error"
|
||||
}
|
||||
}
|
||||
"@microsoft/sdl/no-angularjs-bypass-sce": "error",
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ module.exports = (pluginSdl) => {
|
|||
return [
|
||||
{
|
||||
plugins: {
|
||||
"@microsoft/sdl": pluginSdl
|
||||
"@microsoft/sdl": pluginSdl,
|
||||
},
|
||||
rules: {
|
||||
"no-caller": "error",
|
||||
|
@ -23,8 +23,8 @@ module.exports = (pluginSdl) => {
|
|||
"@microsoft/sdl/no-insecure-url": "error",
|
||||
"@microsoft/sdl/no-msapp-exec-unsafe": "error",
|
||||
"@microsoft/sdl/no-postmessage-star-origin": "error",
|
||||
"@microsoft/sdl/no-winjs-html-unsafe": "error"
|
||||
}
|
||||
}
|
||||
"@microsoft/sdl/no-winjs-html-unsafe": "error",
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -7,11 +7,11 @@ module.exports = (pluginSdl) => {
|
|||
return [
|
||||
{
|
||||
plugins: {
|
||||
"@microsoft/sdl": pluginSdl
|
||||
"@microsoft/sdl": pluginSdl,
|
||||
},
|
||||
rules: {
|
||||
"@microsoft/sdl/no-electron-node-integration": "error"
|
||||
}
|
||||
}
|
||||
"@microsoft/sdl/no-electron-node-integration": "error",
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -9,19 +9,19 @@ module.exports = (pluginSdl) => {
|
|||
return [
|
||||
{
|
||||
plugins: {
|
||||
n: pluginN
|
||||
n: pluginN,
|
||||
},
|
||||
rules: {
|
||||
"n/no-deprecated-api": "error"
|
||||
}
|
||||
"n/no-deprecated-api": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
"@microsoft/sdl": pluginSdl
|
||||
"@microsoft/sdl": pluginSdl,
|
||||
},
|
||||
rules: {
|
||||
"@microsoft/sdl/no-unsafe-alloc": "error"
|
||||
}
|
||||
"@microsoft/sdl/no-unsafe-alloc": "error",
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -11,33 +11,34 @@ module.exports = (pluginSdl) => {
|
|||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
}
|
||||
}
|
||||
}
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
"react": pluginReact
|
||||
react: pluginReact,
|
||||
},
|
||||
rules: {
|
||||
"react/no-danger": "error",
|
||||
"react/jsx-no-target-blank": ["error",
|
||||
"react/jsx-no-target-blank": [
|
||||
"error",
|
||||
{
|
||||
allowReferrer: false,
|
||||
enforceDynamicLinks: "always",
|
||||
warnOnSpreadAttributes: true,
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
"@microsoft/sdl": pluginSdl,
|
||||
},
|
||||
rules: {
|
||||
"@microsoft/sdl/react-iframe-missing-sandbox": "error"
|
||||
}
|
||||
}
|
||||
"@microsoft/sdl/react-iframe-missing-sandbox": "error",
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -13,28 +13,28 @@ module.exports = () => {
|
|||
ecmaVersion: 6,
|
||||
sourceType: "module",
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
}
|
||||
}
|
||||
}
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["**/*.{ts,tsx}"],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
parser: "@typescript-eslint/parser",
|
||||
}
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
"@typescript-eslint": pluginTypescript
|
||||
"@typescript-eslint": pluginTypescript,
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-implied-eval": "error",
|
||||
// @typescript-eslint/no-implied-eval offers more accurate results for typescript.
|
||||
// thus we turn the more generic rule off for ts and tsx files.
|
||||
// This also avoids duplicate hits.
|
||||
"no-implied-eval": "off"
|
||||
}
|
||||
}
|
||||
"no-implied-eval": "off",
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -4,4 +4,4 @@ Calls to `$sceProvider.enabled(false)`, `$sceDelegate.trustAs()`, `$sce.trustAs(
|
|||
|
||||
SCE should be bypassed only in very rare and justifiable cases after careful review so that the risk of introducing Cross-Site-Scripting (XSS) vulnerability is minimized.
|
||||
|
||||
See [official documentation](https://docs.angularjs.org/api/ng/service/$sce#strict-contextual-escaping) for more details.
|
||||
See [official documentation](https://docs.angularjs.org/api/ng/service/$sce#strict-contextual-escaping) for more details.
|
||||
|
|
|
@ -6,8 +6,8 @@ Cookies should be used only in rare and justifiable cases after thorough securit
|
|||
|
||||
## Further Reading
|
||||
|
||||
* [Using HTTP cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)
|
||||
- [Using HTTP cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)
|
||||
|
||||
## Related Rules
|
||||
|
||||
* [tslint-microsoft-contrib/no-cookies](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noCookiesRule.ts)
|
||||
- [tslint-microsoft-contrib/no-cookies](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noCookiesRule.ts)
|
||||
|
|
|
@ -4,4 +4,4 @@ Writes to [`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/D
|
|||
|
||||
## Related Rules
|
||||
|
||||
* [tslint-microsoft-contrib/no-document-domain](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noDocumentDomainRule.ts)
|
||||
- [tslint-microsoft-contrib/no-document-domain](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noDocumentDomainRule.ts)
|
||||
|
|
|
@ -4,4 +4,4 @@ Calls to document.write or document.writeln manipulate DOM directly without any
|
|||
|
||||
## Related Rules
|
||||
|
||||
* [tslint-microsoft-contrib/no-document-write](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noDocumentWriteRule.ts)
|
||||
- [tslint-microsoft-contrib/no-document-write](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noDocumentWriteRule.ts)
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
|
||||
## Related Rules
|
||||
|
||||
* [codeql/js/enabling-electron-renderer-node-integration](https://help.semmle.com/wiki/display/JS/Enabling+Node.js+integration+for+Electron+web+content+renderers)
|
||||
- [codeql/js/enabling-electron-renderer-node-integration](https://help.semmle.com/wiki/display/JS/Enabling+Node.js+integration+for+Electron+web+content+renderers)
|
||||
|
|
|
@ -4,4 +4,4 @@ Direct calls to method `html()` often (e.g. in jQuery framework) manipulate DOM
|
|||
|
||||
## Related Rules
|
||||
|
||||
* [tslint-microsoft-contrib/no-inner-html](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noInnerHtml.ts)
|
||||
- [tslint-microsoft-contrib/no-inner-html](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noInnerHtml.ts)
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
Assignments to [innerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)/[outerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML) properties or calls to [insertAdjacentHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML) method manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead.
|
||||
|
||||
* [Rule Source](../../lib/rules/no-inner-html.js)
|
||||
* [Rule Test](../../tests/lib/rules/no-inner-html.js)
|
||||
- [Rule Source](../../lib/rules/no-inner-html.js)
|
||||
- [Rule Test](../../tests/lib/rules/no-inner-html.js)
|
||||
|
||||
## Related Rules
|
||||
|
||||
* [tslint-microsoft-contrib/no-inner-html](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noInnerHtml.ts)
|
||||
* [eslint-plugin-no-unsanitized](https://github.com/mozilla/eslint-plugin-no-unsanitized/blob/master/docs/rules/method.md)
|
||||
- [tslint-microsoft-contrib/no-inner-html](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noInnerHtml.ts)
|
||||
- [eslint-plugin-no-unsanitized](https://github.com/mozilla/eslint-plugin-no-unsanitized/blob/master/docs/rules/method.md)
|
||||
|
|
|
@ -6,12 +6,12 @@ Use crypto.randomBytes() or window.crypto.getRandomValues() instead.
|
|||
|
||||
## Related Rules
|
||||
|
||||
* [tslint-microsoft-contrib/no-insecure-random](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/insecureRandomRule.ts)
|
||||
- https://help.semmle.com/wiki/display/JS/Insecure+randomness
|
||||
- [source](https://github.com/github/codeql/blob/master/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll)
|
||||
- https://vulncat.fortify.com/en/detail?id=desc.semantic.abap.insecure_randomness#JavaScript
|
||||
- https://rules.sonarsource.com/javascript/RSPEC-2245
|
||||
- [source](https://github.com/SonarSource/SonarJS/blob/master/eslint-bridge/src/rules/pseudo-random.ts)
|
||||
- https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-pseudoRandomBytes.js
|
||||
- https://github.com/gkouziik/eslint-plugin-security-node/blob/master/lib/rules/detect-insecure-randomness.js
|
||||
- [tslint-microsoft-contrib/no-insecure-random](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/insecureRandomRule.ts)
|
||||
|
||||
* https://help.semmle.com/wiki/display/JS/Insecure+randomness
|
||||
- [source](https://github.com/github/codeql/blob/master/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll)
|
||||
* https://vulncat.fortify.com/en/detail?id=desc.semantic.abap.insecure_randomness#JavaScript
|
||||
* https://rules.sonarsource.com/javascript/RSPEC-2245
|
||||
- [source](https://github.com/SonarSource/SonarJS/blob/master/eslint-bridge/src/rules/pseudo-random.ts)
|
||||
* https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-pseudoRandomBytes.js
|
||||
* https://github.com/gkouziik/eslint-plugin-security-node/blob/master/lib/rules/detect-insecure-randomness.js
|
||||
|
|
|
@ -6,7 +6,9 @@ Insecure protocols such as [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transf
|
|||
- [Rule Test](../../tests/lib/rules/no-insecure-url.js)
|
||||
|
||||
## Options
|
||||
|
||||
This rule comes with three [default lists](../../lib/rules/no-insecure-url.js#L13):
|
||||
|
||||
- **blocklist** - a RegEx list of insecure URL patterns.
|
||||
- **exceptions** - a RegEx list of common false positive patterns. For example, HTTP URLs to XML schemas are usually allowed as they are used as identifiers, not for establishing actual network connections.
|
||||
- **varExceptions** - a RegEx list of false positive patterns which a derivated from the variable name. For example, a variable that is called "insecureURL" which is used to test HTTP explicitly.
|
||||
|
@ -14,7 +16,9 @@ This rule comes with three [default lists](../../lib/rules/no-insecure-url.js#L1
|
|||
These lists can be overrided by providing options.
|
||||
|
||||
---
|
||||
|
||||
For example, providing these options... :
|
||||
|
||||
```javascript
|
||||
"@microsoft/sdl/no-insecure-url": ["error", {
|
||||
"blocklist": ["^(http|ftp):\\/\\/", "^https:\\/\\/www\\.disallow-example\\.com"],
|
||||
|
@ -24,21 +28,25 @@ For example, providing these options... :
|
|||
```
|
||||
|
||||
... overrides the internal blocklist, blocking the following URL patterns... :
|
||||
|
||||
- `http://`...
|
||||
- `ftp://`...
|
||||
- `https://www.disallow-example.com`
|
||||
|
||||
... and also overrides the internal exceptions list, allowing the following URL patterns as exceptions.:
|
||||
|
||||
- `http://schemas.microsoft.com`
|
||||
- `http://schemas.microsoft.com/sharepoint`
|
||||
- `http://schemas.microsoft.com/path/subpath`
|
||||
|
||||
... and also overrides the internal variable exceptions list, allowing the following declaration name patterns as exceptions.:
|
||||
|
||||
- `var insecureURL = "http://..."`
|
||||
- `var insecureWebsite = "http://..."`
|
||||
- ...
|
||||
|
||||
URLs in neither the blocklist nor the exceptions list, are allowed:
|
||||
|
||||
- `telnet://`...
|
||||
- `ws://`...
|
||||
- ...
|
||||
|
@ -46,16 +54,19 @@ URLs in neither the blocklist nor the exceptions list, are allowed:
|
|||
---
|
||||
|
||||
**Note**: The RegEx for the lists is provided within a string in a JSON. It is without delimiting slashes `/ /` and thus users cannot pass RegEx parameters. We make it case-insensitive after user input. Do not forget to escape characters:
|
||||
|
||||
```javascript
|
||||
let pureRegex = /^https:\/\/www\.disallow-example\.com/;
|
||||
let regexInString = "^https:\\/\\/www\\.disallow-example\\.com";
|
||||
```
|
||||
|
||||
## Related Rules
|
||||
* [tslint-microsoft-contrib/no-http-string](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noHttpStringRule.ts)
|
||||
* [CodeQL/InsecureDownloadCustomizations.qll](https://github.com/github/codeql/blob/master/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll#L62)
|
||||
* [DevSkim/DS137138](https://github.com/microsoft/DevSkim/blob/main/guidance/DS137138.md)
|
||||
* [Fortify/insecure_transport](https://vulncat.fortify.com/en/detail?id=desc.config.java.insecure_transport#JavaScript%2fTypeScript)
|
||||
|
||||
- [tslint-microsoft-contrib/no-http-string](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/noHttpStringRule.ts)
|
||||
- [CodeQL/InsecureDownloadCustomizations.qll](https://github.com/github/codeql/blob/master/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll#L62)
|
||||
- [DevSkim/DS137138](https://github.com/microsoft/DevSkim/blob/main/guidance/DS137138.md)
|
||||
- [Fortify/insecure_transport](https://vulncat.fortify.com/en/detail?id=desc.config.java.insecure_transport#JavaScript%2fTypeScript)
|
||||
|
||||
## Further Reading
|
||||
* [HTTPS Everywhere](https://en.wikipedia.org/wiki/HTTPS_Everywhere)
|
||||
|
||||
- [HTTPS Everywhere](https://en.wikipedia.org/wiki/HTTPS_Everywhere)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Do not use * as target origin when sending data to other windows (no-postmessage-star-origin)
|
||||
# Do not use \* as target origin when sending data to other windows (no-postmessage-star-origin)
|
||||
|
||||
Always provide specific target origin, not * when sending data to other windows using [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Security_concerns) to avoid data leakage outside of trust boundary.
|
||||
Always provide specific target origin, not \* when sending data to other windows using [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Security_concerns) to avoid data leakage outside of trust boundary.
|
||||
|
|
|
@ -4,9 +4,9 @@ When calling [`Buffer.allocUnsafe`](https://nodejs.org/api/buffer.html#buffer_st
|
|||
|
||||
These methods should be used only in justifiable cases (e.g. due to performance reasons) after thorough security review.
|
||||
|
||||
* [Rule Source](../../lib/rules/no-unsafe-alloc.js)
|
||||
* [Rule Test](../../tests/lib/rules/no-unsafe-alloc.js)
|
||||
- [Rule Source](../../lib/rules/no-unsafe-alloc.js)
|
||||
- [Rule Test](../../tests/lib/rules/no-unsafe-alloc.js)
|
||||
|
||||
## Resources
|
||||
|
||||
* [Node.js - What makes Buffer.allocUnsafe() and Buffer.allocUnsafeSlow() "unsafe"?](https://nodejs.org/api/buffer.html#buffer_what_makes_buffer_allocunsafe_and_buffer_allocunsafeslow_unsafe)
|
||||
- [Node.js - What makes Buffer.allocUnsafe() and Buffer.allocUnsafeSlow() "unsafe"?](https://nodejs.org/api/buffer.html#buffer_what_makes_buffer_allocunsafe_and_buffer_allocunsafeslow_unsafe)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Do not set HTML using unsafe methods from WinJS.Utilities (no-winjs-html-unsafe)
|
||||
|
||||
Calls to [`setInnerHTMLUnsafe`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211696(v=win.10)), [`setOuterHTMLUnsafe`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211698(v=win.10)) or [`insertAdjacentHTMLUnsafe`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br229832(v=win.10)) methods from [Windows Library for JavaScript](https://docs.microsoft.com/en-us/previous-versions/windows/apps/mt502392(v=win.10)) do not perform input validation and should be avoided. Use alternate methods such as [`setInnerHTML`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211697(v=win.10)) instead.
|
||||
Calls to [`setInnerHTMLUnsafe`](<https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211696(v=win.10)>), [`setOuterHTMLUnsafe`](<https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211698(v=win.10)>) or [`insertAdjacentHTMLUnsafe`](<https://docs.microsoft.com/en-us/previous-versions/windows/apps/br229832(v=win.10)>) methods from [Windows Library for JavaScript](<https://docs.microsoft.com/en-us/previous-versions/windows/apps/mt502392(v=win.10)>) do not perform input validation and should be avoided. Use alternate methods such as [`setInnerHTML`](<https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211697(v=win.10)>) instead.
|
||||
|
|
|
@ -4,14 +4,14 @@ The [sandbox](https://www.w3schools.com/tags/att_iframe_sandbox.asp) attribute e
|
|||
|
||||
Additional functionality such as the ability to run scripts should be enabled only in justifiable cases after thorough security review.
|
||||
|
||||
* [Rule Source](../../lib/rules/react-iframe-missing-sandbox.js)
|
||||
* [Rule Test](../../tests/lib/rules/react-iframe-missing-sandbox.js)
|
||||
- [Rule Source](../../lib/rules/react-iframe-missing-sandbox.js)
|
||||
- [Rule Test](../../tests/lib/rules/react-iframe-missing-sandbox.js)
|
||||
|
||||
## Related Rules
|
||||
|
||||
* [tslint-microsoft-contrib/react-iframe-missing-sandbox](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/reactIframeMissingSandboxRule.ts)
|
||||
- [tslint-microsoft-contrib/react-iframe-missing-sandbox](https://github.com/microsoft/tslint-microsoft-contrib/blob/master/src/reactIframeMissingSandboxRule.ts)
|
||||
|
||||
## More Reading
|
||||
|
||||
* [How to safely inject HTML in React using an iframe](https://medium.com/the-thinkmill/how-to-safely-inject-html-in-react-using-an-iframe-adc775d458bc)
|
||||
* [Play safely in sandboxed IFrames](https://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/)
|
||||
- [How to safely inject HTML in React using an iframe](https://medium.com/the-thinkmill/how-to-safely-inject-html-in-react-using-an-iframe-adc775d458bc)
|
||||
- [Play safely in sandboxed IFrames](https://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/)
|
||||
|
|
121
lib/ast-utils.js
121
lib/ast-utils.js
|
@ -8,67 +8,62 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
isTypeScriptParserServices(parserServices) {
|
||||
// Check properties specific to @typescript-eslint/parser
|
||||
return (
|
||||
parserServices &&
|
||||
parserServices.program &&
|
||||
parserServices.esTreeNodeToTSNodeMap &&
|
||||
parserServices.tsNodeToESTreeNodeMap
|
||||
);
|
||||
},
|
||||
hasFullTypeInformation(context) {
|
||||
var hasFullTypeInformation = (
|
||||
context &&
|
||||
context.sourceCode &&
|
||||
context.sourceCode.parserServices &&
|
||||
this.isTypeScriptParserServices(context.sourceCode.parserServices)
|
||||
);
|
||||
return hasFullTypeInformation;
|
||||
},
|
||||
getFullTypeChecker(context) {
|
||||
return this.hasFullTypeInformation(context) ? context.sourceCode.parserServices.program.getTypeChecker() : null;
|
||||
},
|
||||
getNodeTypeAsString(fullTypeChecker, node, context) {
|
||||
if (fullTypeChecker && node) {
|
||||
const tsNode = context.sourceCode.parserServices.esTreeNodeToTSNodeMap.get(node);
|
||||
const tsType = fullTypeChecker.getTypeAtLocation(tsNode);
|
||||
const type = fullTypeChecker.typeToString(tsType);
|
||||
return type;
|
||||
}
|
||||
return "any";
|
||||
},
|
||||
isDocumentObject(node, context, fullTypeChecker) {
|
||||
if (fullTypeChecker) {
|
||||
const type = this.getNodeTypeAsString(fullTypeChecker, node, context);
|
||||
return (type === "Document");
|
||||
}
|
||||
|
||||
// Best-effort checking without Type information
|
||||
switch (node.type) {
|
||||
case "Identifier":
|
||||
return node != undefined && node.name == "document";
|
||||
case "MemberExpression":
|
||||
return (
|
||||
node != undefined &&
|
||||
node.property != undefined &&
|
||||
node.property.name == "document" && (
|
||||
(node.object != undefined &&
|
||||
typeof node.object.name === "string" &&
|
||||
node.object.name.toLowerCase().endsWith('window')) ||
|
||||
(
|
||||
node.object != undefined &&
|
||||
node.object.property != undefined &&
|
||||
node.object.property.name == "window" &&
|
||||
(
|
||||
|
||||
(node.object.object != undefined && node.object.object.type == "ThisExpression") ||
|
||||
(node.object.object != undefined && node.object.object.name == "globalThis")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
return false;
|
||||
isTypeScriptParserServices(parserServices) {
|
||||
// Check properties specific to @typescript-eslint/parser
|
||||
return (
|
||||
parserServices &&
|
||||
parserServices.program &&
|
||||
parserServices.esTreeNodeToTSNodeMap &&
|
||||
parserServices.tsNodeToESTreeNodeMap
|
||||
);
|
||||
},
|
||||
hasFullTypeInformation(context) {
|
||||
var hasFullTypeInformation =
|
||||
context &&
|
||||
context.sourceCode &&
|
||||
context.sourceCode.parserServices &&
|
||||
this.isTypeScriptParserServices(context.sourceCode.parserServices);
|
||||
return hasFullTypeInformation;
|
||||
},
|
||||
getFullTypeChecker(context) {
|
||||
return this.hasFullTypeInformation(context)
|
||||
? context.sourceCode.parserServices.program.getTypeChecker()
|
||||
: null;
|
||||
},
|
||||
getNodeTypeAsString(fullTypeChecker, node, context) {
|
||||
if (fullTypeChecker && node) {
|
||||
const tsNode = context.sourceCode.parserServices.esTreeNodeToTSNodeMap.get(node);
|
||||
const tsType = fullTypeChecker.getTypeAtLocation(tsNode);
|
||||
const type = fullTypeChecker.typeToString(tsType);
|
||||
return type;
|
||||
}
|
||||
};
|
||||
return "any";
|
||||
},
|
||||
isDocumentObject(node, context, fullTypeChecker) {
|
||||
if (fullTypeChecker) {
|
||||
const type = this.getNodeTypeAsString(fullTypeChecker, node, context);
|
||||
return type === "Document";
|
||||
}
|
||||
|
||||
// Best-effort checking without Type information
|
||||
switch (node.type) {
|
||||
case "Identifier":
|
||||
return node != undefined && node.name == "document";
|
||||
case "MemberExpression":
|
||||
return (
|
||||
node != undefined &&
|
||||
node.property != undefined &&
|
||||
node.property.name == "document" &&
|
||||
((node.object != undefined &&
|
||||
typeof node.object.name === "string" &&
|
||||
node.object.name.toLowerCase().endsWith("window")) ||
|
||||
(node.object != undefined &&
|
||||
node.object.property != undefined &&
|
||||
node.object.property.name == "window" &&
|
||||
((node.object.object != undefined && node.object.object.type == "ThisExpression") ||
|
||||
(node.object.object != undefined && node.object.object.name == "globalThis"))))
|
||||
);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
|
79
lib/index.js
79
lib/index.js
|
@ -9,32 +9,32 @@ const pluginSecurity = require("eslint-plugin-security");
|
|||
const pkg = require(path.join("..", "package.json"));
|
||||
|
||||
const plugin = {
|
||||
meta: {
|
||||
name: pkg.name,
|
||||
version: pkg.version
|
||||
},
|
||||
rules: {
|
||||
"no-angular-bypass-sanitizer": require("./rules/no-angular-bypass-sanitizer"),
|
||||
"no-angular-sanitization-trusted-urls": require("./rules/no-angular-sanitization-trusted-urls"),
|
||||
"no-angularjs-bypass-sce": require("./rules/no-angularjs-bypass-sce"),
|
||||
"no-angularjs-enable-svg": require("./rules/no-angularjs-enable-svg"),
|
||||
"no-angularjs-sanitization-whitelist": require("./rules/no-angularjs-sanitization-whitelist"),
|
||||
"no-cookies": require("./rules/no-cookies"),
|
||||
"no-document-domain": require("./rules/no-document-domain"),
|
||||
"no-document-write": require("./rules/no-document-write"),
|
||||
"no-electron-node-integration": require("./rules/no-electron-node-integration"),
|
||||
"no-html-method": require("./rules/no-html-method"),
|
||||
"no-inner-html": require("./rules/no-inner-html"),
|
||||
"no-insecure-random": require("./rules/no-insecure-random"),
|
||||
"no-insecure-url": require("./rules/no-insecure-url"),
|
||||
"no-msapp-exec-unsafe": require("./rules/no-msapp-exec-unsafe"),
|
||||
"no-postmessage-star-origin": require("./rules/no-postmessage-star-origin"),
|
||||
"no-unsafe-alloc": require("./rules/no-unsafe-alloc"),
|
||||
"no-winjs-html-unsafe": require("./rules/no-winjs-html-unsafe"),
|
||||
"react-iframe-missing-sandbox": require("./rules/react-iframe-missing-sandbox"),
|
||||
},
|
||||
// Filled in later in order to reference plugin itself.
|
||||
configs: {}
|
||||
meta: {
|
||||
name: pkg.name,
|
||||
version: pkg.version,
|
||||
},
|
||||
rules: {
|
||||
"no-angular-bypass-sanitizer": require("./rules/no-angular-bypass-sanitizer"),
|
||||
"no-angular-sanitization-trusted-urls": require("./rules/no-angular-sanitization-trusted-urls"),
|
||||
"no-angularjs-bypass-sce": require("./rules/no-angularjs-bypass-sce"),
|
||||
"no-angularjs-enable-svg": require("./rules/no-angularjs-enable-svg"),
|
||||
"no-angularjs-sanitization-whitelist": require("./rules/no-angularjs-sanitization-whitelist"),
|
||||
"no-cookies": require("./rules/no-cookies"),
|
||||
"no-document-domain": require("./rules/no-document-domain"),
|
||||
"no-document-write": require("./rules/no-document-write"),
|
||||
"no-electron-node-integration": require("./rules/no-electron-node-integration"),
|
||||
"no-html-method": require("./rules/no-html-method"),
|
||||
"no-inner-html": require("./rules/no-inner-html"),
|
||||
"no-insecure-random": require("./rules/no-insecure-random"),
|
||||
"no-insecure-url": require("./rules/no-insecure-url"),
|
||||
"no-msapp-exec-unsafe": require("./rules/no-msapp-exec-unsafe"),
|
||||
"no-postmessage-star-origin": require("./rules/no-postmessage-star-origin"),
|
||||
"no-unsafe-alloc": require("./rules/no-unsafe-alloc"),
|
||||
"no-winjs-html-unsafe": require("./rules/no-winjs-html-unsafe"),
|
||||
"react-iframe-missing-sandbox": require("./rules/react-iframe-missing-sandbox"),
|
||||
},
|
||||
// Filled in later in order to reference plugin itself.
|
||||
configs: {},
|
||||
};
|
||||
|
||||
plugin.configs["angular"] = require("../config/angular")(plugin);
|
||||
|
@ -46,23 +46,22 @@ plugin.configs["react"] = require("../config/react")(plugin);
|
|||
plugin.configs["typescript"] = require("../config/react")(plugin);
|
||||
|
||||
plugin.configs["required"] = [
|
||||
...plugin.configs["angular"],
|
||||
...plugin.configs["angularjs"],
|
||||
...plugin.configs["common"],
|
||||
...plugin.configs["electron"],
|
||||
...plugin.configs["node"],
|
||||
...plugin.configs["react"]
|
||||
...plugin.configs["angular"],
|
||||
...plugin.configs["angularjs"],
|
||||
...plugin.configs["common"],
|
||||
...plugin.configs["electron"],
|
||||
...plugin.configs["node"],
|
||||
...plugin.configs["react"],
|
||||
];
|
||||
|
||||
plugin.configs["recommended"] = [
|
||||
...plugin.configs["required"],
|
||||
...plugin.configs["typescript"],
|
||||
{
|
||||
plugins: {
|
||||
security: pluginSecurity
|
||||
}
|
||||
}
|
||||
...plugin.configs["required"],
|
||||
...plugin.configs["typescript"],
|
||||
{
|
||||
plugins: {
|
||||
security: pluginSecurity,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
module.exports = plugin;
|
||||
|
|
|
@ -8,32 +8,31 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "Calls to bypassSecurityTrustHtml, bypassSecurityTrustScript and similar methods bypass DomSanitizer in Angular and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angular-bypass-sanitizer.md"
|
||||
},
|
||||
messages: {
|
||||
noBypass: "Do not bypass Angular's built-in sanitizer"
|
||||
}
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description:
|
||||
"Calls to bypassSecurityTrustHtml, bypassSecurityTrustScript and similar methods bypass DomSanitizer in Angular and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angular-bypass-sanitizer.md",
|
||||
},
|
||||
create: function(context) {
|
||||
return {
|
||||
"CallExpression[arguments!=''][callee.property.name=/bypassSecurityTrust(Html|ResourceUrl|Script|Style|Url)/]"(node) {
|
||||
context.report(
|
||||
{
|
||||
node: node,
|
||||
messageId: "noBypass"
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
messages: {
|
||||
noBypass: "Do not bypass Angular's built-in sanitizer",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
return {
|
||||
"CallExpression[arguments!=''][callee.property.name=/bypassSecurityTrust(Html|ResourceUrl|Script|Style|Url)/]"(
|
||||
node,
|
||||
) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "noBypass",
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -6,34 +6,33 @@
|
|||
* @author Vivien Flouirac
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "Calls to [`$compileProvider.aHrefSanitizationTrustedUrlList`](https://docs.angularjs.org/api/ng/provider/$compileProvider#aHrefSanitizationTrustedUrlList) configure allowed Url list in AngularJS sanitizer and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angular-sanitization-trusted-urls.md"
|
||||
},
|
||||
messages: {
|
||||
noSanitizationTrustedUrls: "Do not modify the trusted Urls list in AngularJS"
|
||||
}
|
||||
},
|
||||
create: function(context) {
|
||||
return {
|
||||
"CallExpression[arguments!=''][callee.object.name='$compileProvider'][callee.property.name=/(aHref|imgSrc)SanitizationTrustedUrlList/]"(node) {
|
||||
context.report(
|
||||
{
|
||||
node: node,
|
||||
messageId: "noSanitizationTrustedUrls"
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description:
|
||||
"Calls to [`$compileProvider.aHrefSanitizationTrustedUrlList`](https://docs.angularjs.org/api/ng/provider/$compileProvider#aHrefSanitizationTrustedUrlList) configure allowed Url list in AngularJS sanitizer and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angular-sanitization-trusted-urls.md",
|
||||
},
|
||||
messages: {
|
||||
noSanitizationTrustedUrls: "Do not modify the trusted Urls list in AngularJS",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
return {
|
||||
"CallExpression[arguments!=''][callee.object.name='$compileProvider'][callee.property.name=/(aHref|imgSrc)SanitizationTrustedUrlList/]"(
|
||||
node,
|
||||
) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "noSanitizationTrustedUrls",
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,56 +8,62 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "Calls to $sceProvider.enabled(false), $sceDelegate.trustAs(), $sce.trustAs() and relevant shorthand methods (e.g. trustAsHtml or trustAsJs) bypass Strict Contextual Escaping (SCE) in AngularJS and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angularjs-bypass-sce.md"
|
||||
},
|
||||
messages: {
|
||||
doNotBypass: "Do not bypass Strict Contextual Escaping (SCE) in AngularJS"
|
||||
}
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description:
|
||||
"Calls to $sceProvider.enabled(false), $sceDelegate.trustAs(), $sce.trustAs() and relevant shorthand methods (e.g. trustAsHtml or trustAsJs) bypass Strict Contextual Escaping (SCE) in AngularJS and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angularjs-bypass-sce.md",
|
||||
},
|
||||
create: function (context) {
|
||||
messages: {
|
||||
doNotBypass: "Do not bypass Strict Contextual Escaping (SCE) in AngularJS",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
function reportIt(node) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "doNotBypass",
|
||||
});
|
||||
}
|
||||
|
||||
function reportIt(node) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "doNotBypass"
|
||||
});
|
||||
return {
|
||||
"CallExpression[arguments!=''][callee.object.name='$sceProvider'][callee.property.name='enabled']"(
|
||||
node,
|
||||
) {
|
||||
// Known false positives
|
||||
if (
|
||||
node.arguments == undefined ||
|
||||
node.arguments.length != 1 ||
|
||||
(node.arguments[0].type == "Literal" && /true|1/.test(node.arguments[0].value))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return reportIt(node);
|
||||
},
|
||||
"CallExpression[arguments!=''][callee.object.name='$sceDelegate'][callee.property.name='trustAs']":
|
||||
reportIt,
|
||||
"CallExpression[arguments!=''][callee.object.name='$sce'][callee.property.name=/trustAs(Css|Html|Js|ResourceUrl|Url)?/]"(
|
||||
node,
|
||||
) {
|
||||
// Known false positives
|
||||
if (
|
||||
node.arguments &&
|
||||
node.arguments.length === 1 &&
|
||||
node.arguments[0].type === "Literal" &&
|
||||
node.arguments[0].value === ""
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
"CallExpression[arguments!=''][callee.object.name='$sceProvider'][callee.property.name='enabled']"(node) {
|
||||
// Known false positives
|
||||
if (node.arguments == undefined || node.arguments.length != 1 || (node.arguments[0].type == "Literal" && /true|1/.test(node.arguments[0].value))){
|
||||
return;
|
||||
}
|
||||
return reportIt(node)
|
||||
},
|
||||
"CallExpression[arguments!=''][callee.object.name='$sceDelegate'][callee.property.name='trustAs']": reportIt,
|
||||
"CallExpression[arguments!=''][callee.object.name='$sce'][callee.property.name=/trustAs(Css|Html|Js|ResourceUrl|Url)?/]"(node) {
|
||||
// Known false positives
|
||||
if (
|
||||
node.arguments
|
||||
&& node.arguments.length === 1
|
||||
&& node.arguments[0].type === "Literal"
|
||||
&& node.arguments[0].value === ""
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
return reportIt(node);
|
||||
}
|
||||
};
|
||||
}
|
||||
return reportIt(node);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: Review https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider#resourceUrlWhitelist and https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider#resourceUrlBlacklist
|
||||
|
|
|
@ -8,46 +8,41 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "Calls to $sanitizeProvider.enableSvg(true) increase attack surface of the application by enabling SVG support in AngularJS sanitizer and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angularjs-enable-svg.md"
|
||||
},
|
||||
messages: {
|
||||
doNotEnableSVG: "Do not enable SVG support in AngularJS"
|
||||
}
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description:
|
||||
"Calls to $sanitizeProvider.enableSvg(true) increase attack surface of the application by enabling SVG support in AngularJS sanitizer and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angularjs-enable-svg.md",
|
||||
},
|
||||
create: function (context) {
|
||||
return {
|
||||
"CallExpression[callee.object.name='$sanitizeProvider'][callee.property.name='enableSvg']"(node) {
|
||||
// Known false positives
|
||||
if (
|
||||
(node.arguments != undefined &&
|
||||
node.arguments.length != 1) ||
|
||||
(
|
||||
node.arguments[0].type == "Literal" && (
|
||||
node.arguments[0].value == "false" || node.arguments[0].value == "0"
|
||||
)
|
||||
))
|
||||
{
|
||||
return;
|
||||
}
|
||||
context.report(
|
||||
{
|
||||
node: node,
|
||||
messageId: "doNotEnableSVG"
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
messages: {
|
||||
doNotEnableSVG: "Do not enable SVG support in AngularJS",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
return {
|
||||
"CallExpression[callee.object.name='$sanitizeProvider'][callee.property.name='enableSvg']"(
|
||||
node,
|
||||
) {
|
||||
// Known false positives
|
||||
if (
|
||||
(node.arguments != undefined && node.arguments.length != 1) ||
|
||||
(node.arguments[0].type == "Literal" &&
|
||||
(node.arguments[0].value == "false" || node.arguments[0].value == "0"))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "doNotEnableSVG",
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: Add rules for $sanitizeProvider.addValidElements() and $sanitizeProvider.addValidAttrs()
|
||||
// TODO: Add rules for $sanitizeProvider.addValidElements() and $sanitizeProvider.addValidAttrs()
|
||||
|
|
|
@ -8,32 +8,31 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "Calls to [`$compileProvider.aHrefSanitizationWhitelist`](https://docs.angularjs.org/api/ng/provider/$compileProvider#aHrefSanitizationWhitelist) or [`$compileProvider.imgSrcSanitizationWhitelist`](https://docs.angularjs.org/api/ng/provider/$compileProvider#imgSrcSanitizationWhitelist) configure whitelists in AngularJS sanitizer and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angularjs-sanitization-whitelist.md"
|
||||
},
|
||||
messages: {
|
||||
noSanitizationWhitelist: "Do not modify sanitization whitelist in AngularJS"
|
||||
}
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description:
|
||||
"Calls to [`$compileProvider.aHrefSanitizationWhitelist`](https://docs.angularjs.org/api/ng/provider/$compileProvider#aHrefSanitizationWhitelist) or [`$compileProvider.imgSrcSanitizationWhitelist`](https://docs.angularjs.org/api/ng/provider/$compileProvider#imgSrcSanitizationWhitelist) configure whitelists in AngularJS sanitizer and need to be reviewed.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-angularjs-sanitization-whitelist.md",
|
||||
},
|
||||
create: function (context) {
|
||||
return {
|
||||
"CallExpression[arguments!=''][callee.object.name='$compileProvider'][callee.property.name=/(aHref|imgSrc)SanitizationWhitelist/]"(node) {
|
||||
context.report(
|
||||
{
|
||||
node: node,
|
||||
messageId: "noSanitizationWhitelist"
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
messages: {
|
||||
noSanitizationWhitelist: "Do not modify sanitization whitelist in AngularJS",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
return {
|
||||
"CallExpression[arguments!=''][callee.object.name='$compileProvider'][callee.property.name=/(aHref|imgSrc)SanitizationWhitelist/]"(
|
||||
node,
|
||||
) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "noSanitizationWhitelist",
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,9 +10,6 @@
|
|||
|
||||
const astUtils = require("../ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
@ -20,12 +17,13 @@ module.exports = {
|
|||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "HTTP cookies are an old client-side storage mechanism with inherent risks and limitations. Use Web Storage, IndexedDB or other more modern methods instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-cookies.md"
|
||||
description:
|
||||
"HTTP cookies are an old client-side storage mechanism with inherent risks and limitations. Use Web Storage, IndexedDB or other more modern methods instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-cookies.md",
|
||||
},
|
||||
messages: {
|
||||
doNotUseCookies: "Do not use HTTP cookies in modern applications"
|
||||
}
|
||||
doNotUseCookies: "Do not use HTTP cookies in modern applications",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
const fullTypeChecker = astUtils.getFullTypeChecker(context);
|
||||
|
@ -34,10 +32,10 @@ module.exports = {
|
|||
if (astUtils.isDocumentObject(node.object, context, fullTypeChecker)) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "doNotUseCookies"
|
||||
messageId: "doNotUseCookies",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,9 +10,6 @@
|
|||
|
||||
const astUtils = require("../ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
@ -20,25 +17,25 @@ module.exports = {
|
|||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "Writes to [`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain) property must be reviewed to avoid bypass of [same-origin checks](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin). Usage of top level domains such as `azurewebsites.net` is strictly prohibited.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-document-domain.md"
|
||||
description:
|
||||
"Writes to [`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain) property must be reviewed to avoid bypass of [same-origin checks](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin). Usage of top level domains such as `azurewebsites.net` is strictly prohibited.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-document-domain.md",
|
||||
},
|
||||
messages: {
|
||||
default: 'Do not write to document.domain property'
|
||||
}
|
||||
default: "Do not write to document.domain property",
|
||||
},
|
||||
},
|
||||
create: function(context) {
|
||||
create: function (context) {
|
||||
const fullTypeChecker = astUtils.getFullTypeChecker(context);
|
||||
return {
|
||||
"AssignmentExpression[operator='='][left.property.name='domain']"(node) {
|
||||
if (astUtils.isDocumentObject(node.left.object, context, fullTypeChecker)) {
|
||||
context.report(
|
||||
{
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,9 +10,6 @@
|
|||
|
||||
const astUtils = require("../ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
@ -20,25 +17,25 @@ module.exports = {
|
|||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "Calls to document.write or document.writeln manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-document-write.md"
|
||||
description:
|
||||
"Calls to document.write or document.writeln manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-document-write.md",
|
||||
},
|
||||
messages: {
|
||||
default: 'Do not write to DOM directly using document.write or document.writeln methods'
|
||||
}
|
||||
default: "Do not write to DOM directly using document.write or document.writeln methods",
|
||||
},
|
||||
},
|
||||
create: function(context) {
|
||||
create: function (context) {
|
||||
const fullTypeChecker = astUtils.getFullTypeChecker(context);
|
||||
return {
|
||||
"CallExpression[arguments.length=1][callee.property.name=/write|writeln/]"(node) {
|
||||
if (astUtils.isDocumentObject(node.callee.object, context, fullTypeChecker)) {
|
||||
context.report(
|
||||
{
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -7,32 +7,31 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "[Node.js Integration](https://www.electronjs.org/docs/tutorial/security#2-do-not-enable-nodejs-integration-for-remote-content) must not be enabled in any renderer that loads remote content to avoid remote code execution attacks.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-electron-node-integration.md"
|
||||
},
|
||||
messages: {
|
||||
default: "Do not enable Node.js Integration for Remote Content"
|
||||
}
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description:
|
||||
"[Node.js Integration](https://www.electronjs.org/docs/tutorial/security#2-do-not-enable-nodejs-integration-for-remote-content) must not be enabled in any renderer that loads remote content to avoid remote code execution attacks.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-electron-node-integration.md",
|
||||
},
|
||||
create: function(context) {
|
||||
return {
|
||||
"NewExpression[callee.name=/BrowserWindow|BrowserView/] > ObjectExpression.arguments > Property.properties[key.name=webPreferences] > ObjectExpression.value > Property.properties[key.name=/nodeIntegration|nodeIntegrationInWorker|nodeIntegrationInSubFrames/][value.value='true']"(node) {
|
||||
context.report(
|
||||
{
|
||||
node: node,
|
||||
messageId: "default"
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
messages: {
|
||||
default: "Do not enable Node.js Integration for Remote Content",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
return {
|
||||
"NewExpression[callee.name=/BrowserWindow|BrowserView/] > ObjectExpression.arguments > Property.properties[key.name=webPreferences] > ObjectExpression.value > Property.properties[key.name=/nodeIntegration|nodeIntegrationInWorker|nodeIntegrationInSubFrames/][value.value='true']"(
|
||||
node,
|
||||
) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default",
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,26 +10,24 @@
|
|||
|
||||
const astUtils = require("../ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs:{
|
||||
description: "Direct calls to method `html()` often (e.g. in jQuery framework) manipulate DOM without any sanitization and should be avoided. Use document.createElement() or similar methods instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-html-method.md"
|
||||
docs: {
|
||||
description:
|
||||
"Direct calls to method `html()` often (e.g. in jQuery framework) manipulate DOM without any sanitization and should be avoided. Use document.createElement() or similar methods instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-html-method.md",
|
||||
},
|
||||
messages: {
|
||||
default: 'Do not write to DOM directly using jQuery html() method'
|
||||
}
|
||||
default: "Do not write to DOM directly using jQuery html() method",
|
||||
},
|
||||
},
|
||||
create: function(context) {
|
||||
create: function (context) {
|
||||
const fullTypeChecker = astUtils.getFullTypeChecker(context);
|
||||
return {
|
||||
// TODO:
|
||||
// TODO:
|
||||
// - Cover similar methods that can manipulate DOM such as append(string), jQuery(string)
|
||||
// - Improve rule with type information from TypeScript parser
|
||||
// - Consider ignoring all Literals?
|
||||
|
@ -37,20 +35,16 @@ module.exports = {
|
|||
// Known false positives
|
||||
if (
|
||||
// element.html("")
|
||||
node.parent.arguments[0].type === "Literal"
|
||||
&& (
|
||||
node.parent.arguments[0].value === ""
|
||||
|| node.parent.arguments[0].value === null
|
||||
)
|
||||
node.parent.arguments[0].type === "Literal" &&
|
||||
(node.parent.arguments[0].value === "" || node.parent.arguments[0].value === null)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
context.report(
|
||||
{
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
});
|
||||
}
|
||||
messageId: "default",
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,22 +10,20 @@
|
|||
|
||||
const astUtils = require("../ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
description: "Assignments to [innerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)/[outerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML) properties or calls to [insertAdjacentHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML) method manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-inner-html.md"
|
||||
description:
|
||||
"Assignments to [innerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)/[outerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML) properties or calls to [insertAdjacentHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML) method manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-inner-html.md",
|
||||
},
|
||||
messages: {
|
||||
noInnerHtml: 'Do not write to DOM directly using innerHTML/outerHTML property',
|
||||
noInsertAdjacentHTML: 'Do not write to DOM using insertAdjacentHTML method'
|
||||
}
|
||||
noInnerHtml: "Do not write to DOM directly using innerHTML/outerHTML property",
|
||||
noInsertAdjacentHTML: "Do not write to DOM using insertAdjacentHTML method",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
const fullTypeChecker = astUtils.getFullTypeChecker(context);
|
||||
|
@ -36,15 +34,18 @@ module.exports = {
|
|||
}
|
||||
|
||||
return {
|
||||
"CallExpression[arguments.length=2] > MemberExpression.callee[property.name='insertAdjacentHTML']"(node) {
|
||||
"CallExpression[arguments.length=2] > MemberExpression.callee[property.name='insertAdjacentHTML']"(
|
||||
node,
|
||||
) {
|
||||
// Ignore known false positives
|
||||
if (
|
||||
node.parent != undefined
|
||||
&& node.parent.arguments != undefined
|
||||
&& node.parent.arguments.length >= 1
|
||||
&& node.parent.arguments[1] != undefined
|
||||
node.parent != undefined &&
|
||||
node.parent.arguments != undefined &&
|
||||
node.parent.arguments.length >= 1 &&
|
||||
node.parent.arguments[1] != undefined &&
|
||||
// element.insertAdjacentHTML('')
|
||||
&& node.parent.arguments[1].type === 'Literal' && node.parent.arguments[1].value === ''
|
||||
node.parent.arguments[1].type === "Literal" &&
|
||||
node.parent.arguments[1].value === ""
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -52,16 +53,19 @@ module.exports = {
|
|||
if (mightBeHTMLElement(node.object)) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "noInsertAdjacentHTML"
|
||||
messageId: "noInsertAdjacentHTML",
|
||||
});
|
||||
}
|
||||
},
|
||||
"AssignmentExpression[left.type='MemberExpression'][left.property.name=/innerHTML|outerHTML/]"(node) {
|
||||
"AssignmentExpression[left.type='MemberExpression'][left.property.name=/innerHTML|outerHTML/]"(
|
||||
node,
|
||||
) {
|
||||
// Ignore known false positives
|
||||
if (
|
||||
node.right != undefined
|
||||
node.right != undefined &&
|
||||
// element.innerHTML = ''
|
||||
&& node.right.type === 'Literal' && node.right.value === ''
|
||||
node.right.type === "Literal" &&
|
||||
node.right.value === ""
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -69,10 +73,10 @@ module.exports = {
|
|||
if (mightBeHTMLElement(node.left.object)) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "noInnerHtml"
|
||||
messageId: "noInnerHtml",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -9,38 +9,36 @@
|
|||
"use strict";
|
||||
|
||||
const astUtils = require("../ast-utils");
|
||||
const path = require('path');
|
||||
const path = require("path");
|
||||
|
||||
const bannedRandomLibraries = [
|
||||
'chance',
|
||||
'random-number',
|
||||
'random-int',
|
||||
'random-float',
|
||||
'random-seed',
|
||||
'unique-random'
|
||||
]
|
||||
"chance",
|
||||
"random-number",
|
||||
"random-int",
|
||||
"random-float",
|
||||
"random-seed",
|
||||
"unique-random",
|
||||
];
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs:{
|
||||
docs: {
|
||||
description: `Methods such as Math.random or crypto.pseudoRandomBytes do not produce cryptographically-secure random numbers and must not be used for security purposes such as generating tokens, passwords or keys.
|
||||
|
||||
Use crypto.randomBytes() or window.crypto.getRandomValues() instead.
|
||||
|
||||
`,
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-insecure-random.md"
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-insecure-random.md",
|
||||
},
|
||||
messages: {
|
||||
default: 'Do not use pseudo-random number generators for generating secret values such as tokens, passwords or keys.'
|
||||
}
|
||||
default:
|
||||
"Do not use pseudo-random number generators for generating secret values such as tokens, passwords or keys.",
|
||||
},
|
||||
},
|
||||
create: function(context) {
|
||||
create: function (context) {
|
||||
const fullTypeChecker = astUtils.getFullTypeChecker(context);
|
||||
return {
|
||||
"CallExpression > MemberExpression[property.name='pseudoRandomBytes']"(node) {
|
||||
|
@ -49,50 +47,50 @@ module.exports = {
|
|||
if (fullTypeChecker) {
|
||||
const type = astUtils.getNodeTypeAsString(fullTypeChecker, node.object, context);
|
||||
notFalsePositive = type === "any" || type === "Crypto";
|
||||
}else{
|
||||
notFalsePositive = node.object.name === 'crypto';
|
||||
} else {
|
||||
notFalsePositive = node.object.name === "crypto";
|
||||
}
|
||||
|
||||
if(notFalsePositive){
|
||||
if (notFalsePositive) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
"CallExpression > MemberExpression[property.name='random']"(node) {
|
||||
var notFalsePositive = false;
|
||||
if (fullTypeChecker) {
|
||||
const type = astUtils.getNodeTypeAsString(fullTypeChecker, node.object, context);
|
||||
notFalsePositive = type === "any" || type === "Math";
|
||||
}else{
|
||||
notFalsePositive = node.object.name === 'Math';
|
||||
} else {
|
||||
notFalsePositive = node.object.name === "Math";
|
||||
}
|
||||
|
||||
if(notFalsePositive){
|
||||
if (notFalsePositive) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
},
|
||||
ImportDeclaration(node){
|
||||
if(bannedRandomLibraries.includes(path.basename(node.source.value))){
|
||||
ImportDeclaration(node) {
|
||||
if (bannedRandomLibraries.includes(path.basename(node.source.value))) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
});
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
},
|
||||
"CallExpression[callee.name='require'][arguments.length=1]"(node){
|
||||
"CallExpression[callee.name='require'][arguments.length=1]"(node) {
|
||||
var requireName = path.parse(path.basename(node.arguments[0].value)).name;
|
||||
if(bannedRandomLibraries.includes(requireName)){
|
||||
if (bannedRandomLibraries.includes(requireName)) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
});
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,139 +1,159 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/**
|
||||
* @fileoverview Disallows usage of insecure protocols in URL strings
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
const DEFAULT_BLOCKLIST = [
|
||||
/^(ftp|http|telnet|ws):\/\//i
|
||||
];
|
||||
|
||||
const DEFAULT_EXCEPTIONS = [ // TODO: add more typical false positives such as XML schemas after more testing
|
||||
/^http:(\/\/|\\u002f\\u002f)schemas\.microsoft\.com(\/\/|\\u002f\\u002f)?.*/i,
|
||||
/^http:(\/\/|\\u002f\\u002f)schemas\.openxmlformats\.org(\/\/|\\u002f\\u002f)?.*/i,
|
||||
/^http:(\/|\\u002f){2}localhost(:|\/|\\u002f)*/i,
|
||||
/^http:(\/\/)www\.w3\.org\/1999\/xhtml/i,
|
||||
/^http:(\/\/)www\.w3\.org\/2000\/svg/i
|
||||
];
|
||||
|
||||
const DEFAULT_VARIABLES_EXECEPTIONS = [];
|
||||
|
||||
module.exports = {
|
||||
defaultBlocklist: DEFAULT_BLOCKLIST,
|
||||
defaultExceptions: DEFAULT_EXCEPTIONS,
|
||||
defaultVarExecptions: DEFAULT_VARIABLES_EXECEPTIONS,
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
blocklist: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
exceptions: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
varExceptions: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "Insecure protocols such as [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) or [FTP](https://en.wikipedia.org/wiki/File_Transfer_Protocol) should be replaced by their encrypted counterparts ([HTTPS](https://en.wikipedia.org/wiki/HTTPS), [FTPS](https://en.wikipedia.org/wiki/FTPS)) to avoid sending (potentially sensitive) data over untrusted network in plaintext.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-insecure-url.md"
|
||||
},
|
||||
messages: {
|
||||
doNotUseInsecureUrl: "Do not use insecure URLs"
|
||||
}
|
||||
},
|
||||
create: function (context) {
|
||||
const options = context.options[0] || {};
|
||||
const blocklist = (options.blocklist || DEFAULT_BLOCKLIST).map((pattern) => { return new RegExp(pattern, "i"); });
|
||||
const exceptions = (options.exceptions || DEFAULT_EXCEPTIONS).map((pattern) => { return new RegExp(pattern, "i"); });
|
||||
const varExceptions = (options.varExceptions || DEFAULT_VARIABLES_EXECEPTIONS).map((pattern) => { return new RegExp(pattern, "i"); });
|
||||
|
||||
function matches(patterns, value) {
|
||||
return patterns.find((re) => { return re.test(value) }) !== undefined;
|
||||
}
|
||||
|
||||
function shouldFix( varExceptions,context, node) {
|
||||
// check variable for unfixable pattern e.g. `var insecureURL = "http://..."`
|
||||
let text = node.parent
|
||||
? context.sourceCode.getText(node.parent)
|
||||
: context.sourceCode.getText(node);
|
||||
// if no match, fix the line
|
||||
return !matches(varExceptions,text);
|
||||
}
|
||||
|
||||
return {
|
||||
"Literal"(node) {
|
||||
if (typeof node.value === "string") {
|
||||
// Add an exception for xmlns attributes
|
||||
if(node.parent && node.parent.type === "JSXAttribute" && node.parent.name && node.parent.name.name === "xmlns")
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else if (matches(blocklist, node.value) && !matches(exceptions, node.value) && shouldFix(varExceptions,context, node)) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "doNotUseInsecureUrl",
|
||||
fix(fixer) {
|
||||
// Only fix if it contains an http url
|
||||
if (node.value.toLowerCase().includes("http")) {
|
||||
let fixedString = node.value.replace(/http:/i, "https:");
|
||||
//insert an "s" before ":/" to change http:/ to https:/
|
||||
return fixer.replaceText(node, JSON.stringify(fixedString));
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
"TemplateElement"(node) {
|
||||
if (typeof node.value.raw === "string" && typeof node.value.cooked === "string") {
|
||||
const rawStringText = node.value.raw;
|
||||
const cookedStringText = node.value.cooked;
|
||||
|
||||
if (shouldFix(varExceptions,context, node) && (matches(blocklist, rawStringText) && !matches(exceptions, rawStringText)) ||
|
||||
(matches(blocklist, cookedStringText) && !matches(exceptions, cookedStringText))) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "doNotUseInsecureUrl",
|
||||
fix(fixer) {
|
||||
// Only fix if it contains an http url
|
||||
if (node.value.raw.toLowerCase().includes("http")) {
|
||||
let escapedString = JSON.stringify(context.sourceCode.getText(node));
|
||||
// delete "" that JSON.stringify created and convert to `` string
|
||||
escapedString = ``+ escapedString.substring(1, escapedString.length-1);
|
||||
let fixedString = escapedString.replace(/http:/i, "https:");
|
||||
//insert an "s" before ":/" to change http:/ to https:/
|
||||
return fixer.replaceText(node, fixedString);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/**
|
||||
* @fileoverview Disallows usage of insecure protocols in URL strings
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const DEFAULT_BLOCKLIST = [/^(ftp|http|telnet|ws):\/\//i];
|
||||
|
||||
const DEFAULT_EXCEPTIONS = [
|
||||
// TODO: add more typical false positives such as XML schemas after more testing
|
||||
/^http:(\/\/|\\u002f\\u002f)schemas\.microsoft\.com(\/\/|\\u002f\\u002f)?.*/i,
|
||||
/^http:(\/\/|\\u002f\\u002f)schemas\.openxmlformats\.org(\/\/|\\u002f\\u002f)?.*/i,
|
||||
/^http:(\/|\\u002f){2}localhost(:|\/|\\u002f)*/i,
|
||||
/^http:(\/\/)www\.w3\.org\/1999\/xhtml/i,
|
||||
/^http:(\/\/)www\.w3\.org\/2000\/svg/i,
|
||||
];
|
||||
|
||||
const DEFAULT_VARIABLES_EXECEPTIONS = [];
|
||||
|
||||
module.exports = {
|
||||
defaultBlocklist: DEFAULT_BLOCKLIST,
|
||||
defaultExceptions: DEFAULT_EXCEPTIONS,
|
||||
defaultVarExecptions: DEFAULT_VARIABLES_EXECEPTIONS,
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
blocklist: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
exceptions: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
varExceptions: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description:
|
||||
"Insecure protocols such as [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) or [FTP](https://en.wikipedia.org/wiki/File_Transfer_Protocol) should be replaced by their encrypted counterparts ([HTTPS](https://en.wikipedia.org/wiki/HTTPS), [FTPS](https://en.wikipedia.org/wiki/FTPS)) to avoid sending (potentially sensitive) data over untrusted network in plaintext.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-insecure-url.md",
|
||||
},
|
||||
messages: {
|
||||
doNotUseInsecureUrl: "Do not use insecure URLs",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
const options = context.options[0] || {};
|
||||
const blocklist = (options.blocklist || DEFAULT_BLOCKLIST).map((pattern) => {
|
||||
return new RegExp(pattern, "i");
|
||||
});
|
||||
const exceptions = (options.exceptions || DEFAULT_EXCEPTIONS).map((pattern) => {
|
||||
return new RegExp(pattern, "i");
|
||||
});
|
||||
const varExceptions = (options.varExceptions || DEFAULT_VARIABLES_EXECEPTIONS).map(
|
||||
(pattern) => {
|
||||
return new RegExp(pattern, "i");
|
||||
},
|
||||
);
|
||||
|
||||
function matches(patterns, value) {
|
||||
return (
|
||||
patterns.find((re) => {
|
||||
return re.test(value);
|
||||
}) !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
function shouldFix(varExceptions, context, node) {
|
||||
// check variable for unfixable pattern e.g. `var insecureURL = "http://..."`
|
||||
let text = node.parent
|
||||
? context.sourceCode.getText(node.parent)
|
||||
: context.sourceCode.getText(node);
|
||||
// if no match, fix the line
|
||||
return !matches(varExceptions, text);
|
||||
}
|
||||
|
||||
return {
|
||||
Literal(node) {
|
||||
if (typeof node.value === "string") {
|
||||
// Add an exception for xmlns attributes
|
||||
if (
|
||||
node.parent &&
|
||||
node.parent.type === "JSXAttribute" &&
|
||||
node.parent.name &&
|
||||
node.parent.name.name === "xmlns"
|
||||
) {
|
||||
// Do nothing
|
||||
} else if (
|
||||
matches(blocklist, node.value) &&
|
||||
!matches(exceptions, node.value) &&
|
||||
shouldFix(varExceptions, context, node)
|
||||
) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "doNotUseInsecureUrl",
|
||||
fix(fixer) {
|
||||
// Only fix if it contains an http url
|
||||
if (node.value.toLowerCase().includes("http")) {
|
||||
let fixedString = node.value.replace(/http:/i, "https:");
|
||||
//insert an "s" before ":/" to change http:/ to https:/
|
||||
return fixer.replaceText(node, JSON.stringify(fixedString));
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
TemplateElement(node) {
|
||||
if (typeof node.value.raw === "string" && typeof node.value.cooked === "string") {
|
||||
const rawStringText = node.value.raw;
|
||||
const cookedStringText = node.value.cooked;
|
||||
|
||||
if (
|
||||
(shouldFix(varExceptions, context, node) &&
|
||||
matches(blocklist, rawStringText) &&
|
||||
!matches(exceptions, rawStringText)) ||
|
||||
(matches(blocklist, cookedStringText) && !matches(exceptions, cookedStringText))
|
||||
) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "doNotUseInsecureUrl",
|
||||
fix(fixer) {
|
||||
// Only fix if it contains an http url
|
||||
if (node.value.raw.toLowerCase().includes("http")) {
|
||||
let escapedString = JSON.stringify(context.sourceCode.getText(node));
|
||||
// delete "" that JSON.stringify created and convert to `` string
|
||||
escapedString = `` + escapedString.substring(1, escapedString.length - 1);
|
||||
let fixedString = escapedString.replace(/http:/i, "https:");
|
||||
//insert an "s" before ":/" to change http:/ to https:/
|
||||
return fixer.replaceText(node, fixedString);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,31 +8,30 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs:{
|
||||
description: "Calls to [`MSApp.execUnsafeLocalFunction()`](https://docs.microsoft.com/en-us/previous-versions/hh772324(v=vs.85)) bypass script injection validation and should be avoided.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-msapp-exec-unsafe.md"
|
||||
docs: {
|
||||
description:
|
||||
"Calls to [`MSApp.execUnsafeLocalFunction()`](https://docs.microsoft.com/en-us/previous-versions/hh772324(v=vs.85)) bypass script injection validation and should be avoided.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-msapp-exec-unsafe.md",
|
||||
},
|
||||
messages: {
|
||||
default: 'Do not bypass script injection validation'
|
||||
}
|
||||
default: "Do not bypass script injection validation",
|
||||
},
|
||||
},
|
||||
create: function(context) {
|
||||
create: function (context) {
|
||||
return {
|
||||
"CallExpression[arguments.length=1][callee.object.name='MSApp'][callee.property.name='execUnsafeLocalFunction']"(node) {
|
||||
context.report(
|
||||
{
|
||||
node: node,
|
||||
messageId: "default"
|
||||
"CallExpression[arguments.length=1][callee.object.name='MSApp'][callee.property.name='execUnsafeLocalFunction']"(
|
||||
node,
|
||||
) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -9,35 +9,36 @@
|
|||
|
||||
const astUtils = require("../ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
description: "Always provide specific target origin, not * when sending data to other windows using [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Security_concerns) to avoid data leakage outside of trust boundary.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-postmessage-star-origin.md"
|
||||
description:
|
||||
"Always provide specific target origin, not * when sending data to other windows using [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Security_concerns) to avoid data leakage outside of trust boundary.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-postmessage-star-origin.md",
|
||||
},
|
||||
messages: {
|
||||
default: 'Do not use * as target origin when sending data to other windows'
|
||||
}
|
||||
default: "Do not use * as target origin when sending data to other windows",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
const fullTypeChecker = astUtils.getFullTypeChecker(context);
|
||||
return {
|
||||
"CallExpression[arguments.length>=2][arguments.length<=3][callee.property.name=postMessage]"(node) {
|
||||
|
||||
"CallExpression[arguments.length>=2][arguments.length<=3][callee.property.name=postMessage]"(
|
||||
node,
|
||||
) {
|
||||
// Check that second argument (target origin) is Literal "*"
|
||||
if (!(node.arguments[1].type === 'Literal' && node.arguments[1].value == '*')) {
|
||||
if (!(node.arguments[1].type === "Literal" && node.arguments[1].value == "*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that object type is Window when full type information is available
|
||||
if (fullTypeChecker) {
|
||||
const tsNode = context.sourceCode.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") {
|
||||
|
@ -47,9 +48,9 @@ module.exports = {
|
|||
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,21 +3,19 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs: {
|
||||
description: "When calling [`Buffer.allocUnsafe`](https://nodejs.org/api/buffer.html#buffer_static_method_buffer_allocunsafe_size) and [`Buffer.allocUnsafeSlow`](https://nodejs.org/api/buffer.html#buffer_static_method_buffer_allocunsafeslow_size), the allocated memory is not wiped-out and can contain old, potentially sensitive data.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-unsafe-alloc.md"
|
||||
description:
|
||||
"When calling [`Buffer.allocUnsafe`](https://nodejs.org/api/buffer.html#buffer_static_method_buffer_allocunsafe_size) and [`Buffer.allocUnsafeSlow`](https://nodejs.org/api/buffer.html#buffer_static_method_buffer_allocunsafeslow_size), the allocated memory is not wiped-out and can contain old, potentially sensitive data.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-unsafe-alloc.md",
|
||||
},
|
||||
messages: {
|
||||
default: 'Do not allocate uninitialized buffers in Node.js'
|
||||
}
|
||||
default: "Do not allocate uninitialized buffers in Node.js",
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
return {
|
||||
|
@ -28,19 +26,19 @@ module.exports = {
|
|||
node.parent.arguments != undefined &&
|
||||
node.parent.arguments.length != undefined &&
|
||||
// Buffer.allocUnsafe(0);
|
||||
node.parent.type === 'CallExpression' &&
|
||||
node.parent.arguments.length == 1 &&
|
||||
node.parent.type === "CallExpression" &&
|
||||
node.parent.arguments.length == 1 &&
|
||||
node.parent.arguments[0] != undefined &&
|
||||
node.parent.arguments[0].type === 'Literal' &&
|
||||
node.parent.arguments[0].value == '0'
|
||||
node.parent.arguments[0].type === "Literal" &&
|
||||
node.parent.arguments[0].value == "0"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,31 +8,30 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
docs:{
|
||||
description: "Calls to [`WinJS.Utilities.setInnerHTMLUnsafe()`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211696(v=win.10)) and similar methods do not perform any input validation and should be avoided. Use [`WinJS.Utilities.setInnerHTML()`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211697(v=win.10)) instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-winjs-html-unsafe.md"
|
||||
docs: {
|
||||
description:
|
||||
"Calls to [`WinJS.Utilities.setInnerHTMLUnsafe()`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211696(v=win.10)) and similar methods do not perform any input validation and should be avoided. Use [`WinJS.Utilities.setInnerHTML()`](https://docs.microsoft.com/en-us/previous-versions/windows/apps/br211697(v=win.10)) instead.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/no-winjs-html-unsafe.md",
|
||||
},
|
||||
messages: {
|
||||
default: 'Do not set HTML using unsafe methods from WinJS.Utilities'
|
||||
}
|
||||
default: "Do not set HTML using unsafe methods from WinJS.Utilities",
|
||||
},
|
||||
},
|
||||
create: function(context) {
|
||||
create: function (context) {
|
||||
return {
|
||||
"CallExpression[callee.object.object.name='WinJS'][callee.object.property.name='Utilities'][callee.property.name=/(insertAdjacent|setInner|setOuter)HTMLUnsafe/]"(node) {
|
||||
context.report(
|
||||
{
|
||||
"CallExpression[callee.object.object.name='WinJS'][callee.object.property.name='Utilities'][callee.property.name=/(insertAdjacent|setInner|setOuter)HTMLUnsafe/]"(
|
||||
node,
|
||||
) {
|
||||
context.report({
|
||||
node: node,
|
||||
messageId: "default"
|
||||
messageId: "default",
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
|
||||
// TODO: Follow-up on https://github.com/yannickcr/eslint-plugin-react/issues/2754 and try to merge rule into eslint-plugin-react
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
@ -19,35 +16,38 @@ module.exports = {
|
|||
schema: [],
|
||||
docs: {
|
||||
category: "Security",
|
||||
description: "The [sandbox](https://www.w3schools.com/tags/att_iframe_sandbox.asp) attribute enables an extra set of restrictions for the content in the iframe and should always be specified.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/react-iframe-missing-sandbox.md"
|
||||
description:
|
||||
"The [sandbox](https://www.w3schools.com/tags/att_iframe_sandbox.asp) attribute enables an extra set of restrictions for the content in the iframe and should always be specified.",
|
||||
url: "https://github.com/microsoft/eslint-plugin-sdl/blob/master/docs/rules/react-iframe-missing-sandbox.md",
|
||||
},
|
||||
messages: {
|
||||
attributeMissing: 'An iframe element is missing a sandbox attribute',
|
||||
invalidValue: 'An iframe element defines a sandbox attribute with invalid value "{{ value }}"',
|
||||
invalidCombination: 'An iframe element defines a sandbox attribute with both allow-scripts and allow-same-origin which is invalid'
|
||||
}
|
||||
attributeMissing: "An iframe element is missing a sandbox attribute",
|
||||
invalidValue:
|
||||
'An iframe element defines a sandbox attribute with invalid value "{{ value }}"',
|
||||
invalidCombination:
|
||||
"An iframe element defines a sandbox attribute with both allow-scripts and allow-same-origin which is invalid",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const ALLOWED_VALUES = [
|
||||
// From https://www.w3schools.com/tags/att_iframe_sandbox.asp
|
||||
'',
|
||||
'allow-forms',
|
||||
'allow-modals',
|
||||
'allow-orientation-lock',
|
||||
'allow-pointer-lock',
|
||||
'allow-popups',
|
||||
'allow-popups-to-escape-sandbox',
|
||||
'allow-presentation',
|
||||
'allow-same-origin',
|
||||
'allow-scripts',
|
||||
'allow-top-navigation',
|
||||
'allow-top-navigation-by-user-activation'
|
||||
"",
|
||||
"allow-forms",
|
||||
"allow-modals",
|
||||
"allow-orientation-lock",
|
||||
"allow-pointer-lock",
|
||||
"allow-popups",
|
||||
"allow-popups-to-escape-sandbox",
|
||||
"allow-presentation",
|
||||
"allow-same-origin",
|
||||
"allow-scripts",
|
||||
"allow-top-navigation",
|
||||
"allow-top-navigation-by-user-activation",
|
||||
];
|
||||
|
||||
function validateSandboxAttribute(node, attribute) {
|
||||
const values = attribute.value.value.split(' ');
|
||||
const values = attribute.value.value.split(" ");
|
||||
let allowScripts = false;
|
||||
let allowSameOrigin = false;
|
||||
values.forEach((attributeValue) => {
|
||||
|
@ -55,23 +55,23 @@ module.exports = {
|
|||
if (ALLOWED_VALUES.indexOf(trimmedAttributeValue) === -1) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'invalidValue',
|
||||
messageId: "invalidValue",
|
||||
data: {
|
||||
value: trimmedAttributeValue
|
||||
}
|
||||
value: trimmedAttributeValue,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (trimmedAttributeValue === 'allow-scripts') {
|
||||
if (trimmedAttributeValue === "allow-scripts") {
|
||||
allowScripts = true;
|
||||
}
|
||||
if (trimmedAttributeValue === 'allow-same-origin') {
|
||||
if (trimmedAttributeValue === "allow-same-origin") {
|
||||
allowSameOrigin = true;
|
||||
}
|
||||
});
|
||||
if (allowScripts && allowSameOrigin) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'invalidCombination'
|
||||
messageId: "invalidCombination",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -80,17 +80,14 @@ module.exports = {
|
|||
'JSXOpeningElement[name.name="iframe"]'(node) {
|
||||
let sandboxAttributeFound = false;
|
||||
node.attributes.forEach((attribute) => {
|
||||
if (attribute.type === 'JSXAttribute'
|
||||
&& attribute.name
|
||||
&& attribute.name.type === 'JSXIdentifier'
|
||||
&& attribute.name.name === 'sandbox'
|
||||
if (
|
||||
attribute.type === "JSXAttribute" &&
|
||||
attribute.name &&
|
||||
attribute.name.type === "JSXIdentifier" &&
|
||||
attribute.name.name === "sandbox"
|
||||
) {
|
||||
sandboxAttributeFound = true;
|
||||
if (
|
||||
attribute.value
|
||||
&& attribute.value.type === 'Literal'
|
||||
&& attribute.value.value
|
||||
) {
|
||||
if (attribute.value && attribute.value.type === "Literal" && attribute.value.value) {
|
||||
// Only string literals are supported for now
|
||||
validateSandboxAttribute(node, attribute);
|
||||
}
|
||||
|
@ -99,10 +96,10 @@ module.exports = {
|
|||
if (!sandboxAttributeFound) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'attributeMissing'
|
||||
messageId: "attributeMissing",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"@typescript-eslint/parser": "~8.6.0",
|
||||
"eslint": "~9.11.0",
|
||||
"mocha": "~10.7.0",
|
||||
"prettier": "~3.3.0",
|
||||
"typescript": "~5.5.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2728,6 +2729,21 @@
|
|||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
|
||||
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
"bugs": "https://github.com/microsoft/eslint-plugin-sdl/issues",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"check-fmt": "prettier . --check",
|
||||
"fmt": "prettier . --write",
|
||||
"test": "mocha tests --recursive"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -29,6 +31,7 @@
|
|||
"@typescript-eslint/parser": "~8.6.0",
|
||||
"eslint": "~9.11.0",
|
||||
"mocha": "~10.7.0",
|
||||
"prettier": "~3.3.0",
|
||||
"typescript": "~5.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
{
|
||||
"include": [
|
||||
"estree.ts"
|
||||
]
|
||||
}
|
||||
"include": ["estree.ts"]
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": [
|
||||
"estree.tsx"
|
||||
]
|
||||
}
|
||||
"compilerOptions": {
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": ["estree.tsx"]
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
|
@ -11,7 +11,7 @@ ruleTester.run(ruleId, rule, {
|
|||
valid: [
|
||||
"bypassSecurityTrustHtml('XSS')",
|
||||
"x.bypassSecurityTrustHtml()",
|
||||
"x.BypassSecurityTrustHtml('XSS')"
|
||||
"x.BypassSecurityTrustHtml('XSS')",
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
|
@ -22,25 +22,25 @@ ruleTester.run(ruleId, rule, {
|
|||
line: 1,
|
||||
endLine: 1,
|
||||
column: 1,
|
||||
endColumn: 38
|
||||
}
|
||||
]
|
||||
endColumn: 38,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: "$('p').bypassSecurityTrustResourceUrl('XSS')",
|
||||
errors: [{ messageId: "noBypass"}]
|
||||
errors: [{ messageId: "noBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$('p').bypassSecurityTrustScript('XSS')",
|
||||
errors: [{ messageId: "noBypass"}]
|
||||
errors: [{ messageId: "noBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$('p').bypassSecurityTrustStyle('XSS')",
|
||||
errors: [{ messageId: "noBypass"}]
|
||||
errors: [{ messageId: "noBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$('p').bypassSecurityTrustUrl('XSS')",
|
||||
errors: [{ messageId: "noBypass"}]
|
||||
}
|
||||
]
|
||||
});
|
||||
errors: [{ messageId: "noBypass" }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
|
@ -12,7 +12,7 @@ ruleTester.run(ruleId, rule, {
|
|||
"aHrefSanitizationTrustedUrlList ('.*')",
|
||||
"x.aHrefSanitizationTrustedUrlList ('.*')",
|
||||
"$compileProvider.aHrefSanitizationTrustedUrlList ()",
|
||||
"$compileProvider.AHrefSanitizationTrustedUrlList ('.*')"
|
||||
"$compileProvider.AHrefSanitizationTrustedUrlList ('.*')",
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
|
@ -23,9 +23,9 @@ ruleTester.run(ruleId, rule, {
|
|||
line: 1,
|
||||
endLine: 1,
|
||||
column: 1,
|
||||
endColumn: 56
|
||||
}
|
||||
]
|
||||
endColumn: 56,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: "$compileProvider.imgSrcSanitizationTrustedUrlList('.*');",
|
||||
|
@ -35,9 +35,9 @@ ruleTester.run(ruleId, rule, {
|
|||
line: 1,
|
||||
endLine: 1,
|
||||
column: 1,
|
||||
endColumn: 56
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
endColumn: 56,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
|
@ -21,43 +21,43 @@ ruleTester.run(ruleId, rule, {
|
|||
invalid: [
|
||||
{
|
||||
code: "$sceDelegate.trustAs($sce.HTML, 'XSS')",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$sce.trustAs($sce.HTML, 'XSS')",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$sce.trustAsCss('XSS')",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$sce.trustAsHtml('XSS')",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$sce.trustAsJs('XSS')",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$sce.trustAsResourceUrl('XSS')",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$sce.trustAsUrl('XSS')",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$sceProvider.enabled(false)",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$sceProvider.enabled(0)",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
{
|
||||
code: "$sceProvider.enabled(true != true)",
|
||||
errors: [{ messageId: "doNotBypass" }]
|
||||
}
|
||||
]
|
||||
});
|
||||
errors: [{ messageId: "doNotBypass" }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
|
@ -14,16 +14,16 @@ ruleTester.run(ruleId, rule, {
|
|||
"$sanitizeProvider.enableSvg()",
|
||||
"$sanitizeProvider.enableSvg(false)",
|
||||
"$sanitizeProvider.enableSvg(0)",
|
||||
"$sanitizeProvider.EnableSvg(0)"
|
||||
"$sanitizeProvider.EnableSvg(0)",
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: "$sanitizeProvider.enableSvg(true)",
|
||||
errors: [{ messageId: "doNotEnableSVG" }]
|
||||
errors: [{ messageId: "doNotEnableSVG" }],
|
||||
},
|
||||
{
|
||||
code: "$sanitizeProvider.enableSvg(1)",
|
||||
errors: [{ messageId: "doNotEnableSVG" }]
|
||||
}
|
||||
]
|
||||
});
|
||||
errors: [{ messageId: "doNotEnableSVG" }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
|
@ -12,7 +12,7 @@ ruleTester.run(ruleId, rule, {
|
|||
"aHrefSanitizationWhitelist('.*')",
|
||||
"x.aHrefSanitizationWhitelist('.*')",
|
||||
"$compileProvider.aHrefSanitizationWhitelist()",
|
||||
"$compileProvider.AHrefSanitizationWhitelist('.*')"
|
||||
"$compileProvider.AHrefSanitizationWhitelist('.*')",
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
|
@ -23,9 +23,9 @@ ruleTester.run(ruleId, rule, {
|
|||
line: 1,
|
||||
endLine: 1,
|
||||
column: 1,
|
||||
endColumn: 50
|
||||
}
|
||||
]
|
||||
endColumn: 50,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: "$compileProvider.imgSrcSanitizationWhitelist('.*');",
|
||||
|
@ -35,9 +35,9 @@ ruleTester.run(ruleId, rule, {
|
|||
line: 1,
|
||||
endLine: 1,
|
||||
column: 1,
|
||||
endColumn: 51
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
endColumn: 51,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
const testUtils = require("../test-utils");
|
||||
|
||||
|
@ -39,25 +39,25 @@ function X() {
|
|||
}
|
||||
|
||||
documentLikeAPIFunction().cookie = '...';
|
||||
`
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: "document.cookie = '...'",
|
||||
errors: [{ messageId: "doNotUseCookies" }]
|
||||
errors: [{ messageId: "doNotUseCookies" }],
|
||||
},
|
||||
{
|
||||
code: "window.document.cookie = '...'",
|
||||
errors: [{ messageId: "doNotUseCookies" }]
|
||||
errors: [{ messageId: "doNotUseCookies" }],
|
||||
},
|
||||
{
|
||||
code: "this.window.document.cookie = '...'",
|
||||
errors: [{ messageId: "doNotUseCookies" }]
|
||||
errors: [{ messageId: "doNotUseCookies" }],
|
||||
},
|
||||
{
|
||||
code: "globalThis.window.document.cookie = '...'",
|
||||
errors: [{ messageId: "doNotUseCookies" }]
|
||||
errors: [{ messageId: "doNotUseCookies" }],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
|
@ -67,7 +67,7 @@ function documentFunction(): Document {
|
|||
}
|
||||
documentFunction().cookie = '...';
|
||||
`,
|
||||
errors: [{ messageId: "doNotUseCookies" }]
|
||||
errors: [{ messageId: "doNotUseCookies" }],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
|
@ -78,7 +78,7 @@ namespace Sample {
|
|||
}
|
||||
}
|
||||
`,
|
||||
errors: [{ messageId: "doNotUseCookies" }]
|
||||
}
|
||||
]
|
||||
});
|
||||
errors: [{ messageId: "doNotUseCookies" }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
const path = require("path");
|
||||
const testUtils = require("../test-utils");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
|
@ -23,22 +23,22 @@ function main() {
|
|||
var document: DocumentLikeAPI = documentLikeAPIFunction();
|
||||
document.domain = 'somevalue';
|
||||
}
|
||||
`
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
code: "var doc = window.document; doc.domain = 'somevalue';",
|
||||
errors: [{ messageId: "default" }]
|
||||
errors: [{ messageId: "default" }],
|
||||
},
|
||||
{
|
||||
code: "document.domain = 'somevalue'",
|
||||
errors: [{ messageId: "default" }]
|
||||
errors: [{ messageId: "default" }],
|
||||
},
|
||||
{
|
||||
code: "window.document.domain = 'somevalue'",
|
||||
errors: [{ messageId: "default" }]
|
||||
errors: [{ messageId: "default" }],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
|
@ -48,19 +48,19 @@ window.document.domain = somevalue;
|
|||
newWindow.document.domain = somevalue;
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
{
|
||||
line: 3,
|
||||
messageId: "default"
|
||||
messageId: "default",
|
||||
},
|
||||
{
|
||||
line: 4,
|
||||
messageId: "default"
|
||||
messageId: "default",
|
||||
},
|
||||
{
|
||||
line: 5,
|
||||
messageId: "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
messageId: "default",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
const path = require("path");
|
||||
const testUtils = require("../test-utils");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
|
@ -23,7 +23,7 @@ ruleTester.run(ruleId, rule, {
|
|||
writeln: () => {},
|
||||
};
|
||||
}
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
|
@ -43,8 +43,8 @@ ruleTester.run(ruleId, rule, {
|
|||
document.write('', '');
|
||||
document.writeln();
|
||||
document.writeln('', '');
|
||||
`
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
|
@ -63,8 +63,8 @@ ruleTester.run(ruleId, rule, {
|
|||
{ messageId: "default", line: 3 },
|
||||
{ messageId: "default", line: 4 },
|
||||
{ messageId: "default", line: 8 },
|
||||
{ messageId: "default", line: 9 }
|
||||
]
|
||||
{ messageId: "default", line: 9 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
|
@ -81,8 +81,8 @@ ruleTester.run(ruleId, rule, {
|
|||
{ messageId: "default", line: 4 },
|
||||
{ messageId: "default", line: 5 },
|
||||
{ messageId: "default", line: 6 },
|
||||
{ messageId: "default", line: 7 }
|
||||
]
|
||||
}
|
||||
]
|
||||
{ messageId: "default", line: 7 },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
|
@ -23,8 +23,8 @@ ruleTester.run(ruleId, rule, {
|
|||
nodeIntegration: false
|
||||
}
|
||||
});
|
||||
`
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
|
@ -38,10 +38,10 @@ ruleTester.run(ruleId, rule, {
|
|||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 4},
|
||||
{ messageId: "default", line: 5},
|
||||
{ messageId: "default", line: 6}
|
||||
]
|
||||
{ messageId: "default", line: 4 },
|
||||
{ messageId: "default", line: 5 },
|
||||
{ messageId: "default", line: 6 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
|
@ -54,10 +54,10 @@ ruleTester.run(ruleId, rule, {
|
|||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 4},
|
||||
{ messageId: "default", line: 5},
|
||||
{ messageId: "default", line: 6}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
{ messageId: "default", line: 4 },
|
||||
{ messageId: "default", line: 5 },
|
||||
{ messageId: "default", line: 6 },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
const testUtils = require("../test-utils");
|
||||
|
@ -14,16 +14,16 @@ ruleTester.run(ruleId, rule, {
|
|||
"test.html()",
|
||||
"test.html('','')",
|
||||
"element.html('');",
|
||||
"element.html(null);"
|
||||
"element.html(null);",
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: "$('p').html('XSS')",
|
||||
errors: [{ messageId: "default", line: 1 }]
|
||||
errors: [{ messageId: "default", line: 1 }],
|
||||
},
|
||||
{
|
||||
code: "$(selector).html(sample_function())",
|
||||
errors: [{ messageId: "default", line: 1 }]
|
||||
errors: [{ messageId: "default", line: 1 }],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
|
@ -31,9 +31,7 @@ ruleTester.run(ruleId, rule, {
|
|||
import $ from "jquery";
|
||||
test.html('XSS');
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 3 }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
errors: [{ messageId: "default", line: 3 }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
const testUtils = require("../test-utils");
|
||||
|
@ -29,8 +29,8 @@ ruleTester.run(ruleId, rule, {
|
|||
let test = new Test("test");
|
||||
test.innerHTML = test;
|
||||
test.outerHTML = test;
|
||||
`
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
// TypeScript with full type information
|
||||
|
@ -45,8 +45,8 @@ ruleTester.run(ruleId, rule, {
|
|||
errors: [
|
||||
{ messageId: "noInnerHtml", line: 3 },
|
||||
{ messageId: "noInnerHtml", line: 4 },
|
||||
{ messageId: "noInsertAdjacentHTML", line: 5 }
|
||||
]
|
||||
{ messageId: "noInsertAdjacentHTML", line: 5 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
|
@ -55,8 +55,8 @@ ruleTester.run(ruleId, rule, {
|
|||
`,
|
||||
errors: [
|
||||
{ messageId: "noInnerHtml", line: 2 },
|
||||
{ messageId: "noInnerHtml", line: 3 }
|
||||
]
|
||||
{ messageId: "noInnerHtml", line: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: `
|
||||
|
@ -65,12 +65,12 @@ ruleTester.run(ruleId, rule, {
|
|||
`,
|
||||
errors: [
|
||||
{ messageId: "noInnerHtml", line: 2 },
|
||||
{ messageId: "noInnerHtml", line: 3 }
|
||||
]
|
||||
{ messageId: "noInnerHtml", line: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: "element.insertAdjacentHTML('beforebegin', 'foo')",
|
||||
errors: [{ messageId: "noInsertAdjacentHTML", line: 1 }]
|
||||
}
|
||||
]
|
||||
});
|
||||
errors: [{ messageId: "noInsertAdjacentHTML", line: 1 }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
const testUtils = require("../test-utils");
|
||||
|
@ -20,38 +20,36 @@ ruleTester.run(ruleId, rule, {
|
|||
Math.random;
|
||||
math.random();
|
||||
random();
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
||||
code:`
|
||||
code: `
|
||||
require('./node_modules/not-unsafe-random');
|
||||
require('eslint');
|
||||
require('test');
|
||||
require('random-package');
|
||||
require('random-float2');
|
||||
require('random2-seed');
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
code:`
|
||||
code: `
|
||||
import './node_modules/untest';
|
||||
import 'random';
|
||||
import 'random-3';
|
||||
import 'eslint';
|
||||
import 'eslint-plugin-sdl';
|
||||
import 'testing';
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
||||
code:`
|
||||
code: `
|
||||
cryptos.pseudoRandomBytes();
|
||||
pseudoRandomBytes();
|
||||
pseudoRandomByte();
|
||||
cryptos.pseudoRondomBytes();
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
|
@ -62,11 +60,11 @@ ruleTester.run(ruleId, rule, {
|
|||
|
||||
Math.Random;
|
||||
Math.random;
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
code:`
|
||||
code: `
|
||||
function pseudoRandomBytes(){}
|
||||
function pseudoRandomByte(){}
|
||||
|
||||
|
@ -74,8 +72,8 @@ ruleTester.run(ruleId, rule, {
|
|||
pseudoRandomByte();
|
||||
cryptos.pseudoRondomBytes();
|
||||
cryptos.pseudoRondomBytes();
|
||||
`
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
|
@ -85,8 +83,8 @@ ruleTester.run(ruleId, rule, {
|
|||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 2 },
|
||||
{ messageId: "default", line: 3 }
|
||||
]
|
||||
{ messageId: "default", line: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
|
@ -96,8 +94,8 @@ ruleTester.run(ruleId, rule, {
|
|||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 2 },
|
||||
{ messageId: "default", line: 3 }
|
||||
]
|
||||
{ messageId: "default", line: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
|
@ -108,18 +106,14 @@ ruleTester.run(ruleId, rule, {
|
|||
|
||||
notMath().random();
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 6 }
|
||||
]
|
||||
errors: [{ messageId: "default", line: 6 }],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
code: `
|
||||
crypto.pseudoRandomBytes();
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 2 }
|
||||
]
|
||||
errors: [{ messageId: "default", line: 2 }],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
|
@ -130,13 +124,11 @@ ruleTester.run(ruleId, rule, {
|
|||
|
||||
notCrypto().pseudoRandomBytes();
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 6 }
|
||||
]
|
||||
errors: [{ messageId: "default", line: 6 }],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
code:`
|
||||
code: `
|
||||
import './node_modules/unique-random';
|
||||
import 'chance';
|
||||
import 'random-number';
|
||||
|
@ -150,12 +142,12 @@ ruleTester.run(ruleId, rule, {
|
|||
{ messageId: "default", line: 4 },
|
||||
{ messageId: "default", line: 5 },
|
||||
{ messageId: "default", line: 6 },
|
||||
{ messageId: "default", line: 7 }
|
||||
]
|
||||
{ messageId: "default", line: 7 },
|
||||
],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
code:`
|
||||
code: `
|
||||
import * as chance1 from 'chance';
|
||||
import defaultExport from 'chance';
|
||||
import { chance } from 'chance';
|
||||
|
@ -167,11 +159,11 @@ ruleTester.run(ruleId, rule, {
|
|||
{ messageId: "default", line: 3 },
|
||||
{ messageId: "default", line: 4 },
|
||||
{ messageId: "default", line: 5 },
|
||||
{ messageId: "default", line: 6 }
|
||||
]
|
||||
{ messageId: "default", line: 6 },
|
||||
],
|
||||
},
|
||||
{
|
||||
code:`
|
||||
code: `
|
||||
require('./node_modules/unique-random');
|
||||
require('**/chance.js');
|
||||
require('random-number');
|
||||
|
@ -185,8 +177,8 @@ ruleTester.run(ruleId, rule, {
|
|||
{ messageId: "default", line: 4 },
|
||||
{ messageId: "default", line: 5 },
|
||||
{ messageId: "default", line: 6 },
|
||||
{ messageId: "default", line: 7 }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
{ messageId: "default", line: 7 },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -15,60 +15,75 @@ const testUtils = require("../test-utils");
|
|||
let ruleTester = new RuleTester();
|
||||
|
||||
ruleTester.run(ruleId, rule, {
|
||||
valid: [
|
||||
{ // should allow https,ftps strings in variables
|
||||
code: `
|
||||
valid: [
|
||||
{
|
||||
// should allow https,ftps strings in variables
|
||||
code: `
|
||||
var x = 'https://www.example.com'
|
||||
var y = 'ftps://www.example.com'
|
||||
`
|
||||
},
|
||||
{ // should allow https,ftps template strings in variables
|
||||
code: `
|
||||
`,
|
||||
},
|
||||
{
|
||||
// should allow https,ftps template strings in variables
|
||||
code: `
|
||||
var x = \`https://www.template-examples.com\`
|
||||
var y = \`ftps://www.template-file-examples.com\`
|
||||
`,
|
||||
languageOptions: testUtils.es6LanguageOptions
|
||||
},
|
||||
{ // should allow https,ftps multipart template strings in variables
|
||||
code: `
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
},
|
||||
{
|
||||
// should allow https,ftps multipart template strings in variables
|
||||
code: `
|
||||
var x = \`https://www.\${multipartExample}.com\`
|
||||
var y = \`ftps://www.\${multipartExample}.com\`
|
||||
`,
|
||||
languageOptions: testUtils.es6LanguageOptions
|
||||
},
|
||||
{ // should allow http,ftp in middle of string
|
||||
code: "var x = 'The protocol may be http://, https://, ftp:// or ftps://'"
|
||||
},
|
||||
{ // should allow https,ftps strings in default values
|
||||
code: `
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
},
|
||||
{
|
||||
// should allow http,ftp in middle of string
|
||||
code: "var x = 'The protocol may be http://, https://, ftp:// or ftps://'",
|
||||
},
|
||||
{
|
||||
// should allow https,ftps strings in default values
|
||||
code: `
|
||||
function f(x : string = 'https://www.example.com') {}
|
||||
function f(y : string = 'ftps://www.example.com') {}
|
||||
`,
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
},
|
||||
{ // should allow user-provided exceptions matches, regardless of upper/lower-case
|
||||
code: `
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
},
|
||||
{
|
||||
// should allow user-provided exceptions matches, regardless of upper/lower-case
|
||||
code: `
|
||||
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'
|
||||
`,
|
||||
options: [{
|
||||
exceptions: ["HTTP:\/\/www\.allow-example\.com\/?.*", "FtP:\/\/www\.allow-file-example\.com", "LdaP:\/\/www\.allow-ldap-example\.com"]
|
||||
}]
|
||||
options: [
|
||||
{
|
||||
exceptions: [
|
||||
"HTTP://www.allow-example.com/?.*",
|
||||
"FtP://www.allow-file-example.com",
|
||||
"LdaP://www.allow-ldap-example.com",
|
||||
],
|
||||
},
|
||||
{ // should allow user-provided exceptions for variable name matches, regardless of upper/lower-case
|
||||
code: `
|
||||
],
|
||||
},
|
||||
{
|
||||
// should allow user-provided exceptions for variable name matches, regardless of upper/lower-case
|
||||
code: `
|
||||
var insecureURL = 'http://www.allow-example.com'
|
||||
var InSeCuReURL = 'ftp://www.allow-example.com/path'
|
||||
`,
|
||||
options: [{
|
||||
varExceptions: ["insecure?.*"]
|
||||
}]
|
||||
},
|
||||
options: [
|
||||
{
|
||||
// should allow xml namespaces, as they are not accessed by the browser
|
||||
code: `
|
||||
varExceptions: ["insecure?.*"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
// should allow xml namespaces, as they are not accessed by the browser
|
||||
code: `
|
||||
const someSvg: React.FC = () => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
|
@ -76,121 +91,132 @@ ruleTester.run(ruleId, rule, {
|
|||
);
|
||||
};
|
||||
`,
|
||||
languageOptions: testUtils.tsReactLanguageOptions,
|
||||
},
|
||||
{
|
||||
// should allow localhost
|
||||
code: `
|
||||
languageOptions: testUtils.tsReactLanguageOptions,
|
||||
},
|
||||
{
|
||||
// should allow localhost
|
||||
code: `
|
||||
var x = "http://localhost/test";
|
||||
var y = "http://localhost";
|
||||
`
|
||||
},
|
||||
{
|
||||
// should allow xml namespaces for XHTML and SVG even if outside of jsx xmlns attribute
|
||||
code: `
|
||||
`,
|
||||
},
|
||||
{
|
||||
// should allow xml namespaces for XHTML and SVG even if outside of jsx xmlns attribute
|
||||
code: `
|
||||
var x = "http://www.w3.org/1999/xhtml";
|
||||
var y = "http://www.w3.org/2000/svg";
|
||||
`
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{ // should ban http,ftp strings in variables
|
||||
code: `
|
||||
`,
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
// should ban http,ftp strings in variables
|
||||
code: `
|
||||
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'
|
||||
`,
|
||||
output: `
|
||||
output: `
|
||||
var x1 = "https://www.examples.com"
|
||||
var x2 = "https://www.examples.com"
|
||||
var y1 = 'ftp://www.file-examples.com'
|
||||
var y2 = 'FTP://www.file-examples.com'
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 4},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 5}
|
||||
],
|
||||
},
|
||||
{ // should ban http,ftp template strings in variables
|
||||
code: `
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 4 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 5 },
|
||||
],
|
||||
},
|
||||
{
|
||||
// should ban http,ftp template strings in variables
|
||||
code: `
|
||||
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\`
|
||||
`,
|
||||
output: `
|
||||
output: `
|
||||
var x1 = \`https://www.template-examples.com\`
|
||||
var x2 = \`https://www.template-examples.com\`
|
||||
var y1 = \`ftp://www.file-examples.com\`
|
||||
var y2 = \`FTP://www.file-examples.com\`
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 4},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 5}
|
||||
],
|
||||
languageOptions: testUtils.es6LanguageOptions
|
||||
},
|
||||
{ // should ban http,ftp multipart template strings in variables
|
||||
code: `
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 4 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 5 },
|
||||
],
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
},
|
||||
{
|
||||
// should ban http,ftp multipart template strings in variables
|
||||
code: `
|
||||
var x1 = \`http://www.\${multipartExample}.com\`;
|
||||
var y1 = \`ftp://www.\${multipartExample}.com\`;
|
||||
`,
|
||||
output: `
|
||||
output: `
|
||||
var x1 = \`https://www.\${multipartExample}.com\`;
|
||||
var y1 = \`ftp://www.\${multipartExample}.com\`;
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3},
|
||||
],
|
||||
languageOptions: testUtils.es6LanguageOptions
|
||||
},
|
||||
{ // should ban http,ftp strings in default values
|
||||
code: `
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3 },
|
||||
],
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
},
|
||||
{
|
||||
// should ban http,ftp strings in default values
|
||||
code: `
|
||||
function f(x : string = 'http://www.example.com') {}
|
||||
function f(y : string = 'ftp://www.example.com') {}
|
||||
`,
|
||||
output: `
|
||||
output: `
|
||||
function f(x : string = "https://www.example.com") {}
|
||||
function f(y : string = 'ftp://www.example.com') {}
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3},
|
||||
],
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
},
|
||||
{ // should ban user-provided blacklist matches, regardless of upper/lower-case
|
||||
code: `
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3 },
|
||||
],
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
},
|
||||
{
|
||||
// should ban user-provided blacklist matches, regardless of upper/lower-case
|
||||
code: `
|
||||
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'
|
||||
`,
|
||||
output: `
|
||||
output: `
|
||||
var a1 = "https://www.ban-example.com"
|
||||
var a2 = "https://www.ban-example.com/path"
|
||||
var b1 = 'FtP://www.ban-file-example.com'
|
||||
var c1 = 'LDAp://www.ban-ldap-example.com'
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 4},
|
||||
{ messageId: "doNotUseInsecureUrl", line: 5}
|
||||
],
|
||||
options: [{
|
||||
blocklist: ["htTp:\/\/www\.ban-example\.com\/?.*", "fTp:\/\/www\.ban-file-example\.com\/?.*", "lDAp:\/\/www\.ban-ldap-example\.com\/?.*"]
|
||||
}]
|
||||
},
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 2 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 3 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 4 },
|
||||
{ messageId: "doNotUseInsecureUrl", line: 5 },
|
||||
],
|
||||
options: [
|
||||
{
|
||||
// should ban any other xml attribute with urls in them
|
||||
code: `
|
||||
blocklist: [
|
||||
"htTp://www.ban-example.com/?.*",
|
||||
"fTp://www.ban-file-example.com/?.*",
|
||||
"lDAp://www.ban-ldap-example.com/?.*",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
// should ban any other xml attribute with urls in them
|
||||
code: `
|
||||
const someSvg: React.FC = () => {
|
||||
return (
|
||||
<svg someOtherAttribute="http://ban-example.com/">
|
||||
|
@ -198,7 +224,7 @@ ruleTester.run(ruleId, rule, {
|
|||
);
|
||||
};
|
||||
`,
|
||||
output: `
|
||||
output: `
|
||||
const someSvg: React.FC = () => {
|
||||
return (
|
||||
<svg someOtherAttribute="https://ban-example.com/">
|
||||
|
@ -206,38 +232,30 @@ ruleTester.run(ruleId, rule, {
|
|||
);
|
||||
};
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 4},
|
||||
],
|
||||
languageOptions: testUtils.tsReactLanguageOptions,
|
||||
},
|
||||
{
|
||||
// should escape the url string correctly
|
||||
code: `var a1 = "http://moz\ti\tlla.org";`,
|
||||
output: `var a1 = "https://moz\\ti\\tlla.org";`,
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 1},
|
||||
],
|
||||
},
|
||||
{
|
||||
// should fix url in `` correctly
|
||||
code: "var x1 = `http://foo${multipartExample} http://${multipartExample}.com`;",
|
||||
output: "var x1 = `https://foo${multipartExample} http://${multipartExample}.com`;",
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 1},
|
||||
],
|
||||
errors: [{ messageId: "doNotUseInsecureUrl", line: 4 }],
|
||||
languageOptions: testUtils.tsReactLanguageOptions,
|
||||
},
|
||||
{
|
||||
// should escape the url string correctly
|
||||
code: `var a1 = "http://moz\ti\tlla.org";`,
|
||||
output: `var a1 = "https://moz\\ti\\tlla.org";`,
|
||||
errors: [{ messageId: "doNotUseInsecureUrl", line: 1 }],
|
||||
},
|
||||
{
|
||||
// should fix url in `` correctly
|
||||
code: "var x1 = `http://foo${multipartExample} http://${multipartExample}.com`;",
|
||||
output: "var x1 = `https://foo${multipartExample} http://${multipartExample}.com`;",
|
||||
errors: [{ messageId: "doNotUseInsecureUrl", line: 1 }],
|
||||
|
||||
languageOptions: testUtils.es6LanguageOptions
|
||||
},
|
||||
{
|
||||
// should escape the string and fix it properly in ``
|
||||
code: `var a1 = \`http://moz\ti\tlla.org\`;`,
|
||||
output: `var a1 = \`https://moz\\ti\\tlla.org\`;`,
|
||||
errors: [
|
||||
{ messageId: "doNotUseInsecureUrl", line: 1},
|
||||
],
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
},
|
||||
{
|
||||
// should escape the string and fix it properly in ``
|
||||
code: `var a1 = \`http://moz\ti\tlla.org\`;`,
|
||||
output: `var a1 = \`https://moz\\ti\\tlla.org\`;`,
|
||||
errors: [{ messageId: "doNotUseInsecureUrl", line: 1 }],
|
||||
|
||||
languageOptions: testUtils.es6LanguageOptions
|
||||
},
|
||||
]
|
||||
});
|
||||
languageOptions: testUtils.es6LanguageOptions,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,22 +3,17 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
const testUtils = require("../test-utils");
|
||||
|
||||
ruleTester.run(ruleId, rule, {
|
||||
valid: [
|
||||
"test.execUnsafeLocalFunction = 'test'",
|
||||
"MSApp.execUnsafeLocalFunction()"
|
||||
],
|
||||
valid: ["test.execUnsafeLocalFunction = 'test'", "MSApp.execUnsafeLocalFunction()"],
|
||||
invalid: [
|
||||
{
|
||||
code: "MSApp.execUnsafeLocalFunction(testfunc)",
|
||||
errors: [
|
||||
{ messageId: "default", line: 1, type: 'CallExpression' }
|
||||
]
|
||||
}
|
||||
]
|
||||
errors: [{ messageId: "default", line: 1, type: "CallExpression" }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
const path = require("path");
|
||||
const testUtils = require("../test-utils");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
|
@ -27,8 +27,8 @@ function main() {
|
|||
var w: WindowLike = new WindowLike();
|
||||
w.postMessage('test', '*');
|
||||
}
|
||||
`
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
|
@ -38,8 +38,8 @@ function main() {
|
|||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 2 },
|
||||
{ messageId: "default", line: 3 }
|
||||
]
|
||||
{ messageId: "default", line: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
languageOptions: testUtils.tsLanguageOptions,
|
||||
|
@ -50,8 +50,8 @@ function main() {
|
|||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 2 },
|
||||
{ messageId: "default", line: 4 }
|
||||
]
|
||||
{ messageId: "default", line: 4 },
|
||||
],
|
||||
},
|
||||
]
|
||||
});
|
||||
],
|
||||
});
|
||||
|
|
|
@ -4,16 +4,12 @@
|
|||
"use strict";
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
|
||||
ruleTester.run(ruleId, rule, {
|
||||
valid: [
|
||||
"foo.allocUnsafe",
|
||||
"Buffer.allocUnsafe(0)",
|
||||
"Buffer.allocUnsafeSlow(0)"
|
||||
],
|
||||
valid: ["foo.allocUnsafe", "Buffer.allocUnsafe(0)", "Buffer.allocUnsafeSlow(0)"],
|
||||
invalid: [
|
||||
{
|
||||
code: `
|
||||
|
@ -22,8 +18,8 @@ ruleTester.run(ruleId, rule, {
|
|||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 2 },
|
||||
{ messageId: "default", line: 3 }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
{ messageId: "default", line: 3 },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
var ruleTester = new RuleTester();
|
||||
const testUtils = require("../test-utils");
|
||||
|
||||
ruleTester.run(ruleId, rule, {
|
||||
valid: [
|
||||
'element.insertAdjacentHTMLUnsafe = "test";'
|
||||
],
|
||||
valid: ['element.insertAdjacentHTMLUnsafe = "test";'],
|
||||
invalid: [
|
||||
{
|
||||
code: `
|
||||
|
@ -20,10 +18,10 @@ ruleTester.run(ruleId, rule, {
|
|||
WinJS.Utilities.setOuterHTMLUnsafe(element, text);
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: "default", line: 2, type: 'CallExpression' },
|
||||
{ messageId: "default", line: 3, type: 'CallExpression' },
|
||||
{ messageId: "default", line: 4, type: 'CallExpression' }
|
||||
]
|
||||
}
|
||||
]
|
||||
{ messageId: "default", line: 2, type: "CallExpression" },
|
||||
{ messageId: "default", line: 3, type: "CallExpression" },
|
||||
{ messageId: "default", line: 4, type: "CallExpression" },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
const path = require("path");
|
||||
const ruleId = path.parse(__filename).name;
|
||||
const rule = require(path.join('../../../lib/rules/', ruleId));
|
||||
const rule = require(path.join("../../../lib/rules/", ruleId));
|
||||
const RuleTester = require("eslint").RuleTester;
|
||||
|
||||
var ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
sourceType: "module",
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
}
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
ruleTester.run(ruleId, rule, {
|
||||
|
@ -37,45 +37,49 @@ ruleTester.run(ruleId, rule, {
|
|||
{ code: '<iframe sandbox="allow-same-origin"></iframe>' },
|
||||
{ code: '<iframe sandbox="allow-scripts"></iframe>' },
|
||||
{ code: '<iframe sandbox="allow-top-navigation"></iframe>' },
|
||||
{ code: '<iframe sandbox="allow-top-navigation-by-user-activation"></iframe>' },
|
||||
{
|
||||
code: '<iframe sandbox="allow-top-navigation-by-user-activation"></iframe>',
|
||||
},
|
||||
{ code: '<iframe sandbox="allow-forms allow-modals"></iframe>' },
|
||||
{ code: '<iframe sandbox="allow-popups allow-popups-to-escape-sandbox allow-pointer-lock allow-same-origin allow-top-navigation"></iframe>' }
|
||||
{
|
||||
code: '<iframe sandbox="allow-popups allow-popups-to-escape-sandbox allow-pointer-lock allow-same-origin allow-top-navigation"></iframe>',
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: '<iframe></iframe>;',
|
||||
errors: [{ messageId: 'attributeMissing' }]
|
||||
code: "<iframe></iframe>;",
|
||||
errors: [{ messageId: "attributeMissing" }],
|
||||
},
|
||||
{
|
||||
code: '<iframe/>;',
|
||||
errors: [{ messageId: 'attributeMissing' }]
|
||||
code: "<iframe/>;",
|
||||
errors: [{ messageId: "attributeMissing" }],
|
||||
},
|
||||
{
|
||||
code: '<iframe sandbox="__unknown__"></iframe>',
|
||||
errors: [{ messageId: 'invalidValue', data: { value: '__unknown__' } }]
|
||||
errors: [{ messageId: "invalidValue", data: { value: "__unknown__" } }],
|
||||
},
|
||||
{
|
||||
code: '<iframe sandbox="allow-popups __unknown__"/>',
|
||||
errors: [{ messageId: 'invalidValue', data: { value: '__unknown__' } }]
|
||||
errors: [{ messageId: "invalidValue", data: { value: "__unknown__" } }],
|
||||
},
|
||||
{
|
||||
code: '<iframe sandbox="__unknown__ allow-popups"/>',
|
||||
errors: [{ messageId: 'invalidValue', data: { value: '__unknown__' } }]
|
||||
errors: [{ messageId: "invalidValue", data: { value: "__unknown__" } }],
|
||||
},
|
||||
{
|
||||
code: '<iframe sandbox=" allow-forms __unknown__ allow-popups __unknown__ "/>',
|
||||
errors: [
|
||||
{ messageId: 'invalidValue', data: { value: '__unknown__' } },
|
||||
{ messageId: 'invalidValue', data: { value: '__unknown__' } }
|
||||
]
|
||||
{ messageId: "invalidValue", data: { value: "__unknown__" } },
|
||||
{ messageId: "invalidValue", data: { value: "__unknown__" } },
|
||||
],
|
||||
},
|
||||
{
|
||||
code: '<iframe sandbox="allow-scripts allow-same-origin"></iframe>;',
|
||||
errors: [{ messageId: 'invalidCombination' }]
|
||||
errors: [{ messageId: "invalidCombination" }],
|
||||
},
|
||||
{
|
||||
code: '<iframe sandbox="allow-same-origin allow-scripts"/>;',
|
||||
errors: [{ messageId: 'invalidCombination' }]
|
||||
}
|
||||
]
|
||||
});
|
||||
errors: [{ messageId: "invalidCombination" }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -11,27 +11,27 @@ const path = require("path");
|
|||
const tsParser = require("@typescript-eslint/parser");
|
||||
|
||||
module.exports = {
|
||||
es6LanguageOptions: {
|
||||
parserOptions: {
|
||||
ecmaVersion: 6,
|
||||
sourceType: "module"
|
||||
}
|
||||
es6LanguageOptions: {
|
||||
parserOptions: {
|
||||
ecmaVersion: 6,
|
||||
sourceType: "module",
|
||||
},
|
||||
tsLanguageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
tsconfigRootDir: path.join(__dirname, "..", "fixtures", "ts"),
|
||||
projectService: true,
|
||||
}
|
||||
},
|
||||
tsLanguageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
tsconfigRootDir: path.join(__dirname, "..", "fixtures", "ts"),
|
||||
projectService: true,
|
||||
},
|
||||
tsReactLanguageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
tsconfigRootDir: path.join(__dirname, "..", "fixtures", "tsx"),
|
||||
projectService: true,
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
tsReactLanguageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
tsconfigRootDir: path.join(__dirname, "..", "fixtures", "tsx"),
|
||||
projectService: true,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче