OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / test / unit / api-safe-config.test.js

131 lines · javascript ref:
import test from 'brittle'
import {
  buildSafeConfigPayload,
  restoreWizardConfig,
  snapshotWizardConfig
} from '../../packages/core/core/relay-node/api-safe-config.js'

test('api safe config: emits only operator-safe persisted config fields', (t) => {
  const node = {
    _operatingMode: 'private',
    config: {
      name: 'relay',
      storage: '/data',
      acceptMode: 'review',
      acceptAllowlist: ['a'.repeat(64)],
      plugins: ['poker'],
      regions: ['NA'],
      discovery: { dht: false },
      access: { open: false },
      pairing: { enabled: true },
      transports: { udp: true, websocket: true },
      subsidy: { enabled: true, payoutDestination: 'operator@example.com' },
      apiPort: 9100,
      apiHost: '127.0.0.1',
      corsOrigins: ['https://operator.example'],
      maxConnections: 32,
      maxStorageBytes: 1000,
      maxRelayBandwidthMbps: 50,
      enableRelay: true,
      enableSeeding: true,
      enableServices: true,
      enableMetrics: true,
      enableAPI: true,
      registryAutoAccept: false,
      maxCircuitsPerPeer: 5,
      maxCircuitDuration: 1000,
      maxCircuitBytes: 2048,
      announceInterval: 3000,
      requireSignedCatalog: true,
      catalogSignatureMaxAgeMs: 4000,
      catalogMaxAppAgeMs: 5000,
      strictSeedingPrivacy: true,
      enableDistributedDriveBridge: false,
      gatewayPublicOnlyPrivacyTier: true,
      replicationCheckInterval: 6000,
      replicationRepairEnabled: true,
      targetReplicaFloor: 3,
      shutdownTimeoutMs: 7000,
      apiKey: 'do-not-persist',
      ui: { exposeToken: true },
      holesail: { connectionKey: 'hole-secret' },
      tor: { onionAddress: 'secret.onion' },
      pairingToken: 'pair-secret',
      privateKey: 'private-secret'
    }
  }

  const payload = buildSafeConfigPayload(node)
  t.is(payload.name, 'relay')
  t.is(payload.mode, 'private')
  t.alike(payload.plugins, ['poker'])
  t.alike(payload.transports, { udp: true, websocket: true })
  t.alike(payload.subsidy, { enabled: true, payoutDestination: 'operator@example.com' })
  t.absent(Object.prototype.hasOwnProperty.call(payload, 'apiKey'))
  t.absent(Object.prototype.hasOwnProperty.call(payload, 'ui'))
  t.absent(Object.prototype.hasOwnProperty.call(payload, 'holesail'))
  t.absent(Object.prototype.hasOwnProperty.call(payload, 'tor'))
  t.absent(Object.prototype.hasOwnProperty.call(payload, 'pairingToken'))
  t.absent(Object.prototype.hasOwnProperty.call(payload, 'privateKey'))
  t.absent(JSON.stringify(payload).includes('do-not-persist'))
  t.absent(JSON.stringify(payload).includes('hole-secret'))
  t.absent(JSON.stringify(payload).includes('secret.onion'))
  t.absent(JSON.stringify(payload).includes('pair-secret'))
})

test('api safe config: normalizes missing arrays and nested defaults', (t) => {
  const payload = buildSafeConfigPayload({ config: {} })
  t.alike(payload.acceptAllowlist, [])
  t.alike(payload.plugins, [])
  t.alike(payload.regions, [])
  t.alike(payload.discovery, { dht: true, announce: true, mdns: false })
  t.alike(payload.access, { open: true, allowlist: [] })
  t.alike(payload.pairing, { enabled: false })
  t.alike(payload.transports, { udp: true })
  t.alike(payload.subsidy, { enabled: false, payoutDestination: null })
  t.is(payload.mode, 'standard')
})

test('api safe config: wizard snapshot and restore preserves missing fields', (t) => {
  const config = {
    name: 'old',
    subsidy: { payoutDestination: 'old@example.com' }
  }
  const snapshot = snapshotWizardConfig(config)
  t.alike(snapshot, {
    name: 'old',
    acceptMode: undefined,
    hasAcceptMode: false,
    registryAutoAccept: undefined,
    hasRegistryAutoAccept: false,
    subsidy: { payoutDestination: 'old@example.com' },
    hasSubsidy: true
  })

  config.name = 'new'
  config.acceptMode = 'open'
  config.registryAutoAccept = true
  config.subsidy.payoutDestination = 'new@example.com'

  restoreWizardConfig(config, snapshot)
  t.is(config.name, 'old')
  t.absent(Object.prototype.hasOwnProperty.call(config, 'acceptMode'))
  t.absent(Object.prototype.hasOwnProperty.call(config, 'registryAutoAccept'))
  t.alike(config.subsidy, { payoutDestination: 'old@example.com' })
})

test('api safe config: wizard restore removes fields absent from snapshot', (t) => {
  const config = {
    acceptMode: 'review',
    registryAutoAccept: false,
    subsidy: { payoutDestination: null }
  }
  const snapshot = snapshotWizardConfig({})

  restoreWizardConfig(config, snapshot)
  t.absent(Object.prototype.hasOwnProperty.call(config, 'name'))
  t.absent(Object.prototype.hasOwnProperty.call(config, 'acceptMode'))
  t.absent(Object.prototype.hasOwnProperty.call(config, 'registryAutoAccept'))
  t.absent(Object.prototype.hasOwnProperty.call(config, 'subsidy'))
})