🐛 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
Native-mode GM_download calls GM_xmlhttpRequest directly to perform the cross-origin request, which skipped GM_xmlhttpRequest's @connect / blacklist / site-access checks. Extract that check into verifyXhrConnect and have native download reuse it, so both paths behave the same.
|
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.
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 / 截图