From 44e40508520eb8a5ebfa8886bd3ebfdfe3a1cfa0 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Sat, 1 Aug 2026 19:56:36 +0800 Subject: [PATCH] fix(driver): support installation over insecure HTTP --- .../components/config/DriverStoreDialog.vue | 11 +++++----- .../connection/ConnectionDialog.vue | 2 +- .../src/lib/common/__tests__/utils.spec.ts | 22 +++++++++++++++++++ .../driverInstallOperationId.test.ts | 19 ++++++++++++++++ 4 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 apps/desktop/src/lib/common/__tests__/utils.spec.ts create mode 100644 packages/app-tests/driverInstallOperationId.test.ts diff --git a/apps/desktop/src/components/config/DriverStoreDialog.vue b/apps/desktop/src/components/config/DriverStoreDialog.vue index d6e794fa1..1947f04da 100644 --- a/apps/desktop/src/components/config/DriverStoreDialog.vue +++ b/apps/desktop/src/components/config/DriverStoreDialog.vue @@ -13,6 +13,7 @@ import DriverInstallProgressCircle from "@/components/config/DriverInstallProgre import DatabaseIcon from "@/components/icons/DatabaseIcon.vue"; import { useToast } from "@/composables/useToast"; import { isTauriRuntime } from "@/lib/backend/tauriRuntime"; +import { uuid } from "@/lib/common/utils"; import { countAvailableDriverUpdates } from "@/lib/connection/agentDriverUpdateBadge"; import type { JdbcDriverInfo, JdbcLocalBundleInfo, JdbcMavenBundleInfo, JdbcPluginStatus } from "@/types/database"; import * as api from "@/lib/backend/api"; @@ -465,7 +466,7 @@ async function installDriver(dbType: string) { async function runDriverInstall(dbType: string) { const label = driverLabel(dbType); installing.value = dbType; - activeAgentOperationId.value = crypto.randomUUID(); + activeAgentOperationId.value = uuid(); resetAgentInstallProgress(); try { if (isPrestoSqlBuiltinDriver(dbType)) { @@ -509,7 +510,7 @@ async function runQueuedDriverInstalls() { async function upgradeAll() { upgradingAll.value = true; - activeAgentOperationId.value = crypto.randomUUID(); + activeAgentOperationId.value = uuid(); upgradingCompletedCount.value = 0; queuedDriverInstalls.value = []; resetAgentInstallProgress(); @@ -623,7 +624,7 @@ async function importOfflineZip() { } if (!selected) return; importingZip.value = true; - activeAgentOperationId.value = crypto.randomUUID(); + activeAgentOperationId.value = uuid(); resetAgentInstallProgress(); try { const count = await api.importAgentsFromZip(selected, activeAgentOperationId.value); @@ -655,7 +656,7 @@ async function importDriverFile(driver: AgentDriverInfo) { const isWindows = navigator.userAgent.toLowerCase().includes("windows"); const installSelectedFile = async (selected: string | File) => { if (isOfflineDriverPackage(selected)) { - activeAgentOperationId.value = crypto.randomUUID(); + activeAgentOperationId.value = uuid(); resetAgentInstallProgress(); try { const count = await api.importAgentsFromZip(selected, activeAgentOperationId.value); @@ -701,7 +702,7 @@ async function importDriverFile(driver: AgentDriverInfo) { async function reinstallJre(jreKey: string) { reinstallingJre.value = jreKey; - activeAgentOperationId.value = crypto.randomUUID(); + activeAgentOperationId.value = uuid(); resetAgentInstallProgress(); try { await api.reinstallJre(jreKey, activeAgentOperationId.value); diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index f577b79a4..c570d8441 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -1482,7 +1482,7 @@ async function refreshLocalAgentDrivers(): Promise { } function beginAgentDriverInstall(driverKey: string, label: string) { - agentInstallOperationId.value = crypto.randomUUID(); + agentInstallOperationId.value = uuid(); agentInstallDriverKey.value = driverKey; agentInstallLabel.value = label; agentInstallProgress.value = null; diff --git a/apps/desktop/src/lib/common/__tests__/utils.spec.ts b/apps/desktop/src/lib/common/__tests__/utils.spec.ts new file mode 100644 index 000000000..abc72e22e --- /dev/null +++ b/apps/desktop/src/lib/common/__tests__/utils.spec.ts @@ -0,0 +1,22 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; +import { uuid } from "@/lib/common/utils"; + +describe("uuid", () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it("uses crypto.randomUUID when available", () => { + const randomUUID = vi.fn(() => "123e4567-e89b-42d3-a456-426614174000"); + vi.stubGlobal("crypto", { randomUUID }); + + expect(uuid()).toBe("123e4567-e89b-42d3-a456-426614174000"); + expect(randomUUID).toHaveBeenCalledOnce(); + }); + + it("generates a UUID when crypto.randomUUID is unavailable", () => { + vi.stubGlobal("crypto", {}); + + expect(uuid()).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/); + }); +}); diff --git a/packages/app-tests/driverInstallOperationId.test.ts b/packages/app-tests/driverInstallOperationId.test.ts new file mode 100644 index 000000000..1b5c5fe30 --- /dev/null +++ b/packages/app-tests/driverInstallOperationId.test.ts @@ -0,0 +1,19 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import path from "node:path"; +import { test } from "vitest"; + +function source(relativePath: string): string { + return readFileSync(path.resolve(relativePath), "utf8"); +} + +test("driver installation operation IDs support insecure HTTP contexts", () => { + const driverStore = source("apps/desktop/src/components/config/DriverStoreDialog.vue"); + const connectionDialog = source("apps/desktop/src/components/connection/ConnectionDialog.vue"); + + assert.match(driverStore, /import \{ uuid \} from "@\/lib\/common\/utils"/); + assert.doesNotMatch(driverStore, /crypto\.randomUUID\(\)/); + assert.match(driverStore, /activeAgentOperationId\.value = uuid\(\)/); + assert.doesNotMatch(connectionDialog, /crypto\.randomUUID\(\)/); + assert.match(connectionDialog, /agentInstallOperationId\.value = uuid\(\)/); +});