@lipemat/eslint-config 5.0.0-beta.4 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/helpers/config.js +2 -2
- package/package.json +1 -1
- package/plugins/security/helpers/dom-purify.js +18 -0
- package/plugins/security/helpers/element.js +18 -0
- package/plugins/security/helpers/string.js +39 -0
- package/plugins/security/helpers/ts-types.js +9 -0
- package/plugins/security/rules/dangerously-set-inner-html.js +1 -1
- package/plugins/security/rules/html-executing-assignment.js +3 -1
- package/plugins/security/rules/html-executing-function.js +3 -1
- package/plugins/security/rules/html-sinks.js +2 -1
- package/plugins/security/rules/jquery-executing.js +2 -1
- package/plugins/security/rules/window-escaping.js +2 -1
- package/types/plugins/security/helpers/dom-purify.d.ts +6 -0
- package/types/plugins/security/helpers/element.d.ts +10 -0
- package/types/plugins/security/helpers/string.d.ts +20 -0
- package/types/plugins/security/helpers/ts-types.d.ts +6 -0
- package/plugins/security/utils/shared.js +0 -78
- package/types/plugins/security/utils/shared.d.ts +0 -39
package/helpers/config.js
CHANGED
|
@@ -21,11 +21,11 @@ import { getExtensionsConfig } from '@lipemat/js-boilerplate/helpers/config.js';
|
|
|
21
21
|
*/
|
|
22
22
|
export function getConfig(configs) {
|
|
23
23
|
const BASE = {
|
|
24
|
-
configs
|
|
24
|
+
configs,
|
|
25
25
|
};
|
|
26
26
|
const mergedConfig = {
|
|
27
27
|
...BASE,
|
|
28
|
-
...getExtensionsConfig('eslint.config', BASE)
|
|
28
|
+
...getExtensionsConfig('eslint.config', BASE),
|
|
29
29
|
};
|
|
30
30
|
return mergedConfig.configs;
|
|
31
31
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Check if a node is a call to a known sanitization function.
|
|
4
|
+
* - Currently recognizes `sanitize(...)` and `DOMPurify.sanitize(...)`.
|
|
5
|
+
*/
|
|
6
|
+
export function isSanitized(node) {
|
|
7
|
+
if (AST_NODE_TYPES.CallExpression !== node.type) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
if (AST_NODE_TYPES.Identifier === node.callee.type && 'sanitize' === node.callee.name) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
if (AST_NODE_TYPES.MemberExpression === node.callee.type && AST_NODE_TYPES.Identifier === node.callee.object.type) {
|
|
14
|
+
return 'dompurify' === node.callee.object.name.toLowerCase() &&
|
|
15
|
+
AST_NODE_TYPES.Identifier === node.callee.property.type && 'sanitize' === node.callee.property.name;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getType } from './ts-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Is the type of variable being passed a DOM element?
|
|
4
|
+
*
|
|
5
|
+
* - DOM elements are of the type `HTML{*}Element`.
|
|
6
|
+
* - DOM elements do not require sanitization.
|
|
7
|
+
*
|
|
8
|
+
* @link https://typescript-eslint.io/developers/custom-rules/#typed-rules
|
|
9
|
+
*/
|
|
10
|
+
export function isDomElementType(expression, context) {
|
|
11
|
+
const type = getType(expression, context);
|
|
12
|
+
const name = type.getSymbol()?.escapedName ?? '';
|
|
13
|
+
// Match any type that ends with "Element", e.g., HTMLElement, HTMLDivElement, Element, etc.
|
|
14
|
+
if ('Element' === name) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return name.startsWith('HTML') && name.endsWith('Element');
|
|
18
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
import { getType } from './ts-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Is the node of type string.
|
|
5
|
+
* - String literals.
|
|
6
|
+
* - constants of type string.
|
|
7
|
+
* - template literals.
|
|
8
|
+
* - intrinsic type string.
|
|
9
|
+
*/
|
|
10
|
+
export function isStringLike(node, context) {
|
|
11
|
+
const type = getType(node, context);
|
|
12
|
+
const literal = type.isStringLiteral();
|
|
13
|
+
const intrinsic = 'intrinsicName' in type && 'string' === type.intrinsicName;
|
|
14
|
+
return (AST_NODE_TYPES.Literal === node.type && 'string' === typeof node.value) || (AST_NODE_TYPES.TemplateLiteral === node.type) || literal || intrinsic;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check if a node is a literal string
|
|
18
|
+
*/
|
|
19
|
+
export function isLiteralString(node) {
|
|
20
|
+
return AST_NODE_TYPES.Literal === node.type && 'string' === typeof node.value;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if a node is a literal string that is safe to use in an HTML context.
|
|
24
|
+
* - Must be a literal string. Or a conditional expression where both branches are safe literal strings.
|
|
25
|
+
* - Must not contain `<script`.
|
|
26
|
+
* - Must not start with a dangerous protocol (javascript:, data:, vbscript:, about:, livescript:).
|
|
27
|
+
*/
|
|
28
|
+
export function isSafeLiteralString(node) {
|
|
29
|
+
if (AST_NODE_TYPES.ConditionalExpression === node.type) {
|
|
30
|
+
return isSafeLiteralString(node.consequent) && isSafeLiteralString(node.alternate);
|
|
31
|
+
}
|
|
32
|
+
if (!isLiteralString(node)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (node.value.includes('<script')) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return !/^\s*(?:javascript|data|vbscript|about|livescript)\s*:/i.test(decodeURIComponent(node.value.replace(/[\u0000-\u001F\u007F]+/g, '')));
|
|
39
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Get the TypeScript type of node.
|
|
4
|
+
*/
|
|
5
|
+
export function getType(expression, context) {
|
|
6
|
+
const { getTypeAtLocation } = ESLintUtils.getParserServices(context);
|
|
7
|
+
const type = getTypeAtLocation(expression);
|
|
8
|
+
return type.getNonNullableType();
|
|
9
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import { isSanitized } from '../
|
|
2
|
+
import { isSanitized } from '../helpers/dom-purify.js';
|
|
3
3
|
function isDangerouslySetInnerHTML(node) {
|
|
4
4
|
return ('JSXAttribute' === node.type &&
|
|
5
5
|
'dangerouslySetInnerHTML' === node.name.name);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import {
|
|
2
|
+
import { isSafeLiteralString } from '../helpers/string.js';
|
|
3
|
+
import { isSanitized } from '../helpers/dom-purify.js';
|
|
4
|
+
import { isDomElementType } from '../helpers/element.js';
|
|
3
5
|
const UNSAFE_PROPERTIES = [
|
|
4
6
|
'innerHTML',
|
|
5
7
|
'outerHTML',
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import { isDomElementType, isSafeLiteralString, isSanitized } from '../utils/shared.js';
|
|
3
2
|
import { isJQueryCall } from './jquery-executing.js';
|
|
3
|
+
import { isSafeLiteralString } from '../helpers/string.js';
|
|
4
|
+
import { isSanitized } from '../helpers/dom-purify.js';
|
|
5
|
+
import { isDomElementType } from '../helpers/element.js';
|
|
4
6
|
const DOCUMENT_METHODS = [
|
|
5
7
|
'document.write',
|
|
6
8
|
'document.writeln',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import { isLiteralString,
|
|
2
|
+
import { isLiteralString, isStringLike } from '../helpers/string.js';
|
|
3
|
+
import { isSanitized } from '../helpers/dom-purify.js';
|
|
3
4
|
/**
|
|
4
5
|
* Get the callee name from a call expression
|
|
5
6
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import {
|
|
2
|
+
import { isSanitized } from '../helpers/dom-purify.js';
|
|
3
|
+
import { getType } from '../helpers/ts-types.js';
|
|
3
4
|
/**
|
|
4
5
|
* @link https://docs.wpvip.com/security/javascript-security-recommendations/#h-stripping-tags
|
|
5
6
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import { isLiteralString
|
|
2
|
+
import { isLiteralString } from '../helpers/string.js';
|
|
3
|
+
import { isSanitized } from '../helpers/dom-purify.js';
|
|
3
4
|
// Window and location properties that need special handling
|
|
4
5
|
const LOCATION_PROPS = new Set(['href', 'src', 'action',
|
|
5
6
|
'protocol', 'host', 'hostname', 'pathname', 'search', 'hash', 'username', 'port', 'name', 'status',
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Check if a node is a call to a known sanitization function.
|
|
4
|
+
* - Currently recognizes `sanitize(...)` and `DOMPurify.sanitize(...)`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isSanitized(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Is the type of variable being passed a DOM element?
|
|
4
|
+
*
|
|
5
|
+
* - DOM elements are of the type `HTML{*}Element`.
|
|
6
|
+
* - DOM elements do not require sanitization.
|
|
7
|
+
*
|
|
8
|
+
* @link https://typescript-eslint.io/developers/custom-rules/#typed-rules
|
|
9
|
+
*/
|
|
10
|
+
export declare function isDomElementType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(expression: TSESTree.CallExpressionArgument, context: Context): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Is the node of type string.
|
|
4
|
+
* - String literals.
|
|
5
|
+
* - constants of type string.
|
|
6
|
+
* - template literals.
|
|
7
|
+
* - intrinsic type string.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isStringLike(node: TSESTree.CallExpressionArgument, context: Readonly<TSESLint.RuleContext<string, readonly []>>): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Check if a node is a literal string
|
|
12
|
+
*/
|
|
13
|
+
export declare function isLiteralString(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): node is TSESTree.StringLiteral;
|
|
14
|
+
/**
|
|
15
|
+
* Check if a node is a literal string that is safe to use in an HTML context.
|
|
16
|
+
* - Must be a literal string. Or a conditional expression where both branches are safe literal strings.
|
|
17
|
+
* - Must not contain `<script`.
|
|
18
|
+
* - Must not start with a dangerous protocol (javascript:, data:, vbscript:, about:, livescript:).
|
|
19
|
+
*/
|
|
20
|
+
export declare function isSafeLiteralString(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): boolean;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import type { Type } from 'typescript';
|
|
3
|
+
/**
|
|
4
|
+
* Get the TypeScript type of node.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(expression: TSESTree.CallExpressionArgument, context: Context): Type;
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
import {} from 'typescript';
|
|
3
|
-
/**
|
|
4
|
-
* Is the node of type string.
|
|
5
|
-
* - String literals.
|
|
6
|
-
* - constants of type string.
|
|
7
|
-
* - template literals.
|
|
8
|
-
* - intrinsic type string.
|
|
9
|
-
*/
|
|
10
|
-
export function isStringLike(node, context) {
|
|
11
|
-
const type = getType(node, context);
|
|
12
|
-
const literal = type.isStringLiteral();
|
|
13
|
-
const intrinsic = 'intrinsicName' in type && 'string' === type.intrinsicName;
|
|
14
|
-
return (AST_NODE_TYPES.Literal === node.type && 'string' === typeof node.value) || (AST_NODE_TYPES.TemplateLiteral === node.type) || literal || intrinsic;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Get the TypeScript type of node.
|
|
18
|
-
*/
|
|
19
|
-
export function getType(expression, context) {
|
|
20
|
-
const { getTypeAtLocation } = ESLintUtils.getParserServices(context);
|
|
21
|
-
const type = getTypeAtLocation(expression);
|
|
22
|
-
return type.getNonNullableType();
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Is the type of variable being passed a DOM element?
|
|
26
|
-
*
|
|
27
|
-
* - DOM elements are of the type `HTML{*}Element`.
|
|
28
|
-
* - DOM elements do not require sanitization.
|
|
29
|
-
*
|
|
30
|
-
* @link https://typescript-eslint.io/developers/custom-rules/#typed-rules
|
|
31
|
-
*/
|
|
32
|
-
export function isDomElementType(expression, context) {
|
|
33
|
-
const type = getType(expression, context);
|
|
34
|
-
const name = type.getSymbol()?.escapedName ?? '';
|
|
35
|
-
// Match any type that ends with "Element", e.g., HTMLElement, HTMLDivElement, Element, etc.
|
|
36
|
-
if ('Element' === name) {
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
return name.startsWith('HTML') && name.endsWith('Element');
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Check if a node is a call to a known sanitization function.
|
|
43
|
-
* - Currently recognizes `sanitize(...)` and `DOMPurify.sanitize(...)`.
|
|
44
|
-
*/
|
|
45
|
-
export function isSanitized(node) {
|
|
46
|
-
if (AST_NODE_TYPES.CallExpression !== node.type) {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
if (AST_NODE_TYPES.Identifier === node.callee.type && 'sanitize' === node.callee.name) {
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
if (AST_NODE_TYPES.MemberExpression === node.callee.type && AST_NODE_TYPES.Identifier === node.callee.object.type) {
|
|
53
|
-
return 'dompurify' === node.callee.object.name.toLowerCase() &&
|
|
54
|
-
AST_NODE_TYPES.Identifier === node.callee.property.type && 'sanitize' === node.callee.property.name;
|
|
55
|
-
}
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Check if a node is a literal string
|
|
60
|
-
*/
|
|
61
|
-
export function isLiteralString(node) {
|
|
62
|
-
return AST_NODE_TYPES.Literal === node.type && 'string' === typeof node.value;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Check if a node is a literal string that is safe to use in an HTML context.
|
|
66
|
-
* - Must be a literal string.
|
|
67
|
-
* - Must not contain `<script`.
|
|
68
|
-
* - Must not start with a dangerous protocol (javascript:, data:, vbscript:, about:, livescript:).
|
|
69
|
-
*/
|
|
70
|
-
export function isSafeLiteralString(node) {
|
|
71
|
-
if (!isLiteralString(node)) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
if (node.value.includes('<script')) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
return !/^\s*(?:javascript|data|vbscript|about|livescript)\s*:/i.test(decodeURIComponent(node.value.replace(/[\u0000-\u001F\u007F]+/g, '')));
|
|
78
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
-
import { type Type } from 'typescript';
|
|
3
|
-
/**
|
|
4
|
-
* Is the node of type string.
|
|
5
|
-
* - String literals.
|
|
6
|
-
* - constants of type string.
|
|
7
|
-
* - template literals.
|
|
8
|
-
* - intrinsic type string.
|
|
9
|
-
*/
|
|
10
|
-
export declare function isStringLike(node: TSESTree.CallExpressionArgument, context: Readonly<TSESLint.RuleContext<string, readonly []>>): boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Get the TypeScript type of node.
|
|
13
|
-
*/
|
|
14
|
-
export declare function getType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(expression: TSESTree.CallExpressionArgument, context: Context): Type;
|
|
15
|
-
/**
|
|
16
|
-
* Is the type of variable being passed a DOM element?
|
|
17
|
-
*
|
|
18
|
-
* - DOM elements are of the type `HTML{*}Element`.
|
|
19
|
-
* - DOM elements do not require sanitization.
|
|
20
|
-
*
|
|
21
|
-
* @link https://typescript-eslint.io/developers/custom-rules/#typed-rules
|
|
22
|
-
*/
|
|
23
|
-
export declare function isDomElementType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(expression: TSESTree.CallExpressionArgument, context: Context): boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Check if a node is a call to a known sanitization function.
|
|
26
|
-
* - Currently recognizes `sanitize(...)` and `DOMPurify.sanitize(...)`.
|
|
27
|
-
*/
|
|
28
|
-
export declare function isSanitized(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): boolean;
|
|
29
|
-
/**
|
|
30
|
-
* Check if a node is a literal string
|
|
31
|
-
*/
|
|
32
|
-
export declare function isLiteralString(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): node is TSESTree.StringLiteral;
|
|
33
|
-
/**
|
|
34
|
-
* Check if a node is a literal string that is safe to use in an HTML context.
|
|
35
|
-
* - Must be a literal string.
|
|
36
|
-
* - Must not contain `<script`.
|
|
37
|
-
* - Must not start with a dangerous protocol (javascript:, data:, vbscript:, about:, livescript:).
|
|
38
|
-
*/
|
|
39
|
-
export declare function isSafeLiteralString(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): boolean;
|