@lipemat/eslint-config 5.0.1 → 5.1.0-beta.1

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.
Files changed (63) hide show
  1. package/helpers/config.js +1 -0
  2. package/helpers/config.js.map +1 -0
  3. package/{types/helpers/config.d.ts → helpers/config.ts} +16 -5
  4. package/index.js +1 -0
  5. package/package.json +8 -11
  6. package/plugins/security/helpers/dom-purify.js +1 -0
  7. package/plugins/security/helpers/dom-purify.js.map +1 -0
  8. package/plugins/security/helpers/dom-purify.ts +21 -0
  9. package/plugins/security/helpers/element.js +1 -0
  10. package/plugins/security/helpers/element.js.map +1 -0
  11. package/plugins/security/helpers/element.ts +22 -0
  12. package/plugins/security/helpers/string.js +1 -0
  13. package/plugins/security/helpers/string.js.map +1 -0
  14. package/plugins/security/helpers/string.ts +44 -0
  15. package/plugins/security/helpers/ts-types.js +1 -0
  16. package/plugins/security/helpers/ts-types.js.map +1 -0
  17. package/plugins/security/helpers/ts-types.ts +11 -0
  18. package/plugins/security/index.js +10 -0
  19. package/plugins/security/index.js.map +1 -0
  20. package/plugins/security/index.ts +74 -0
  21. package/plugins/security/package.json +25 -0
  22. package/plugins/security/rules/dangerously-set-inner-html.js +1 -0
  23. package/plugins/security/rules/dangerously-set-inner-html.js.map +1 -0
  24. package/plugins/security/rules/dangerously-set-inner-html.ts +93 -0
  25. package/plugins/security/rules/html-executing-assignment.js +1 -0
  26. package/plugins/security/rules/html-executing-assignment.js.map +1 -0
  27. package/plugins/security/rules/html-executing-assignment.ts +78 -0
  28. package/plugins/security/rules/html-executing-function.js +1 -0
  29. package/plugins/security/rules/html-executing-function.js.map +1 -0
  30. package/plugins/security/rules/html-executing-function.ts +164 -0
  31. package/plugins/security/rules/html-sinks.js +1 -0
  32. package/plugins/security/rules/html-sinks.js.map +1 -0
  33. package/plugins/security/rules/html-sinks.ts +146 -0
  34. package/plugins/security/rules/html-string-concat.js +1 -0
  35. package/plugins/security/rules/html-string-concat.js.map +1 -0
  36. package/plugins/security/rules/html-string-concat.ts +71 -0
  37. package/plugins/security/rules/jquery-executing.js +1 -0
  38. package/plugins/security/rules/jquery-executing.js.map +1 -0
  39. package/plugins/security/rules/jquery-executing.ts +134 -0
  40. package/plugins/security/rules/no-at-html-tags.js +53 -0
  41. package/plugins/security/rules/no-at-html-tags.js.map +1 -0
  42. package/plugins/security/rules/no-at-html-tags.ts +74 -0
  43. package/plugins/security/rules/vulnerable-tag-stripping.js +1 -0
  44. package/plugins/security/rules/vulnerable-tag-stripping.js.map +1 -0
  45. package/plugins/security/rules/vulnerable-tag-stripping.ts +89 -0
  46. package/plugins/security/rules/window-escaping.js +2 -1
  47. package/plugins/security/rules/window-escaping.js.map +1 -0
  48. package/plugins/security/rules/window-escaping.ts +220 -0
  49. package/plugins/tsconfig.json +8 -0
  50. package/types/index.d.ts +0 -3
  51. package/types/plugins/security/helpers/dom-purify.d.ts +0 -6
  52. package/types/plugins/security/helpers/element.d.ts +0 -10
  53. package/types/plugins/security/helpers/string.d.ts +0 -20
  54. package/types/plugins/security/helpers/ts-types.d.ts +0 -6
  55. package/types/plugins/security/index.d.ts +0 -8
  56. package/types/plugins/security/rules/dangerously-set-inner-html.d.ts +0 -4
  57. package/types/plugins/security/rules/html-executing-assignment.d.ts +0 -4
  58. package/types/plugins/security/rules/html-executing-function.d.ts +0 -6
  59. package/types/plugins/security/rules/html-sinks.d.ts +0 -4
  60. package/types/plugins/security/rules/html-string-concat.d.ts +0 -9
  61. package/types/plugins/security/rules/jquery-executing.d.ts +0 -17
  62. package/types/plugins/security/rules/vulnerable-tag-stripping.d.ts +0 -4
  63. package/types/plugins/security/rules/window-escaping.d.ts +0 -5
package/helpers/config.js CHANGED
@@ -29,3 +29,4 @@ export function getConfig(configs) {
29
29
  };
30
30
  return mergedConfig.configs;
31
31
  }
