|
1 | 1 | import {Str} from 'expensify-common'; |
2 | 2 | import {Alert, Linking, Platform} from 'react-native'; |
| 3 | +import ReactNativeBlobUtil from 'react-native-blob-util'; |
| 4 | +import type {ReactNativeBlobUtilReadStream} from 'react-native-blob-util'; |
3 | 5 | import ImageSize from 'react-native-image-size'; |
4 | 6 | import type {TupleToUnion, ValueOf} from 'type-fest'; |
5 | 7 | import DateUtils from '@libs/DateUtils'; |
@@ -272,19 +274,55 @@ function validateImageForCorruption(file: FileObject): Promise<{width: number; h |
272 | 274 |
|
273 | 275 | /** Verify file format based on the magic bytes of the file - some formats might be identified by multiple signatures */ |
274 | 276 | function verifyFileFormat({fileUri, formatSignatures}: {fileUri: string; formatSignatures: readonly string[]}) { |
275 | | - return fetch(fileUri) |
276 | | - .then((file) => file.arrayBuffer()) |
277 | | - .then((arrayBuffer) => { |
278 | | - const uintArray = new Uint8Array(arrayBuffer, 4, 12); |
| 277 | + const BYTES_TO_READ = 1028; |
279 | 278 |
|
280 | | - const hexString = Array.from(uintArray) |
| 279 | + const cleanUri = fileUri.replace('file://', ''); |
| 280 | + |
| 281 | + return ReactNativeBlobUtil.fs |
| 282 | + .readStream(cleanUri, 'base64', BYTES_TO_READ, 0) |
| 283 | + .then((stream: ReactNativeBlobUtilReadStream) => { |
| 284 | + let base64Chunk = ''; |
| 285 | + |
| 286 | + return new Promise<string>((resolve, reject) => { |
| 287 | + stream.open(); |
| 288 | + |
| 289 | + stream.onData((chunk: string | number[]) => { |
| 290 | + const chunkStr = Array.isArray(chunk) ? String.fromCharCode(...chunk) : chunk; |
| 291 | + base64Chunk += chunkStr; |
| 292 | + }); |
| 293 | + |
| 294 | + stream.onError((error: Error) => { |
| 295 | + reject(error); |
| 296 | + }); |
| 297 | + |
| 298 | + stream.onEnd(() => { |
| 299 | + resolve(base64Chunk); |
| 300 | + }); |
| 301 | + }); |
| 302 | + }) |
| 303 | + .then((base64Data: string) => { |
| 304 | + const binary = Buffer.from(base64Data, 'base64').toString('binary'); |
| 305 | + |
| 306 | + const bytes = new Uint8Array(binary.length); |
| 307 | + for (let i = 0; i < binary.length; i++) { |
| 308 | + bytes[i] = binary.charCodeAt(i); |
| 309 | + } |
| 310 | + |
| 311 | + const startIndex = Math.min(4, bytes.length); |
| 312 | + const endIndex = Math.min(16, bytes.length); |
| 313 | + const view = bytes.subarray(startIndex, endIndex); |
| 314 | + |
| 315 | + const hex = Array.from(view) |
281 | 316 | .map((b) => b.toString(16).padStart(2, '0')) |
282 | 317 | .join(''); |
283 | 318 |
|
284 | | - return hexString; |
| 319 | + return hex; |
285 | 320 | }) |
286 | | - .then((hexSignature) => { |
| 321 | + .then((hexSignature: string) => { |
287 | 322 | return formatSignatures.some((signature) => hexSignature.startsWith(signature)); |
| 323 | + }) |
| 324 | + .catch(() => { |
| 325 | + return false; |
288 | 326 | }); |
289 | 327 | } |
290 | 328 |
|
|
0 commit comments