|
@@ -7,48 +7,52 @@ import { parseMeta, matchUserScript } from './script';
|
|
|
import { fileSchemeRequestable, getTabUrl, NEWTAB_URL_RE, tabsOnUpdated } from './tabs';
|
|
|
import { FIREFOX } from './ua';
|
|
|
|
|
|
-const CONFIRM_URL_BASE = `${extensionRoot}confirm/index.html#`;
|
|
|
-
|
|
|
addPublicCommands({
|
|
|
async CheckInstallerTab(tabId, src) {
|
|
|
const tab = IS_FIREFOX && (src.url || '').startsWith('file:')
|
|
|
&& await browser.tabs.get(tabId).catch(noop);
|
|
|
return tab && getTabUrl(tab).startsWith(CONFIRM_URL_BASE);
|
|
|
},
|
|
|
- async ConfirmInstall({ code, from, url, fs, parsed }, { tab = {} }) {
|
|
|
- if (!fs) {
|
|
|
- if (!code) code = (await request(url)).data;
|
|
|
- // TODO: display the error in UI
|
|
|
- if (!parsed && !matchUserScript(code)) {
|
|
|
- throw `${i18n('msgInvalidScript')}\n\n${
|
|
|
- code.trim().split(/[\r\n]+\s*/, 9/*max lines*/).join('\n')
|
|
|
- .slice(0, 500/*max overall length*/)
|
|
|
- }...`;
|
|
|
- }
|
|
|
- cache.put(url, code, 3000);
|
|
|
- }
|
|
|
- const confirmKey = getUniqId();
|
|
|
- const { active, id: tabId, incognito } = tab;
|
|
|
- // Not testing tab.pendingUrl because it will be always equal to `url`
|
|
|
- const canReplaceCurTab = (!incognito || IS_FIREFOX) && (
|
|
|
- url === from
|
|
|
- || cache.has(`autoclose:${tabId}`)
|
|
|
- || NEWTAB_URL_RE.test(from));
|
|
|
- /** @namespace VM.ConfirmCache */
|
|
|
- cache.put(`confirm-${confirmKey}`, { incognito, url, from, tabId, fs, ff: FIREFOX });
|
|
|
- const confirmUrl = CONFIRM_URL_BASE + confirmKey;
|
|
|
- const { [kWindowId]: windowId } = canReplaceCurTab
|
|
|
- // The tab may have been closed already, in which case we'll open a new tab
|
|
|
- && await browser.tabs.update(tabId, { url: confirmUrl }).catch(noop)
|
|
|
- || await commands.TabOpen({ url: confirmUrl, active: !!active }, { tab });
|
|
|
- if (active && windowId !== tab[kWindowId]) {
|
|
|
- await browserWindows?.update(windowId, { focused: true });
|
|
|
- }
|
|
|
- },
|
|
|
+ ConfirmInstall: confirmInstall,
|
|
|
});
|
|
|
|
|
|
+async function confirmInstall({ code, from, url, fs, parsed }, { tab = {} }) {
|
|
|
+ if (!fs) {
|
|
|
+ code ??= parsed
|
|
|
+ ? request(url).then(r => r.data) // cache the Promise and start fetching now
|
|
|
+ : (await request(url)).data;
|
|
|
+ // TODO: display the error in UI
|
|
|
+ if (!parsed && !matchUserScript(code)) {
|
|
|
+ throw `${i18n('msgInvalidScript')}\n\n${
|
|
|
+ code.trim().split(/[\r\n]+\s*/, 9/*max lines*/).join('\n')
|
|
|
+ .slice(0, 500/*max overall length*/)
|
|
|
+ }...`;
|
|
|
+ }
|
|
|
+ cache.put(url, code, 3000);
|
|
|
+ }
|
|
|
+ const confirmKey = getUniqId();
|
|
|
+ const { active, id: tabId, incognito } = tab;
|
|
|
+ // Not testing tab.pendingUrl because it will be always equal to `url`
|
|
|
+ const canReplaceCurTab = (!incognito || IS_FIREFOX) && (
|
|
|
+ url === from
|
|
|
+ || cache.has(`autoclose:${tabId}`)
|
|
|
+ || NEWTAB_URL_RE.test(from));
|
|
|
+ /** @namespace VM.ConfirmCache */
|
|
|
+ cache.put(`confirm-${confirmKey}`, { incognito, url, from, tabId, fs, ff: FIREFOX });
|
|
|
+ const confirmUrl = CONFIRM_URL_BASE + confirmKey;
|
|
|
+ const { [kWindowId]: windowId } = canReplaceCurTab
|
|
|
+ // The tab may have been closed already, in which case we'll open a new tab
|
|
|
+ && await browser.tabs.update(tabId, { url: confirmUrl }).catch(noop)
|
|
|
+ || await commands.TabOpen({ url: confirmUrl, active: !!active }, { tab });
|
|
|
+ if (active && windowId !== tab[kWindowId]) {
|
|
|
+ await browserWindows?.update(windowId, { focused: true });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const CONFIRM_URL_BASE = `${extensionRoot}confirm/index.html#`;
|
|
|
const whitelistRe = re`/^https:\/\/(
|
|
|
(greas|sleaz)yfork\.org\/scripts\/[^/]*\/code|
|
|
|
+ update\.(greas|sleaz)yfork\.org\/scripts\/\d+|
|
|
|
openuserjs\.org\/install\/[^/]*|
|
|
|
github\.com\/[^/]*\/[^/]*\/(
|
|
|
raw\/[^/]*|
|
|
@@ -74,12 +78,12 @@ const maybeRedirectVirtualUrlFF = virtualUrlRe && ((tabId, src) => {
|
|
|
}
|
|
|
});
|
|
|
|
|
|
-async function maybeInstallUserJs(tabId, url) {
|
|
|
+async function maybeInstallUserJs(tabId, url, isWhitelisted) {
|
|
|
// Getting the tab now before it navigated
|
|
|
const tab = tabId >= 0 && await browser.tabs.get(tabId) || {};
|
|
|
- const { data: code } = await request(url).catch(noop) || {};
|
|
|
- if (code && parseMeta(code).name) {
|
|
|
- commands.ConfirmInstall({ code, url, from: tab.url, parsed: true }, { tab });
|
|
|
+ const { data: code } = !isWhitelisted && await request(url).catch(noop) || {};
|
|
|
+ if (isWhitelisted || code && parseMeta(code).name) {
|
|
|
+ confirmInstall({ code, url, from: tab.url, parsed: true }, { tab });
|
|
|
} else {
|
|
|
cache.put(`bypass:${url}`, true, 10e3);
|
|
|
const error = `${VIOLENTMONKEY} installer skipped ${url}.
|
|
@@ -118,7 +122,7 @@ browser.tabs.onCreated.addListener((tab) => {
|
|
|
}
|
|
|
if (isUserJS && isFile && !fileSchemeRequestable && !IS_FIREFOX
|
|
|
&& getOption('helpForLocalFile')) {
|
|
|
- commands.ConfirmInstall({ url, fs: true }, { tab });
|
|
|
+ confirmInstall({ url, fs: true }, { tab });
|
|
|
}
|
|
|
});
|
|
|
|
|
@@ -131,9 +135,10 @@ browser.webRequest.onBeforeRequest.addListener((req) => {
|
|
|
if (url.startsWith(extensionRoot)) {
|
|
|
return { redirectUrl: resolveVirtualUrl(url) };
|
|
|
}
|
|
|
+ let isWhitelisted;
|
|
|
if (!cache.has(`bypass:${url}`)
|
|
|
- && (!blacklistRe.test(url) || whitelistRe.test(url))) {
|
|
|
- maybeInstallUserJs(tabId, url);
|
|
|
+ && ((isWhitelisted = whitelistRe.test(url)) || !blacklistRe.test(url))) {
|
|
|
+ maybeInstallUserJs(tabId, url, isWhitelisted);
|
|
|
return IS_FIREFOX
|
|
|
? { cancel: true } // for sites with strict CSP in FF
|
|
|
: { redirectUrl: 'javascript:void 0' }; // eslint-disable-line no-script-url
|