mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-04-24 08:46:15 -04:00
fix(base64-file-converter): fix downloading of index.html content without data preambula (#750)
* fix(base64-file-converter): fix downloading of index.html content without data preambula * feat(base64-file-converter): infer mime type from base64 signature --------- Co-authored-by: akharlov <harl_aa@skbkontur.ru>
This commit is contained in:
parent
ca43a25569
commit
043e4f0a08
2 changed files with 72 additions and 12 deletions
32
src/composable/downloadBase64.test.ts
Normal file
32
src/composable/downloadBase64.test.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { getMimeTypeFromBase64 } from './downloadBase64';
|
||||
|
||||
describe('downloadBase64', () => {
|
||||
describe('getMimeTypeFromBase64', () => {
|
||||
it('when the base64 string has a data URI, it returns the mime type', () => {
|
||||
expect(getMimeTypeFromBase64({ base64String: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA' })).to.deep.equal({ mimeType: 'image/png' });
|
||||
expect(getMimeTypeFromBase64({ base64String: 'data:image/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA' })).to.deep.equal({ mimeType: 'image/jpg' });
|
||||
});
|
||||
|
||||
it('when the base64 string has no data URI, it try to infer the mime type from the signature', () => {
|
||||
// https://en.wikipedia.org/wiki/List_of_file_signatures
|
||||
|
||||
// PNG
|
||||
expect(getMimeTypeFromBase64({ base64String: 'iVBORw0KGgoAAAANSUhEUgAAAAUA' })).to.deep.equal({ mimeType: 'image/png' });
|
||||
|
||||
// GIF
|
||||
expect(getMimeTypeFromBase64({ base64String: 'R0lGODdh' })).to.deep.equal({ mimeType: 'image/gif' });
|
||||
expect(getMimeTypeFromBase64({ base64String: 'R0lGODlh' })).to.deep.equal({ mimeType: 'image/gif' });
|
||||
|
||||
// JPG
|
||||
expect(getMimeTypeFromBase64({ base64String: '/9j/' })).to.deep.equal({ mimeType: 'image/jpg' });
|
||||
|
||||
// PDF
|
||||
expect(getMimeTypeFromBase64({ base64String: 'JVBERi0' })).to.deep.equal({ mimeType: 'application/pdf' });
|
||||
});
|
||||
|
||||
it('when the base64 string has no data URI and no signature, it returns an undefined mimeType', () => {
|
||||
expect(getMimeTypeFromBase64({ base64String: 'JVBERi' })).to.deep.equal({ mimeType: undefined });
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,32 +1,60 @@
|
|||
import { extension as getExtensionFromMime } from 'mime-types';
|
||||
import type { Ref } from 'vue';
|
||||
import _ from 'lodash';
|
||||
|
||||
function getFileExtensionFromBase64({
|
||||
base64String,
|
||||
export { getMimeTypeFromBase64, useDownloadFileFromBase64 };
|
||||
|
||||
const commonMimeTypesSignatures = {
|
||||
'JVBERi0': 'application/pdf',
|
||||
'R0lGODdh': 'image/gif',
|
||||
'R0lGODlh': 'image/gif',
|
||||
'iVBORw0KGgo': 'image/png',
|
||||
'/9j/': 'image/jpg',
|
||||
};
|
||||
|
||||
function getMimeTypeFromBase64({ base64String }: { base64String: string }) {
|
||||
const [,mimeTypeFromBase64] = base64String.match(/data:(.*?);base64/i) ?? [];
|
||||
|
||||
if (mimeTypeFromBase64) {
|
||||
return { mimeType: mimeTypeFromBase64 };
|
||||
}
|
||||
|
||||
const inferredMimeType = _.find(commonMimeTypesSignatures, (_mimeType, signature) => base64String.startsWith(signature));
|
||||
|
||||
if (inferredMimeType) {
|
||||
return { mimeType: inferredMimeType };
|
||||
}
|
||||
|
||||
return { mimeType: undefined };
|
||||
}
|
||||
|
||||
function getFileExtensionFromMimeType({
|
||||
mimeType,
|
||||
defaultExtension = 'txt',
|
||||
}: {
|
||||
base64String: string
|
||||
mimeType: string | undefined
|
||||
defaultExtension?: string
|
||||
}) {
|
||||
const hasMimeType = base64String.match(/data:(.*?);base64/i);
|
||||
|
||||
if (hasMimeType) {
|
||||
return getExtensionFromMime(hasMimeType[1]) || defaultExtension;
|
||||
if (mimeType) {
|
||||
return getExtensionFromMime(mimeType) ?? defaultExtension;
|
||||
}
|
||||
|
||||
return defaultExtension;
|
||||
}
|
||||
|
||||
export function useDownloadFileFromBase64({ source, filename }: { source: Ref<string>; filename?: string }) {
|
||||
function useDownloadFileFromBase64({ source, filename }: { source: Ref<string>; filename?: string }) {
|
||||
return {
|
||||
download() {
|
||||
const base64String = source.value;
|
||||
|
||||
if (base64String === '') {
|
||||
if (source.value === '') {
|
||||
throw new Error('Base64 string is empty');
|
||||
}
|
||||
|
||||
const cleanFileName = filename ?? `file.${getFileExtensionFromBase64({ base64String })}`;
|
||||
const { mimeType } = getMimeTypeFromBase64({ base64String: source.value });
|
||||
const base64String = mimeType
|
||||
? source.value
|
||||
: `data:text/plain;base64,${source.value}`;
|
||||
|
||||
const cleanFileName = filename ?? `file.${getFileExtensionFromMimeType({ mimeType })}`;
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = base64String;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue