Skip to content

Commit

Permalink
feat: improved Origin detection via img tag (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
lidel authored Oct 21, 2020
1 parent 782b66b commit 8407e80
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 39 deletions.
100 changes: 67 additions & 33 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/*
This program will check IPFS gateways status using 2 methods
This program will check IPFS gateways status using 3 methods
1) By asking for a script through a <script src=""> tag, which when loaded, it executes some code
2) By asking data through ajax requests to verify gateway's CORS configuration
2) By asking data through fetch requests to verify gateway's CORS configuration
3) By asking data through img requests to verify subdomain configuration
*/

const HASH_TO_TEST = 'bafybeifx7yeb55armcsxwwitkymga5xf53dxiarykms3ygqic223w5sk3m';
const SCRIPT_HASH = 'bafybeietzsezxbgeeyrmwicylb5tpvf7yutrm3bxrfaoulaituhbi7q6yi';
const IMG_HASH = 'bafybeibwzifw52ttrkqlikfzext5akxu7lz4xiwjgwzmqcpdzmp3n5vnbe'; // 1x1.png
const HASH_STRING = 'Hello from IPFS Gateway Checker';

const ipfs_http_client = window.IpfsHttpClient({
Expand All @@ -19,13 +21,13 @@ let checker = document.getElementById('checker');
checker.nodes = [];

checker.checkGateways = function(gateways) {
gateways.forEach((gateway) => {
let node = new Node(this.results, gateway, this.nodes.length);
this.nodes.push(node);
this.results.append(node.tag);
node.check();
});
};
for (const gateway of gateways) {
const node = new Node(this.results, gateway, this.nodes.length)
this.nodes.push(node)
this.results.append(node.tag)
setTimeout(() => node.check(), 100 * this.nodes.length);
}
}

checker.updateStats = function() {
this.stats.update();
Expand Down Expand Up @@ -78,6 +80,36 @@ 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
// by privacy protections present in modern browsers or in extensions such as Privacy Badger
const imgCheckTimeout = 15000
return new Promise((resolve, reject) => {
const timeout = () => {
if (!timer) return false
clearTimeout(timer)
timer = null
return true
}
let timer = setTimeout(() => { if (timeout()) reject() }, imgCheckTimeout)
const img = new Image()
img.onerror = () => {
timeout()
reject()
}
img.onload = () => {
timeout()
resolve()
}
// now - ensures we don't read from browser cache
// filename - ensures correct content-type is returned / sniffed
// x-ipfs-companion-no-redirect - hint for our browser extension, makes sure we test remote server
img.src = `${imgUrl}?now=${Date.now()}&filename=1x1.png#x-ipfs-companion-no-redirect`
})
}

Status.prototype.check = function() {
let gatewayAndScriptHash = this.parent.gateway.replace(":hash", SCRIPT_HASH);

Expand Down Expand Up @@ -134,23 +166,20 @@ let Cors = function(parent) {
};

Cors.prototype.check = function() {
const gatewayAndHash = this.parent.gateway.replace(':hash', HASH_TO_TEST);
const now = Date.now();
const testUrl = `${gatewayAndHash}?now=${now}#x-ipfs-companion-no-redirect`;
fetch(testUrl).then((res) => {
return res.text();
}).then((text) => {
const matched = (HASH_STRING === text.trim());
if (matched) {
this.parent.checked();
this.tag.textContent = '✅';
} else {
this.onerror();
}
}).catch((err) => {
this.onerror();
});
};
const gatewayAndHash = this.parent.gateway.replace(':hash', HASH_TO_TEST)
const now = Date.now()
const testUrl = `${gatewayAndHash}?now=${now}#x-ipfs-companion-no-redirect`
fetch(testUrl).then((res) => res.text()).then((text) => {
const matched = (HASH_STRING === text.trim())
if (matched) {
this.parent.checked()
this.tag.textContent = '✅'
this.parent.tag.classList.add('cors')
} else {
this.onerror()
}
}).catch((err) => this.onerror())
}

Cors.prototype.onerror = function() {
this.tag.textContent = '❌';
Expand All @@ -164,13 +193,18 @@ let Origin = function(parent) {
};

Origin.prototype.check = function() {
const cidInSubdomain = this.parent.gateway.startsWith('https://:hash.ipfs.');
if (cidInSubdomain) {
this.tag.textContent = '✅';
} else {
this.onerror();
}
};
// 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 imgUrl = new URL(this.parent.gateway)
imgUrl.pathname = '/'
imgUrl.hostname = `${IMG_HASH}.ipfs.${imgUrl.hostname}`
checkViaImgSrc(imgUrl.toString()).then((res) => {
this.tag.textContent = '✅';
this.parent.tag.classList.add('origin')
this.parent.checked()
}).catch(() => this.onerror())
}

Origin.prototype.onerror = function() {
this.tag.textContent = '❌';
Expand Down
11 changes: 5 additions & 6 deletions gateways.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[
"https://ipfs.io/ipfs/:hash",
"https://:hash.ipfs.dweb.link",
"https://dweb.link/ipfs/:hash",
"https://gateway.ipfs.io/ipfs/:hash",
"https://ipfs.infura.io/ipfs/:hash",
"https://ninetailed.ninja/ipfs/:hash",
Expand All @@ -10,8 +10,8 @@
"https://hardbin.com/ipfs/:hash",
"https://gateway.blocksec.com/ipfs/:hash",
"https://cloudflare-ipfs.com/ipfs/:hash",
"https://:hash.ipfs.cf-ipfs.com",
"https://ipns.co/:hash",
"https://cf-ipfs.com/ipfs/:hash",
"https://ipns.co/ipfs/:hash",
"https://ipfs.mrh.io/ipfs/:hash",
"https://gateway.originprotocol.com/ipfs/:hash",
"https://gateway.pinata.cloud/ipfs/:hash",
Expand All @@ -29,12 +29,11 @@
"https://permaweb.io/ipfs/:hash",
"https://ipfs.stibarc.com/ipfs/:hash",
"https://ipfs.best-practice.se/ipfs/:hash",
"https://:hash.ipfs.2read.net",
"https://2read.net/ipfs/:hash",
"https://ipfs.2read.net/ipfs/:hash",
"https://storjipfs-gateway.com/ipfs/:hash",
"https://ipfs.runfission.com/ipfs/:hash",
"https://trusti.id/ipfs/:hash",
"https://:hash.ipfs.cosmos-ink.net",
"https://ipfs.overpi.com/ipfs/:hash",
"https://ipfs.lc/ipfs/:hash",
"https://ipfs.leiyun.org/ipfs/:hash",
Expand All @@ -52,7 +51,7 @@
"https://ipfs.fleek.co/ipfs/:hash",
"https://ipfs.jbb.one/ipfs/:hash",
"https://ipfs.yt/ipfs/:hash",
"https://:hash.ipfs.jacl.tech",
"https://jacl.tech/ipfs/:hash",
"https://hashnews.k1ic.com/ipfs/:hash",
"https://ipfs.vip/ipfs/:hash",
"https://ipfs.k1ic.com/ipfs/:hash"
Expand Down
4 changes: 4 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,7 @@ div.Node div.Took {
font-size: 80%;
font-style: italic;
}

div.Node.origin div.Link::after {
content: " 💚"
}

0 comments on commit 8407e80

Please sign in to comment.