( file: File, )
| 188 | }; |
| 189 | |
| 190 | export const validateAndSanitizeFile = async ( |
| 191 | file: File, |
| 192 | ): Promise<File | null> => { |
| 193 | const {isValid, detectedType} = await verifyFileSignature(file); |
| 194 | |
| 195 | if (!isValid) { |
| 196 | console.warn(`[Security] Rejected file "${file.name}": Invalid signature.`); |
| 197 | return null; |
| 198 | } |
| 199 | |
| 200 | const ext = file.name.split('.').pop()?.toLowerCase() || ''; |
| 201 | const isJpeg = detectedType === 'jpg' && (ext === 'jpg' || ext === 'jpeg'); |
| 202 | const isPng = detectedType === 'png' && ext === 'png'; |
| 203 | const isWebp = detectedType === 'webp' && ext === 'webp'; |
| 204 | const isAvif = detectedType === 'avif' && ext === 'avif'; |
| 205 | const isQoi = detectedType === 'qoi' && ext === 'qoi'; |
| 206 | const isJxl = detectedType === 'jxl' && ext === 'jxl'; |
| 207 | const isGif = detectedType === 'gif' && ext === 'gif'; |
| 208 | const isSvg = detectedType === 'svg' && ext === 'svg'; |
| 209 | |
| 210 | if ( |
| 211 | !isJpeg && |
| 212 | !isPng && |
| 213 | !isWebp && |
| 214 | !isAvif && |
| 215 | !isQoi && |
| 216 | !isJxl && |
| 217 | !isGif && |
| 218 | !isSvg |
| 219 | ) { |
| 220 | console.warn( |
| 221 | `[Security] Rejected file "${file.name}": Extension (.${ext}) does not match detected content (${detectedType}).`, |
| 222 | ); |
| 223 | return null; |
| 224 | } |
| 225 | |
| 226 | if (isSvg) { |
| 227 | return await sanitizeSvg(file); |
| 228 | } |
| 229 | |
| 230 | return file; |
| 231 | }; |
no test coverage detected