diff --git a/packages/web/src/lib/ai-email/invoice-service.ts b/packages/web/src/lib/ai-email/invoice-service.ts index 58d8cc4d..08884882 100644 --- a/packages/web/src/lib/ai-email/invoice-service.ts +++ b/packages/web/src/lib/ai-email/invoice-service.ts @@ -9,6 +9,7 @@ import { import { eq, and } from 'drizzle-orm'; import { parseUnits } from 'viem'; import Decimal from 'decimal.js'; +import { randomBytes } from 'crypto'; /** * Invoice Service for AI Email Agent @@ -98,11 +99,13 @@ function getCurrencyDecimals(currency: string): number { } /** - * Generate a unique invoice number. + * Generate a unique invoice number using cryptographically secure random bytes. + * Uses crypto.randomBytes instead of Math.random() to prevent predictable invoice IDs. */ function generateInvoiceNumber(): string { const timestamp = Date.now().toString(36).toUpperCase(); - const random = Math.random().toString(36).substring(2, 6).toUpperCase(); + // Use cryptographically secure random bytes instead of Math.random() + const random = randomBytes(3).toString('hex').toUpperCase(); return `AI-${timestamp}-${random}`; } diff --git a/packages/web/src/lib/ai-email/workspace-mapping.ts b/packages/web/src/lib/ai-email/workspace-mapping.ts index e3f930cc..58a5f8ec 100644 --- a/packages/web/src/lib/ai-email/workspace-mapping.ts +++ b/packages/web/src/lib/ai-email/workspace-mapping.ts @@ -3,6 +3,7 @@ import { workspaces, workspaceMembers, users } from '@/db/schema'; import { eq, and, ilike } from 'drizzle-orm'; import { generateText } from 'ai'; import { createOpenAI } from '@ai-sdk/openai'; +import { randomInt } from 'crypto'; /** * Workspace Mapping for AI Email Agent @@ -413,7 +414,7 @@ Generate a unique handle:`, } } - // Fallback: Generate a random handle + // Fallback: Generate a random handle using cryptographically secure randomness const fallbackNames = [ 'alex.morgan', 'jordan.lee', @@ -424,9 +425,9 @@ Generate a unique handle:`, 'avery.wilson', 'blake.thomas', ]; - const randomName = - fallbackNames[Math.floor(Math.random() * fallbackNames.length)]; - const randomSuffix = Math.floor(Math.random() * 1000); + // Use crypto.randomInt instead of Math.random() for secure randomness + const randomName = fallbackNames[randomInt(fallbackNames.length)]; + const randomSuffix = randomInt(1000); const fallbackHandle = `ai-${randomName}${randomSuffix}`; if (!existingSet.has(fallbackHandle)) {