OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / test / integration / blind-real-relay-browser-config.test.js

152 lines · javascript ref:
import { webcrypto } from 'node:crypto'
import b4a from 'b4a'
import test from 'brittle'
import {
  ENDPOINT_ROLE,
  FAMILY,
  OPERATION,
  PRIVACY_PROFILE,
  TRANSPORT_SUPPORT
} from '@hiverelay/blind-protocol'
import { createRealBlindRelayTestFixture } from '../../scripts/run-real-blind-relay-lab.mjs'

const browserClientUrl = new URL(
  '../../packages/blind-client/browser-artifacts/blind-client-control-v1.mjs',
  import.meta.url
)

test('real relay fixture exports sufficient public metadata for the shipped browser client', { timeout: 45_000 }, async t => {
  const client = await import(browserClientUrl)
  const fixture = await createRealBlindRelayTestFixture()
  try {
    const config = fixture.browserQualificationConfig()
    t.is(config.schema, 'HiveRelayRealBlindBrowserQualificationConfigV1')
    t.is(config.localTestOnly, true)
    t.is(config.currentEpoch, fixture.currentEpoch)
    t.ok(Object.isFrozen(config))
    t.ok(Object.isFrozen(config.candidate))
    t.ok(Object.isFrozen(config.genesis))
    t.ok(Object.isFrozen(config.supportedProtocolProfiles))
    t.ok(Object.isFrozen(config.supportedTransportProfiles))
    t.ok(Object.isFrozen(config.advertisedAdmissionProfile))

    for (const value of [
      config.candidate.canonicalUrl,
      config.candidate.expectedDescriptorHash,
      config.candidate.continuityRootRelayPublicKey,
      config.candidate.storeId,
      config.genesis.descriptorBytes,
      config.genesis.descriptorHash,
      config.supportedProtocolProfiles[0].profileHash,
      config.supportedTransportProfiles[0].transportProfileHash,
      config.advertisedAdmissionProfile.parameterHash
    ]) t.ok(value instanceof Uint8Array)
    if (config.advertisedAdmissionProfile.parameterUrl != null) {
      t.ok(config.advertisedAdmissionProfile.parameterUrl instanceof Uint8Array)
    }

    const descriptorHash = config.candidate.expectedDescriptorHash
    const descriptorHashSnapshot = b4a.from(descriptorHash)
    descriptorHash[0] ^= 0xff
    t.alike(config.candidate.expectedDescriptorHash, descriptorHashSnapshot)
    const storeId = config.candidate.storeId
    const storeIdSnapshot = b4a.from(storeId)
    storeId.fill(0)
    t.alike(config.candidate.storeId, storeIdSnapshot)

    t.alike(config.cellPutRequirement, {
      familyId: FAMILY.CELL,
      operationId: OPERATION.CELL.PUT,
      endpointId: 1,
      requiredRoleBits: ENDPOINT_ROLE.STORAGE,
      privacyProfileBit: PRIVACY_PROFILE.DIRECT,
      transportSupportBit: TRANSPORT_SUPPORT.DIRECT_HTTP
    })
    t.alike(config.cellGetRequirement, {
      familyId: FAMILY.CELL,
      operationId: OPERATION.CELL.GET,
      endpointId: 1,
      requiredRoleBits: ENDPOINT_ROLE.STORAGE,
      privacyProfileBit: PRIVACY_PROFILE.DIRECT,
      transportSupportBit: TRANSPORT_SUPPORT.DIRECT_HTTP
    })
    t.alike(config.admissionParametersRequirement, {
      familyId: FAMILY.DESCRIBE,
      operationId: OPERATION.DESCRIBE.ADMISSION_PARAMETERS,
      endpointId: 1,
      requiredRoleBits: ENDPOINT_ROLE.QUOTA_REDEEMER,
      privacyProfileBit: PRIVACY_PROFILE.DIRECT,
      transportSupportBit: TRANSPORT_SUPPORT.DIRECT_HTTP
    })

    const runtime = client.createBrowserCryptoRuntime(webcrypto)
    const trustStore = new client.DescriptorTrustStore()
    const verifiedGenesis = client.verifyDescriptorBytes(config.genesis.descriptorBytes, {
      nowEpoch: config.currentEpoch,
      supportedProtocolProfiles: config.supportedProtocolProfiles,
      supportedTransportProfiles: config.supportedTransportProfiles
    })
    await trustStore.accept(verifiedGenesis, {
      pinnedDescriptorHash: config.genesis.descriptorHash,
      continuityRootRelayPublicKey: config.candidate.continuityRootRelayPublicKey
    })
    const qualifier = new client.BlindRelayQualifier({
      runtime,
      nowEpoch: () => config.currentEpoch,
      fetch: fixture.fetch,
      trustStore,
      supportedProtocolProfiles: config.supportedProtocolProfiles,
      supportedTransportProfiles: config.supportedTransportProfiles
    })

    const qualifiedPut = await qualifier.qualifyCandidate(
      config.candidate,
      config.cellPutRequirement
    )
    const qualifiedGet = await qualifier.qualifyCandidate(
      config.candidate,
      config.cellGetRequirement
    )
    const qualifiedAdmission = await qualifier.qualifyCandidate(
      config.candidate,
      config.admissionParametersRequirement
    )
    t.is(client.verifiedEndpointContext(qualifiedPut.endpoint).operationId, OPERATION.CELL.PUT)
    t.is(client.verifiedEndpointContext(qualifiedGet.endpoint).operationId, OPERATION.CELL.GET)
    t.is(client.verifiedEndpointContext(qualifiedAdmission.endpoint).operationId,
      OPERATION.DESCRIBE.ADMISSION_PARAMETERS)

    const admissionRequest = client.createAdmissionParametersRequest({
      runtime,
      profileId: config.advertisedAdmissionProfile.profileId,
      schemeId: config.advertisedAdmissionProfile.schemeId
    })
    const direct = new client.BlindDirectHttpClient({ runtime, fetch: fixture.fetch })
    const admissionResult = await direct.request({
      endpoint: qualifiedAdmission.endpoint,
      ...admissionRequest.wire,
      body: admissionRequest.requestBytes
    })
    t.is(admissionResult.ok, true)
    let verifiedAdmission
    try {
      verifiedAdmission = client.verifyAdmissionParametersBytes(
        admissionResult.body,
        qualifiedAdmission.trustedDescriptor,
        config.advertisedAdmissionProfile,
        { nowEpoch: config.currentEpoch }
      )
    } catch (error) {
      t.fail(`advertised admission profile did not verify: ${error.code || 'ERROR'} ${error.message}`)
      return
    }
    t.ok(b4a.equals(
      verifiedAdmission.parameterHash,
      config.advertisedAdmissionProfile.parameterHash
    ))
    t.is(fixture.errors().length, 0)
  } finally {
    await fixture.close()
  }
})