fix: fix crypto.randomUUID crash (#573)

This commit is contained in:
Abhishek 2026-07-23 11:39:32 +05:30 committed by GitHub
parent c0559fed88
commit 69572e1d9a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 60 additions and 3 deletions

View file

@ -21,6 +21,7 @@ import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Textarea } from "@/components/ui/textarea";
import { createUuid } from "@/lib/uuid";
import {
type ContextDestinationRouteRow,
@ -397,7 +398,7 @@ export function TransferCallToolConfig({
onClick={() => onContextDestinationRoutesChange([
...contextDestinationRoutes,
{
id: crypto.randomUUID(),
id: createUuid(),
context_value: "",
destination: "",
},

View file

@ -43,6 +43,7 @@ import { TOOL_DOCUMENTATION_URLS } from "@/constants/documentation";
import { useOrgConfig } from "@/context/OrgConfigContext";
import { detailFromError } from "@/lib/apiError";
import { useAuth } from "@/lib/auth";
import { createUuid } from "@/lib/uuid";
import {
type ContextDestinationRouteRow,
@ -248,7 +249,7 @@ export default function ToolDetailPage() {
setTransferContextDestinationRoutes(
(config.context_mapping?.routes || []).map((route) => ({
...route,
id: crypto.randomUUID(),
id: createUuid(),
}))
);
setTransferFallbackDestination(

View file

@ -15,6 +15,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { NODE_DOCUMENTATION_URLS } from "@/constants/documentation";
import { useAppConfig } from "@/context/AppConfigContext";
import { cn } from "@/lib/utils";
import { createUuid } from "@/lib/uuid";
import { resolveWebhookBaseUrl } from "@/lib/webhookUrl";
import { NodeContent } from "./common/NodeContent";
@ -517,7 +518,7 @@ export const GenericNode = memo(({ data, selected, id, type }: GenericNodeProps)
useEffect(() => {
if (type !== "trigger") return;
if (data.trigger_path) return;
const newPath = crypto.randomUUID();
const newPath = createUuid();
handleSaveNodeData({ ...data, trigger_path: newPath });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [type]);

28
ui/src/lib/uuid.test.ts Normal file
View file

@ -0,0 +1,28 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { createUuid } from "./uuid";
describe("createUuid", () => {
afterEach(() => {
vi.unstubAllGlobals();
});
it("uses crypto.randomUUID when it is available", () => {
const randomUUID = vi.fn(() => "27f3a42d-0eb3-43b1-a539-d4d09dd9065e");
vi.stubGlobal("crypto", { randomUUID });
expect(createUuid()).toBe("27f3a42d-0eb3-43b1-a539-d4d09dd9065e");
expect(randomUUID).toHaveBeenCalledOnce();
});
it("creates a version 4 UUID when crypto.randomUUID is unavailable", () => {
const getRandomValues = vi.fn((bytes: Uint8Array) => {
bytes.fill(0);
return bytes;
});
vi.stubGlobal("crypto", { getRandomValues });
expect(createUuid()).toBe("00000000-0000-4000-8000-000000000000");
expect(getRandomValues).toHaveBeenCalledOnce();
});
});

26
ui/src/lib/uuid.ts Normal file
View file

@ -0,0 +1,26 @@
export function createUuid(): string {
const webCrypto = globalThis.crypto;
if (typeof webCrypto?.randomUUID === "function") {
return webCrypto.randomUUID();
}
if (typeof webCrypto?.getRandomValues !== "function") {
throw new Error("Secure random number generation is unavailable");
}
const bytes = webCrypto.getRandomValues(new Uint8Array(16));
// Mark the generated value as an RFC 4122 version 4 UUID.
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
return [
hex.slice(0, 4).join(""),
hex.slice(4, 6).join(""),
hex.slice(6, 8).join(""),
hex.slice(8, 10).join(""),
hex.slice(10, 16).join(""),
].join("-");
}