Skip to content

Commit

Permalink
fix(origin): confirm paths redirect to subdomain (#156)
Browse files Browse the repository at this point in the history
This makes the Origin check more strict: after confirming subdomains
work, additional request for path is made, to confirm legacy paths are
redirected to expected subdomains.

Adding this test is necessary, because there are misconfigured gateways
that don't redirect /ipfs/{cid} paths to {cid}.ipfs.example.com
subdomains and return data from the root origin, effectively defeating
any Origin isolation provided by subdomains.
  • Loading branch information
lidel authored Jun 21, 2021
1 parent 15fd028 commit b837a35
Showing 1 changed file with 31 additions and 4 deletions.
35 changes: 31 additions & 4 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ let Status = function(parent, index) {
this.tag.textContent = '🕑';
};


function checkViaImgSrc (imgUrl) {
// we check if gateway is up by loading 1x1 px image:
// this is more robust check than loading js, as it won't be blocked
Expand Down Expand Up @@ -155,7 +154,7 @@ Status.prototype.check = function() {
// test by loading subresource via img.src (path will work on both old and subdomain gws)
const gwUrl = new URL(this.parent.gateway)
const imgPathUrl = new URL(`${gwUrl.protocol}//${gwUrl.hostname}/ipfs/${IMG_HASH}?now=${Date.now()}&filename=1x1.png#x-ipfs-companion-no-redirect`)
checkViaImgSrc(imgPathUrl).then((res) => {
checkViaImgSrc(imgPathUrl).then(() => {
this.tag.textContent = '🌍';
this.parent.checked()
}).catch(() => {
Expand Down Expand Up @@ -226,24 +225,52 @@ let Origin = function(parent) {
this.tag.textContent = '🕑';
};

function expectSubdomainRedirect(url) {
// Detecting redirects on remote Origins is extra tricky,
// but we seem to be able to access xhr.responseURL which is enough to see
// if paths are redirected to subdomains.
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('GET', url, true)
xhr.onload = function () {
// expect to be redirected to subdomain where first DNS label is CID
if (new URL(xhr.responseURL).hostname.startsWith(IMG_HASH)) {
resolve()
} else {
reject()
}
}
xhr.onerror = function (err) {
console.error(url, err)
reject()
}
xhr.send(null)
})
}

Origin.prototype.check = function() {
// we are unable to check url after subdomain redirect because some gateways
// may not have proper CORS in place. instead, we manually construct subdomain
// URL and check if it loading known image works
const gwUrl = new URL(this.parent.gateway)
// const imgPathUrl = new URL(`${gwUrl.protocol}//${gwUrl.hostname}/ipfs/${IMG_HASH}?now=${now}&filename=1x1.png#x-ipfs-companion-no-redirect`)
const imgSubdomainUrl = new URL(`${gwUrl.protocol}//${IMG_HASH}.ipfs.${gwUrl.hostname}/?now=${Date.now()}&filename=1x1.png#x-ipfs-companion-no-redirect`)
checkViaImgSrc(imgSubdomainUrl).then((res) => {
const imgRedirectedPathUrl = new URL(`${gwUrl.protocol}//${gwUrl.hostname}/ipfs/${IMG_HASH}?now=${Date.now()}&filename=1x1.png#x-ipfs-companion-no-redirect`)
checkViaImgSrc(imgSubdomainUrl)
.then(() => expectSubdomainRedirect(imgRedirectedPathUrl)
.then(() => {
this.tag.textContent = '✅';
this.parent.tag.classList.add('origin')
this.parent.checked()
}).catch(() => this.onerror())
}))
.catch(() => this.onerror())
}

Origin.prototype.onerror = function() {
this.tag.textContent = '⚠️';
};


let Flag = function(parent, hostname) {
this.parent = parent;
this.tag = document.createElement("div");
Expand Down

0 comments on commit b837a35

Please sign in to comment.