Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
1 line
12 KiB
Plaintext
1 line
12 KiB
Plaintext
{"version":3,"sources":["../../src/uploads/checkFileRestrictions.ts"],"sourcesContent":["import { fileTypeFromBuffer } from 'file-type'\n\nimport type { checkFileRestrictionsParams, FileAllowList } from './types.js'\n\nimport { ValidationError } from '../errors/index.js'\nimport { validateMimeType } from '../utilities/validateMimeType.js'\nimport { validatePDF } from '../utilities/validatePDF.js'\nimport { detectSvgFromXml } from './detectSvgFromXml.js'\nimport { getFileTypeFallback } from './getFileTypeFallback.js'\nimport { validateSvg } from './validateSvg.js'\n\n/**\n * Restricted file types and their extensions.\n */\nexport const RESTRICTED_FILE_EXT_AND_TYPES: FileAllowList = [\n { extensions: ['exe', 'dll'], mimeType: 'application/x-msdownload' },\n { extensions: ['exe', 'com', 'app', 'action'], mimeType: 'application/x-executable' },\n { extensions: ['bat', 'cmd'], mimeType: 'application/x-msdos-program' },\n { extensions: ['exe', 'com'], mimeType: 'application/x-ms-dos-executable' },\n { extensions: ['dmg'], mimeType: 'application/x-apple-diskimage' },\n { extensions: ['deb'], mimeType: 'application/x-debian-package' },\n { extensions: ['rpm'], mimeType: 'application/x-redhat-package-manager' },\n { extensions: ['exe', 'dll'], mimeType: 'application/vnd.microsoft.portable-executable' },\n { extensions: ['msi'], mimeType: 'application/x-msi' },\n { extensions: ['jar', 'ear', 'war'], mimeType: 'application/java-archive' },\n { extensions: ['desktop'], mimeType: 'application/x-desktop' },\n { extensions: ['cpl'], mimeType: 'application/x-cpl' },\n { extensions: ['lnk'], mimeType: 'application/x-ms-shortcut' },\n { extensions: ['pkg'], mimeType: 'application/x-apple-installer' },\n { extensions: ['htm', 'html', 'shtml', 'xhtml'], mimeType: 'text/html' },\n { extensions: ['php', 'phtml'], mimeType: 'application/x-httpd-php' },\n { extensions: ['js', 'jse'], mimeType: 'text/javascript' },\n { extensions: ['jsp'], mimeType: 'application/x-jsp' },\n { extensions: ['py'], mimeType: 'text/x-python' },\n { extensions: ['rb'], mimeType: 'text/x-ruby' },\n { extensions: ['pl'], mimeType: 'text/x-perl' },\n { extensions: ['ps1', 'psc1', 'psd1', 'psh', 'psm1'], mimeType: 'application/x-powershell' },\n { extensions: ['vbe', 'vbs'], mimeType: 'application/x-vbscript' },\n { extensions: ['ws', 'wsc', 'wsf', 'wsh'], mimeType: 'application/x-ms-wsh' },\n { extensions: ['scr'], mimeType: 'application/x-msdownload' },\n { extensions: ['asp', 'aspx'], mimeType: 'application/x-asp' },\n { extensions: ['hta'], mimeType: 'application/x-hta' },\n { extensions: ['reg'], mimeType: 'application/x-registry' },\n { extensions: ['url'], mimeType: 'application/x-url' },\n { extensions: ['workflow'], mimeType: 'application/x-workflow' },\n { extensions: ['command'], mimeType: 'application/x-command' },\n]\n\nexport const checkFileRestrictions = async ({\n collection,\n file,\n req,\n}: checkFileRestrictionsParams): Promise<void> => {\n const errors: string[] = []\n const { upload: uploadConfig } = collection\n const useTempFiles = req?.payload?.config?.upload?.useTempFiles ?? false\n const configMimeTypes =\n uploadConfig &&\n typeof uploadConfig === 'object' &&\n 'mimeTypes' in uploadConfig &&\n Array.isArray(uploadConfig.mimeTypes)\n ? uploadConfig.mimeTypes\n : []\n\n const allowRestrictedFileTypes =\n uploadConfig && typeof uploadConfig === 'object' && 'allowRestrictedFileTypes' in uploadConfig\n ? (uploadConfig as { allowRestrictedFileTypes?: boolean }).allowRestrictedFileTypes\n : false\n\n const expectsDetectableType = (mimeType: string): boolean => {\n const textBasedTypes = ['/svg', 'image/svg+xml', 'image/x-xbitmap', 'image/x-xpixmap']\n\n if (textBasedTypes.includes(mimeType)) {\n return false\n }\n\n return (\n mimeType.startsWith('image/') ||\n mimeType.startsWith('video/') ||\n mimeType.startsWith('audio/') ||\n mimeType === 'application/pdf'\n )\n }\n\n // Skip validation if `allowRestrictedFileTypes` is true\n if (allowRestrictedFileTypes) {\n return\n }\n\n // Secondary mimetype check to assess file type from buffer\n if (configMimeTypes.length > 0) {\n let detected = await fileTypeFromBuffer(file.data)\n const typeFromExtension = file.name.split('.').pop() || ''\n\n // Handle SVG files that are detected as XML due to <?xml declarations\n if (\n detected?.mime === 'application/xml' &&\n configMimeTypes.some(\n (type) => type.includes('image/') && (type.includes('svg') || type === 'image/*'),\n )\n ) {\n const isSvg = detectSvgFromXml(file.data)\n if (isSvg) {\n detected = { ext: 'svg' as any, mime: 'image/svg+xml' as any }\n }\n }\n\n if (!detected && !useTempFiles) {\n const mimeTypeFromExtension = getFileTypeFallback(file.name).mime\n const extIsValid = validateMimeType(mimeTypeFromExtension, configMimeTypes)\n\n if (!extIsValid) {\n errors.push(\n `File type ${mimeTypeFromExtension} (from extension ${typeFromExtension}) is not allowed.`,\n )\n } else {\n // SVG security check (text-based files not detectable by buffer)\n if (typeFromExtension.toLowerCase() === 'svg') {\n const isSafeSvg = validateSvg(file.data)\n if (!isSafeSvg) {\n errors.push('SVG file contains potentially harmful content.')\n }\n }\n\n // PDF validation\n if (mimeTypeFromExtension === 'application/pdf') {\n const isValidPDF = validatePDF(file.data)\n if (!isValidPDF) {\n errors.push('Invalid or corrupted PDF file.')\n }\n }\n }\n\n if (expectsDetectableType(mimeTypeFromExtension)) {\n req.payload.logger.warn(\n `File buffer returned no detectable MIME type for ${file.name}. Falling back to extension-based validation.`,\n )\n }\n }\n\n const passesMimeTypeCheck = detected?.mime && validateMimeType(detected.mime, configMimeTypes)\n\n if (passesMimeTypeCheck && detected?.mime === 'application/pdf') {\n const isValidPDF = validatePDF(file?.data)\n if (!isValidPDF) {\n errors.push('Invalid PDF file.')\n }\n }\n\n if (detected && !passesMimeTypeCheck) {\n errors.push(`Invalid MIME type: ${detected.mime}.`)\n }\n } else {\n const isRestricted = RESTRICTED_FILE_EXT_AND_TYPES.some((type) => {\n const hasRestrictedExt = type.extensions.some((ext) => file.name.toLowerCase().endsWith(ext))\n const hasRestrictedMime = type.mimeType === file.mimetype\n return hasRestrictedExt || hasRestrictedMime\n })\n if (isRestricted) {\n errors.push(\n `File type '${file.mimetype}' not allowed ${file.name}: Restricted file type detected -- set 'allowRestrictedFileTypes' to true to skip this check for this Collection.`,\n )\n }\n }\n\n if (errors.length > 0) {\n req.payload.logger.error(errors.join(', '))\n throw new ValidationError({\n errors: [{ message: errors.join(', '), path: 'file' }],\n })\n }\n}\n"],"names":["fileTypeFromBuffer","ValidationError","validateMimeType","validatePDF","detectSvgFromXml","getFileTypeFallback","validateSvg","RESTRICTED_FILE_EXT_AND_TYPES","extensions","mimeType","checkFileRestrictions","collection","file","req","errors","upload","uploadConfig","useTempFiles","payload","config","configMimeTypes","Array","isArray","mimeTypes","allowRestrictedFileTypes","expectsDetectableType","textBasedTypes","includes","startsWith","length","detected","data","typeFromExtension","name","split","pop","mime","some","type","isSvg","ext","mimeTypeFromExtension","extIsValid","push","toLowerCase","isSafeSvg","isValidPDF","logger","warn","passesMimeTypeCheck","isRestricted","hasRestrictedExt","endsWith","hasRestrictedMime","mimetype","error","join","message","path"],"mappings":"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"} |