32
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAC,MAAM,2CAA2C,CAAC;AAM9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,SAAS,CAAE,OAA4B;IACtD,MAAM,IAAI,GAAG;QACZ,OAAO;KACP,CAAC;IACF,MAAM,YAAY,GAAqB;QACtC,GAAG,IAAI;QACP,GAAG,mBAAmB,CAAoB,eAAe,EAAE,IAAI,CAAE;KACjE,CAAC;IACF,OAAO,YAAY,CAAC,OAAO,CAAC;AAC7B,CAAC"}
@@ -1,7 +1,9 @@
1
- import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint';
2
- export type ExtensionConfigs = {
3
- configs: FlatConfig.Config[];
4
- };
1
+ import {getExtensionsConfig} from '@lipemat/js-boilerplate/helpers/config.js';
2
+ import type {FlatConfig} from '@typescript-eslint/utils/ts-eslint';
3
+
4
+
5
+ export type ExtensionConfigs = { configs: FlatConfig.Config[] };
6
+
5
7
  /**
6
8
  * Get a config from our /index.js merged with any
7
9
  * matching configuration from the project directory.
@@ -22,4 +24,13 @@ export type ExtensionConfigs = {
22
24
  * return config
23
25
  * }
24
26
  */
25
- export declare function getConfig(configs: FlatConfig.Config[]): FlatConfig.Config[];
27
+ export function getConfig( configs: FlatConfig.Config[] ): FlatConfig.Config[] {
28
+ const BASE = {
29
+ configs,
30
+ };
31
+ const mergedConfig: ExtensionConfigs = {
32
+ ...BASE,
33
+ ...getExtensionsConfig<ExtensionConfigs>( 'eslint.config', BASE ),
34
+ };
35
+ return mergedConfig.configs;
36
+ }
package/index.js CHANGED
@@ -137,3 +137,4 @@ export default [
137
137
  ...fixupConfigRules(flatCompat.extends('plugin:deprecation/recommended')),
138
138
  ...mergedConfig,
139
139
  ];
140
+ //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lipemat/eslint-config",
3
- "version": "5.0.1",
3
+ "version": "5.1.0-beta.1",
4
4
  "license": "MIT",
5
5
  "description": "Eslint configuration for all @lipemat packages",
6
6
  "engines": {
@@ -8,12 +8,10 @@
8
8
  },
9
9
  "type": "module",
10
10
  "main": "index.js",
11
- "types": "types",
12
11
  "files": [
13
12
  "index.js",
14
- "helpers/**/*.js",
15
- "plugins/**/*.js",
16
- "types"
13
+ "helpers",
14
+ "plugins"
17
15
  ],
18
16
  "repository": {
19
17
  "type": "git",
@@ -24,11 +22,11 @@
24
22
  },
25
23
  "homepage": "https://github.com/lipemat/eslint-config#readme",
26
24
  "scripts": {
27
- "build": "tsc --project ./plugins --declaration --declarationDir types",
25
+ "build": "tsc --project ./plugins",
28
26
  "prepublishOnly": "yarn run build",
29
27
  "test": "lipemat-js-boilerplate test",
30
28
  "validate-ts": "tsc --project ./plugins --noEmit",
31
- "watch": "tsc --project ./plugins --watch --inlineSourceMap"
29
+ "watch": "tsc --project ./plugins --watch"
32
30
  },
33
31
  "dependencies": {
34
32
  "@eslint/compat": "^1.2.4",
@@ -52,18 +50,17 @@
52
50
  "@types/jquery": "^3.5.16",
53
51
  "@types/node": "^20",
54
52
  "@typescript-eslint/rule-tester": "^8.40.0",
55
- "@typescript-eslint/types": "^8.40.0",
56
53
  "dompurify": "^3.2.6",
57
54
  "execa": "^5.1.1",
58
55
  "jest": "^29",
59
56
  "jest-runner-eslint": "^2.2.1",
60
- "typescript": "5.8.3"
57
+ "typescript": "~5.8.3"
61
58
  },
62
59
  "peerDependencies": {
63
- "typescript": "^5.8.3"
60
+ "typescript": "~5.8.3"
64
61
  },
65
62
  "resolutions": {
66
63
  "@babel/runtime": "^7.27.0"
67
64
  },
68
- "packageManager": "yarn@4.9.2"
65
+ "packageManager": "yarn@4.9.4"
69
66
  }
@@ -16,3 +16,4 @@ export function isSanitized(node) {
16
16
  }
17
17
  return false;
18
18
  }
