fix: replace unguarded crypto.randomUUID() with safe generateUUID() utility

This commit is contained in:
Linus Rath
2026-04-02 14:51:21 +02:00
parent 1bdc51dcc7
commit c4673acb65
14 changed files with 38 additions and 25 deletions
+2 -3
View File
@@ -1,4 +1,5 @@
import type { CalendarEvent, CalendarParticipant } from '@/lib/jmap/types';
import { generateUUID } from '@/lib/utils';
export interface ParticipantInfo {
id: string;
@@ -104,9 +105,7 @@ export function buildParticipantMap(
): Record<string, Partial<CalendarParticipant>> {
const participants: Record<string, Partial<CalendarParticipant>> = {};
const generateId = () => typeof crypto !== 'undefined' && crypto.randomUUID
? crypto.randomUUID()
: `p-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
const generateId = () => generateUUID();
participants[generateId()] = {
'@type': 'Participant',
+4 -2
View File
@@ -5,6 +5,8 @@
* All line endings are CRLF per RFC 5322.
*/
import { generateUUID } from '@/lib/utils';
const CRLF = '\r\n';
export interface MimeAttachment {
@@ -43,7 +45,7 @@ export function buildMimeMessage(input: MimeMessageInput): Uint8Array {
// BCC is intentionally omitted from the MIME headers per RFC 5322
lines.push(formatHeader('Subject', encodeHeaderValue(input.subject)));
lines.push(formatHeader('Date', formatDate(input.date ?? new Date())));
lines.push(formatHeader('Message-ID', input.messageId ?? `<${crypto.randomUUID()}@smime.local>`));
lines.push(formatHeader('Message-ID', input.messageId ?? `<${generateUUID()}@smime.local>`));
if (input.inReplyTo) {
lines.push(formatHeader('In-Reply-To', input.inReplyTo));
}
@@ -245,7 +247,7 @@ export function wrapCmsAsSmimeMessage(cmsBlob: Blob | ArrayBuffer | Uint8Array,
}
lines.push(formatHeader('Subject', encodeHeaderValue(input.subject)));
lines.push(formatHeader('Date', formatDate(input.date ?? new Date())));
lines.push(formatHeader('Message-ID', input.messageId ?? `<${crypto.randomUUID()}@smime.local>`));
lines.push(formatHeader('Message-ID', input.messageId ?? `<${generateUUID()}@smime.local>`));
if (input.inReplyTo) {
lines.push(formatHeader('In-Reply-To', input.inReplyTo));
}
+2 -1
View File
@@ -1,5 +1,6 @@
import * as asn1js from 'asn1js';
import * as pkijs from 'pkijs';
import { generateUUID } from '@/lib/utils';
import {
extractCertificateInfo,
classifyCapabilities,
@@ -154,7 +155,7 @@ export async function importPkcs12(
const email = certInfo.emailAddresses[0] ?? '';
const keyRecord: SmimeKeyRecord = {
id: crypto.randomUUID(),
id: generateUUID(),
email: email.toLowerCase(),
certificate: leafCertDer,
certificateChain: chainCertsDer,
+2 -1
View File
@@ -1,6 +1,7 @@
import DOMPurify from 'dompurify';
import type { EmailTemplate } from './template-types';
import { BUILT_IN_PLACEHOLDERS } from './template-types';
import { generateUUID } from './utils';
const PLACEHOLDER_REGEX = /\{\{(\w+)\}\}/g;
const MAX_TEMPLATE_NAME_LENGTH = 200;
@@ -149,7 +150,7 @@ export function importTemplates(json: string): ImportResult {
const recipients = t.defaultRecipients as Record<string, unknown> | undefined;
templates.push({
id: crypto.randomUUID(),
id: generateUUID(),
name: sanitizeText(t.name),
subject: sanitizeText(t.subject),
body: sanitizeText(t.body),
+7
View File
@@ -7,6 +7,13 @@ export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export function generateUUID(): string {
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
}
export function formatDate(date: Date | string): string {
const d = typeof date === "string" ? new Date(date) : date;
const now = new Date();
+2 -1
View File
@@ -1,4 +1,5 @@
import type { ContactCard, NameComponent, ContactOnlineService, AnniversaryDate, PartialDate } from "@/lib/jmap/types";
import { generateUUID } from "@/lib/utils";
// Convert RFC 9553 AnniversaryDate (PartialDate|Timestamp|string) to vCard date string
function anniversaryDateToVcardString(date: AnniversaryDate): string {
@@ -153,7 +154,7 @@ export function parseVCard(vcfString: string): ContactCard[] {
}
function buildContact(raw: Record<string, string[]>): ContactCard | null {
const id = `import-${crypto.randomUUID()}`;
const id = `import-${generateUUID()}`;
const card: ContactCard = { id, addressBookIds: {} };
for (const [fullKey, values] of Object.entries(raw)) {