diff --git a/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.test.ts b/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.test.ts index 8ef4ffa1aea..5473de27478 100644 --- a/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.test.ts +++ b/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.test.ts @@ -188,6 +188,30 @@ describe('ExtensionServerClient', () => { expect(client.connection).toBeUndefined() expect(mockSocketServer.clients.length).toBe(0) }) + + test('generates a random UUID for the client id using crypto.randomUUID when available', () => { + const uuid = '12345678-1234-1234-1234-123456789012' + const randomUUIDSpy = vi.spyOn(globalThis.crypto, 'randomUUID').mockReturnValue(uuid) + + const client = new ExtensionServerClient() + + expect(client.id).toBe(uuid) + expect(randomUUIDSpy).toHaveBeenCalled() + + randomUUIDSpy.mockRestore() + }) + + test('falls back to Math.random for the client id when crypto.randomUUID is not available', () => { + const originalCrypto = globalThis.crypto + delete (globalThis as any).crypto + + const client = new ExtensionServerClient() + + expect(client.id).toBeDefined() + expect(client.id.length).toBeLessThanOrEqual(10) + + globalThis.crypto = originalCrypto + }) }) describe('on()', () => { diff --git a/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.ts b/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.ts index 507bfb5df73..913a1596430 100644 --- a/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.ts +++ b/packages/ui-extensions-server-kit/src/ExtensionServerClient/ExtensionServerClient.ts @@ -32,7 +32,11 @@ export class ExtensionServerClient implements ExtensionServer.Client { private uiExtensionsByUuid: Record = {} constructor(options: DeepPartial = {}) { - this.id = (Math.random() + 1).toString(36).substring(7) + // Use a cryptographically secure random number generator if available to avoid predictable IDs + this.id = + typeof globalThis.crypto?.randomUUID === 'function' + ? globalThis.crypto.randomUUID() + : (Math.random() + 1).toString(36).substring(7) this.options = getValidatedOptions({ ...options, connection: {