19
+ //# sourceMappingURL=dom-purify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-purify.js","sourceRoot":"","sources":["dom-purify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAgB,MAAM,0BAA0B,CAAC;AAGvE;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAE,IAAsF;IAClH,IAAK,cAAc,CAAC,cAAc,KAAK,IAAI,CAAC,IAAI,EAAG,CAAC;QACnD,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAK,cAAc,CAAC,UAAU,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,UAAU,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,EAAG,CAAC;QACzF,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAK,cAAc,CAAC,gBAAgB,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,cAAc,CAAC,UAAU,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAG,CAAC;QACrH,OAAO,WAAW,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE;YAC3D,cAAc,CAAC,UAAU,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,IAAI,UAAU,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;IACtG,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC"}
@@ -0,0 +1,21 @@
1
+ import {AST_NODE_TYPES, type TSESTree} from '@typescript-eslint/utils';
2
+ import type ESTree from 'estree';
3
+
4
+ /**
5
+ * Check if a node is a call to a known sanitization function.
6
+ * - Currently recognizes `sanitize(...)` and `DOMPurify.sanitize(...)`.
7
+ */
8
+ export function isSanitized( node: ESTree.Expression | TSESTree.Property['value'] | TSESTree.CallExpressionArgument ): boolean {
9
+ if ( AST_NODE_TYPES.CallExpression !== node.type ) {
10
+ return false;
11
+ }
12
+ if ( AST_NODE_TYPES.Identifier === node.callee.type && 'sanitize' === node.callee.name ) {
13
+ return true;
14
+ }
15
+
16
+ if ( AST_NODE_TYPES.MemberExpression === node.callee.type && AST_NODE_TYPES.Identifier === node.callee.object.type ) {
17
+ return 'dompurify' === node.callee.object.name.toLowerCase() &&
18
+ AST_NODE_TYPES.Identifier === node.callee.property.type && 'sanitize' === node.callee.property.name;
19
+ }
20
+ return false;
21
+ }
@@ -16,3 +16,4 @@ export function isDomElementType(expression, context) {
16
16
  }
17
17
  return name.startsWith('HTML') && name.endsWith('Element');
18
18
  }
19
+ //# sourceMappingURL=element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element.js","sourceRoot":"","sources":["element.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AAEtC;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAuE,UAA2C,EAAE,OAAgB;IACnK,MAAM,IAAI,GAAS,OAAO,CAAW,UAAU,EAAE,OAAO,CAAE,CAAC;IAE3D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,EAAE,WAAW,IAAI,EAAE,CAAC;IACjD,4FAA4F;IAC5F,IAAK,SAAS,KAAK,IAAI,EAAG,CAAC;QAC1B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,IAAI,CAAC,UAAU,CAAE,MAAM,CAAE,IAAI,IAAI,CAAC,QAAQ,CAAE,SAAS,CAAE,CAAC;AAChE,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type {TSESLint, TSESTree} from '@typescript-eslint/utils';
2
+ import type {Type} from 'typescript';
3
+ import {getType} from './ts-types.js';
4
+
5
+ /**
6
+ * Is the type of variable being passed a DOM element?
7
+ *
8
+ * - DOM elements are of the type `HTML{*}Element`.
9
+ * - DOM elements do not require sanitization.
10
+ *
11
+ * @link https://typescript-eslint.io/developers/custom-rules/#typed-rules
12
+ */
13
+ export function isDomElementType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>( expression: TSESTree.CallExpressionArgument, context: Context ): boolean {
14
+ const type: Type = getType<Context>( expression, context );
15
+
16
+ const name = type.getSymbol()?.escapedName ?? '';
17
+ // Match any type that ends with "Element", e.g., HTMLElement, HTMLDivElement, Element, etc.
18
+ if ( 'Element' === name ) {
19
+ return true;
20
+ }
21
+ return name.startsWith( 'HTML' ) && name.endsWith( 'Element' );
22
+ }
@@ -37,3 +37,4 @@ export function isSafeLiteralString(node) {
37
37
  }
38
38
  return !/^\s*(?:javascript|data|vbscript|about|livescript)\s*:/i.test(decodeURIComponent(node.value.replace(/[\u0000-\u001F\u007F]+/g, '')));
39
39
  }
