For anyone looking out to create password protected zip file in NextJS (compatible with NodeJS as well) server side, please refer this :
You can place this code under api folder in NextJS
import { NextApiRequest, NextApiResponse } from 'next';
import formidable from 'formidable';
import { join } from 'path';
import { spawn } from 'child_process';
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
return new Promise<void>((resolve, reject) => {
try {
const form = new formidable.IncomingForm();
form.parse(req, async (err, fields, files) => {
if (err) {
console.error('Error parsing form data:', err);
res.status(500).json({ error: 'Failed to parse form data' });
reject(err);
return;
}
const password: string = fields.password.toString();
const myFile = fields.myFile;
if (!myFile) {
res.status(400).json({ error: 'File not found in request' });
return;
}
// Decode the Base64 string into a buffer
const fileBuffer = Buffer.from(Array.isArray(myFile) ? myFile[0] : myFile, 'base64');
// Save the file buffer to a temporary file
const tempFilePath = join(process.cwd(), 'zippedFiles', 'temp_file');
require('fs').writeFileSync(tempFilePath, fileBuffer);
// Create a password-protected zip using the `zip` command with `-j` flag
// `-j` flag will store just the file, not the directories
const zipFilePath = join(process.cwd(), 'zippedFiles', 'protected.zip');
const zipProcess = spawn('zip', ['-j', '-P', password, zipFilePath, tempFilePath]);
zipProcess.on('exit', (code) => {
if (code === 0) {
// Zip file creation successful
res.status(200).json({ zipPath: 'protected.zip' });
resolve();
} else {
// Zip file creation failed
console.error('Error creating password-protected zip file');
res.status(500).json({ error: 'Failed to create zip file' });
reject(new Error('Failed to create zip file'));
}
// Delete the temporary file
require('fs').unlinkSync(tempFilePath);
});
});
} catch (error) {
console.error('Error generating password-protected zip:', error);
res.status(500).json({ error: 'Failed to generate zip file' });
reject(error);
}
});
}
I am also providing sample client side code for end to end implementation
import axios from 'axios';
const createPasswordProtectedZip = async (selectedFile: File, password: string) => {
let data = undefined
const base64Data = await readFileAsBase64(selectedFile);
const formData = new FormData();
formData.append('myFile', base64Data);
formData.append('password', password);
data = await axios.post('/api/download-zip', formData).then((res: any) => {
console.log('File response:', res.data);
return res.data
}).catch((e: any) => {
console.log('File error:', e);
return undefined
});
return data
};
const readFileAsBase64 = (file: File) => {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
const result = reader.result;
if (typeof result === 'string') {
const base64Data = result.split(',')[1];
if (base64Data) {
resolve(base64Data);
} else {
reject(new Error('Failed to read the file.'));
}
} else {
reject(new Error('Failed to read the file.'));
}
};
reader.onerror = (error) => {
reject(error);
};
reader.readAsDataURL(file);
});
};
export default createPasswordProtectedZip;
Please note that I am using typescript.