Skip to content

Commit 8866f76

Browse files
authored
fix: Origin in API requests under Chromium 72 (#631)
WebExtension running in background context of Chromium Beta 72 sends `Origin: chrome-extension://{uid}` which triggers false-positive Forbidden 403 in go-ipfs
1 parent ff00efa commit 8866f76

File tree

2 files changed

+57
-9
lines changed

2 files changed

+57
-9
lines changed

add-on/src/lib/ipfs-request.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,22 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru
122122
// by js-ipfs-api running in WebExtension context to remove need
123123
// for manual whitelisting Access-Control-Allow-Origin at go-ipfs
124124
// More info:
125-
// Chrome: https://github.com/ipfs-shipyard/ipfs-companion/pull/616
126125
// Firefox: https://github.com/ipfs-shipyard/ipfs-companion/issues/622
126+
// Chromium 71: https://github.com/ipfs-shipyard/ipfs-companion/pull/616
127+
// Chromium 72: https://github.com/ipfs-shipyard/ipfs-companion/issues/630
127128
const isWebExtensionOrigin = (origin) => {
128-
// Chromium
129+
// console.log(`origin=${origin}, webExtensionOrigin=${webExtensionOrigin}`)
130+
// Chromium <= 71 returns opaque Origin as defined in
131+
// https://html.spec.whatwg.org/multipage/origin.html#ascii-serialisation-of-an-origin
129132
if (origin == null || origin === 'null') {
130133
return true
131134
}
132-
// Firefox Nightly 65 sets moz-extension://{extension-installation-id}
133-
if (origin && origin.startsWith('moz-extension://') && new URL(origin).origin === webExtensionOrigin) {
135+
// Firefox Nightly 65 sets moz-extension://{extension-installation-id}
136+
// Chromium Beta 72 sets chrome-extension://{uid}
137+
if (origin &&
138+
(origin.startsWith('moz-extension://') ||
139+
origin.startsWith('chrome-extension://')) &&
140+
new URL(origin).origin === webExtensionOrigin) {
134141
return true
135142
}
136143
return false

test/functional/lib/ipfs-request-workarounds.test.js

+46-5
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,25 @@ const { optionDefaults } = require('../../../add-on/src/lib/options')
1313
// const nodeTypes = ['external', 'embedded']
1414

1515
describe('modifyRequest processing', function () {
16-
let state, dnslinkResolver, ipfsPathValidator, modifyRequest, runtime
16+
let state, getState, dnslinkResolver, ipfsPathValidator, modifyRequest, runtime
1717

1818
before(function () {
19+
// stub URL.origin in test context to return something other than null
20+
Object.defineProperty(URL.prototype, 'origin', {
21+
get: function () {
22+
let fakeOrigin = this.href.split('/')
23+
if (fakeOrigin.length >= 3) {
24+
return fakeOrigin.slice(0, 3).join('/')
25+
}
26+
}
27+
})
1928
global.URL = URL
2029
global.browser = browser
21-
browser.runtime.getURL.withArgs('/').returns('moz-extension://0f334731-19e3-42f8-85e2-03dbf50026df/')
2230
})
2331

2432
beforeEach(async function () {
2533
state = initState(optionDefaults)
26-
const getState = () => state
34+
getState = () => state
2735
dnslinkResolver = createDnslinkResolver(getState)
2836
runtime = Object.assign({}, await createRuntimeChecks(browser)) // make it mutable for tests
2937
ipfsPathValidator = createIpfsPathValidator(getState, dnslinkResolver)
@@ -47,7 +55,13 @@ describe('modifyRequest processing', function () {
4755
})
4856

4957
describe('a request to <apiURL>/api/v0/ with Origin=moz-extension://{extension-installation-id}', function () {
50-
it('should remove Origin header ', function () {
58+
it('should remove Origin header with moz-extension://', async function () {
59+
// set vendor-specific Origin for WebExtension context
60+
browser.runtime.getURL.withArgs('/').returns('moz-extension://0f334731-19e3-42f8-85e2-03dbf50026df/')
61+
// ensure clean modifyRequest
62+
runtime = Object.assign({}, await createRuntimeChecks(browser)) // make it mutable for tests
63+
modifyRequest = createRequestModifier(getState, dnslinkResolver, ipfsPathValidator, runtime)
64+
// test
5165
const bogusOriginHeader = { name: 'Origin', value: 'moz-extension://0f334731-19e3-42f8-85e2-03dbf50026df' }
5266
const request = {
5367
requestHeaders: [ bogusOriginHeader ],
@@ -60,8 +74,34 @@ describe('modifyRequest processing', function () {
6074
})
6175
})
6276

77+
describe('a request to <apiURL>/api/v0/ with Origin=chrome-extension://{extension-installation-id}', function () {
78+
it('should remove Origin header with chrome-extension://', async function () {
79+
// set vendor-specific Origin for WebExtension context
80+
browser.runtime.getURL.withArgs('/').returns('chrome-extension://trolrorlrorlrol/')
81+
// ensure clean modifyRequest
82+
runtime = Object.assign({}, await createRuntimeChecks(browser)) // make it mutable for tests
83+
modifyRequest = createRequestModifier(getState, dnslinkResolver, ipfsPathValidator, runtime)
84+
// test
85+
const bogusOriginHeader = { name: 'Origin', value: 'chrome-extension://trolrorlrorlrol' }
86+
const request = {
87+
requestHeaders: [ bogusOriginHeader ],
88+
type: 'xmlhttprequest',
89+
url: `${state.apiURLString}api/v0/id`
90+
}
91+
modifyRequest.onBeforeRequest(request) // executes before onBeforeSendHeaders, may mutate state
92+
expect(modifyRequest.onBeforeSendHeaders(request).requestHeaders).to.not.include(bogusOriginHeader)
93+
browser.runtime.getURL.flush()
94+
})
95+
})
96+
6397
describe('a request to <apiURL>/api/v0/ with Origin=null', function () {
64-
it('should remove Origin header ', function () {
98+
it('should remove Origin header ', async function () {
99+
// set vendor-specific Origin for WebExtension context
100+
browser.runtime.getURL.withArgs('/').returns(undefined)
101+
// ensure clean modifyRequest
102+
runtime = Object.assign({}, await createRuntimeChecks(browser)) // make it mutable for tests
103+
modifyRequest = createRequestModifier(getState, dnslinkResolver, ipfsPathValidator, runtime)
104+
// test
65105
const bogusOriginHeader = { name: 'Origin', value: 'null' }
66106
const request = {
67107
requestHeaders: [ bogusOriginHeader ],
@@ -70,6 +110,7 @@ describe('modifyRequest processing', function () {
70110
}
71111
modifyRequest.onBeforeRequest(request) // executes before onBeforeSendHeaders, may mutate state
72112
expect(modifyRequest.onBeforeSendHeaders(request).requestHeaders).to.not.include(bogusOriginHeader)
113+
browser.runtime.getURL.flush()
73114
})
74115
})
75116

0 commit comments

Comments
 (0)