40
+ //# sourceMappingURL=string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string.js","sourceRoot":"","sources":["string.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAA+B,MAAM,0BAA0B,CAAC;AAEtF,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAE,IAAqC,EAAE,OAA4D;IAChI,MAAM,IAAI,GAAG,OAAO,CAAE,IAAI,EAAE,OAAO,CAAE,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,eAAe,IAAI,IAAI,IAAI,QAAQ,KAAK,IAAI,CAAC,aAAa,CAAC;IAC7E,OAAO,CAAE,cAAc,CAAC,OAAO,KAAK,IAAI,CAAC,IAAI,IAAI,QAAQ,KAAK,OAAO,IAAI,CAAC,KAAK,CAAE,IAAI,CAAE,cAAc,CAAC,eAAe,KAAK,IAAI,CAAC,IAAI,CAAE,IAAI,OAAO,IAAI,SAAS,CAAC;AAC/J,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAE,IAAkE;IAClG,OAAO,cAAc,CAAC,OAAO,KAAK,IAAI,CAAC,IAAI,IAAI,QAAQ,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC;AAC/E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAE,IAAkE;IACtG,IAAK,cAAc,CAAC,qBAAqB,KAAK,IAAI,CAAC,IAAI,EAAG,CAAC;QAC1D,OAAO,mBAAmB,CAAE,IAAI,CAAC,UAAU,CAAE,IAAI,mBAAmB,CAAE,IAAI,CAAC,SAAS,CAAE,CAAC;IACxF,CAAC;IAED,IAAK,CAAE,eAAe,CAAE,IAAI,CAAE,EAAG,CAAC;QACjC,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAE,SAAS,CAAE,EAAG,CAAC;QACxC,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,CAAE,wDAAwD,CAAC,IAAI,CAAE,kBAAkB,CAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAE,yBAAyB,EAAE,EAAE,CAAE,CAAE,CAAE,CAAC;AACrJ,CAAC"}
@@ -0,0 +1,44 @@
1
+ import {AST_NODE_TYPES, type TSESLint, type TSESTree} from '@typescript-eslint/utils';
2
+
3
+ import {getType} from './ts-types.js';
4
+
5
+ /**
6
+ * Is the node of type string.
7
+ * - String literals.
8
+ * - constants of type string.
9
+ * - template literals.
10
+ * - intrinsic type string.
11
+ */
12
+ export function isStringLike( node: TSESTree.CallExpressionArgument, context: Readonly<TSESLint.RuleContext<string, readonly []>> ): boolean {
13
+ const type = getType( node, context );
14
+ const literal = type.isStringLiteral();
15
+ const intrinsic = 'intrinsicName' in type && 'string' === type.intrinsicName;
16
+ return ( AST_NODE_TYPES.Literal === node.type && 'string' === typeof node.value ) || ( AST_NODE_TYPES.TemplateLiteral === node.type ) || literal || intrinsic;
17
+ }
18
+
19
+ /**
20
+ * Check if a node is a literal string
21
+ */
22
+ export function isLiteralString( node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument ): node is TSESTree.StringLiteral {
23
+ return AST_NODE_TYPES.Literal === node.type && 'string' === typeof node.value;
24
+ }
25
+
26
+ /**
27
+ * Check if a node is a literal string that is safe to use in an HTML context.
28
+ * - Must be a literal string. Or a conditional expression where both branches are safe literal strings.
29
+ * - Must not contain `<script`.
30
+ * - Must not start with a dangerous protocol (javascript:, data:, vbscript:, about:, livescript:).
31
+ */
32
+ export function isSafeLiteralString( node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument ): boolean {
33
+ if ( AST_NODE_TYPES.ConditionalExpression === node.type ) {
34
+ return isSafeLiteralString( node.consequent ) && isSafeLiteralString( node.alternate );
35
+ }
36
+
37
+ if ( ! isLiteralString( node ) ) {
38
+ return false;
39
+ }
40
+ if ( node.value.includes( '<script' ) ) {
41
+ return false;
42
+ }
43
+ return ! /^\s*(?:javascript|data|vbscript|about|livescript)\s*:/i.test( decodeURIComponent( node.value.replace( /[\u0000-\u001F\u007F]+/g, '' ) ) );
44
+ }
@@ -7,3 +7,4 @@ export function getType(expression, context) {
7
7
  const type = getTypeAtLocation(expression);
8
8
  return type.getNonNullableType();
9
9
  }
10
+ //# sourceMappingURL=ts-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ts-types.js","sourceRoot":"","sources":["ts-types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAA+B,MAAM,0BAA0B,CAAC;AAGnF;;GAEG;AACH,MAAM,UAAU,OAAO,CAAuE,UAA2C,EAAE,OAAgB;IAC1J,MAAM,EAAC,iBAAiB,EAAC,GAAG,WAAW,CAAC,iBAAiB,CAAE,OAAO,CAAE,CAAC;IACrE,MAAM,IAAI,GAAG,iBAAiB,CAAE,UAAU,CAAE,CAAC;IAC7C,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import {ESLintUtils, type TSESLint, type TSESTree} from '@typescript-eslint/utils';
2
+ import type {Type} from 'typescript';
3
+
4
+ /**
5
+ * Get the TypeScript type of node.
6
+ */
7
+ export function getType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>( expression: TSESTree.CallExpressionArgument, context: Context ): Type {
8
+ const {getTypeAtLocation} = ESLintUtils.getParserServices( context );
9
+ const type = getTypeAtLocation( expression );
10
+ return type.getNonNullableType();
11
+ }
@@ -6,6 +6,7 @@ import htmlStringConcat from './rules/html-string-concat.js';
6
6
  import jqueryExecuting from './rules/jquery-executing.js';
7
7
  import vulnerableTagStripping from './rules/vulnerable-tag-stripping.js';
8
8
  import windowEscaping from './rules/window-escaping.js';
