diff --git a/package-lock.json b/package-lock.json index b41b5e2..ed96231 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ }, "devDependencies": { "@types/jest": "^26.0.13", + "@types/mime-types": "2.1.4", "form-data": "^4.0.0", "genversion": "^3.0.1", "husky": "^4.3.0", @@ -1315,6 +1316,12 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "node_modules/@types/mime-types": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", + "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", + "dev": true + }, "node_modules/@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", @@ -7936,6 +7943,12 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "@types/mime-types": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", + "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", + "dev": true + }, "@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", diff --git a/package.json b/package.json index 139cffd..7e3c5dd 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ }, "devDependencies": { "@types/jest": "^26.0.13", + "@types/mime-types": "2.1.4", "form-data": "^4.0.0", "genversion": "^3.0.1", "husky": "^4.3.0", diff --git a/src/packages/StorageFileApi.ts b/src/packages/StorageFileApi.ts index b44a320..34b2f0a 100644 --- a/src/packages/StorageFileApi.ts +++ b/src/packages/StorageFileApi.ts @@ -1,6 +1,7 @@ import { isStorageError, StorageError, StorageUnknownError } from '../lib/errors' import { Fetch, get, head, post, remove } from '../lib/fetch' import { recursiveToCamel, resolveFetch } from '../lib/helpers' +import { lookup } from 'mime-types' import { FileObject, FileOptions, @@ -169,6 +170,12 @@ export default class StorageFileApi { return this.uploadOrUpdate('POST', path, fileBody, fileOptions) } + private _getExpectedContentType(path: string): string { + const extension = path.split('.').pop() || '' + const mimeType = lookup(extension) + return mimeType || '' + } + /** * Upload a file with a token generated from `createSignedUploadUrl`. * @param path The file path, including the file name. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload. @@ -205,7 +212,15 @@ export default class StorageFileApi { } else { body = fileBody headers['cache-control'] = `max-age=${options.cacheControl}` + + const expectedContentType = this._getExpectedContentType(path) headers['content-type'] = options.contentType as string + + if (headers['content-type'] !== expectedContentType) { + throw new StorageError( + `Content-type mismatch. Expected: "${expectedContentType}", but received: "${headers['content-type']}" for file "${path}"` + ) + } } const res = await this.fetch(url.toString(), {