diff --git a/src/client/Main.ts b/src/client/Main.ts index e1fdb6e7d..0d48e939d 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -11,6 +11,7 @@ import { HostLobbyModal as HostPrivateLobbyModal } from "./HostLobbyModal"; import { JoinPrivateLobbyModal } from "./JoinPrivateLobbyModal"; import { generateID } from "../core/Util"; import { initializeLogSender } from "./LogSender"; +import { generateCryptoRandomUUID } from "./Utils"; @@ -126,14 +127,14 @@ export function getPersistentIDFromCookie(): string { } // If no cookie exists, create new ID and set cookie - const newId = crypto.randomUUID() // Using built-in UUID generator + const newID = generateCryptoRandomUUID() document.cookie = [ - `${COOKIE_NAME}=${newId}`, + `${COOKIE_NAME}=${newID}`, `max-age=${5 * 365 * 24 * 60 * 60}`, // 5 years 'path=/', 'SameSite=Strict', 'Secure' ].join(';') - return newId + return newID } diff --git a/src/client/Utils.ts b/src/client/Utils.ts index c88ea87fd..8bbb05b6a 100644 --- a/src/client/Utils.ts +++ b/src/client/Utils.ts @@ -34,4 +34,33 @@ export function createCanvas(): HTMLCanvasElement { return canvas } +/** + * A polyfill for crypto.randomUUID that provides fallback implementations + * for older browsers, particularly Safari versions < 15.4 + */ +export function generateCryptoRandomUUID(): string { + // Type guard to check if randomUUID is available + if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) { + return crypto.randomUUID(); + } + // Fallback using crypto.getRandomValues + if (typeof crypto !== 'undefined' && 'getRandomValues' in crypto) { + return ([1e7] as any + -1e3 + -4e3 + -8e3 + -1e11).replace( + /[018]/g, + (c: number): string => + (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4)).toString(16) + ); + } + + // Last resort fallback using Math.random + // Note: This is less cryptographically secure but ensures functionality + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace( + /[xy]/g, + (c: string): string => { + const r: number = Math.random() * 16 | 0; + const v: number = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + } + ); +} \ No newline at end of file