eslint-plugin-chrome-extensions 2.4.2 → 2.5.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 +87 -6
- package/package.json +3 -2
- package/src/data/apis.js +166 -115
- package/src/data/deprecations.js +7 -7
- package/src/data/i18n.js +11 -69
- package/src/data/manifest.js +61 -57
- package/src/data/permissions.js +29 -29
- package/src/data/regex.js +10 -0
- package/src/index.js +7 -124
- package/src/rules/manifest-key-order.js +8 -8
- package/src/rules/manifest-spacing.js +5 -5
- package/src/rules/no-content-style-leak.js +6 -4
- package/src/rules/no-deprecated-apis.js +4 -4
- package/src/rules/no-duplicate-manifest-keys.js +3 -4
- package/src/rules/no-insecure-messaging.js +4 -4
- package/src/rules/no-invalid-permissions.js +10 -11
- package/src/rules/no-missing-default-locale.js +7 -9
- package/src/rules/no-missing-i18n-keys.js +22 -21
- package/src/rules/no-missing-permissions.js +7 -6
- package/src/rules/no-missing-web-accessible-resources.js +7 -6
- package/src/rules/no-remote-code.js +12 -12
- package/src/rules/no-sensitive-permissions.js +75 -0
- package/src/rules/no-unrestricted-host-permissions.js +8 -7
- package/src/rules/no-unused-i18n-keys.js +11 -10
- package/src/rules/no-unused-permissions.js +22 -23
- package/src/rules/require-license-file.js +4 -5
- package/src/rules/require-mv3.js +4 -5
- package/src/rules/require-short-name-when-useful.js +4 -3
- package/src/rules/valid-filenames.js +3 -10
- package/src/rules/valid-license-file.js +18 -11
- package/src/rules/valid-manifest-icons.js +6 -5
- package/src/rules/valid-mv3-schema.js +21 -21
- package/src/rules/valid-service-worker.js +34 -13
- package/src/rules/valid-url-fields.js +10 -7
- package/src/rules/valid-version-field.js +4 -8
- package/src/utils/extension.js +39 -33
- package/src/utils/i18n.js +55 -0
- package/src/utils/init.js +105 -0
- package/src/utils/license.js +55 -0
- package/src/utils/node.js +20 -19
- package/src/utils/pkg.js +12 -10
- package/src/utils/rules.js +6 -4
- package/src/utils/text.js +13 -0
- package/src/data/license.js +0 -28
- package/src/data/text-parser.js +0 -11
- package/src/utils/bundle.js +0 -10
package/README.md
CHANGED
|
@@ -1008,6 +1008,76 @@ If you intentionally target forks w/ relaxed CSPs. For individual patterns you s
|
|
|
1008
1008
|
|
|
1009
1009
|
</details>
|
|
1010
1010
|
|
|
1011
|
+
<h3 id="no-sensitive-permissions">
|
|
1012
|
+
<code>no-sensitive-permissions</code>
|
|
1013
|
+
<a title="Included in recommended config" href="#usage">
|
|
1014
|
+
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
1015
|
+
<a title="Included in security config" href="#usage">
|
|
1016
|
+
<img height=18 alt="[Security]" src="https://img.shields.io/badge/Security-e8357a?style=flat-square" align="middle"></a>
|
|
1017
|
+
<a title="Works in 'json/json' config block" href="#usage">
|
|
1018
|
+
<img height=18 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
|
|
1019
|
+
<a title="Accepts array w/ options" href="#usage">
|
|
1020
|
+
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
1021
|
+
<a title="Copy rule URL" target="_blank"
|
|
1022
|
+
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23no-sensitive-permissions">
|
|
1023
|
+
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
1024
|
+
</h3>
|
|
1025
|
+
|
|
1026
|
+
<details>
|
|
1027
|
+
|
|
1028
|
+
<summary>Flags sensitive manifest permissions that warrant security review.</summary>
|
|
1029
|
+
|
|
1030
|
+
<h4 id="no-sensitive-permissions-options">Options</h4>
|
|
1031
|
+
|
|
1032
|
+
- `allowedPermissions` (default `[]`) – sensitive permission names to explicitly allow, as a single string or array
|
|
1033
|
+
|
|
1034
|
+
#### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/gray.svg" align="bottom"> Incorrect code
|
|
1035
|
+
|
|
1036
|
+
```diff
|
|
1037
|
+
{
|
|
1038
|
+
"manifest_version": 3,
|
|
1039
|
+
! "permissions": ["tabs", "cookies", "storage"]
|
|
1040
|
+
}
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
#### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> Correct code
|
|
1044
|
+
|
|
1045
|
+
```diff
|
|
1046
|
+
{
|
|
1047
|
+
"manifest_version": 3,
|
|
1048
|
+
- "permissions": ["tabs", "cookies", "storage"]
|
|
1049
|
+
+ "permissions": ["storage"]
|
|
1050
|
+
}
|
|
1051
|
+
```
|
|
1052
|
+
|
|
1053
|
+
#### When not to use it
|
|
1054
|
+
|
|
1055
|
+
If you legitimately require sensitive permissions, or prefer manual security review.
|
|
1056
|
+
|
|
1057
|
+
#### Introduced in
|
|
1058
|
+
|
|
1059
|
+
v2.5.0 (Unreleased)
|
|
1060
|
+
|
|
1061
|
+
#### See also
|
|
1062
|
+
|
|
1063
|
+
- [`no-invalid-permissions`](#no-invalid-permissions)
|
|
1064
|
+
<a title="Included in recommended config" href="#usage"><img height=14 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
1065
|
+
<a title="Works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest]" src="https://img.shields.io/badge/Manifest-999999?style=flat-square" align="middle"></a>
|
|
1066
|
+
<a title="Accepts array w/ options" href="#no-invalid-permissions-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
1067
|
+
- [`no-unused-permissions`](#no-unused-permissions)
|
|
1068
|
+
<a title="Only works in 'json/json' config block" href="#usage"><img height=14 alt="[Manifest only]" src="https://img.shields.io/badge/Manifest_only-999999?style=flat-square" align="middle"></a>
|
|
1069
|
+
- <img height=12 src="https://www.google.com/s2/favicons?domain=developer.chrome.com&sz=64"> <a target="_blank" href="https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions">Chrome for Developers — Declare permissions</a>
|
|
1070
|
+
|
|
1071
|
+
<div align="center">
|
|
1072
|
+
|
|
1073
|
+
[Back to index ↑][epce-rules]
|
|
1074
|
+
|
|
1075
|
+
</div>
|
|
1076
|
+
|
|
1077
|
+
---
|
|
1078
|
+
|
|
1079
|
+
</details>
|
|
1080
|
+
|
|
1011
1081
|
<h3 id="no-unrestricted-host-permissions">
|
|
1012
1082
|
<code>no-unrestricted-host-permissions</code>
|
|
1013
1083
|
<a title="Only works in 'json/json' config block" href="#usage">
|
|
@@ -1253,6 +1323,7 @@ If you intentionally omit a license, or it's injected at build time.
|
|
|
1253
1323
|
|
|
1254
1324
|
- [`valid-license-file`](#valid-license-file)
|
|
1255
1325
|
<a title="Only works in license config block" href="#usage"><img height=14 alt="[License only]" src="https://img.shields.io/badge/License_only-559bff?style=flat-square" align="middle"></a>
|
|
1326
|
+
<a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix"><img height=14 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
|
|
1256
1327
|
<a title="Accepts array w/ options" href="#valid-license-file-options"><img height=14 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
1257
1328
|
|
|
1258
1329
|
<div align="center">
|
|
@@ -1427,7 +1498,7 @@ If you primarily target a browser that doesn't support `short_name`.
|
|
|
1427
1498
|
|
|
1428
1499
|
```diff
|
|
1429
1500
|
// files
|
|
1430
|
-
! /extension/_metadata/
|
|
1501
|
+
! /extension/_metadata/extension.json
|
|
1431
1502
|
! /extension/content script.js
|
|
1432
1503
|
|
|
1433
1504
|
// manifest.json
|
|
@@ -1440,8 +1511,8 @@ If you primarily target a browser that doesn't support `short_name`.
|
|
|
1440
1511
|
#### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/green.svg" align="bottom"> Correct code
|
|
1441
1512
|
|
|
1442
1513
|
```diff
|
|
1443
|
-
- /extension/_metadata/
|
|
1444
|
-
+ /extension/metadata/
|
|
1514
|
+
- /extension/_metadata/extension.json
|
|
1515
|
+
+ /extension/metadata/extension.json
|
|
1445
1516
|
- /extension/content script.js
|
|
1446
1517
|
+ /extension/content-script.js
|
|
1447
1518
|
|
|
@@ -1484,6 +1555,8 @@ If you don't use conventional filenames or paths, or they're generated at build
|
|
|
1484
1555
|
<code>valid-license-file</code>
|
|
1485
1556
|
<a title="Only works in license config block" href="#usage">
|
|
1486
1557
|
<img height=18 alt="[License only]" src="https://img.shields.io/badge/License_only-559bff?style=flat-square" align="middle"></a>
|
|
1558
|
+
<a title="Accepts eslint --fix" target="_blank" href="https://eslint.org/docs/latest/use/command-line-interface#--fix">
|
|
1559
|
+
<img height=18 alt="[Auto-fixable]" src="https://img.shields.io/badge/Auto--fixable-3b5bdb?style=flat-square" align="middle"></a>
|
|
1487
1560
|
<a title="Accepts array w/ options" href="#usage">
|
|
1488
1561
|
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
1489
1562
|
<a title="Copy rule URL" target="_blank"
|
|
@@ -1524,11 +1597,11 @@ If you don't use conventional filenames or paths, or they're generated at build
|
|
|
1524
1597
|
|
|
1525
1598
|
#### Benefits
|
|
1526
1599
|
|
|
1527
|
-
|
|
1600
|
+
Enables machine-readability for compliance scanners, SBOM generators & CI gates.
|
|
1528
1601
|
|
|
1529
1602
|
#### When not to use it
|
|
1530
1603
|
|
|
1531
|
-
If your license is injected at build time, or you use
|
|
1604
|
+
If your license is injected at build time, or you use one w/ no existing SPDX identifier.
|
|
1532
1605
|
|
|
1533
1606
|
#### Introduced in
|
|
1534
1607
|
|
|
@@ -1694,6 +1767,8 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
|
|
|
1694
1767
|
<code>valid-service-worker</code>
|
|
1695
1768
|
<a title="Included in recommended config" href="#usage">
|
|
1696
1769
|
<img height=18 alt="[Recommended]" src="https://img.shields.io/badge/Recommended-f1f20a?style=flat-square" align="middle"></a>
|
|
1770
|
+
<a title="Accepts array w/ options" href="#usage">
|
|
1771
|
+
<img height=18 alt="[Configurable]" src="https://img.shields.io/badge/Configurable-black?style=flat-square" align="middle"></a>
|
|
1697
1772
|
<a title="Copy rule URL" target="_blank"
|
|
1698
1773
|
href="https://copy-to-clipboard.onrender.com/copy/https%3A%2F%2Fcodeberg.org%2Fadamlui%2Feslint-plugin-chrome-extensions%2F%23valid-service-worker">
|
|
1699
1774
|
<img height=16 width=21 alt="[Copy rule URL]" src="https://api.iconify.design/mdi/content-copy.svg?color=%23cccccc" align="middle"></a>
|
|
@@ -1703,6 +1778,12 @@ If you intentionally target MV2 for a browser that still supports it (e.g. Firef
|
|
|
1703
1778
|
|
|
1704
1779
|
<summary>Enforces valid service worker lifecycle and isolation.</summary>
|
|
1705
1780
|
|
|
1781
|
+
<h4 id="mit-worker-options">Options</h4>
|
|
1782
|
+
|
|
1783
|
+
- `checkListenerTopLevel` (default `true`) – require `chrome.*.addListener()` calls at module top level
|
|
1784
|
+
- `checkKeepaliveTimer` (default `true`) – flag sub-30s timers used as a keepalive workaround
|
|
1785
|
+
- `checkDOMglobals` (default `true`) – flag DOM globals (`window`, `document`, `localStorage`) inside the service worker
|
|
1786
|
+
|
|
1706
1787
|
#### <img width=13 height=13 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/99f14247b2/assets/images/icons/square/with-symbol/gray.svg" align="bottom"> Incorrect code
|
|
1707
1788
|
|
|
1708
1789
|
```diff
|
|
@@ -1919,7 +2000,7 @@ If you don't care about version format consistency, or your version is injected
|
|
|
1919
2000
|
## <img height=30 width=27 align="top" src="https://api.iconify.design/ic/baseline-account-balance.svg?color=%232b2b2a"> License
|
|
1920
2001
|
|
|
1921
2002
|
<a target="_blank" href="https://codeberg.org/adamlui/eslint-plugin-chrome-extensions/src/branch/main/docs/LICENSE.md">
|
|
1922
|
-
<img height=
|
|
2003
|
+
<img height=80 src="https://cdn.staticdelivr.com/gl/adamlui/eslint-plugin-greasemonkey/9e820e5d51/assets/images/logos/mit-license/red-pixelated.png"></a>
|
|
1923
2004
|
<br><br>
|
|
1924
2005
|
|
|
1925
2006
|
<details>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-chrome-extensions",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "ESLint rules for Chrome extensions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -62,7 +62,8 @@
|
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"globals": "^17.13.0",
|
|
65
|
-
"spdx-license-ids": "^3.0.24"
|
|
65
|
+
"spdx-license-ids": "^3.0.24",
|
|
66
|
+
"spdx-license-list": "^6.12.0"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"@e18e/eslint-plugin": "^0.8.1",
|
package/src/data/apis.js
CHANGED
|
@@ -1,116 +1,167 @@
|
|
|
1
|
-
export
|
|
2
|
-
[
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
['chrome.
|
|
33
|
-
[
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
]
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
]
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
1
|
+
export default {
|
|
2
|
+
deprecated: new Map([
|
|
3
|
+
['chrome.browserAction', 'chrome.action'],
|
|
4
|
+
['chrome.declarativeWebRequest', 'chrome.declarativeNetRequest'],
|
|
5
|
+
['chrome.extension.connect', 'chrome.runtime.connect'],
|
|
6
|
+
['chrome.extension.getBackgroundPage', 'chrome.runtime.getContexts'],
|
|
7
|
+
['chrome.extension.getURL', 'chrome.runtime.getURL'],
|
|
8
|
+
['chrome.extension.lastError', 'chrome.runtime.lastError'],
|
|
9
|
+
['chrome.extension.onConnect', 'chrome.runtime.onConnect'],
|
|
10
|
+
['chrome.extension.onConnectExternal', 'chrome.runtime.onConnectExternal'],
|
|
11
|
+
['chrome.extension.onRequest', 'chrome.runtime.onMessage'],
|
|
12
|
+
['chrome.extension.onRequestExternal', 'chrome.runtime.onMessageExternal'],
|
|
13
|
+
['chrome.extension.sendRequest', 'chrome.runtime.sendMessage'],
|
|
14
|
+
['chrome.fileBrowserHandler', 'File Handling API'],
|
|
15
|
+
['chrome.pageAction.show', 'chrome.action.enable'],
|
|
16
|
+
['chrome.pageAction.hide', 'chrome.action.disable'],
|
|
17
|
+
['chrome.pageAction.setIcon', 'chrome.action.setIcon'],
|
|
18
|
+
['chrome.pageAction.setTitle', 'chrome.action.setTitle'],
|
|
19
|
+
['chrome.pageAction.setPopup', 'chrome.action.setPopup'],
|
|
20
|
+
['chrome.pageAction.getTitle', 'chrome.action.getTitle'],
|
|
21
|
+
['chrome.pageAction.getPopup', 'chrome.action.getPopup'],
|
|
22
|
+
['chrome.pageAction', 'chrome.action'], // must stay after pageAction.* — prefix match
|
|
23
|
+
['chrome.tabs.executeScript', 'chrome.scripting.executeScript'],
|
|
24
|
+
['chrome.tabs.getAllInWindow', 'chrome.tabs.query({ currentWindow: true })'],
|
|
25
|
+
['chrome.tabs.getSelected', 'chrome.tabs.query({ active: true })'],
|
|
26
|
+
['chrome.tabs.insertCSS', 'chrome.scripting.insertCSS'],
|
|
27
|
+
['chrome.tabs.onActiveChanged', 'chrome.tabs.onActivated'],
|
|
28
|
+
['chrome.tabs.onSelectionChanged', 'chrome.tabs.onActivated'],
|
|
29
|
+
['chrome.tabs.removeCSS', 'chrome.scripting.removeCSS'],
|
|
30
|
+
['chrome.tabs.sendRequest', 'chrome.tabs.sendMessage']
|
|
31
|
+
]),
|
|
32
|
+
externalMsgListeners: new Set(['chrome.runtime.onMessageExternal', 'chrome.runtime.onConnectExternal']),
|
|
33
|
+
permissionMap: new Map([
|
|
34
|
+
['chrome.accessibilityFeatures.set', 'accessibilityFeatures.modify'],
|
|
35
|
+
['chrome.accessibilityFeatures.clear', 'accessibilityFeatures.modify'],
|
|
36
|
+
['chrome.accessibilityFeatures', 'accessibilityFeatures.read'],
|
|
37
|
+
['chrome.alarms', 'alarms'],
|
|
38
|
+
['chrome.audio', 'audio'],
|
|
39
|
+
['chrome.bookmarks', 'bookmarks'],
|
|
40
|
+
['chrome.browsingData', 'browsingData'],
|
|
41
|
+
['chrome.certificateProvider', 'certificateProvider'],
|
|
42
|
+
['chrome.contentSettings', 'contentSettings'],
|
|
43
|
+
['chrome.contextMenus', 'contextMenus'],
|
|
44
|
+
['chrome.cookies', 'cookies'],
|
|
45
|
+
['chrome.debugger', 'debugger'],
|
|
46
|
+
['chrome.declarativeContent', 'declarativeContent'],
|
|
47
|
+
['chrome.declarativeNetRequest', 'declarativeNetRequest'],
|
|
48
|
+
['chrome.dns', 'dns'],
|
|
49
|
+
['chrome.desktopCapture', 'desktopCapture'],
|
|
50
|
+
['chrome.documentScan', 'documentScan'],
|
|
51
|
+
['chrome.downloads.open', 'downloads.open'],
|
|
52
|
+
['chrome.downloads.setUiOptions', 'downloads.ui'],
|
|
53
|
+
['chrome.downloads', 'downloads'],
|
|
54
|
+
['chrome.enterprise.deviceAttributes', 'enterprise.deviceAttributes'],
|
|
55
|
+
['chrome.enterprise.hardwarePlatform', 'enterprise.hardwarePlatform'],
|
|
56
|
+
['chrome.enterprise.networkingAttributes','enterprise.networkingAttributes'],
|
|
57
|
+
['chrome.enterprise.platformKeys', 'enterprise.platformKeys'],
|
|
58
|
+
['chrome.favicon', 'favicon'],
|
|
59
|
+
['chrome.fileBrowserHandler', 'fileBrowserHandler'],
|
|
60
|
+
['chrome.fontSettings', 'fontSettings'],
|
|
61
|
+
['chrome.gcm', 'gcm'],
|
|
62
|
+
['chrome.instanceID', 'gcm'],
|
|
63
|
+
['chrome.history', 'history'],
|
|
64
|
+
['chrome.identity.getProfileUserInfo', 'identity.email'],
|
|
65
|
+
['chrome.identity', 'identity'],
|
|
66
|
+
['chrome.idle', 'idle'],
|
|
67
|
+
['chrome.loginState', 'loginState'],
|
|
68
|
+
['chrome.management', 'management'],
|
|
69
|
+
['chrome.runtime.connectNative', 'nativeMessaging'],
|
|
70
|
+
['chrome.runtime.sendNativeMessage', 'nativeMessaging'],
|
|
71
|
+
['chrome.notifications', 'notifications'],
|
|
72
|
+
['chrome.offscreen', 'offscreen'],
|
|
73
|
+
['chrome.pageCapture', 'pageCapture'],
|
|
74
|
+
['chrome.platformKeys', 'platformKeys'],
|
|
75
|
+
['chrome.power', 'power'],
|
|
76
|
+
['chrome.printerProvider', 'printerProvider'],
|
|
77
|
+
['chrome.printingMetrics', 'printingMetrics'],
|
|
78
|
+
['chrome.printing', 'printing'],
|
|
79
|
+
['chrome.privacy', 'privacy'],
|
|
80
|
+
['chrome.processes', 'processes'],
|
|
81
|
+
['chrome.proxy', 'proxy'],
|
|
82
|
+
['chrome.publicSuffix', 'publicSuffix'],
|
|
83
|
+
['chrome.readingList', 'readingList'],
|
|
84
|
+
['chrome.scripting', 'scripting'],
|
|
85
|
+
['chrome.search', 'search'],
|
|
86
|
+
['chrome.sessions', 'sessions'],
|
|
87
|
+
['chrome.sidePanel', 'sidePanel'],
|
|
88
|
+
['chrome.storage', 'storage'],
|
|
89
|
+
['chrome.system.cpu', 'system.cpu'],
|
|
90
|
+
['chrome.system.display', 'system.display'],
|
|
91
|
+
['chrome.system.memory', 'system.memory'],
|
|
92
|
+
['chrome.system.storage', 'system.storage'],
|
|
93
|
+
['chrome.tabCapture', 'tabCapture'],
|
|
94
|
+
['chrome.tabGroups', 'tabGroups'],
|
|
95
|
+
['chrome.tabs.query', 'tabs'],
|
|
96
|
+
['chrome.topSites', 'topSites'],
|
|
97
|
+
['chrome.ttsEngine', 'ttsEngine'],
|
|
98
|
+
['chrome.tts', 'tts'],
|
|
99
|
+
['chrome.userScripts', 'userScripts'],
|
|
100
|
+
['chrome.vpnProvider', 'vpnProvider'],
|
|
101
|
+
['chrome.wallpaper', 'wallpaper'],
|
|
102
|
+
['chrome.webAuthenticationProxy', 'webAuthenticationProxy'],
|
|
103
|
+
['chrome.webNavigation', 'webNavigation'],
|
|
104
|
+
['chrome.webRequest', 'webRequest']
|
|
105
|
+
]),
|
|
106
|
+
permless: new Set([
|
|
107
|
+
'chrome.i18n',
|
|
108
|
+
'chrome.management.getPermissionWarningsByManifest',
|
|
109
|
+
'chrome.management.getSelf',
|
|
110
|
+
'chrome.management.uninstallSelf',
|
|
111
|
+
'chrome.runtime.connect',
|
|
112
|
+
'chrome.runtime.getManifest',
|
|
113
|
+
'chrome.runtime.getPlatformInfo',
|
|
114
|
+
'chrome.runtime.getURL',
|
|
115
|
+
'chrome.runtime.onBrowserUpdateAvailable', // eslint-disable-line no-secrets/no-secrets
|
|
116
|
+
'chrome.runtime.onConnect',
|
|
117
|
+
'chrome.runtime.onConnectExternal',
|
|
118
|
+
'chrome.runtime.onInstalled',
|
|
119
|
+
'chrome.runtime.onMessage',
|
|
120
|
+
'chrome.runtime.onMessageExternal',
|
|
121
|
+
'chrome.runtime.onStartup',
|
|
122
|
+
'chrome.runtime.onSuspend',
|
|
123
|
+
'chrome.runtime.onSuspendCanceled',
|
|
124
|
+
'chrome.runtime.onUpdateAvailable',
|
|
125
|
+
'chrome.runtime.openOptionsPage',
|
|
126
|
+
'chrome.runtime.reload',
|
|
127
|
+
'chrome.runtime.requestUpdateCheck',
|
|
128
|
+
'chrome.runtime.restart',
|
|
129
|
+
'chrome.runtime.restartAfterDelay',
|
|
130
|
+
'chrome.runtime.sendMessage',
|
|
131
|
+
'chrome.runtime.setUninstallURL',
|
|
132
|
+
'chrome.tabs.captureVisibleTab',
|
|
133
|
+
'chrome.tabs.connect',
|
|
134
|
+
'chrome.tabs.create',
|
|
135
|
+
'chrome.tabs.detectLanguage',
|
|
136
|
+
'chrome.tabs.discard',
|
|
137
|
+
'chrome.tabs.duplicate',
|
|
138
|
+
'chrome.tabs.executeScript',
|
|
139
|
+
'chrome.tabs.get',
|
|
140
|
+
'chrome.tabs.getCurrent',
|
|
141
|
+
'chrome.tabs.goBack',
|
|
142
|
+
'chrome.tabs.goForward',
|
|
143
|
+
'chrome.tabs.highlight',
|
|
144
|
+
'chrome.tabs.insertCSS',
|
|
145
|
+
'chrome.tabs.move',
|
|
146
|
+
'chrome.tabs.reload',
|
|
147
|
+
'chrome.tabs.remove',
|
|
148
|
+
'chrome.tabs.removeCSS',
|
|
149
|
+
'chrome.tabs.sendMessage',
|
|
150
|
+
'chrome.tabs.update',
|
|
151
|
+
'chrome.windows'
|
|
152
|
+
]),
|
|
153
|
+
findDeprecated(api) {
|
|
154
|
+
for (const [deprecated, replacement] of this.deprecated)
|
|
155
|
+
if (api == deprecated || api.startsWith(`${deprecated}.`))
|
|
156
|
+
return { deprecated, replacement }
|
|
157
|
+
return null
|
|
158
|
+
},
|
|
159
|
+
findPermission(api) {
|
|
160
|
+
if (this.permless.has(api)) return null
|
|
161
|
+
for (const [prefix, permission] of this.permissionMap)
|
|
162
|
+
if (api == prefix || api.startsWith(`${prefix}.`))
|
|
163
|
+
return permission
|
|
164
|
+
return null
|
|
165
|
+
},
|
|
166
|
+
isExternalMsgListener(api) { return this.externalMsgListeners.has(api) }
|
|
106
167
|
}
|
|
107
|
-
|
|
108
|
-
export function findPermission(api) {
|
|
109
|
-
if (permlessAPIs.has(api)) return null
|
|
110
|
-
for (const [prefix, permission] of apiPermissionMap)
|
|
111
|
-
if (api == prefix || api.startsWith(`${prefix}.`))
|
|
112
|
-
return permission
|
|
113
|
-
return null
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function isExternalMessagingListener(api) { return externalMsgListeners.has(api) }
|
package/src/data/deprecations.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Delete a line to end support
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export default {
|
|
4
|
+
bundles: {
|
|
5
|
+
'no-invalid-permissions': ['recommended'], // 2026-10-5 announced future removal
|
|
6
|
+
'require-mv3': ['recommended'], // 2026-10-5 announced future removal
|
|
7
|
+
'valid-mv3-schema': ['recommended'], // 2026-10-5 announced future removal
|
|
8
|
+
'valid-version-field': ['recommended'] // 2026-10-5 announced future removal
|
|
9
|
+
}
|
|
8
10
|
}
|
|
9
|
-
|
|
10
|
-
export default { bundles }
|
package/src/data/i18n.js
CHANGED
|
@@ -1,71 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function collectUsedKeys(root, scanExtensions) {
|
|
15
|
-
const used = new Set(),
|
|
16
|
-
patterns = [],
|
|
17
|
-
exts = new Set(scanExtensions),
|
|
18
|
-
stack = [root]
|
|
19
|
-
while (stack.length) {
|
|
20
|
-
const dir = stack.pop()
|
|
21
|
-
let entries
|
|
22
|
-
try { entries = fs.readdirSync(dir, { withFileTypes: true }) } catch { continue }
|
|
23
|
-
for (const entry of entries) {
|
|
24
|
-
if (entry.name.startsWith('.') || entry.name == 'node_modules') continue
|
|
25
|
-
const full = path.join(dir, entry.name)
|
|
26
|
-
if (entry.isDirectory()) { stack.push(full) ; continue }
|
|
27
|
-
const ext = path.extname(entry.name).slice(1).toLowerCase()
|
|
28
|
-
if (!exts.has(ext)) continue
|
|
29
|
-
let text
|
|
30
|
-
try { text = fs.readFileSync(full, 'utf8') } catch { continue }
|
|
31
|
-
for (const match of text.matchAll(re.msgPlaceholder))
|
|
32
|
-
if (!isPredefined(match[1])) used.add(match[1])
|
|
33
|
-
for (const match of text.matchAll(re.getMsgLiteral))
|
|
34
|
-
used.add(match[1])
|
|
35
|
-
for (const match of text.matchAll(re.getMsgTemplate)) {
|
|
36
|
-
const body = match[1]
|
|
37
|
-
if (body.includes('${')) patterns.push(templateToPattern(body))
|
|
38
|
-
else used.add(body)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return { used, patterns }
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export const defaultScanExtensions = [
|
|
46
|
-
'cjs', 'css', 'htm', 'html', 'js', 'json', 'jsx', 'md', 'mjs', 'svg', 'ts', 'tsx', 'txt']
|
|
47
|
-
|
|
48
|
-
export function findExtensionRoot(startPath) {
|
|
49
|
-
let dir = path.dirname(startPath)
|
|
50
|
-
while (dir != path.dirname(dir)) {
|
|
51
|
-
if (fs.existsSync(path.join(dir, 'manifest.json'))) return dir
|
|
52
|
-
dir = path.dirname(dir)
|
|
1
|
+
export default {
|
|
2
|
+
defaultScanExtensions: ['cjs', 'css', 'htm', 'html', 'js', 'json', 'jsx', 'md', 'mjs', 'svg', 'ts', 'tsx', 'txt'],
|
|
3
|
+
re: {
|
|
4
|
+
getMsg: {
|
|
5
|
+
literal: /\b(?:browser|chrome)\.i18n\.getMessage\(\s*['"]([^'"]+)['"]/g,
|
|
6
|
+
path: /^(?:browser|chrome)\.i18n\.getMessage$/,
|
|
7
|
+
template: /\b(?:browser|chrome)\.i18n\.getMessage\(\s*`([^`]*)`/g
|
|
8
|
+
},
|
|
9
|
+
msgPlaceholder: /__MSG_([\w@]+)__/g,
|
|
10
|
+
specialChars: /[.*+?^${}()|[\]\\]/g,
|
|
11
|
+
templateExpr: /\$\{[^}]*\}/g
|
|
53
12
|
}
|
|
54
13
|
}
|
|
55
|
-
|
|
56
|
-
export function isPredefined(key) { return key.startsWith('@@') }
|
|
57
|
-
|
|
58
|
-
export function readDefaultLocaleMessages(manifest, root) {
|
|
59
|
-
const locale = manifest?.default_locale
|
|
60
|
-
if (typeof locale != 'string') return null
|
|
61
|
-
const filePath = path.join(root, '_locales', locale, 'messages.json')
|
|
62
|
-
let messages
|
|
63
|
-
try { messages = JSON.parse(fs.readFileSync(filePath, 'utf8')) } catch { return null }
|
|
64
|
-
if (!messages || typeof messages != 'object' || Array.isArray(messages)) return null
|
|
65
|
-
return { locale, messages }
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function templateToPattern(body) {
|
|
69
|
-
const parts = body.split(re.templateExpr).map(part => part.replace(re.specialChars, '\\$&'))
|
|
70
|
-
return new RegExp(`^${parts.join('.*')}$`) // eslint-disable-line security/detect-non-literal-regexp
|
|
71
|
-
}
|