eslint-plugin-chrome-extensions 2.7.0 → 2.8.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/README.md +266 -43
- package/package.json +9 -8
- package/src/data/apis.js +74 -88
- package/src/data/manifest.js +3 -1
- package/src/data/regex.js +2 -1
- package/src/index.d.ts +42 -0
- package/src/rules/css-spacing.js +29 -21
- package/src/rules/manifest-key-order.js +1 -1
- package/src/rules/manifest-spacing.js +1 -1
- package/src/rules/no-content-style-leak.js +12 -11
- package/src/rules/no-deprecated-apis.js +2 -2
- package/src/rules/no-host-page-selectors.js +5 -6
- package/src/rules/no-inline-event-handlers.js +116 -0
- package/src/rules/no-inline-scripts.js +65 -0
- package/src/rules/no-insecure-fetch.js +7 -6
- package/src/rules/no-insecure-messaging.js +4 -4
- package/src/rules/no-invalid-locales.js +3 -5
- package/src/rules/no-missing-default-locale.js +1 -1
- package/src/rules/no-missing-permissions.js +2 -3
- package/src/rules/no-missing-web-accessible-resources.js +2 -2
- package/src/rules/no-remote-code.js +77 -28
- package/src/rules/no-remote-objects.js +55 -0
- package/src/rules/no-remote-urls.js +20 -20
- package/src/rules/no-scrollbar-styling.js +8 -10
- package/src/rules/no-unrestricted-host-permissions.js +1 -1
- package/src/rules/no-unused-permissions.js +5 -4
- package/src/rules/require-license-file.js +1 -1
- package/src/rules/require-mv3.js +3 -2
- package/src/rules/valid-filenames.js +3 -3
- package/src/rules/valid-manifest-icons.js +2 -2
- package/src/rules/valid-mv3-schema.js +5 -5
- package/src/rules/valid-url-fields.js +2 -2
- package/src/rules/valid-version-field.js +2 -2
- package/src/utils/api.js +20 -0
- package/src/utils/extension.js +1 -3
- package/src/utils/html.js +29 -0
- package/src/utils/i18n.js +2 -2
- package/src/utils/init.js +11 -3
- package/src/utils/license.js +1 -1
- package/src/utils/node.js +3 -1
- package/src/utils/pkg.js +19 -2
- package/src/utils/rules.js +1 -1
|
@@ -6,7 +6,7 @@ import regex from '../data/regex.js'
|
|
|
6
6
|
const re = {
|
|
7
7
|
absoluteURL: /^[a-z][a-z0-9+.-]*:\/\/[^\s/]+/i,
|
|
8
8
|
match: /^(\*|https?|file|ftp):\/\/([^/]*)(\/.*)$/,
|
|
9
|
-
template: /\{[^}]+\}/g
|
|
9
|
+
template: /\{[^{}]+\}/g
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
function collectStrings(obj, path = [], out = []) {
|
|
@@ -15,7 +15,7 @@ function collectStrings(obj, path = [], out = []) {
|
|
|
15
15
|
else if (Array.isArray(obj))
|
|
16
16
|
for (const elem of obj) collectStrings(elem, path, out)
|
|
17
17
|
else if (typeof obj == 'object')
|
|
18
|
-
for (const key of Object.keys(obj)) //
|
|
18
|
+
for (const key of Object.keys(obj)) // oxlint-disable-next-line security/detect-object-injection
|
|
19
19
|
collectStrings(obj[key], [...path, key], out)
|
|
20
20
|
return out
|
|
21
21
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import extension from '../utils/extension.js'
|
|
2
2
|
import regex from '../data/regex.js'
|
|
3
3
|
|
|
4
|
-
const re = {
|
|
4
|
+
const re = { // oxlint-disable security/detect-unsafe-regex
|
|
5
5
|
chromeParts: /^\d+(?:\.\d+){0,3}$/,
|
|
6
6
|
date: /^\d{4}\.(?:0?[1-9]|1[0-2])\.(?:0?[1-9]|[12]\d|3[01])(?:\.\d+)?$/,
|
|
7
7
|
semver: /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/
|
|
8
|
-
}
|
|
8
|
+
} // oxlint-enable security/detect-unsafe-regex
|
|
9
9
|
|
|
10
10
|
export default {
|
|
11
11
|
meta: {
|
package/src/utils/api.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import apis from '../data/apis.js'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
findDeprecated(api) {
|
|
5
|
+
for (const [deprecated, replacement] of apis.deprecated)
|
|
6
|
+
if (api == deprecated || api.startsWith(`${deprecated}.`))
|
|
7
|
+
return { deprecated, replacement }
|
|
8
|
+
return null
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
findPermission(api) {
|
|
12
|
+
if (apis.permless.has(api)) return null
|
|
13
|
+
for (const [prefix, permission] of apis.permissionMap)
|
|
14
|
+
if (api == prefix || api.startsWith(`${prefix}.`))
|
|
15
|
+
return permission
|
|
16
|
+
return null
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
isExternalMsgListener(api) { return apis.externalMsgListeners.has(api) }
|
|
20
|
+
}
|
package/src/utils/extension.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// oxlint-disable security/detect-non-literal-fs-filename
|
|
2
2
|
|
|
3
3
|
import fs from 'node:fs'
|
|
4
4
|
import path from 'node:path'
|
|
@@ -40,8 +40,6 @@ const utils = {
|
|
|
40
40
|
|
|
41
41
|
manifest: {
|
|
42
42
|
permission: {
|
|
43
|
-
valid: permissions.valid,
|
|
44
|
-
sensitive: permissions.sensitive,
|
|
45
43
|
isValid(name, target = 'mv3') {
|
|
46
44
|
if (permissions.valid.has(name)) return true
|
|
47
45
|
if (target == 'mv3') return false
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import regex from '../data/regex.js'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
isHTML(text) { return text.trimStart().startsWith('<') },
|
|
5
|
+
|
|
6
|
+
isRemote(src, allowedPrefixes) {
|
|
7
|
+
if (!src || allowedPrefixes.some(prefix => src.startsWith(prefix))) return false
|
|
8
|
+
return regex.scheme.test(src)
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
offsetToLoc(text, offset) {
|
|
12
|
+
let line = 1, column = 1
|
|
13
|
+
for (let i = 0; i < offset && i < text.length; i++) {
|
|
14
|
+
if (text[i] == '\n') { line++ ; column = 1 } // oxlint-disable-line security/detect-object-injection
|
|
15
|
+
else column++
|
|
16
|
+
}
|
|
17
|
+
return { line, column }
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
pickAttrVal(match) { return match ? (match[1] ?? match[2] ?? match[3] ?? '') : null },
|
|
21
|
+
|
|
22
|
+
re: {
|
|
23
|
+
attr: {
|
|
24
|
+
data: /\sdata\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i,
|
|
25
|
+
src: /\ssrc\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i,
|
|
26
|
+
type: /\stype\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/utils/i18n.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// oxlint-disable security/detect-non-literal-fs-filename
|
|
2
2
|
|
|
3
3
|
import fs from 'node:fs'
|
|
4
4
|
import path from 'node:path'
|
|
@@ -7,7 +7,7 @@ import i18n from '../data/i18n.js'
|
|
|
7
7
|
|
|
8
8
|
function templateToPattern(body) {
|
|
9
9
|
const parts = body.split(i18n.re.templateExpr).map(part => part.replace(i18n.re.specialChars, '\\$&'))
|
|
10
|
-
return new RegExp(`^${parts.join('.*')}$`) //
|
|
10
|
+
return new RegExp(`^${parts.join('.*')}$`) // oxlint-disable-line security/detect-non-literal-regexp
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export default {
|
package/src/utils/init.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import css from '@eslint/css'
|
|
2
2
|
import html from '@html-eslint/eslint-plugin'
|
|
3
3
|
import json from '@eslint/json'
|
|
4
|
+
import pkg from './pkg.js'
|
|
4
5
|
import rulesUtils from './rules.js'
|
|
5
6
|
import text from './text.js'
|
|
6
7
|
|
|
@@ -12,6 +13,8 @@ import noDeprecatedAPIs from '../rules/no-deprecated-apis.js'
|
|
|
12
13
|
import noDuplicateManifestKeys from '../rules/no-duplicate-manifest-keys.js'
|
|
13
14
|
import noGlobalKeyframes from '../rules/no-global-keyframes.js'
|
|
14
15
|
import noHostPageSelectors from '../rules/no-host-page-selectors.js'
|
|
16
|
+
import noInlineEventHandlers from '../rules/no-inline-event-handlers.js'
|
|
17
|
+
import noInlineScripts from '../rules/no-inline-scripts.js'
|
|
15
18
|
import noInsecureFetch from '../rules/no-insecure-fetch.js'
|
|
16
19
|
import noInsecureMessaging from '../rules/no-insecure-messaging.js'
|
|
17
20
|
import noInvalidLocales from '../rules/no-invalid-locales.js'
|
|
@@ -21,6 +24,7 @@ import noMissingI18nKeys from '../rules/no-missing-i18n-keys.js'
|
|
|
21
24
|
import noMissingPermissions from '../rules/no-missing-permissions.js'
|
|
22
25
|
import noMissingWebAccessibleResources from '../rules/no-missing-web-accessible-resources.js'
|
|
23
26
|
import noRemoteCode from '../rules/no-remote-code.js'
|
|
27
|
+
import noRemoteObjects from '../rules/no-remote-objects.js'
|
|
24
28
|
import noRemoteURLs from '../rules/no-remote-urls.js'
|
|
25
29
|
import noScrollbarStyling from '../rules/no-scrollbar-styling.js'
|
|
26
30
|
import noSensitivePermissions from '../rules/no-sensitive-permissions.js'
|
|
@@ -38,7 +42,8 @@ import validServiceWorker from '../rules/valid-service-worker.js'
|
|
|
38
42
|
import validURLfields from '../rules/valid-url-fields.js'
|
|
39
43
|
import validVersionField from '../rules/valid-version-field.js'
|
|
40
44
|
|
|
41
|
-
const
|
|
45
|
+
const pkgName = pkg.getName(),
|
|
46
|
+
namespace = pkgName.replace(/^@[^/]+\//, '').replace(/^eslint-plugin-/, '')
|
|
42
47
|
|
|
43
48
|
export default {
|
|
44
49
|
configs(plugin) {
|
|
@@ -67,7 +72,7 @@ export default {
|
|
|
67
72
|
}
|
|
68
73
|
},
|
|
69
74
|
|
|
70
|
-
plugin() { return { rules: {}, configs: {} }},
|
|
75
|
+
plugin() { return { meta: { name: pkgName }, rules: {}, configs: {} }},
|
|
71
76
|
|
|
72
77
|
rules(plugin) {
|
|
73
78
|
plugin.rules = {
|
|
@@ -79,6 +84,8 @@ export default {
|
|
|
79
84
|
'no-duplicate-manifest-keys': noDuplicateManifestKeys,
|
|
80
85
|
'no-global-keyframes': noGlobalKeyframes,
|
|
81
86
|
'no-host-page-selectors': noHostPageSelectors,
|
|
87
|
+
'no-inline-event-handlers': noInlineEventHandlers,
|
|
88
|
+
'no-inline-scripts': noInlineScripts,
|
|
82
89
|
'no-insecure-fetch': noInsecureFetch,
|
|
83
90
|
'no-insecure-messaging': noInsecureMessaging,
|
|
84
91
|
'no-invalid-locales': noInvalidLocales,
|
|
@@ -88,6 +95,7 @@ export default {
|
|
|
88
95
|
'no-missing-permissions': noMissingPermissions,
|
|
89
96
|
'no-missing-web-accessible-resources': noMissingWebAccessibleResources,
|
|
90
97
|
'no-remote-code': noRemoteCode,
|
|
98
|
+
'no-remote-objects': noRemoteObjects,
|
|
91
99
|
'no-remote-urls': noRemoteURLs,
|
|
92
100
|
'no-scrollbar-styling': noScrollbarStyling,
|
|
93
101
|
'no-sensitive-permissions': noSensitivePermissions,
|
|
@@ -106,6 +114,6 @@ export default {
|
|
|
106
114
|
'valid-version-field': validVersionField
|
|
107
115
|
}
|
|
108
116
|
for (const [ruleId, rule] of Object.entries(plugin.rules))
|
|
109
|
-
rule.meta.docs.url = `https://codeberg.org/adamlui
|
|
117
|
+
rule.meta.docs.url = `https://codeberg.org/adamlui/${pkgName}/#${ruleId}`
|
|
110
118
|
}
|
|
111
119
|
}
|
package/src/utils/license.js
CHANGED
package/src/utils/node.js
CHANGED
package/src/utils/pkg.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url'
|
|
1
2
|
import fs from 'node:fs'
|
|
2
3
|
import path from 'node:path'
|
|
3
4
|
|
|
@@ -11,11 +12,27 @@ export default {
|
|
|
11
12
|
current = parent
|
|
12
13
|
continue
|
|
13
14
|
}
|
|
14
|
-
if ( //
|
|
15
|
+
if ( // oxlint-disable-next-line security/detect-non-literal-fs-filename
|
|
15
16
|
fs.existsSync(path.join(current, 'package.json'))) return current
|
|
16
17
|
const parent = path.dirname(current)
|
|
17
18
|
if (parent === current) return null
|
|
18
19
|
current = parent
|
|
19
20
|
}
|
|
20
|
-
}
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
getName() { // oxlint-disable security/detect-non-literal-fs-filename
|
|
24
|
+
let current = path.dirname(fileURLToPath(import.meta.url))
|
|
25
|
+
while (current) {
|
|
26
|
+
const pkgPath = path.join(current, 'package.json')
|
|
27
|
+
if (fs.existsSync(pkgPath))
|
|
28
|
+
try {
|
|
29
|
+
const { name } = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
|
|
30
|
+
if (name) return name
|
|
31
|
+
} catch { /* malformed, keep walking */ }
|
|
32
|
+
const parent = path.dirname(current)
|
|
33
|
+
if (parent === current) return null
|
|
34
|
+
current = parent
|
|
35
|
+
}
|
|
36
|
+
return null
|
|
37
|
+
} // oxlint-enable security/detect-non-literal-fs-filename
|
|
21
38
|
}
|
package/src/utils/rules.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
bundle(rules, predicate, pluginName) {
|
|
3
3
|
return Object.fromEntries(Object.entries(rules)
|
|
4
|
-
.filter(([, rule]) => predicate(rule))
|
|
4
|
+
.filter(([, rule]) => !rule.meta.deprecated && predicate(rule))
|
|
5
5
|
.map(([ruleId]) => [`${pluginName}/${ruleId}`, 'error']))
|
|
6
6
|
}
|
|
7
7
|
}
|