Is there a way to make `clipboard.writeText()` work even for "moz-extension://"(javascript on popup)?

I want to migrate this Chrome extension to Firefox-> https://github.com/lamrongol/copy_twitter.com_address .
However, on Firefox I found navigator.clipboard.writeText(text) works only on Secure contexts(https://).
I want to use clipboard.writeText() on javascript of popup of the extension, which “protocol” is “moz-extension”.

You’re right: access to the clipboard requires a secure context (https://developer.mozilla.org/en-US/docs/Web/API/Clipboard). However, if you want to port the copy_twitter extension to Firefox, aren’t you redirecting the https://x.com/… link to https://twitter.com/… So, I don’t quite understand why you would want access to moz-extension://… ? All your code appears to be missing is the clipboardWrite permission in your manifest file (https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions#clipboardwrite)

why you would want access to moz-extension://… ?

Because “protocol” of popup.html is “moz-extension://”.

missing is the clipboardWrite permission

I addded the permission but still error occurs. I found following answer says same thing but a comment saying error remains is added:

Which error are you getting?

Which error are you getting?

Same as above link of Stack overflow question:
" uncaught (in promise) DOMException: clipboard write was blocked due to lack of user activation."

This error suggests you are not running the code in the user-action handler:

See also similar transient activation (not really relevant for this API I think):

You mean I need to open popup by browserAction.openPopup() when user clicks the toolbar button although popup is opened by default when user clicks the toolbar button?

Or, for example, deleting default_popup from manifest.json and set service_worker.js to open popup?

The what? :smiley:
I’m just interpreting the error - clipboard write was blocked due to lack of user activation. This means that you can’t use clipboard.write API outside of a “user-action” handler.
So if you want to write to clipboard, you can only do it in a event handler that handles some user action, like a button click.

This is a security measure to prevent extensions from changing your clipboard when you are not interacting with the extension.

Can you share the piece of code that sets your clipboard? And when does it run? And is it executed in an async function?

I’ve tested the following in Firefox 131.0.3 (64-bit) on Linux Mint 22.

Why the original extension doesn’t work in Firefox:

  1. Download the extension from https://github.com/lamrongol/copy_twitter.com_address and unzip the downloaded file
  2. Go to about:debugging#/runtime/this-firefox
  3. Load the extension with “Load Temporary Add-on”
  4. Click “Inspect”
  5. Go to https://x.com/mozilla
  6. Debug the popup, as described in Debugging popups
  7. Error: “Uncaught (in promise) DOMException: Clipboard write was blocked due to lack of user activation.”
  8. Clipboard API > Security considerations > Firefox Web Extensions:
    Writing text is available in secure context and with transient activation. With the Web Extension clipboardWrite permission transient activation is not required.

I can think of two solutions:

  1. Add the “clipboardWrite” permission to manifest.json.
  2. Remove the popup from the extension, and use a browser.action.onClicked listener instead. Then you don’t need the “clipboardWrite” permission anymore. But since you don’t have a popup to display the success/error message in, you need to use browser.notifications.create(), which requires the “notifications” permission.

Does this mean that extension pages (such as popups) and the background page count as “secure contexts”, even though they’re not HTTPS pages? I’m not sure, but it appears so.

Test extension for the second solution:
copy_twitter.com_address (no popup).zip (6.8 KB)

1 Like

Great analysis Hans!
I did a poor job reading this thread, I’m sorry for providing bad info :upside_down_face:.
(I’m a bit overworked these days…)

Too much Beat Saber, Juraj?

The following works like a charm on my end. Just added the clipboardWrite permission. No issues encountered!

{
  "name": "Copy twitter.com url for preview",
  "version": "0.1.1",
  "description": "x.com doesn't provide preview but twitter.com does, so this extension copy twitter.com address",
  "permissions": ["activeTab", "clipboardWrite"],
  "action": {
    "default_title": "Copy twitter.com URL",
    "default_popup": "popup.html"
  },
  "icons": {
    "16": "images/icon-16.png",
    "48": "images/icon-48.png",
    "128": "images/icon-128.png"
  },
  "manifest_version": 3
}

1 Like

I re-tried now and succeeded, thank you.

2 Likes