diff --git a/apps/sim/app/api/tools/google_vault/download-export-file/route.ts b/apps/sim/app/api/tools/google_vault/download-export-file/route.ts index e33e362d7..01bdfd3f5 100644 --- a/apps/sim/app/api/tools/google_vault/download-export-file/route.ts +++ b/apps/sim/app/api/tools/google_vault/download-export-file/route.ts @@ -15,7 +15,6 @@ const logger = createLogger('GoogleVaultDownloadExportFileAPI') const GoogleVaultDownloadExportFileSchema = z.object({ accessToken: z.string().min(1, 'Access token is required'), - matterId: z.string().min(1, 'Matter ID is required'), bucketName: z.string().min(1, 'Bucket name is required'), objectName: z.string().min(1, 'Object name is required'), fileName: z.string().optional().nullable(), diff --git a/apps/sim/app/api/tools/onedrive/upload/route.ts b/apps/sim/app/api/tools/onedrive/upload/route.ts index 63d50ae73..8919b528c 100644 --- a/apps/sim/app/api/tools/onedrive/upload/route.ts +++ b/apps/sim/app/api/tools/onedrive/upload/route.ts @@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server' import * as XLSX from 'xlsx' import { z } from 'zod' import { checkInternalAuth } from '@/lib/auth/hybrid' +import { validateMicrosoftGraphId } from '@/lib/core/security/input-validation' import { secureFetchWithValidation } from '@/lib/core/security/input-validation.server' import { generateRequestId } from '@/lib/core/utils/request' import { RawFileInputSchema } from '@/lib/uploads/utils/file-schemas' @@ -57,28 +58,6 @@ interface ExcelRangeData { values?: unknown[][] } -/** Validates Microsoft Graph item IDs (alphanumeric with some special chars) */ -function validateMicrosoftGraphId( - id: string, - paramName: string -): { isValid: boolean; error?: string } { - // Microsoft Graph IDs are typically alphanumeric, may include hyphens and exclamation marks - const validIdPattern = /^[a-zA-Z0-9!-]+$/ - if (!validIdPattern.test(id)) { - return { - isValid: false, - error: `Invalid ${paramName}: contains invalid characters`, - } - } - if (id.length > 256) { - return { - isValid: false, - error: `Invalid ${paramName}: exceeds maximum length`, - } - } - return { isValid: true } -} - export async function POST(request: NextRequest) { const requestId = generateRequestId() diff --git a/apps/sim/tools/microsoft_teams/server-utils.ts b/apps/sim/tools/microsoft_teams/server-utils.ts index 55d530f6e..18372d421 100644 --- a/apps/sim/tools/microsoft_teams/server-utils.ts +++ b/apps/sim/tools/microsoft_teams/server-utils.ts @@ -117,7 +117,8 @@ export async function uploadFilesForTeamsMessage(params: { }) // Get file details for attachment reference - const fileDetailsUrl = `https://graph.microsoft.com/v1.0/me/drive/items/${uploadedFile.id}?$select=id,name,webDavUrl,eTag,size` + // Note: webDavUrl requires 'select' without the '$' prefix to be reliably returned + const fileDetailsUrl = `https://graph.microsoft.com/v1.0/me/drive/items/${uploadedFile.id}?select=id,name,webDavUrl,eTag,size` const fileDetailsResponse = await secureFetchWithValidation( fileDetailsUrl, @@ -144,13 +145,21 @@ export async function uploadFilesForTeamsMessage(params: { eTag: fileDetails.eTag, }) + // Validate webDavUrl is present (required for Teams attachment references) + if (!fileDetails.webDavUrl) { + log.error(`[${requestId}] webDavUrl missing from file details`, { fileId: uploadedFile.id }) + throw new Error( + `Failed to get file URL for attachment "${file.name}". The file was uploaded but Teams attachment reference could not be created.` + ) + } + // Create attachment reference const attachmentId = fileDetails.eTag?.match(/\{([a-f0-9-]+)\}/i)?.[1] || fileDetails.id attachments.push({ id: attachmentId, contentType: 'reference', - contentUrl: fileDetails.webDavUrl!, + contentUrl: fileDetails.webDavUrl, name: file.name, })