( file: File, )
| 72 | }; |
| 73 | |
| 74 | export const verifyFileSignature = async ( |
| 75 | file: File, |
| 76 | ): Promise<{isValid: boolean; detectedType: string | null}> => { |
| 77 | try { |
| 78 | const buffer = await file.slice(0, 16).arrayBuffer(); |
| 79 | const bytes = new Uint8Array(buffer); |
| 80 | |
| 81 | // PNG signature |
| 82 | if ( |
| 83 | bytes[0] === 0x89 && |
| 84 | bytes[1] === 0x50 && |
| 85 | bytes[2] === 0x4e && |
| 86 | bytes[3] === 0x47 |
| 87 | ) { |
| 88 | return {isValid: true, detectedType: 'png'}; |
| 89 | } |
| 90 | |
| 91 | // JPEG signature |
| 92 | if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) { |
| 93 | return {isValid: true, detectedType: 'jpg'}; |
| 94 | } |
| 95 | |
| 96 | // WEBP signature |
| 97 | if ( |
| 98 | bytes[0] === 0x52 && |
| 99 | bytes[1] === 0x49 && |
| 100 | bytes[2] === 0x46 && |
| 101 | bytes[3] === 0x46 && |
| 102 | bytes[8] === 0x57 && |
| 103 | bytes[9] === 0x45 && |
| 104 | bytes[10] === 0x42 && |
| 105 | bytes[11] === 0x50 |
| 106 | ) { |
| 107 | return {isValid: true, detectedType: 'webp'}; |
| 108 | } |
| 109 | |
| 110 | // AVIF signature |
| 111 | if ( |
| 112 | bytes[4] === 0x66 && |
| 113 | bytes[5] === 0x74 && |
| 114 | bytes[6] === 0x79 && |
| 115 | bytes[7] === 0x70 && |
| 116 | bytes[8] === 0x61 && |
| 117 | bytes[9] === 0x76 && |
| 118 | bytes[10] === 0x69 && |
| 119 | bytes[11] === 0x66 |
| 120 | ) { |
| 121 | return {isValid: true, detectedType: 'avif'}; |
| 122 | } |
| 123 | |
| 124 | // QOI signature |
| 125 | if ( |
| 126 | bytes[0] === 0x71 && |
| 127 | bytes[1] === 0x6f && |
| 128 | bytes[2] === 0x69 && |
| 129 | bytes[3] === 0x66 |
| 130 | ) { |
| 131 | return {isValid: true, detectedType: 'qoi'}; |
no outgoing calls
no test coverage detected