🐛 Make native GM_download honor @connect, like GM_xmlhttpRequest#1506
🐛 Make native GM_download honor @connect, like GM_xmlhttpRequest#1506DudeAint wants to merge 1 commit into
Conversation
|
This looks acceptable to me. |
@CodFrm No need for Tampermonkey compatibility? The following script can run without @DudeAint Currently it is intended to enforce // ==UserScript==
// @name GM_download API Demonstration
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Adds a floating button to download a file using GM_download
// @author You
// @match *://*/*?test_GM_download
// @grant GM_download
// ==/UserScript==
(function() {
'use strict';
// 1. Create a floating button on the page
const btn = document.createElement('button');
btn.textContent = '🚀 Download File';
btn.style.position = 'fixed';
btn.style.top = '20px';
btn.style.left = '20px';
btn.style.zIndex = '99999';
btn.style.padding = '10px 15px';
btn.style.backgroundColor = '#007bff';
btn.style.color = '#fff';
btn.style.border = 'none';
btn.style.borderRadius = '5px';
btn.style.cursor = 'pointer';
btn.style.fontWeight = 'bold';
document.body.appendChild(btn);
// 2. Set up the download event
btn.addEventListener('click', () => {
btn.textContent = '⏳ Downloading...';
btn.disabled = true;
GM_download({
url: 'https://www.w3.org/assets/logos/w3c/w3c-no-bars.svg',
name: 'w3c-logo-downloaded.svg',
saveAs: false, // Set to true if you want the browser's "Save As" prompt to appear
onload: function() {
alert('Download completed successfully!');
btn.textContent = '🚀 Download File';
btn.disabled = false;
},
onerror: function(error) {
alert('Download failed: ' + error.error);
btn.textContent = '❌ Failed';
btn.disabled = false;
console.error(error);
},
onprogress: function(progress) {
if (progress.lengthComputable) {
const percent = Math.round((progress.loaded / progress.total) * 100);
btn.textContent = `⏳ ${percent}%`;
}
},
ontimeout: function() {
alert('Download timed out!');
btn.textContent = '🚀 Download File';
btn.disabled = false;
}
});
});
})(); |
|
Personally speaking, The use of API is to avoid the cookie sending or doing cross domain request. In modern design, all the network API endpoints should have token/bearer to protect the unauthorized usage. Even you can do the cors request, the script still cannot steal your personal information or do something danger on behalf of you. ScriptCat just follow Tampermonkey to do these silly things. And I can tell you that the deeper blockage is not implemented in SC like TM. In the past year my focus is just to fix the compatibility issues to make ScriptCat can be used - not to duplicate Tampermonkey. For example, don't let the Don't need to bother with those security things too much. There is no security once you have installed the malware userscripts. Or can we tell users that, if the script does not declare |
From a code-execution standpoint this doesn't actually break TM compatibility, so I think it's acceptable. From a security angle, native
Even without I don't think that's a bad design — I think it's a necessary one. Otherwise, while you're on x.com, a malicious script could directly reach youtube.com, grab your logged-in account info, and use it to push ads, all without your knowledge. With
At the very least we can tell users that the script won't do anything that affects sites other than the current one — |
If this PR merges, the following will only work in TM not SC. // ==UserScript==
// @name GM_download API Demonstration
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Adds a floating button to download a file using GM_download
// @author You
// @match *://*/*?test_GM_download
// @connect abc.com
// @grant GM_download
// ==/UserScript==
(function() {
'use strict';
// 1. Create a floating button on the page
const btn = document.createElement('button');
btn.textContent = '🚀 Download File';
btn.style.position = 'fixed';
btn.style.top = '20px';
btn.style.left = '20px';
btn.style.zIndex = '99999';
btn.style.padding = '10px 15px';
btn.style.backgroundColor = '#007bff';
btn.style.color = '#fff';
btn.style.border = 'none';
btn.style.borderRadius = '5px';
btn.style.cursor = 'pointer';
btn.style.fontWeight = 'bold';
document.body.appendChild(btn);
// 2. Set up the download event
btn.addEventListener('click', () => {
btn.textContent = '⏳ Downloading...';
btn.disabled = true;
GM_download({
url: 'https://www.w3.org/assets/logos/w3c/w3c-no-bars.svg',
name: 'w3c-logo-downloaded.svg',
saveAs: false, // Set to true if you want the browser's "Save As" prompt to appear
onload: function() {
alert('Download completed successfully!');
btn.textContent = '🚀 Download File';
btn.disabled = false;
},
onerror: function(error) {
alert('Download failed: ' + error.error);
btn.textContent = '❌ Failed';
btn.disabled = false;
console.error(error);
},
onprogress: function(progress) {
if (progress.lengthComputable) {
const percent = Math.round((progress.loaded / progress.total) * 100);
btn.textContent = `⏳ ${percent}%`;
}
},
ontimeout: function() {
alert('Download timed out!');
btn.textContent = '🚀 Download File';
btn.disabled = false;
}
});
});
})(); |
I understand. Alternatively, could we change I’d like to close this security gap. |
up to you. Tampermonkey is intended to do it for xhr/fetch only. not for download. |
There was a problem hiding this comment.
No Comment to Accept or Reject. Respect CodFrm's decision.
Remarks:
- Breaking Change and leading incompatibilities to Tampermonkey scripts.
- Requires Documentation Update
- CodFrm / DudeAint shall test with different
@connectdeclaring cases to confirm no issue.
GM_xmlhttpRequest gates cross-origin requests via @connect / blacklist / site-access, but native GM_download re-entered the request engine with a direct call that skipped the check. Route it through the same check. Unlike TM (which scopes @connect to xhr/fetch only), an undeclared host prompts the user instead of being refused, so existing download scripts keep working with consent. @connect-matched hosts, the blacklist, and browser/blob downloads are unaffected; GM_xmlhttpRequest is unchanged.
907b534 to
b310661
Compare
|
Reworked per the feedback. @cyfung1031 is right that TM scopes @connect to xhr/fetch only, so a hard refusal in GM_download would break existing TM scripts. So instead of refusing, native GM_download now prompts the user when the host isn't in @connect (per @CodFrm's suggestion). Behavior: @connect matched hosts download silently as before; unlisted hosts show a confirm dialog and the user decides; the blacklist still hard-blocks; browser/blob downloads and GM_xmlhttpRequest are unchanged. Tested locally across the matched / allow / deny cases. Docs should note that SC prompts here, since this differs from TM. |
I agree that we can do it this way, so users can still run the script. |
Checklist / 检查清单
Description / 描述
GM_xmlhttpRequestruns every request through aconfirmcheck (@connect, blacklist, site-access).GM_downloadinnativemode does its request by callingGM_xmlhttpRequestdirectly:That call skips
handlerRequest, so the check never runs. Sincenativeis the default, a script with@grant GM_downloadcan fetch a host outside its@connectlist (whichGM_xmlhttpRequestwould refuse)and skip the blacklist. Native download is
GM_xmlhttpRequestunderneath, so it should get the same check.Fix: extracted the check into a private
verifyXhrConnectand run it from both APIs;GM_downloadonly for
downloadMode === "native"(browser/blob unchanged).Behavior change: native downloads now show the site-access prompt for un-granted hosts, same as
GM_xmlhttpRequest.Tested: a native
GM_downloadto a non-@connecthost is now refused (was downloading);@connect'dand browser/blob downloads still work.
tsc/eslint/tests green.src/app/service/service_worker/gm_api/gm_api.tsverifyXhrConnect; gate nativeGM_download.Screenshots / 截图