diff --git a/src/GatewayNode.ts b/src/GatewayNode.ts index 20580076..f6f45328 100644 --- a/src/GatewayNode.ts +++ b/src/GatewayNode.ts @@ -3,6 +3,7 @@ import { URL } from 'url-ponyfill' import { Cors } from './Cors' import { Flag } from './Flag' import { Origin } from './Origin' +import { Trustless } from './Trustless' import type { Results } from './Results' import { Status } from './Status' import { UiComponent } from './UiComponent' @@ -18,6 +19,7 @@ class GatewayNode extends UiComponent /* implements Checkable */ { status: Status cors: Cors origin: Origin + trustless: Trustless link: HTMLDivElement & { url?: URL } flag: Flag took: HTMLDivElement @@ -43,6 +45,9 @@ class GatewayNode extends UiComponent /* implements Checkable */ { this.origin = new Origin(this) this.tag.append(this.origin.tag) + this.trustless = new Trustless(this) + this.tag.append(this.trustless.tag) + this.link = document.createElement('div') const gatewayAndHash = gateway.replace(':hash', HASH_TO_TEST) this.link.url = new URL(gatewayAndHash) @@ -72,7 +77,9 @@ class GatewayNode extends UiComponent /* implements Checkable */ { // this.flag.check().then(() => log.debug(this.gateway, 'Flag success')), this.status.check().then(() => log.debug(this.gateway, 'Status success')).then(this.onSuccessfulCheck.bind(this)), this.cors.check().then(() => log.debug(this.gateway, 'CORS success')).then(this.onSuccessfulCheck.bind(this)), - this.origin.check().then(() => log.debug(this.gateway, 'Origin success')).then(this.onSuccessfulCheck.bind(this)) + this.origin.check().then(() => log.debug(this.gateway, 'Origin success')).then(this.onSuccessfulCheck.bind(this)), + this.trustless.check().then( + () => log.debug(this.gateway, 'Trustless success')).then(this.onSuccessfulCheck.bind(this)) ] // we care only about the fastest method to return a success diff --git a/src/Tag.ts b/src/Tag.ts index 8a5c5cf1..a0470b02 100644 --- a/src/Tag.ts +++ b/src/Tag.ts @@ -1,6 +1,6 @@ import { TagStatus } from './TagStatus' -type TagClasses = 'Status' | 'Node' | 'Cors' | 'Origin' | 'Flag' +type TagClasses = 'Status' | 'Node' | 'Cors' | 'Origin' | 'Flag' | 'Trustless' type TagContent = TagStatus diff --git a/src/Trustless.ts b/src/Trustless.ts new file mode 100644 index 00000000..27e44e60 --- /dev/null +++ b/src/Trustless.ts @@ -0,0 +1,56 @@ +import fetchPonyfill from 'fetch-ponyfill' + +import { CheckBase } from './CheckBase' +import { HASH_TO_TEST, TRUSTLESS_RESPONSE_TYPES } from './constants' +import type { GatewayNode } from './GatewayNode' + +import { Log } from './Log' + +const { fetch } = fetchPonyfill() + +const log = new Log('Trustless') + +class Trustless extends CheckBase implements Checkable { + _className = 'Trustless' + _tagName = 'div' + constructor (protected parent: GatewayNode) { + super(parent, 'div', 'Trustless') + } + + async check (): Promise { + const now = Date.now() + const gatewayAndHash = this.parent.gateway.replace(':hash', HASH_TO_TEST) + this.parent.tag.classList.add('trustless') + try { + const trustlessResponseTypesTests = await Promise.all(TRUSTLESS_RESPONSE_TYPES.map( + async (trustlessTypes): Promise => { + const testUrl = `${gatewayAndHash}?format=${trustlessTypes}&now=${now}#x-ipfs-companion-no-redirect` + const response = await fetch(testUrl) + return Boolean(response.headers.get('Content-Type')?.includes(`application/vnd.ipld.${trustlessTypes}`)) + } + )) + + if (!trustlessResponseTypesTests.includes(false)) { + this.tag.win() + } else { + log.debug('The response type did not match the expected type') + this.onerror() + throw new Error(`URL '${gatewayAndHash} does not support Trustless`) + } + } catch (err) { + log.error(err) + this.onerror() + throw err + } + } + + checked (): void { + log.warn('Not implemented yet') + } + + onerror (): void { + this.tag.err() + } +} + +export { Trustless } diff --git a/src/constants.ts b/src/constants.ts index 8a83ed77..a13ac832 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,10 +3,12 @@ const HASH_TO_TEST = 'bafybeifx7yeb55armcsxwwitkymga5xf53dxiarykms3ygqic223w5sk3 const IMG_HASH = 'bafybeibwzifw52ttrkqlikfzext5akxu7lz4xiwjgwzmqcpdzmp3n5vnbe' // 1x1.png // const IFRAME_HASH = 'bafkreifx3g6bkkwl7b4v43lvcqfo5vshbiehuvmpky2zayhfpg5qj7y3ca' const HASH_STRING = 'Hello from IPFS Gateway Checker' +const TRUSTLESS_RESPONSE_TYPES = ['raw', 'car'] export { HASH_STRING, HASH_TO_TEST, // IFRAME_HASH, - IMG_HASH + IMG_HASH, + TRUSTLESS_RESPONSE_TYPES } diff --git a/src/index.html b/src/index.html index e8f999eb..674c8f35 100644 --- a/src/index.html +++ b/src/index.html @@ -56,6 +56,7 @@

Public Gateways

Online
+
Country
ΔT
diff --git a/src/styles.css b/src/styles.css index 795d8289..72565b82 100644 --- a/src/styles.css +++ b/src/styles.css @@ -70,8 +70,9 @@ div.Node a, div#origin-warning a { div.Node div.Status, div.Node div.Cors, div.Node div.Origin, +div.Node div.Trustless, div.Node div.Flag { - width: 5em; + width: 6em; text-align: center; margin: 0 0.5em; user-select: none; @@ -93,6 +94,10 @@ div.Node div.Took { font-style: italic; } +div.Node.trustless div.Trustless { + margin: 0 1.3em; +} + div.Node.origin div.Link::after { content: " 💚" }