diff options
author | jbukl <noreply@github.com> | 2023-10-20 02:37:47 -0400 |
---|---|---|
committer | jbukl <noreply@github.com> | 2023-10-20 15:25:52 -0400 |
commit | 9a39d0a7e2896edd4a6deebad00b8550cfffc15b (patch) | |
tree | ab4aa25d9c89856066ae9d1c347da3ad9bb6ea4e /ext/js/background | |
parent | c3be9af7b6f00dad7107fcdae60a8004cc81936a (diff) |
fix: chromium clipboard access
on chromium, backend calls to clipboardGet are forwarded to an offscreen script
Diffstat (limited to 'ext/js/background')
-rw-r--r-- | ext/js/background/backend.js | 73 |
1 files changed, 67 insertions, 6 deletions
diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index 565f4abf..57565eec 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -57,12 +57,19 @@ class Backend { }); this._anki = new AnkiConnect(); this._mecab = new Mecab(); - this._clipboardReader = new ClipboardReader({ - // eslint-disable-next-line no-undef - document: (typeof document === 'object' && document !== null ? document : null), - pasteTargetSelector: '#clipboard-paste-target', - richContentPasteTargetSelector: '#clipboard-rich-content-paste-target' - }); + + this._clipboardReader = { + getText: this._getTextOffscreen.bind(this) + }; + if (!chrome || !chrome.offscreen) { + this._clipboardReader = new ClipboardReader({ + // eslint-disable-next-line no-undef + document: (typeof document === 'object' && document !== null ? document : null), + pasteTargetSelector: '#clipboard-paste-target', + richContentPasteTargetSelector: '#clipboard-rich-content-paste-target' + }); + } + this._clipboardMonitor = new ClipboardMonitor({ japaneseUtil: this._japaneseUtil, clipboardReader: this._clipboardReader @@ -97,6 +104,8 @@ class Backend { this._permissions = null; this._permissionsUtil = new PermissionsUtil(); + this._creatingOffscreen = null; + this._messageHandlers = new Map([ ['requestBackendReadySignal', {async: false, contentScript: true, handler: this._onApiRequestBackendReadySignal.bind(this)}], ['optionsGet', {async: false, contentScript: true, handler: this._onApiOptionsGet.bind(this)}], @@ -557,6 +566,21 @@ class Backend { return this._clipboardReader.getText(false); } + async _getTextOffscreen(useRichText) { + await this._setupOffscreenDocument(); + return new Promise((resolve, reject) => { + const callback = (response) => { + try { + resolve(this._getMessageResponseResult(response)); + } catch (error) { + reject(error); + } + }; + + chrome.runtime.sendMessage({action: 'clipboardGetOffscreen', params: {useRichText}}, callback); + }); + } + async _onApiGetDisplayTemplatesHtml() { return await this._fetchAsset('/display-templates.html'); } @@ -2262,4 +2286,41 @@ class Backend { return {targetTabId, targetFrameId}; } + + // https://developer.chrome.com/docs/extensions/reference/offscreen/ + async _setupOffscreenDocument() { + // Check all windows controlled by the service worker to see if one + // of them is the offscreen document with the given path + if (await this._hasOffscreenDocument()) { + return; + } + + // create offscreen document + if (this._creatingOffscreen) { + await this._creatingOffscreen; + } else { + this._creatingOffscreen = chrome.offscreen.createDocument({ + url: 'offscreen.html', + reasons: ['CLIPBOARD'], + justification: 'reason for needing the document' + }); + await this._creatingOffscreen; + this._creatingOffscreen = null; + } + } + async _hasOffscreenDocument() { + const offscreenUrl = chrome.runtime.getURL('offscreen.html'); + if (chrome.runtime.getContexts) { + const contexts = await chrome.runtime.getContexts({ + contextTypes: ['OFFSCREEN_DOCUMENT'], + documentUrls: [offscreenUrl] + }); + return Boolean(contexts.length); + } else { + const matchedClients = await clients.matchAll(); + return await matchedClients.some((client) => { + client.url.includes(chrome.runtime.id); + }); + } + } } |