Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(recovery): 🐛 false-positive for non-gateway URLs #1163

Merged
merged 6 commits into from Feb 22, 2023
Merged

Conversation

whizzzkid
Copy link
Contributor

@whizzzkid whizzzkid commented Feb 22, 2023

Closes: #1162

This is a case I should've thought of when working on: #1125. The reason this happens:

  • When Automatic Mode is turned off, the redirect actually happens before the recovery mode begins.
  • Since the redirect happens to local node, the recovery mode gets triggered, asking to redirect to public gateway.
  • The public gateway redirects back to local and results in the endless loop.

Fix: Add check for !state.redirect remove false-positives from sameGateway check.

I would like to merge #1160 and #1161 before this and create a patch release.

@whizzzkid whizzzkid requested review from lidel and a team as code owners February 22, 2023 09:04
Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with Companion is that you need to think with portals ;-)

The !state.redirect hack was a band-aid, and was not fixing problem from https://twitter.com/unicomp21/status/1626244123102679041 at all.

We can improve sameGateway check and clearly detect when someone opens URL equal to the Gateway http://localhost:8080/ – I'll push fix shortly.

add-on/src/lib/ipfs-request.js Outdated Show resolved Hide resolved
@@ -436,12 +436,19 @@ describe('modifyRequest.onBeforeRequest:', function () {
state.gwURL = new URL('http://localhost:8080')
state.pubGwURLString = 'https://ipfs.io'
state.pubGwURL = new URL('https://ipfs.io')
state.redirect = false
Copy link
Member

@lidel lidel Feb 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 It was defined twice in this beforeEach block. I've added more tests and set it explicitly in relevant it blocks.

})
it('should present recovery page if node is offline', function () {
expect(state.nodeActive).to.be.equal(false)
const request = url2request('https://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('chrome-extension://testid/dist/recovery/recovery.html#https%3A%2F%2Fipfs.io%2Fipfs%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%2Ffoo%2Fbar')
})
it('should not block requests when the request is redirecting', function () {
Copy link
Member

@lidel lidel Feb 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 We need to be very clear what we are testing and why. 12 months from now, none of us will remember why we've added this – I've added below

+   it('should not show recovery page if node is offline, redirect is enabled, but non-gateway URL failed to load from the same port', function () {
+      // this covers https://github.com/ipfs/ipfs-companion/issues/1162 and https://twitter.com/unicomp21/status/1626244123102679041

if (!state.nodeActive && // node is not active
!state.redirect && // this is not a redirect request
request.type === 'main_frame' && // this is a request for a root document
sameGateway(request.url, state.gwURL) // this is a request to the local gateway
Copy link
Member

@lidel lidel Feb 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ this was not enough to fix https://twitter.com/unicomp21/status/1626244123102679041 – this screen should never happen and user should not have to disable companion for this to go away.

sameGateway needed to be improved to not return false-positives for URLs that do not look like gateway or RPC requests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out, I was looking into the state and believed I saw redirect being set to true for all calls being redirected to local node, and redirect was set to false when the requests were not being redirected.

Is that wrong?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

state is global, not per request. it informs redirect logic what are current settings and state of RPC.
(bit of a legacy thing, from the XUL time (before v2) when it was less expensive to cache options in one place, but it is still useful when writing tests, to simulate specific state of world).

you probably saw us setting it in tests per different requests to simultate specific flows, and assumed it is per request, but it is is not :)

@@ -144,7 +144,11 @@ export function createRequestModifier (getState, dnslinkResolver, ipfsPathValida

// When local IPFS node is unreachable , show recovery page where user can redirect
// to public gateway.
if (!state.nodeActive && request.type === 'main_frame' && sameGateway(request.url, state.gwURL)) {
if (!state.nodeActive && // node is not active
!state.redirect && // this is not a redirect request
Copy link
Member

@lidel lidel Feb 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 nit: this is a global flag that controls if companion is redirecting requests to the local gateway, or not.
ℹ️ This was not fixing the problem, and the comment was only confusing the reader – I've restored old version and applied proper fix in sameGateway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures sameGateway returns true only if the tested URL is
either a valid path, subdomain, or RPC URL related to local
Gateway or Kubo instance.

Everything else should be ignored, because people may run Kubo Gateway
on localhost:8080, and then stop it, and then run some unrelated HTTP
server on the same port.

This is unfortunate papercut due to the 8080 being very very popular
default port for all things HTTP. Luckily, Companion has enough
information to make this right.
@lidel lidel changed the title fix(recovery): 🐛 No recovery for URLs being redirected. fix(recovery): 🐛 false-positive for non-gateway URLs Feb 22, 2023
Copy link
Member

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@whizzzkid pushed alternative fix for sameGateway check and some tests.
This approach should be more reliable.

Comment on lines +187 to +188
it('should return true on localhost subdomain host match', function () {
const url = 'http://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi.ipfs.localhost:8080/foo/bar'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ we were missing subdomain test, so I've added it

Comment on lines +198 to +201
it('should return true on RPC /api/v0 path 127.0.0.1/0.0.0.0 host match', function () {
// this is misconfiguration, but handling it in sameGateway ensures users who do this dont waste our time debugging
const url = 'http://0.0.0.0:5001/api/v0/id'
const api = 'http://127.0.0.1:5001'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ this saves us a day of debugging when user puts wrong port in wrong field in their config, and then tweets about it ;-)

Comment on lines +440 to +465
it('should present recovery page if node is offline and redirect is enabled', function () {
expect(state.nodeActive).to.be.equal(false)
state.redirect = true
const request = url2request('https://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('chrome-extension://testid/dist/recovery/recovery.html#https%3A%2F%2Fipfs.io%2Fipfs%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%2Ffoo%2Fbar')
})
it('should present recovery page if node is offline and redirect is disabled', function () {
expect(state.nodeActive).to.be.equal(false)
state.redirect = false
const request = url2request('https://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('chrome-extension://testid/dist/recovery/recovery.html#https%3A%2F%2Fipfs.io%2Fipfs%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%2Ffoo%2Fbar')
})
it('should not show recovery page if node is offline, redirect is enabled, but non-gateway URL failed to load from the same port', function () {
// this covers https://github.com/ipfs/ipfs-companion/issues/1162 and https://twitter.com/unicomp21/status/1626244123102679041
state.redirect = true
expect(state.nodeActive).to.be.equal(false)
const request = url2request('https://localhost:8080/')
expect(modifyRequest.onBeforeRequest(request)).to.equal(undefined)
})
it('should not show recovery page if extension is disabled', function () {
// allows user to quickly avoid anything similar to https://github.com/ipfs/ipfs-companion/issues/1162
state.active = false
expect(state.nodeActive).to.be.equal(false)
const request = url2request('https://localhost:8080/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR/foo/bar')
expect(modifyRequest.onBeforeRequest(request)).to.equal(undefined)
})
Copy link
Member

@lidel lidel Feb 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ I think this covers most prominent edge cases, and ensures recovery logic does not depend on redirect state (which was why it was initially difficult to reproduce the bug from #1162)

@whizzzkid whizzzkid merged commit 0ee35d2 into main Feb 22, 2023
@whizzzkid whizzzkid deleted the fix/recovery branch February 22, 2023 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Redirect to local gateway not working
3 participants