mirror of
				https://github.com/CorentinTh/it-tools.git
				synced 2025-11-04 05:53:25 +00: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:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							ca43a25569
						
					
				
				
					commit
					043e4f0a08
				
			
							
								
								
									
										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 { extension as getExtensionFromMime } from 'mime-types';
 | 
				
			||||||
import type { Ref } from 'vue';
 | 
					import type { Ref } from 'vue';
 | 
				
			||||||
 | 
					import _ from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function getFileExtensionFromBase64({
 | 
					export { getMimeTypeFromBase64, useDownloadFileFromBase64 };
 | 
				
			||||||
  base64String,
 | 
					
 | 
				
			||||||
 | 
					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',
 | 
					  defaultExtension = 'txt',
 | 
				
			||||||
}: {
 | 
					}: {
 | 
				
			||||||
  base64String: string
 | 
					  mimeType: string | undefined
 | 
				
			||||||
  defaultExtension?: string
 | 
					  defaultExtension?: string
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  const hasMimeType = base64String.match(/data:(.*?);base64/i);
 | 
					  if (mimeType) {
 | 
				
			||||||
 | 
					    return getExtensionFromMime(mimeType) ?? defaultExtension;
 | 
				
			||||||
  if (hasMimeType) {
 | 
					 | 
				
			||||||
    return getExtensionFromMime(hasMimeType[1]) || defaultExtension;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return defaultExtension;
 | 
					  return defaultExtension;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useDownloadFileFromBase64({ source, filename }: { source: Ref<string>; filename?: string }) {
 | 
					function useDownloadFileFromBase64({ source, filename }: { source: Ref<string>; filename?: string }) {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    download() {
 | 
					    download() {
 | 
				
			||||||
      const base64String = source.value;
 | 
					      if (source.value === '') {
 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (base64String === '') {
 | 
					 | 
				
			||||||
        throw new Error('Base64 string is empty');
 | 
					        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');
 | 
					      const a = document.createElement('a');
 | 
				
			||||||
      a.href = base64String;
 | 
					      a.href = base64String;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user