9
+ import noAtHtmlTags from './rules/no-at-html-tags.js';
9
10
  import { readFileSync } from 'fs';
10
11
  import { resolve } from 'path';
11
12
  const pkg = JSON.parse(readFileSync(resolve('./package.json'), 'utf8'));
@@ -21,11 +22,13 @@ const plugin = {
21
22
  'html-sinks': htmlSinks,
22
23
  'html-string-concat': htmlStringConcat,
23
24
  'jquery-executing': jqueryExecuting,
25
+ 'no-at-html-tags': noAtHtmlTags,
24
26
  'vulnerable-tag-stripping': vulnerableTagStripping,
25
27
  'window-escaping': windowEscaping,
26
28
  },
27
29
  configs: {
28
30
  recommended: {},
31
+ svelte: {},
29
32
  },
30
33
  };
31
34
  // Freeze the plugin to prevent modifications and use the plugin within.
@@ -45,5 +48,12 @@ plugin.configs = Object.freeze({
45
48
  '@lipemat/security/window-escaping': 'error',
46
49
  },
47
50
  },
51
+ svelte: {
52
+ files: ['**/*.svelte', '*.svelte'],
53
+ rules: {
54
+ '@lipemat/security/no-at-html-tags': 'error',
55
+ },
56
+ },
48
57
  });
49
58
  export default plugin;
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,uBAAuB,MAAM,uCAAuC,CAAC;AAC5E,OAAO,uBAAuB,MAAM,sCAAsC,CAAC;AAC3E,OAAO,qBAAqB,MAAM,oCAAoC,CAAC;AACvE,OAAO,SAAS,MAAM,uBAAuB,CAAC;AAC9C,OAAO,gBAAgB,MAAM,+BAA+B,CAAC;AAC7D,OAAO,eAAe,MAAM,6BAA6B,CAAC;AAC1D,OAAO,sBAAsB,MAAM,qCAAqC,CAAC;AACzE,OAAO,cAAc,MAAM,4BAA4B,CAAC;AACxD,OAAO,YAAY,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAC,YAAY,EAAC,MAAM,IAAI,CAAC;AAChC,OAAO,EAAC,OAAO,EAAC,MAAM,MAAM,CAAC;AAI7B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACrB,YAAY,CAAE,OAAO,CAAE,gBAAgB,CAAE,EAAE,MAAM,CAAE,CACnD,CAAC;AAUF,MAAM,MAAM,GAAW;IACtB,IAAI,EAAE;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;KACpB;IACD,KAAK,EAAE;QACN,4BAA4B,EAAE,uBAAuB;QACrD,2BAA2B,EAAE,uBAAuB;QACpD,yBAAyB,EAAE,qBAAqB;QAChD,YAAY,EAAE,SAAS;QACvB,oBAAoB,EAAE,gBAAgB;QACtC,kBAAkB,EAAE,eAAe;QACnC,iBAAiB,EAAE,YAAY;QAC/B,0BAA0B,EAAE,sBAAsB;QAClD,iBAAiB,EAAE,cAAc;KACjC;IACD,OAAO,EAAE;QACR,WAAW,EAAE,EAAE;QACf,MAAM,EAAE,EAAE;KACV;CACD,CAAC;AAEF,wEAAwE;AACxE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAE;IAC/B,WAAW,EAAE;QACZ,OAAO,EAAE;YACR,mBAAmB,EAAE,MAAM;SAC3B;QACD,KAAK,EAAE;YACN,8CAA8C,EAAE,OAAO;YACvD,6CAA6C,EAAE,OAAO;YACtD,2CAA2C,EAAE,OAAO;YACpD,8BAA8B,EAAE,OAAO;YACvC,sCAAsC,EAAE,OAAO;YAC/C,oCAAoC,EAAE,OAAO;YAC7C,4CAA4C,EAAE,OAAO;YACrD,mCAAmC,EAAE,OAAO;SAC5C;KACD;IACD,MAAM,EAAE;QACP,KAAK,EAAE,CAAE,aAAa,EAAE,UAAU,CAAE;QACpC,KAAK,EAAE;YACN,mCAAmC,EAAE,OAAO;SAC5C;KACD;CACD,CAAE,CAAC;AAEJ,eAAe,MAAM,CAAC"}
@@ -0,0 +1,74 @@
1
+ import dangerouslySetInnerHtml from './rules/dangerously-set-inner-html.js';
2
+ import htmlExecutingAssignment from './rules/html-executing-assignment.js';
3
+ import htmlExecutingFunction from './rules/html-executing-function.js';
4
+ import htmlSinks from './rules/html-sinks.js';
5
+ import htmlStringConcat from './rules/html-string-concat.js';
6
+ import jqueryExecuting from './rules/jquery-executing.js';
7
+ import vulnerableTagStripping from './rules/vulnerable-tag-stripping.js';
8
+ import windowEscaping from './rules/window-escaping.js';
9
+ import noAtHtmlTags from './rules/no-at-html-tags.js';
10
+ import {readFileSync} from 'fs';
11
+ import {resolve} from 'path';
12
+ import type {FlatConfig} from '@typescript-eslint/utils/ts-eslint';
13
+
14
+
15
+ const pkg = JSON.parse(
16
+ readFileSync( resolve( './package.json' ), 'utf8' ),
17
+ );
18
+
19
+
20
+ type Plugin = FlatConfig.Plugin & {
21
+ configs: {
22
+ recommended: FlatConfig.Config;
23
+ svelte: FlatConfig.Config;
24
+ }
25
+ }
26
+
27
+ const plugin: Plugin = {
28
+ meta: {
29
+ name: pkg.name,
30
+ version: pkg.version,
31
+ },
32
+ rules: {
33
+ 'dangerously-set-inner-html': dangerouslySetInnerHtml,
34
+ 'html-executing-assignment': htmlExecutingAssignment,
35
+ 'html-executing-function': htmlExecutingFunction,
36
+ 'html-sinks': htmlSinks,
37
+ 'html-string-concat': htmlStringConcat,
38
+ 'jquery-executing': jqueryExecuting,
39
+ 'no-at-html-tags': noAtHtmlTags,
40
+ 'vulnerable-tag-stripping': vulnerableTagStripping,
41
+ 'window-escaping': windowEscaping,
42
+ },
43
+ configs: {
44
+ recommended: {},
45
+ svelte: {},
46
+ },
47
+ };
48
+
49
+ // Freeze the plugin to prevent modifications and use the plugin within.
50
+ plugin.configs = Object.freeze( {
51
+ recommended: {
52
+ plugins: {
53
+ '@lipemat/security': plugin,
54
+ },
55
+ rules: {
56
+ '@lipemat/security/dangerously-set-inner-html': 'error',
57
+ '@lipemat/security/html-executing-assignment': 'error',
58
+ '@lipemat/security/html-executing-function': 'error',
59
+ '@lipemat/security/html-sinks': 'error',
60
+ '@lipemat/security/html-string-concat': 'error',
61
+ '@lipemat/security/jquery-executing': 'error',
62
+ '@lipemat/security/vulnerable-tag-stripping': 'error',
63
+ '@lipemat/security/window-escaping': 'error',
64
+ },
65
+ },
66
+ svelte: {
67
+ files: [ '**/*.svelte', '*.svelte' ],
68
+ rules: {
69
+ '@lipemat/security/no-at-html-tags': 'error',
70
+ },
71
+ },
72
+ } );
73
+
74
+ export default plugin;
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@lipemat/eslint-plugin-security",
3
+ "description": "ESLint rules to replace PHPCS security scanning",
4
+ "version": "1.0.0",
5
+ "private": true,
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "index.js",
9
+ "source": "index.ts",
10
+ "files": [
11
+ "index.ts",
12
+ "index.js",
13
+ "rules/",
14
+ "helpers/"
15
+ ],
16
+ "dependencies": {
17
+ "eslint": "^9",
18
+ "@typescript-eslint/utils": "^8.40.0"
19
+ },
20
+ "peerDependencies": {
21
+ "eslint": "^9",
22
+ "@typescript-eslint/parser": "^8.40.0",
23
+ "typescript": "~5.8.3"
24
+ }
25
+ }
@@ -74,3 +74,4 @@ const plugin = {
74
74
  },
