eslint-plugin-chrome-extensions 2.4.2 → 2.6.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 +272 -115
- package/package.json +6 -8
- package/src/data/apis.js +166 -115
- package/src/data/deprecations.js +5 -7
- package/src/data/i18n.js +19 -69
- package/src/data/manifest.js +61 -57
- package/src/data/permissions.js +23 -30
- 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-locales.js +89 -0
- package/src/rules/no-invalid-permissions.js +10 -13
- package/src/rules/no-missing-default-locale.js +44 -21
- package/src/rules/no-missing-i18n-keys.js +24 -25
- 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 +35 -19
- package/src/rules/no-unused-i18n-keys.js +11 -10
- package/src/rules/no-unused-permissions.js +31 -23
- package/src/rules/require-license-file.js +4 -5
- package/src/rules/require-mv3.js +5 -6
- 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 +35 -6
- package/src/rules/valid-mv3-schema.js +22 -22
- package/src/rules/valid-service-worker.js +34 -13
- package/src/rules/valid-url-fields.js +49 -41
- package/src/rules/valid-version-field.js +5 -9
- package/src/utils/extension.js +52 -33
- package/src/utils/i18n.js +58 -0
- package/src/utils/init.js +107 -0
- package/src/utils/license.js +56 -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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-chrome-extensions",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "ESLint rules for Chrome extensions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -54,15 +54,14 @@
|
|
|
54
54
|
"bump:minor": "bash utils/bump.sh minor",
|
|
55
55
|
"bump:patch": "bash utils/bump.sh patch",
|
|
56
56
|
"demo": "node demo/run.js",
|
|
57
|
-
"lint": "
|
|
58
|
-
"lint:all": "
|
|
59
|
-
"lint:fix": "eslint . --fix --cache && yamllint .",
|
|
60
|
-
"lint:fix-all": "eslint . --fix && yamllint .",
|
|
57
|
+
"lint": "pre-commit run",
|
|
58
|
+
"lint:all": "pre-commit run --all-files",
|
|
61
59
|
"test": "node tests/run.js"
|
|
62
60
|
},
|
|
63
61
|
"dependencies": {
|
|
64
62
|
"globals": "^17.13.0",
|
|
65
|
-
"spdx-license-ids": "^3.0.24"
|
|
63
|
+
"spdx-license-ids": "^3.0.24",
|
|
64
|
+
"spdx-license-list": "^6.12.0"
|
|
66
65
|
},
|
|
67
66
|
"devDependencies": {
|
|
68
67
|
"@e18e/eslint-plugin": "^0.8.1",
|
|
@@ -82,8 +81,7 @@
|
|
|
82
81
|
"eslint-plugin-package-json": "^1.10.1",
|
|
83
82
|
"eslint-plugin-promise": "^7.3.0",
|
|
84
83
|
"eslint-plugin-regexp": "^3.3.1",
|
|
85
|
-
"eslint-plugin-security": "^4.2.0"
|
|
86
|
-
"yamllint-js": "^0.2.4"
|
|
84
|
+
"eslint-plugin-security": "^4.2.0"
|
|
87
85
|
},
|
|
88
86
|
"peerDependencies": {
|
|
89
87
|
"@eslint/css": ">=0.5.0",
|
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,8 @@
|
|
|
1
1
|
// Delete a line to end support
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export default {
|
|
4
|
+
bundles: {
|
|
5
|
+
// <rule-id-a>: [<old-bundle>],
|
|
6
|
+
// <rule-id-b>: [<old-bundle>]
|
|
7
|
+
}
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
export default { bundles }
|
package/src/data/i18n.js
CHANGED
|
@@ -1,71 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
+
locales: {
|
|
4
|
+
supported: new Set([ // https://developer.chrome.com/docs/extensions/reference/api/i18n
|
|
5
|
+
'af', 'am', 'ar', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'en', 'en_AU', 'en_GB', 'en_IN', 'en_US', 'es',
|
|
6
|
+
'es_419', 'es_MX', 'es_US', 'et', 'fa', 'fi', 'fil', 'fr', 'fr_CA', 'fr_FR', 'gu', 'he', 'hi', 'hr', 'hu',
|
|
7
|
+
'id', 'it', 'ja', 'kn', 'ko', 'lt', 'lv', 'ml', 'mr', 'ms', 'nl', 'no', 'pl', 'pt_BR', 'pt_PT', 'ro', 'ru',
|
|
8
|
+
'sk', 'sl', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tr', 'uk', 'vi', 'zh_CN', 'zh_TW'
|
|
9
|
+
])
|
|
10
|
+
},
|
|
11
|
+
re: {
|
|
12
|
+
getMsg: {
|
|
13
|
+
literal: /\b(?:browser|chrome)\.i18n\.getMessage\(\s*['"]([^'"]+)['"]/g,
|
|
14
|
+
path: /^(?:browser|chrome)\.i18n\.getMessage$/,
|
|
15
|
+
template: /\b(?:browser|chrome)\.i18n\.getMessage\(\s*`([^`]*)`/g
|
|
16
|
+
},
|
|
17
|
+
msgPlaceholder: /__MSG_([\w@]+)__/g,
|
|
18
|
+
specialChars: /[.*+?^${}()|[\]\\]/g,
|
|
19
|
+
templateExpr: /\$\{[^}]*\}/g
|
|
53
20
|
}
|
|
54
21
|
}
|
|
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
|
-
}
|
package/src/data/manifest.js
CHANGED
|
@@ -1,61 +1,65 @@
|
|
|
1
1
|
import globals from 'globals'
|
|
2
2
|
|
|
3
3
|
const serviceWorkerGlobals = new Set(Object.keys(globals.serviceworker || {}))
|
|
4
|
-
export const domGlobals = new Set(Object.keys(globals.browser).filter(name => !serviceWorkerGlobals.has(name)))
|
|
5
4
|
|
|
6
|
-
export
|
|
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
|
-
|
|
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
|
-
|
|
5
|
+
export default {
|
|
6
|
+
csp: {
|
|
7
|
+
forbiddenDirectives: [
|
|
8
|
+
`'unsafe-eval'`, `'unsafe-inline'`, `'unsafe-hashes'`, `'wasm-unsafe-eval'`, 'http://', 'https://']
|
|
9
|
+
},
|
|
10
|
+
globals: {
|
|
11
|
+
dom: new Set(Object.keys(globals.browser).filter(name => !serviceWorkerGlobals.has(name))) },
|
|
12
|
+
keys: {
|
|
13
|
+
ff: {
|
|
14
|
+
dataCollectionOptional: new Set([
|
|
15
|
+
'authenticationInfo', 'bookmarksInfo', 'browsingActivity', 'financialAndPaymentInfo',
|
|
16
|
+
'healthInfo', 'locationInfo', 'personalCommunications', 'personallyIdentifyingInfo',
|
|
17
|
+
'searchTerms', 'technicalAndInteraction', 'websiteActivity', 'websiteContent'
|
|
18
|
+
]),
|
|
19
|
+
dataCollectionRequired: new Set([
|
|
20
|
+
'none', 'authenticationInfo', 'bookmarksInfo', 'browsingActivity', 'financialAndPaymentInfo',
|
|
21
|
+
'healthInfo', 'locationInfo', 'personalCommunications', 'personallyIdentifyingInfo', 'searchTerms',
|
|
22
|
+
'websiteActivity', 'websiteContent'
|
|
23
|
+
]),
|
|
24
|
+
mv3BG: new Set(['scripts', 'page'])
|
|
25
|
+
},
|
|
26
|
+
mv2Only: new Set(['browser_action', 'page_action']),
|
|
27
|
+
order: [
|
|
28
|
+
// platform-required
|
|
29
|
+
'manifest_version', 'name', 'version',
|
|
30
|
+
// CWS-required
|
|
31
|
+
'description', 'icons',
|
|
32
|
+
// optional
|
|
33
|
+
'action', 'author', 'background', 'browser_specific_settings', 'chrome_settings_overrides',
|
|
34
|
+
'chrome_url_overrides', 'commands', 'content_scripts', 'content_security_policy',
|
|
35
|
+
'cross_origin_embedder_policy', 'cross_origin_opener_policy', 'dark_theme', 'declarative_net_request',
|
|
36
|
+
'default_locale', 'developer', 'devtools_page', 'dictionaries', 'export', 'externally_connectable',
|
|
37
|
+
'homepage_url', 'host_permissions', 'import', 'incognito', 'key', 'mime_types_handler',
|
|
38
|
+
'minimum_chrome_version', 'oauth2', 'omnibox', 'optional_host_permissions', 'optional_permissions',
|
|
39
|
+
'options_page', 'options_ui', 'permissions', 'protocol_handlers', 'requirements', 'sandbox',
|
|
40
|
+
'short_name', 'sidebar_action', 'side_panel', 'storage', 'theme', 'theme_experiment', 'tts_engine',
|
|
41
|
+
'update_url', 'version_name', 'web_accessible_resources'
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
paths: {
|
|
45
|
+
match: new Set([
|
|
46
|
+
'content_scripts.matches', 'externally_connectable.matches', 'host_permissions',
|
|
47
|
+
'optional_host_permissions', 'web_accessible_resources.matches'
|
|
48
|
+
]),
|
|
49
|
+
url: new Set([
|
|
50
|
+
'homepage_url', 'update_url', 'oauth2.scopes',
|
|
51
|
+
'chrome_settings_overrides.homepage',
|
|
52
|
+
'chrome_settings_overrides.search_provider.alternate_urls',
|
|
53
|
+
'chrome_settings_overrides.search_provider.favicon_url',
|
|
54
|
+
'chrome_settings_overrides.search_provider.image_url',
|
|
55
|
+
'chrome_settings_overrides.search_provider.instant_url',
|
|
56
|
+
'chrome_settings_overrides.search_provider.search_url',
|
|
57
|
+
'chrome_settings_overrides.search_provider.suggest_url',
|
|
58
|
+
'chrome_settings_overrides.startup_pages'
|
|
59
|
+
])
|
|
60
|
+
},
|
|
61
|
+
patterns: {
|
|
62
|
+
remoteCode: [
|
|
63
|
+
'eval', 'new-function', 'string-timer', 'dynamic-import', 'remote-script-src', 'execute-script-url']
|
|
64
|
+
}
|
|
65
|
+
}
|