Skip to content

Commit

Permalink
feat: global config validation (#451)
Browse files Browse the repository at this point in the history
* fix: dont use local storage for text config items

* fix: input toggles dont use localStorage

* fix: input-toggle uses resetKey

* fix: do not use broadcast channels to tell sw to update config

* chore: fix build

* feat: global config validation

fixes #399

* fix: validate before storing config

Also adds more error handling to config-db
  • Loading branch information
SgtPooki authored Nov 14, 2024
1 parent c838307 commit 334a077
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 34 deletions.
7 changes: 4 additions & 3 deletions src/context/config-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { createContext, useCallback, useEffect, useState } from 'react'
import { defaultDnsJsonResolvers, defaultEnableGatewayProviders, defaultEnableRecursiveGateways, defaultEnableWebTransport, defaultEnableWss, defaultGateways, defaultRouters, getConfig, resetConfig, type ConfigDb } from '../lib/config-db.js'
import { isConfigPage } from '../lib/is-config-page.js'
import { getUiComponentLogger } from '../lib/logger.js'
import type { ComponentLogger } from '@libp2p/logger'

const isLoadedInIframe = window.self !== window.top

Expand All @@ -10,7 +11,7 @@ export interface ConfigContextType extends ConfigDb {
isConfigExpanded: boolean
setConfigExpanded(value: boolean): void
setConfig(key: ConfigKey, value: any): void
resetConfig(): Promise<void>
resetConfig(logger?: ComponentLogger): Promise<void>
}

export const ConfigContext = createContext<ConfigContextType>({
Expand Down Expand Up @@ -97,8 +98,8 @@ export const ConfigProvider = ({ children }: { children: JSX.Element[] | JSX.Ele
}
}, [])

const resetConfigLocal = async (): Promise<void> => {
await resetConfig()
const resetConfigLocal: ConfigContextType['resetConfig'] = async (givenLogger): Promise<void> => {
await resetConfig(givenLogger ?? logger)
await loadConfig()
}

Expand Down
69 changes: 45 additions & 24 deletions src/lib/config-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,45 @@ export const defaultEnableGatewayProviders = true

const configDb = new GenericIDB<ConfigDb>('helia-sw', 'config')

export async function resetConfig (): Promise<void> {
await configDb.open()
await configDb.put('gateways', defaultGateways)
await configDb.put('routers', defaultRouters)
await configDb.put('dnsJsonResolvers', defaultDnsJsonResolvers)
await configDb.put('enableWss', defaultEnableWss)
await configDb.put('enableWebTransport', defaultEnableWebTransport)
await configDb.put('enableRecursiveGateways', defaultEnableRecursiveGateways)
await configDb.put('enableGatewayProviders', defaultEnableGatewayProviders)
await configDb.put('debug', '')
configDb.close()
export async function resetConfig (logger: ComponentLogger): Promise<void> {
const log = logger.forComponent('reset-config')
try {
await configDb.open()
await configDb.put('gateways', defaultGateways)
await configDb.put('routers', defaultRouters)
await configDb.put('dnsJsonResolvers', defaultDnsJsonResolvers)
await configDb.put('enableWss', defaultEnableWss)
await configDb.put('enableWebTransport', defaultEnableWebTransport)
await configDb.put('enableRecursiveGateways', defaultEnableRecursiveGateways)
await configDb.put('enableGatewayProviders', defaultEnableGatewayProviders)
await configDb.put('debug', '')
} catch (err) {
log('error resetting config in db', err)
} finally {
configDb.close()
}
}

export async function setConfig (config: ConfigDb, logger: ComponentLogger): Promise<void> {
const log = logger.forComponent('set-config')
enable(config.debug ?? '') // set debug level first.
log('config-debug: setting config %O for domain %s', config, window.location.origin)

await configDb.open()
await configDb.put('gateways', config.gateways)
await configDb.put('routers', config.routers)
await configDb.put('dnsJsonResolvers', config.dnsJsonResolvers)
await configDb.put('enableRecursiveGateways', config.enableRecursiveGateways)
await configDb.put('enableWss', config.enableWss)
await configDb.put('enableWebTransport', config.enableWebTransport)
await configDb.put('enableGatewayProviders', config.enableGatewayProviders)
await configDb.put('debug', config.debug ?? '')
configDb.close()
await validateConfig(config, logger)
try {
log('config-debug: setting config %O for domain %s', config, window.location.origin)
await configDb.open()
await configDb.put('gateways', config.gateways)
await configDb.put('routers', config.routers)
await configDb.put('dnsJsonResolvers', config.dnsJsonResolvers)
await configDb.put('enableRecursiveGateways', config.enableRecursiveGateways)
await configDb.put('enableWss', config.enableWss)
await configDb.put('enableWebTransport', config.enableWebTransport)
await configDb.put('enableGatewayProviders', config.enableGatewayProviders)
await configDb.put('debug', config.debug ?? '')
} catch (err) {
log('error setting config in db', err)
} finally {
configDb.close()
}
}

export async function getConfig (logger: ComponentLogger): Promise<ConfigDb> {
Expand Down Expand Up @@ -81,10 +92,11 @@ export async function getConfig (logger: ComponentLogger): Promise<ConfigDb> {
enableGatewayProviders = await configDb.get('enableGatewayProviders') ?? defaultEnableGatewayProviders

debug = await configDb.get('debug') ?? ''
configDb.close()
enable(debug)
} catch (err) {
log('error loading config from db', err)
} finally {
configDb.close()
}

if (gateways == null || gateways.length === 0) {
Expand All @@ -110,3 +122,12 @@ export async function getConfig (logger: ComponentLogger): Promise<ConfigDb> {
debug
}
}

export async function validateConfig (config: ConfigDb, logger: ComponentLogger): Promise<void> {
const log = logger.forComponent('validate-config')

if (!config.enableRecursiveGateways && !config.enableGatewayProviders && !config.enableWss && !config.enableWebTransport) {
log.error('Config is invalid. At least one of the following must be enabled: recursive gateways, gateway providers, wss, or webtransport.')
throw new Error('Config is invalid. At least one of the following must be enabled: recursive gateways, gateway providers, wss, or webtransport.')
}
}
5 changes: 0 additions & 5 deletions src/lib/get-verified-fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ export async function getVerifiedFetch (config: ConfigDb, logger: ComponentLogge
const log = logger.forComponent('get-verified-fetch')
log(`config-debug: got config for sw location ${self.location.origin}`, JSON.stringify(config, null, 2))

if (!config.enableRecursiveGateways && !config.enableGatewayProviders && !config.enableWss && !config.enableWebTransport) {
// crude validation
throw new Error('Config is invalid. At least one of the following must be enabled: recursive gateways, gateway providers, wss, or webtransport.')
}

// Start by adding the config routers as delegated routers
const routers: Array<Partial<Routing>> = []

Expand Down
5 changes: 3 additions & 2 deletions src/pages/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ function ConfigPage (): React.JSX.Element | null {

const saveConfig = useCallback(async () => {
try {
const config = { gateways, routers, dnsJsonResolvers, debug, enableGatewayProviders, enableRecursiveGateways, enableWss, enableWebTransport }
setIsSaving(true)
await storeConfig({ gateways, routers, dnsJsonResolvers, debug, enableGatewayProviders, enableRecursiveGateways, enableWss, enableWebTransport }, uiComponentLogger)
await storeConfig(config, uiComponentLogger)
log.trace('config-page: sending RELOAD_CONFIG to service worker')
// update the BASE_URL service worker
await tellSwToReloadConfig()
Expand All @@ -132,7 +133,7 @@ function ConfigPage (): React.JSX.Element | null {

const doResetConfig = useCallback(async () => {
// we need to clear out the localStorage items and make sure default values are set, and that all of our inputs are updated
await resetConfig()
await resetConfig(uiComponentLogger)
// now reload all the inputs
setResetKey((prev) => prev + 1)
}, [])
Expand Down

0 comments on commit 334a077

Please sign in to comment.