Skip to content

Commit 3036823

Browse files
committed
fix: replace crypto.randomUUID() with HTTP-compatible implementation
crypto.randomUUID() is only available in secure contexts (HTTPS or localhost), causing errors when running Docker containers over plain HTTP. Use crypto.getRandomValues() with RFC 4122 UUID v4 generation which works in all contexts. Falls back to Math.random() for very old browsers. Updated: - clipboard.ts: Added generateUUID() helper - Keys.tsx: Use generateUUID() instead of crypto.randomUUID()
1 parent 409c6ea commit 3036823

2 files changed

Lines changed: 35 additions & 7 deletions

File tree

packages/frontend/src/lib/clipboard.ts

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/**
2-
* Clipboard utility that handles secure and non-secure contexts.
2+
* Clipboard and crypto utility that handles secure and non-secure contexts.
33
*
4-
* The Clipboard API (navigator.clipboard) is only available in secure contexts
5-
* (HTTPS or localhost). In non-secure HTTP contexts, we fall back to
6-
* document.execCommand('copy') which also won't work, so we properly
7-
* detect availability and provide feedback.
4+
* The Clipboard API (navigator.clipboard) and crypto.randomUUID() are only available
5+
* in secure contexts (HTTPS or localhost). In non-secure HTTP contexts, we provide
6+
* fallbacks that work everywhere.
87
*/
98

109
/**
@@ -49,3 +48,32 @@ export const copyToClipboard = async (text: string): Promise<boolean> => {
4948
return false;
5049
}
5150
};
51+
52+
/**
53+
* Generate a UUID v4 using crypto.getRandomValues().
54+
* Works in both secure (HTTPS) and non-secure (HTTP) contexts.
55+
* Falls back to Math.random() if crypto is unavailable.
56+
*/
57+
export const generateUUID = (): string => {
58+
// Use crypto.getRandomValues if available (works in all contexts including HTTP)
59+
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
60+
const bytes = new Uint8Array(16);
61+
crypto.getRandomValues(bytes);
62+
63+
// Set version (4) and variant (2) bits per RFC 4122
64+
bytes[6] = (bytes[6] & 0x0f) | 0x40; // Version 4
65+
bytes[8] = (bytes[8] & 0x3f) | 0x80; // Variant 10
66+
67+
// Convert to hex string with dashes
68+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
69+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
70+
}
71+
72+
// Fallback to Math.random() - not cryptographically secure but sufficient for API keys
73+
// when running in very old browsers without crypto support
74+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
75+
const r = (Math.random() * 16) | 0;
76+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
77+
return v.toString(16);
78+
});
79+
};

packages/frontend/src/pages/Keys.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
BarChart3,
2323
} from 'lucide-react';
2424
import { formatNumber, formatCost } from '../lib/format';
25-
import { isClipboardAvailable, copyToClipboard } from '../lib/clipboard';
25+
import { isClipboardAvailable, copyToClipboard, generateUUID } from '../lib/clipboard';
2626

2727
const EMPTY_KEY: KeyConfig = {
2828
key: '',
@@ -252,7 +252,7 @@ export const Keys = () => {
252252
};
253253

254254
const generateKey = () => {
255-
const uuid = crypto.randomUUID();
255+
const uuid = generateUUID();
256256
setEditingKey({ ...editingKey, secret: `sk-${uuid}` });
257257
};
258258

0 commit comments

Comments
 (0)