75
75
  };
76
76
  export default plugin;
77
+ //# sourceMappingURL=dangerously-set-inner-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dangerously-set-inner-html.js","sourceRoot":"","sources":["dangerously-set-inner-html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import {AST_NODE_TYPES, type TSESLint, type TSESTree} from '@typescript-eslint/utils';
2
+
3
+ import {isSanitized} from '../helpers/dom-purify.js';
4
+
5
+ type Messages = 'dangerousInnerHtml' | 'sanitize' | 'domPurify';
6
+ type Context = TSESLint.RuleContext<Messages, []>;
7
+
8
+ function isDangerouslySetInnerHTML( node: TSESTree.JSXAttribute ): boolean {
9
+ return (
10
+ 'JSXAttribute' === node.type &&
11
+ 'dangerouslySetInnerHTML' === node.name.name
12
+ );
13
+ }
14
+
15
+ function getDangerouslySetInnerHTMLValue( node: TSESTree.JSXAttribute ): null | TSESTree.Property['value'] {
16
+ // Expecting value like: {{ __html: expr }}
17
+ const val = node.value;
18
+ if ( null === val ) {
19
+ return null; // No value provided
20
+ }
21
+ if ( AST_NODE_TYPES.JSXExpressionContainer !== val.type ) {
22
+ return null;
23
+ }
24
+ const expr = val.expression;
25
+ if ( AST_NODE_TYPES.ObjectExpression !== expr.type ) {
26
+ return null;
27
+ }
28
+ const htmlProp = expr.properties.find( p => (
29
+ AST_NODE_TYPES.Property === p.type &&
30
+ (
31
+ ( AST_NODE_TYPES.Identifier === p.key.type && '__html' === p.key.name ) ||
32
+ ( AST_NODE_TYPES.Literal === p.key.type && '__html' === p.key.value )
33
+ )
34
+ ) );
35
+ if ( undefined !== htmlProp && 'value' in htmlProp ) {
36
+ return htmlProp.value;
37
+ }
38
+ return null;
39
+ }
40
+
41
+
42
+ const plugin: TSESLint.RuleModule<Messages> = {
43
+ defaultOptions: [],
44
+ meta: {
45
+ type: 'problem',
46
+ hasSuggestions: true,
47
+ docs: {
48
+ description: 'Disallow using unsanitized values in dangerouslySetInnerHTML',
49
+ },
50
+ messages: {
51
+ dangerousInnerHtml: 'Any HTML passed to `dangerouslySetInnerHTML` gets executed. Please make sure it\'s properly escaped.',
52
+
53
+ // Suggestions
54
+ domPurify: 'Wrap the content with a `DOMPurify.sanitize()` call.',
55
+ sanitize: 'Wrap the content with a `sanitize()` call.',
56
+ },
57
+ schema: [],
58
+ },
59
+ create( context: Context ): TSESLint.RuleListener {
60
+ return {
61
+ JSXAttribute( node: TSESTree.JSXAttribute ) {
62
+ if ( ! isDangerouslySetInnerHTML( node ) ) {
63
+ return;
64
+ }
65
+ const htmlValue = getDangerouslySetInnerHTMLValue( node );
66
+ if ( null === htmlValue || isSanitized( htmlValue ) ) {
67
+ return;
68
+ }
69
+
70
+ context.report( {
71
+ node,
72
+ messageId: 'dangerousInnerHtml',
73
+ suggest: [
74
+ {
75
+ messageId: 'domPurify',
76
+ fix: ( fixer: TSESLint.RuleFixer ) => {
77
+ return fixer.replaceText( node, `dangerouslySetInnerHTML={{__html: DOMPurify.sanitize( ${context.sourceCode.getText( htmlValue )} )}}` );
78
+ },
79
+ },
80
+ {
81
+ messageId: 'sanitize',
82
+ fix: ( fixer: TSESLint.RuleFixer ) => {
83
+ return fixer.replaceText( node, `dangerouslySetInnerHTML={{__html: sanitize( ${context.sourceCode.getText( htmlValue )} )}}` );
84
+ },
85
+ },
86
+ ],
87
+ } );
88
+ },
89
+ };
90
+ },
91
+ };
92
+
93
+ export default plugin;
@@ -66,3 +66,4 @@ const plugin = {
66
66
  },
