Skip to content

Commit 1ea8b09

Browse files
whizzzkidSgtPooki
andauthored
feat(mv3): Manifest V3 Migration Checklist (#1170)
* feat(mv3): ✨ MV3 Manifest Migration * fix(mv3): 🗑️ No longer needed * fix(mv3): 🔧 Corresponding MV3 Changes * feat(mv3): 📦 Adding deps * feat(telemetry): Refactor Metrics Tracking from background service_worker (#1172) * feat(telemetry): ♻️ Init Telemetry away from background service_worker. * feat(telemetry): ♻️ Track metrics from page context instead of service_worker context * feat(mv3): 🩹 Patch @protobufjs/inquire to not have eval * fix(mv3): 👽 Fixing contextMenus API changes (#1177) * fix(mv3): 👽 Fixing contextMenus API changes * fix(mv3): 🩹 Fixing the browser.action api * fix(mv3): webpack configs (#1178) * fix(mv3): 👽 Fixing contextMenus API changes * fix(mv3): 🩹 Fixing the browser.action api * fix(mv3): 🔧 Fixing webpack config * fix(mv3): 🩹 Patching debug package and making background sw work. * feat(mv3): ✨ XHR to Fetch Migration (#1179) * fix(mv3): 👽 Fixing contextMenus API changes * fix(mv3): 🩹 Fixing the browser.action api * fix(mv3): 🔧 Fixing webpack config * fix(mv3): 🩹 Patching debug package and making background sw work. * feat(mv3): ✨ XMLHttpRequest => fetch * fix(mv3): 🚧 Related changes to ipfs-path * fix(mv3): 🚧 Other Related changes * fix(mv3): 🚧 Changes to companion * fix(mv3): ✅ Fixing tests to account for async code. * Fix(mv3): Popup Was Broken (#1180) * fix(mv3): 👽 Fixing contextMenus API changes * fix(mv3): 🩹 Fixing the browser.action api * fix(mv3): 🔧 Fixing webpack config * fix(mv3): 🩹 Patching debug package and making background sw work. * feat(mv3): ✨ XMLHttpRequest => fetch * fix(mv3): 🚧 Related changes to ipfs-path * fix(mv3): 🚧 Other Related changes * fix(mv3): 🚧 Changes to companion * fix(mv3): ✅ Fixing tests to account for async code. * feat(mv3): ♻️ Implementing a non-windowed companion instance * fix(mv3): 🗑️ Removing calls to background page. * fix: 🗑️ Unneeded debug statement * fix(mv3): 🛂 Limiting permissions to chrome-extension * Update add-on/src/lib/ipfs-companion.js Co-authored-by: Russell Dempsey <[email protected]> --------- Co-authored-by: Russell Dempsey <[email protected]>
1 parent e57f0bf commit 1ea8b09

31 files changed

+4395
-596
lines changed

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v18.14.0

add-on/manifest.chromium.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
{
22
"minimum_chrome_version": "72",
33
"permissions": [
4-
"<all_urls>",
4+
"clipboardWrite",
5+
"contextMenus",
56
"idle",
6-
"tabs",
77
"notifications",
88
"storage",
9+
"tabs",
910
"unlimitedStorage",
10-
"contextMenus",
11-
"clipboardWrite",
1211
"webNavigation",
13-
"webRequest",
14-
"webRequestBlocking"
12+
"webRequest"
1513
],
14+
"host_permissions": ["<all_urls>"],
1615
"incognito": "not_allowed"
1716
}

add-on/manifest.common.json

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"manifest_version": 2,
2+
"manifest_version": 3,
33
"name": "__MSG_manifest_extensionName__",
44
"short_name": "__MSG_manifest_shortExtensionName__",
55
"version": "2.22.1",
@@ -12,9 +12,9 @@
1212
"128": "icons/png/ipfs-logo-on_128.png"
1313
},
1414
"background": {
15-
"page": "dist/background/background.html"
15+
"service_worker": "dist/bundles/backgroundPage.bundle.js"
1616
},
17-
"browser_action": {
17+
"action": {
1818
"default_icon": {
1919
"19": "icons/png/ipfs-logo-off_19.png",
2020
"38": "icons/png/ipfs-logo-off_38.png",
@@ -29,15 +29,24 @@
2929
"page": "dist/options/options.html"
3030
},
3131
"web_accessible_resources": [
32-
"icons/png/ipfs-logo-off_19.png",
33-
"icons/png/ipfs-logo-off_38.png",
34-
"icons/png/ipfs-logo-off_128.png",
35-
"icons/ipfs-logo-on.svg",
36-
"icons/ipfs-logo-off.svg",
37-
"dist/recovery/recovery.css",
38-
"dist/recovery/recovery.html",
39-
"dist/recovery/recovery.js"
32+
{
33+
"resources": [
34+
"icons/png/ipfs-logo-off_19.png",
35+
"icons/png/ipfs-logo-off_38.png",
36+
"icons/png/ipfs-logo-off_128.png",
37+
"icons/ipfs-logo-on.svg",
38+
"icons/ipfs-logo-off.svg",
39+
"dist/recovery/recovery.css",
40+
"dist/recovery/recovery.html",
41+
"dist/recovery/recovery.js"
42+
],
43+
"matches": [
44+
"chrome-extension://*/*"
45+
]
46+
}
4047
],
41-
"content_security_policy": "script-src 'self'; object-src 'self'; frame-src 'self';",
48+
"content_security_policy": {
49+
"extension_pages": "script-src 'self'; object-src 'self'; frame-src 'self';"
50+
},
4251
"default_locale": "en"
4352
}

add-on/manifest.firefox.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"browser_action": {
2+
"action": {
33
"browser_style": false
44
},
55
"options_ui": {

add-on/src/background/background.html

Lines changed: 0 additions & 5 deletions
This file was deleted.

add-on/src/background/background.js

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,15 @@
22
/* eslint-env browser, webextensions */
33

44
import browser from 'webextension-polyfill'
5+
import createIpfsCompanion from '../lib/ipfs-companion.js'
56
import { onInstalled } from '../lib/on-installed.js'
67
import { getUninstallURL } from '../lib/on-uninstalled.js'
7-
import { optionDefaults } from '../lib/options.js'
8-
import createIpfsCompanion from '../lib/ipfs-companion.js'
98

109
// register lifecycle hooks early, otherwise we miss first install event
1110
browser.runtime.onInstalled.addListener(onInstalled)
1211
browser.runtime.setUninstallURL(getUninstallURL(browser))
1312

14-
// init add-on after all libs are loaded
15-
document.addEventListener('DOMContentLoaded', async () => {
16-
browser.runtime.sendMessage({ telemetry: { trackView: 'background' } })
17-
// setting debug namespaces require page reload to get applied
18-
const debugNs = (await browser.storage.local.get({ logNamespaces: optionDefaults.logNamespaces })).logNamespaces
19-
if (debugNs !== localStorage.debug) {
20-
localStorage.debug = debugNs
21-
window.location.reload()
22-
}
23-
// init inlined to read updated localStorage.debug
24-
// @ts-expect-error - TS does not know about window.ipfsCompanion
25-
window.ipfsCompanion = await createIpfsCompanion()
26-
})
13+
const init = async () => {
14+
await createIpfsCompanion()
15+
}
16+
init();

add-on/src/landing-pages/welcome/store.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22
/* eslint-env browser, webextensions */
33
import browser from 'webextension-polyfill'
4+
import { handleConsentFromState, trackView } from '../../lib/telemetry.js'
45

56
export default function createWelcomePageStore (i18n, runtime) {
67
return function welcomePageStore (state, emitter) {
@@ -9,7 +10,8 @@ export default function createWelcomePageStore (i18n, runtime) {
910
state.webuiRootUrl = null
1011
let port
1112
emitter.on('DOMContentLoaded', async () => {
12-
browser.runtime.sendMessage({ telemetry: { trackView: 'welcome' } })
13+
handleConsentFromState(state)
14+
trackView('welcome')
1315
emitter.emit('render')
1416
port = runtime.connect({ name: 'browser-action-port' })
1517
port.onMessage.addListener(async (message) => {

add-on/src/lib/context-menus.js

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -71,29 +71,13 @@ export function createContextMenus (
7171
getState, _runtime, ipfsPathValidator, { onAddFromContext, onCopyRawCid, onCopyAddressAtPublicGw }) {
7272
try {
7373
const createSubmenu = (id, contextType, menuBuilder) => {
74-
browser.contextMenus.create({
75-
id,
76-
title: browser.i18n.getMessage(id),
77-
documentUrlPatterns: ['<all_urls>'],
78-
contexts: [contextType]
79-
})
74+
browser.contextMenus.onClicked.addListener((...args) => console.log(args))
8075
}
8176
const createImportToIpfsMenuItem = (parentId, id, contextType, ipfsAddOptions) => {
8277
const itemId = `${parentId}_${id}`
8378
apiMenuItems.add(itemId)
84-
return browser.contextMenus.create({
85-
id: itemId,
86-
parentId,
87-
title: browser.i18n.getMessage(id),
88-
contexts: [contextType],
89-
documentUrlPatterns: ['<all_urls>'],
90-
enabled: false,
91-
/* no support for 'icons' in Chrome
92-
icons: {
93-
'48': '/ui-kit/icons/stroke_cube.svg'
94-
}, */
95-
onclick: (context) => onAddFromContext(context, contextType, ipfsAddOptions)
96-
})
79+
return browser.contextMenus.onClicked.addListener((context) => onAddFromContext(context, contextType, ipfsAddOptions)
80+
)
9781
}
9882
const createCopierMenuItem = (parentId, id, contextType, handler) => {
9983
const itemId = `${parentId}_${id}`
@@ -102,22 +86,9 @@ export function createContextMenus (
10286
if (apiMenuItemIds.has(id)) {
10387
apiMenuItems.add(itemId)
10488
}
105-
return browser.contextMenus.create({
106-
id: itemId,
107-
parentId,
108-
title: browser.i18n.getMessage(id),
109-
contexts: [contextType],
110-
documentUrlPatterns: [
111-
'*://*/ipfs/*', '*://*/ipns/*',
112-
'*://*.ipfs.dweb.link/*', '*://*.ipns.dweb.link/*', // TODO: add any custom public gateway from Preferences
113-
'*://*.ipfs.localhost/*', '*://*.ipns.localhost/*'
114-
],
115-
/* no support for 'icons' in Chrome
116-
icons: {
117-
'48': '/ui-kit/icons/stroke_copy.svg'
118-
}, */
119-
onclick: (context) => handler(context, contextType)
120-
})
89+
return browser.contextMenus.onClicked.addListener(
90+
(context) => handler(context, contextType)
91+
)
12192
}
12293
const buildSubmenu = (parentId, contextType) => {
12394
createSubmenu(parentId, contextType)

add-on/src/lib/copier.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export default function createCopier (notify, ipfsPathValidator) {
7272

7373
async copyAddressAtPublicGw (context, contextType) {
7474
const url = await findValueForContext(context, contextType)
75-
const publicUrl = ipfsPathValidator.resolveToPublicUrl(url)
75+
const publicUrl = await ipfsPathValidator.resolveToPublicUrl(url)
7676
await copyTextToClipboard(publicUrl, notify)
7777
},
7878

add-on/src/lib/dnslink.js

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ export default function createDnslinkResolver (getState) {
5050
!sameGateway(requestUrl, state.gwURL)
5151
},
5252

53-
dnslinkAtGateway (url, dnslink) {
53+
async dnslinkAtGateway (url, dnslink) {
5454
if (typeof url === 'string') {
5555
url = new URL(url)
5656
}
57-
if (dnslinkResolver.canRedirectToIpns(url, dnslink)) {
57+
if (await dnslinkResolver.canRedirectToIpns(url, dnslink)) {
5858
const state = getState()
5959
// redirect to IPNS and leave it up to the gateway
6060
// to load the correct path from IPFS
@@ -65,12 +65,12 @@ export default function createDnslinkResolver (getState) {
6565
}
6666
},
6767

68-
readAndCacheDnslink (fqdn) {
68+
async readAndCacheDnslink (fqdn) {
6969
let dnslink = dnslinkResolver.cachedDnslink(fqdn)
7070
if (typeof dnslink === 'undefined') {
7171
try {
7272
log(`dnslink cache miss for '${fqdn}', running DNS TXT lookup`)
73-
dnslink = dnslinkResolver.readDnslinkFromTxtRecord(fqdn)
73+
dnslink = await dnslinkResolver.readDnslinkFromTxtRecord(fqdn)
7474
if (dnslink) {
7575
// TODO: set TTL as maxAge: setDnslink(fqdn, dnslink, maxAge)
7676
dnslinkResolver.setDnslink(fqdn, dnslink)
@@ -96,6 +96,7 @@ export default function createDnslinkResolver (getState) {
9696
const cachedResult = dnslinkResolver.cachedDnslink(fqdn)
9797
if (cachedResult) return cachedResult
9898
return lookupQueue.add(() => {
99+
// this will resolve eventually.
99100
return dnslinkResolver.readAndCacheDnslink(fqdn)
100101
})
101102
},
@@ -120,7 +121,7 @@ export default function createDnslinkResolver (getState) {
120121
},
121122

122123
// low level lookup without cache
123-
readDnslinkFromTxtRecord (fqdn) {
124+
async readDnslinkFromTxtRecord (fqdn) {
124125
const state = getState()
125126
let apiProvider
126127
if (!state.ipfsNodeType.startsWith('embedded') && state.peerCount !== offlinePeerCount) {
@@ -139,29 +140,29 @@ export default function createDnslinkResolver (getState) {
139140
// TODO: revisit after https://github.com/ipfs/js-ipfs-api/issues/501 is addressed
140141
// TODO: consider worst-case-scenario fallback to https://developers.google.com/speed/public-dns/docs/dns-over-https
141142
const apiCall = `${apiProvider}api/v0/name/resolve/${fqdn}?r=false`
142-
const xhr = new XMLHttpRequest() // older XHR API us used because window.fetch appends Origin which causes error 403 in go-ipfs
143-
// synchronous mode with small timeout
144-
// (it is okay, because we do it only once, then it is cached and read via readAndCacheDnslink)
145-
xhr.open('GET', apiCall, false)
146-
xhr.setRequestHeader('Accept', 'application/json')
147-
xhr.send(null)
148-
if (xhr.status === 200) {
149-
const dnslink = JSON.parse(xhr.responseText).Path
150-
// console.log('readDnslinkFromTxtRecord', readDnslinkFromTxtRecord)
143+
const response = await fetch(apiCall, {
144+
method: 'GET',
145+
headers: {
146+
Accept: 'application/json'
147+
}
148+
})
149+
150+
if (response.ok) {
151+
const { Path: dnslink } = await response.json()
151152
if (!IsIpfs.path(dnslink)) {
152153
throw new Error(`dnslink for '${fqdn}' is not a valid IPFS path: '${dnslink}'`)
153154
}
154155
return dnslink
155-
} else if (xhr.status === 500) {
156+
} else if (response.status === 500) {
156157
// go-ipfs returns 500 if host has no dnslink or an error occurred
157158
// TODO: find/fill an upstream bug to make this more intuitive
158159
return false
159160
} else {
160-
throw new Error(xhr.statusText)
161+
throw new Error(response.statusText)
161162
}
162163
},
163164

164-
canRedirectToIpns (url, dnslink) {
165+
async canRedirectToIpns (url, dnslink) {
165166
if (typeof url === 'string') {
166167
url = new URL(url)
167168
}
@@ -185,7 +186,7 @@ export default function createDnslinkResolver (getState) {
185186
// is found in initial response.
186187
// More: https://github.com/ipfs-shipyard/ipfs-companion/blob/master/docs/dnslink.md
187188
const foundDnslink = dnslink ||
188-
(getState().dnslinkPolicy === 'enabled'
189+
await (getState().dnslinkPolicy === 'enabled'
189190
? dnslinkResolver.readAndCacheDnslink(fqdn)
190191
: dnslinkResolver.cachedDnslink(fqdn))
191192
if (foundDnslink) {
@@ -205,7 +206,7 @@ export default function createDnslinkResolver (getState) {
205206
// Test if URL contains a valid DNSLink FQDN
206207
// in url.hostname OR in url.pathname (/ipns/<fqdn>)
207208
// and return matching FQDN if present
208-
findDNSLinkHostname (url) {
209+
async findDNSLinkHostname (url) {
209210
if (!url) return
210211
// Normalize subdomain and path gateways to to /ipns/<fqdn>
211212
const contentPath = ipfsContentPath(url)
@@ -214,14 +215,14 @@ export default function createDnslinkResolver (getState) {
214215
const ipnsRoot = contentPath.match(/^\/ipns\/([^/]+)/)[1]
215216
// console.log('findDNSLinkHostname ==> inspecting IPNS root', ipnsRoot)
216217
// Ignore PeerIDs, match DNSLink only
217-
if (!IsIpfs.cid(ipnsRoot) && dnslinkResolver.readAndCacheDnslink(ipnsRoot)) {
218+
if (!IsIpfs.cid(ipnsRoot) && await dnslinkResolver.readAndCacheDnslink(ipnsRoot)) {
218219
// console.log('findDNSLinkHostname ==> found DNSLink for FQDN in url.pathname: ', ipnsRoot)
219220
return ipnsRoot
220221
}
221222
}
222223
// Check main hostname
223224
const { hostname } = new URL(url)
224-
if (dnslinkResolver.readAndCacheDnslink(hostname)) {
225+
if (await dnslinkResolver.readAndCacheDnslink(hostname)) {
225226
// console.log('findDNSLinkHostname ==> found DNSLink for url.hostname', hostname)
226227
return hostname
227228
}

0 commit comments

Comments
 (0)