Don't hand file:// URLs to KGet

Ctrl+S on a page you navigated to directly via file:// is still a
"download" as far as chrome.downloads is concerned, so auto-capture
was intercepting it and handing the local path to KGet, which
rejects it with a confusing "protocol is not supported" dialog since
it's a network download manager, not a file copier. Extend the
existing blob:/data: exclusion to also cover file:/filesystem:, and
apply the same guard to the right-click capture path.
This commit is contained in:
2026-08-12 12:11:03 +03:00
parent 235c377361
commit a2cd4184e3
3 changed files with 24 additions and 6 deletions
+5 -3
View File
@@ -83,9 +83,11 @@ git push origin v1.0.0
## Known limitations ## Known limitations
- **`blob:`/`data:` URLs can't be captured.** There's no real network URL to - **`blob:`/`data:`/`file:`/`filesystem:` URLs can't be captured.** There's
hand to KGet, so these downloads proceed normally through Chrome (a console no real network URL to hand to KGet — this includes saving a page you
warning is logged in the extension's service worker). navigated to directly via `file://` (Ctrl+S on it is still a "download" as
far as Chrome is concerned) — so these downloads proceed normally through
Chrome (a console warning is logged in the extension's service worker).
- **Auto-capture has a brief head start.** Manifest V3 removed blocking - **Auto-capture has a brief head start.** Manifest V3 removed blocking
`webRequest`, so Chrome begins the download before the extension can cancel `webRequest`, so Chrome begins the download before the extension can cancel
it. A small/partial temp file may transiently appear before it's erased. it. A small/partial temp file may transiently appear before it's erased.
+18 -2
View File
@@ -11,6 +11,18 @@ async function refreshBadge() {
updateBadge(autoCaptureEnabled); updateBadge(autoCaptureEnabled);
} }
// KGet is a network download manager -- it can't "download" a URL that's
// already local (or embedded in the page), so don't hand it these schemes.
// file: shows up when saving a page you navigated to directly (Ctrl+S on a
// file:// URL is still a "download" as far as chrome.downloads is
// concerned), and KGet's addTransfer rejects it with a confusing
// "protocol is not supported" dialog if we try.
const UNSUPPORTED_SCHEMES = ["blob:", "data:", "file:", "filesystem:"];
function isCapturableUrl(url) {
return !UNSUPPORTED_SCHEMES.some((scheme) => url.startsWith(scheme));
}
function sendToKGet(url, filename) { function sendToKGet(url, filename) {
chrome.runtime.sendNativeMessage( chrome.runtime.sendNativeMessage(
NATIVE_HOST, NATIVE_HOST,
@@ -44,6 +56,10 @@ chrome.contextMenus.onClicked.addListener((info) => {
if (info.menuItemId !== MENU_ID) return; if (info.menuItemId !== MENU_ID) return;
const url = info.linkUrl || info.srcUrl; const url = info.linkUrl || info.srcUrl;
if (!url) return; if (!url) return;
if (!isCapturableUrl(url)) {
console.warn("[kget-capture] cannot hand a local/embedded URL to KGet:", url);
return;
}
sendToKGet(url, null); sendToKGet(url, null);
}); });
@@ -63,8 +79,8 @@ async function captureDownload(item) {
if (!autoCaptureEnabled) return; if (!autoCaptureEnabled) return;
const url = item.finalUrl || item.url; const url = item.finalUrl || item.url;
if (url.startsWith("blob:") || url.startsWith("data:")) { if (!isCapturableUrl(url)) {
console.warn("[kget-capture] cannot redirect blob:/data: URL, letting Chrome handle it:", url); console.warn("[kget-capture] cannot hand a local/embedded URL to KGet, letting Chrome handle it:", url);
return; return;
} }
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "KGet Capture", "name": "KGet Capture",
"version": "1.0.2", "version": "1.0.3",
"description": "Send browser downloads to KGet (KDE Download Manager) on Linux.", "description": "Send browser downloads to KGet (KDE Download Manager) on Linux.",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtM1nFg5pPd3UBzynUJHj6aUy7bjudZaX9AQTWGMqAX3fXylw1lubSzP1/BaS9ivvgOJg/loyEgzEZlcNPzblFVlg8BqEJ3tntdk2OzYvUs0pUdcPzzyjso9TykCkUUTI7ev8JkreW/FYlinfvNwSYN4/c1s3h8/I6XHtxOdmO1G3bS98+BQaXPldbDmxoKwyWR8u1f8gTO2Mg3GY4BHau3RWf1kgtNzh20p9wE3sEFdWkFu7ArgRCIrWLh6m3O6lolnHQSCWPwtOTx893Qkp9Eu6FwUnoWc8rsYx8sqa0eNCTCS6Kjr1Iu3yEJ5y9390jUiDZTQ/c62ueCTQaYv2bwIDAQAB", "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtM1nFg5pPd3UBzynUJHj6aUy7bjudZaX9AQTWGMqAX3fXylw1lubSzP1/BaS9ivvgOJg/loyEgzEZlcNPzblFVlg8BqEJ3tntdk2OzYvUs0pUdcPzzyjso9TykCkUUTI7ev8JkreW/FYlinfvNwSYN4/c1s3h8/I6XHtxOdmO1G3bS98+BQaXPldbDmxoKwyWR8u1f8gTO2Mg3GY4BHau3RWf1kgtNzh20p9wE3sEFdWkFu7ArgRCIrWLh6m3O6lolnHQSCWPwtOTx893Qkp9Eu6FwUnoWc8rsYx8sqa0eNCTCS6Kjr1Iu3yEJ5y9390jUiDZTQ/c62ueCTQaYv2bwIDAQAB",
"permissions": ["downloads", "contextMenus", "storage", "nativeMessaging"], "permissions": ["downloads", "contextMenus", "storage", "nativeMessaging"],