67
67
  };
68
68
  export default plugin;
69
+ //# sourceMappingURL=html-executing-assignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-executing-assignment.js","sourceRoot":"","sources":["html-executing-assignment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAA+B,MAAM,0BAA0B,CAAC;AACtF,OAAO,EAAC,mBAAmB,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,WAAW,EAAC,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAOvD,MAAM,iBAAiB,GAAuB;IAC7C,WAAW;IACX,WAAW;CACX,CAAC;AAEF,SAAS,gBAAgB,CAAE,YAAoB;IAC9C,OAAO,iBAAiB,CAAC,QAAQ,CAAE,YAAgC,CAAE,CAAC;AACvE,CAAC;AAED,MAAM,MAAM,GAAkC;IAC7C,cAAc,EAAE,EAAE;IAClB,IAAI,EAAE;QACL,IAAI,EAAE;YACL,WAAW,EAAE,0EAA0E;SACvF;QACD,cAAc,EAAE,IAAI;QACpB,QAAQ,EAAE;YACT,QAAQ,EAAE,wFAAwF;YAElG,cAAc;YACd,SAAS,EAAE,uDAAuD;YAClE,QAAQ,EAAE,6CAA6C;SACvD;QACD,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,SAAS;KACf;IACD,MAAM,CAAE,OAAgB;QACvB,OAAO;YACN,oBAAoB,CAAE,IAAmC;gBACxD,IAAK,cAAc,CAAC,gBAAgB,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,cAAc,CAAC,UAAU,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAG,CAAC;oBACnH,OAAO;gBACR,CAAC;gBACD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAC7C,IAAK,CAAE,gBAAgB,CAAE,YAAY,CAAE,EAAG,CAAC;oBAC1C,OAAO;gBACR,CAAC;gBACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;gBACzB,IAAK,CAAE,mBAAmB,CAAE,KAAK,CAAE,IAAI,CAAE,WAAW,CAAE,KAAK,CAAE,IAAI,gBAAgB,CAAW,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAE,EAAG,CAAC;oBAC1H,OAAO,CAAC,MAAM,CAAE;wBACf,IAAI;wBACJ,SAAS,EAAE,UAAU;wBACrB,IAAI,EAAE;4BACL,YAAY;yBACZ;wBACD,OAAO,EAAE;4BACR;gCACC,SAAS,EAAE,WAAW;gCACtB,GAAG,EAAE,CAAE,KAAyB,EAAG,EAAE;oCACpC,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAE,KAAK,CAAE,CAAC;oCACtD,OAAO,KAAK,CAAC,WAAW,CAAE,KAAK,EAAE,uBAAuB,SAAS,IAAI,CAAE,CAAC;gCACzE,CAAC;6BACD;4BACD;gCACC,SAAS,EAAE,UAAU;gCACrB,GAAG,EAAE,CAAE,KAAyB,EAAG,EAAE;oCACpC,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAE,KAAK,CAAE,CAAC;oCACtD,OAAO,KAAK,CAAC,WAAW,CAAE,KAAK,EAAE,aAAa,SAAS,IAAI,CAAE,CAAC;gCAC/D,CAAC;6BACD;yBACD;qBACD,CAAE,CAAC;gBACL,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,78 @@
1
+ import {AST_NODE_TYPES, type TSESLint, type TSESTree} from '@typescript-eslint/utils';
2
+ import {isSafeLiteralString} from '../helpers/string.js';
3
+ import {isSanitized} from '../helpers/dom-purify.js';
4
+ import {isDomElementType} from '../helpers/element.js';
5
+
6
+ type UnsafeProperties = 'innerHTML' | 'outerHTML';
7
+
8
+ type Messages = 'executed' | 'sanitize' | 'domPurify';
9
+ type Context = TSESLint.RuleContext<Messages, []>;
10
+
11
+ const UNSAFE_PROPERTIES: UnsafeProperties[] = [
12
+ 'innerHTML',
13
+ 'outerHTML',
14
+ ];
15
+
16
+ function isUnsafeProperty( propertyName: string ): propertyName is UnsafeProperties {
17
+ return UNSAFE_PROPERTIES.includes( propertyName as UnsafeProperties );
18
+ }
19
+
20
+ const plugin: TSESLint.RuleModule<Messages> = {
21
+ defaultOptions: [],
22
+ meta: {
23
+ docs: {
24
+ description: 'Disallow using unsanitized values in HTML executing property assignments',
25
+ },
26
+ hasSuggestions: true,
27
+ messages: {
28
+ executed: 'Any HTML used with `{{propertyName}}` gets executed. Make sure it\'s properly escaped.',
29
+
30
+ // Suggestions
31
+ domPurify: 'Wrap the argument with a `DOMPurify.sanitize()` call.',
32
+ sanitize: 'Wrap the argument with a `sanitize()` call.',
33
+ },
34
+ schema: [],
35
+ type: 'problem',
36
+ },
37
+ create( context: Context ): TSESLint.RuleListener {
38
+ return {
39
+ AssignmentExpression( node: TSESTree.AssignmentExpression ) {
40
+ if ( AST_NODE_TYPES.MemberExpression !== node.left.type || AST_NODE_TYPES.Identifier !== node.left.property.type ) {
41
+ return;
42
+ }
43
+ const propertyName = node.left.property.name;
44
+ if ( ! isUnsafeProperty( propertyName ) ) {
45
+ return;
46
+ }
47
+ const value = node.right;
48
+ if ( ! isSafeLiteralString( value ) && ! isSanitized( value ) && isDomElementType<Context>( node.left.object, context ) ) {
49
+ context.report( {
50
+ node,
51
+ messageId: 'executed',
52
+ data: {
53
+ propertyName,
54
+ },
55
+ suggest: [
56
+ {
57
+ messageId: 'domPurify',
58
+ fix: ( fixer: TSESLint.RuleFixer ) => {
59
+ const valueText = context.sourceCode.getText( value );
60
+ return fixer.replaceText( value, `DOMPurify.sanitize( ${valueText} )` );
61
+ },
62
+ },
63
+ {
64
+ messageId: 'sanitize',
65
+ fix: ( fixer: TSESLint.RuleFixer ) => {
66
+ const valueText = context.sourceCode.getText( value );
67
+ return fixer.replaceText( value, `sanitize( ${valueText} )` );
68
+ },
69
+ },
70
+ ],
71
+ } );
72
+ }
73
+ },
74
+ };
75
+ },
76
+ };
77
+
78
+ export default plugin;
@@ -129,3 +129,4 @@ const plugin = {
129
129
  },
130
130
  };
131
131
  export default plugin;
132
+ //# sourceMappingURL=html-executing-function.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-executing-function.js","sourceRoot":"","sources":["html-executing-function.ts"],"names":[],"mappings":"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"}