fix(ui): support secure UUIDs on LAN HTTP

Avoid eager consent component crashes and registration approval failures where crypto.randomUUID is unavailable. Share the companion audio CSPRNG fallback, preserve UUIDv4/session semantics and fail closed without secure randomness.

Validation: 24 focused UUID, consent mount, registration recovery and companion audio tests passed. Independent review passed; full UI typecheck/build qualification remains in progress.
This commit is contained in:
archipelago
2026-10-08 12:00:17 -04:00
parent cea4fa1a5a
commit 0df423a84f
7 changed files with 79 additions and 13 deletions
@@ -0,0 +1,19 @@
import { mount, flushPromises } from '@vue/test-utils'
import { afterEach, expect, it, vi } from 'vitest'
import { webcrypto } from 'node:crypto'
const files = vi.hoisted(() => ({ login: vi.fn(async () => true), listDirectory: vi.fn(async () => []) }))
vi.mock('@/api/filebrowser-client', () => ({ fileBrowserClient: files }))
import MediaRegistrationConsent from '../MediaRegistrationConsent.vue'
afterEach(() => { vi.unstubAllGlobals(); vi.clearAllMocks() })
it('mounts the inactive dashboard consent and opens its labelled dialog on LAN HTTP', async () => {
vi.stubGlobal('crypto', { getRandomValues: webcrypto.getRandomValues.bind(webcrypto) })
const wrapper = mount(MediaRegistrationConsent, { props: { request: null, phase: 'select', error: '' } })
expect(files.login).not.toHaveBeenCalled()
await wrapper.setProps({ request: { intent: { viewingSeconds: 3600, priceSats: 15 } } as any })
await flushPromises()
const dialog = wrapper.get('[role="dialog"]')
const label = dialog.attributes('aria-labelledby')
expect(label).toMatch(/^media-registration-[0-9a-f-]{36}$/)
expect(wrapper.get('#' + label).text()).toBeTruthy()
wrapper.unmount()
})