Created
December 17, 2021 14:50
-
-
Save multipliedtwice/d60fd9a640f9a7123f182e35169b6ea4 to your computer and use it in GitHub Desktop.
Base64 to File async with Nodejs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as fs from 'fs'; | |
import * as path from 'path'; | |
const base64regex: RegExp = /^data:([A-Za-z-+\/]+);base64,(.+)$/; | |
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | |
const defaultFileOptions = { filePath: './uploads', types: ['jpg', 'jpeg', 'png'], randomizeFileNameLength: 10 }; | |
const typesArrayToRegex = async (types: string[]) => { | |
const typesToString = await Promise.all( | |
types.map((type, index) => (index === types.length - 1 ? `${type}` : `${type}|`)), | |
); | |
const regex = new RegExp(`/(?<=\S+)\.(${typesToString})/gi`); | |
return regex; | |
}; | |
const decodeBase64 = async (base64: string) => { | |
const matches = base64.match(base64regex); | |
if (!matches || matches.length !== 3) { | |
return null; | |
} | |
return { type: matches[1], buffer: Buffer.from(matches[2], 'base64') }; | |
}; | |
const fileTypeControl = async (base64Type: string, types: string[]) => { | |
if (types.length === 0) return true; | |
const validateRegex = await typesArrayToRegex(types); | |
return validateRegex.test(base64Type); | |
}; | |
const createRandomFileName = async (randomizeFileNameLength: number, fileExtention: string) => { | |
let result = ''; | |
const charactersLength = characters.length; | |
for (let i = 0; i < randomizeFileNameLength; i++) { | |
result += characters.charAt(Math.floor(Math.random() * charactersLength)); | |
} | |
return `${result}.${fileExtention}`; | |
}; | |
const writeBase64ToDisk = async (base64Buffer: Buffer, options: any) => { | |
let { fileName } = options; | |
const { randomizeFileNameLength, fileExtention, filePath } = options; | |
try { | |
fileName = fileName | |
? `${fileName}.${fileExtention}` | |
: await createRandomFileName(randomizeFileNameLength, fileExtention); | |
if (fs.statSync(path.resolve(filePath)).isDirectory()) { | |
await fs.promises.writeFile(path.resolve(filePath, fileName), base64Buffer, { encoding: 'base64' }); | |
return { status: true, data: fileName, message: 'File created.' }; | |
} | |
return { status: false, data: null, message: 'No such file or directory' }; | |
} catch (e: any) { | |
if (e.code === 'ENOENT') { | |
return { status: false, data: null, message: 'No such file or directory' }; | |
} else { | |
return { status: false, data: null, message: e.message }; | |
} | |
} | |
}; | |
export default async ( | |
base64: string, | |
options: { | |
types?: string[]; | |
fileName?: string; | |
randomizeFileNameLength?: number; | |
filePath?: string; | |
fileMaxSize?: number; | |
} | null, | |
) => { | |
try { | |
options = Object.assign({}, defaultFileOptions, options); | |
const decodedBase64 = await decodeBase64(base64); | |
if (!decodedBase64) { | |
return new Error('Invalid base64 string!') | |
} | |
if (options.fileMaxSize && decodedBase64.buffer.toString().length > options.fileMaxSize) { | |
return new Error('File too large!') | |
} | |
if (options.types && !fileTypeControl(decodedBase64.type, options.types)) { | |
return new Error('Invalid file type!') | |
} | |
const createdFile = await writeBase64ToDisk(decodedBase64.buffer, { | |
...options, | |
fileExtention: decodedBase64.type.split('/')[1], | |
}); | |
if (createdFile.status) { | |
return createdFile.data | |
} else { | |
return new Error(createdFile.message); | |
} | |
} catch (e: any) { | |
return new Error(e.message); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment