1

Problem

I am making a Chrome extension that downloads files and adds links to these downloaded files to a webpage. When these links are clicked, I would like to relay the click as a "user gesture" to my background script so that the file opens without prompting. Looking at the docs on the relevant method, chrome.downloads.open, there is no discussion of user gestures.

Essentially, I want to get rid of this => prompt I would like to preempt

using the idea in this comment.

Background

It seems like this is possible because

  • This post on what constitutes a user gesture lists click as one of the types of user gestures
  • The spec, which says clicks will generate a user gesture
  • In the code below, logging the event results in a MouseEvent, with type click and isTrusted set to true.
  • [downloads.open] can only run in a code initiated by a user action, like a click on a button. It cannot be executed from non-user events. - Xan, comment for How to open a downloaded file?

Code below aims to be an MCVE.

Content Script

// Add an event listener for every download link
function addDownloadListeners() { 
  const pathElems = document.getElementsByClassName('pathClass');
  for (path of pathElems) {
    path.addEventListener('click', openDownload);
  }
}

// Send a message with the download ID to the background script
function openDownload(event) {
  const selector = '#' + event.currentTarget.id;
  const downloadId = parseInt($(selector).attr('download_id'));
  chrome.runtime.sendMessage({
    'downloadId': downloadId,     
  }, function(response) {
    if (response !== undefined) {
      resolve(response.response);
    } else {
      reject(new Error(response.response));
    }
  });
}

manifest.json

{
  "background": {
    "scripts": ["js/background.js"]
  },
  "content_scripts": [
    {
      "js": [
        "js/content_script.js"
      ],
      "matches": ["*://*.website.com/*/urlpath*"],
      "run_at": "document_end"
    }
  ],
  "permissions": [
    "downloads",
    "downloads.open"
  ],
  "manifest_version": 2,
}

Background Script

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    try {
      chrome.downloads.open(request.downloadId);
    } catch (e) {
      sendResponse({response: 'Error opening file with download id ' +      
        request.downloadId + ' getting error ' + e.toString()
      });
    }
  }
)

Question

How can I get a click to open a download without creating an additional prompt?

Ross Jacobs
  • 2,962
  • 1
  • 17
  • 27
  • 1
    It's highly probable there's a bug in Chrome so it doesn't relay the user gesture from the web page to the background page. In the worst case scenario, this is an intended restriction for chrome.downloads.open so it can be used only inside extension pages such as browser_action popup or any such internal page inside extension. Try getting an official clarification on https://crbug.com or [extensions group](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-extensions). – wOxxOm Oct 29 '19 at 04:54
  • Thank you for your thoughtful response @wOxxOm. If it's a restriction, then I can live with having an extra prompt. I've asked about it on the extension group to see what they think. – Ross Jacobs Oct 30 '19 at 00:52

1 Answers1

1

This is not possible

It is not possible to prevent/use an alternative to prompts for chrome methods that require user consent. Based on this discussion in the Chromium Extension google group,

  • Some Chrome methods (like chrome.downloads.open) need to get user consent via prompt.
  • These are automatically generated via Chrome itself - they cannot be overridden or modified.
  • User gestures outside of prompts are not relevant to methods that require user consent.

This current behavior is circa 2014 for chrome.downloads.open.

Special thanks to @wOxxOm and Decklin Johnston for making this answer possible.

Ross Jacobs
  • 2,962
  • 1
  • 17
  • 27