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

feat: make routers optional and enable local insecure gateways #303

Closed
wants to merge 10 commits into from
4 changes: 2 additions & 2 deletions src/lib/config-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface ConfigDb extends BaseDbConfig {
}

export const defaultGateways = ['https://trustless-gateway.link']
export const defaultRouters = ['https://delegated-ipfs.dev']
export const defaultRouters = []
lidel marked this conversation as resolved.
Show resolved Hide resolved
export const defaultDnsJsonResolvers = {
'.': 'https://delegated-ipfs.dev/dns-query'
}
Expand Down Expand Up @@ -100,7 +100,7 @@ export async function getConfig (logger: ComponentLogger): Promise<ConfigDb> {
gateways = [...defaultGateways]
}

if (routers == null || routers.length === 0) {
if (routers == null) {
routers = [...defaultRouters]
}
if (dnsJsonResolvers == null || Object.keys(dnsJsonResolvers).length === 0) {
Expand Down
33 changes: 33 additions & 0 deletions src/lib/local-gateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { uiLogger } from './logger.js'

export const localGwUrl = 'http://127.0.0.1:8080'
2color marked this conversation as resolved.
Show resolved Hide resolved
// export const localGwUrl = 'http://localhost:8080'
const localGwTestUrl = `${localGwUrl}/ipfs/bafkqablimvwgy3y?format=raw`
const expectedContentType = 'application/vnd.ipld.raw'
const expectedResponseBody = 'hello'

const log = uiLogger.forComponent('local-gateway-prober')

export async function hasLocalGateway (): Promise<boolean> {
try {
log(`probing for local trustless gateway at ${localGwTestUrl}`)
const resp = await fetch(localGwTestUrl)
if (!resp.ok) {
return false
}
if (resp.headers.get('Content-Type') !== expectedContentType) {
return false
}
const respBody = await resp.text()

if (respBody === expectedResponseBody) {
log(`found local trustless gateway at ${localGwTestUrl}`)
return true
} else {
return false
}
} catch (e: unknown) {
log.error('failed to probe trustless gateway', e)
return false
}
}
47 changes: 43 additions & 4 deletions src/pages/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { RouteContext } from '../context/router-context.jsx'
import { ServiceWorkerProvider } from '../context/service-worker-context.jsx'
import { HeliaServiceWorkerCommsChannel } from '../lib/channel.js'
import { defaultDnsJsonResolvers, defaultGateways, defaultRouters, getConfig, loadConfigFromLocalStorage, resetConfig } from '../lib/config-db.js'
import { hasLocalGateway, localGwUrl } from '../lib/local-gateway.js'
import { LOCAL_STORAGE_KEYS } from '../lib/local-storage.js'
import { getUiComponentLogger, uiLogger } from '../lib/logger.js'
import './default-page-styles.css'
Expand All @@ -16,7 +17,7 @@ const uiComponentLogger = getUiComponentLogger('config-page')
const log = uiLogger.forComponent('config-page')
const channel = new HeliaServiceWorkerCommsChannel('WINDOW', uiComponentLogger)

const urlValidationFn = (value: string): Error | null => {
const gatewayArrayValidationFn = (value: string): Error | null => {
try {
const urls = JSON.parse(value) satisfies string[]
let i = 0
Expand All @@ -37,6 +38,24 @@ const urlValidationFn = (value: string): Error | null => {
}
}

const routersArrayValidationFn = (value: string): Error | null => {
try {
const urls = JSON.parse(value) satisfies string[]
let i = 0
try {
urls.map((url, index) => {
i = index
return new URL(url)
})
} catch (e) {
throw new Error(`URL "${urls[i]}" at index ${i} is not valid`)
}
return null
} catch (err) {
return err as Error
}
}

const dnsJsonValidationFn = (value: string): Error | null => {
try {
const urls: Record<string, string> = JSON.parse(value)
Expand Down Expand Up @@ -84,10 +103,30 @@ function ConfigPage (): React.JSX.Element | null {
window.parent?.postMessage({ source: 'helia-sw-config-iframe', target: 'PARENT', action: 'RELOAD_CONFIG', config }, {
targetOrigin
})
log.trace('config-page: RELOAD_CONFIG sent to parent window')
log.trace('RELOAD_CONFIG sent to parent window')
}, [])

useEffect(() => {
hasLocalGateway()
.then(async hasLocalGw => {
if (hasLocalGw) {
// check if local storage has it.
const unparsedGwConf = localStorage.getItem(LOCAL_STORAGE_KEYS.config.gateways)
const gwConf = unparsedGwConf != null ? JSON.parse(unparsedGwConf) as string[] : defaultGateways
if (!gwConf.includes(localGwUrl)) {
log(`Adding ${localGwUrl} to gateway list`)
gwConf.push(localGwUrl)
2color marked this conversation as resolved.
Show resolved Hide resolved
}
// Update localStorage
localStorage.setItem(LOCAL_STORAGE_KEYS.config.gateways, JSON.stringify(gwConf))
await loadConfigFromLocalStorage()
await channel.messageAndWaitForResponse('SW', { target: 'SW', action: 'RELOAD_CONFIG' })
await postFromIframeToParentSw()
setResetKey((prev) => prev + 1)
}
}).catch(err => {
log.error('failed to probe for local gateway', err)
})
/**
* On initial load, we want to send the config to the parent window, so that the reload page can auto-reload if enabled, and the subdomain registered service worker gets the latest config without user interaction.
*/
Expand Down Expand Up @@ -122,8 +161,8 @@ function ConfigPage (): React.JSX.Element | null {
return (
<main className='e2e-config-page pa4-l bg-snow mw7 center pa4'>
<Collapsible collapsedLabel="View config" expandedLabel='Hide config' collapsed={isLoadedInIframe}>
<LocalStorageInput className="e2e-config-page-input e2e-config-page-input-gateways" localStorageKey={LOCAL_STORAGE_KEYS.config.gateways} label='Gateways' validationFn={urlValidationFn} defaultValue={JSON.stringify(defaultGateways)} resetKey={resetKey} />
<LocalStorageInput className="e2e-config-page-input e2e-config-page-input-routers" localStorageKey={LOCAL_STORAGE_KEYS.config.routers} label='Routers' validationFn={urlValidationFn} defaultValue={JSON.stringify(defaultRouters)} resetKey={resetKey} />
<LocalStorageInput className="e2e-config-page-input e2e-config-page-input-gateways" localStorageKey={LOCAL_STORAGE_KEYS.config.gateways} label='Gateways' validationFn={gatewayArrayValidationFn} defaultValue={JSON.stringify(defaultGateways)} resetKey={resetKey} />
<LocalStorageInput className="e2e-config-page-input e2e-config-page-input-routers" localStorageKey={LOCAL_STORAGE_KEYS.config.routers} label='Routers' validationFn={routersArrayValidationFn} defaultValue={JSON.stringify(defaultRouters)} resetKey={resetKey} />
<LocalStorageInput className="e2e-config-page-input e2e-config-page-input-dnsJsonResolvers" localStorageKey={LOCAL_STORAGE_KEYS.config.dnsJsonResolvers} label='DNS (application/dns-json) resolvers' validationFn={dnsJsonValidationFn} defaultValue={JSON.stringify(defaultDnsJsonResolvers)} resetKey={resetKey} />
<LocalStorageToggle className="e2e-config-page-input e2e-config-page-input-autoreload" localStorageKey={LOCAL_STORAGE_KEYS.config.autoReload} onLabel='Auto Reload' offLabel='Show Config' resetKey={resetKey} />
<LocalStorageInput className="e2e-config-page-input" localStorageKey={LOCAL_STORAGE_KEYS.config.debug} label='Debug logging' validationFn={stringValidationFn} defaultValue='' resetKey={resetKey} />
Expand Down
6 changes: 4 additions & 2 deletions src/sw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,10 @@ async function getVerifiedFetch (): Promise<VerifiedFetch> {

const verifiedFetch = await createVerifiedFetch({
gateways: config.gateways,
routers: config.routers,
dnsResolvers
routers: config.routers ?? [],
dnsResolvers,
allowInsecure: true,
allowLocal: true
}, {
contentTypeParser
})
Expand Down
Loading