feat: improve batch ID generation and validation for file uploads

- Add batch ID validation function with specific format requirements
- Generate more secure and unique batch IDs using timestamp and random string
- Update client-side batch ID generation to create consistent, unique identifiers
- Enhance upload initialization route to validate batch ID before processing
- Modify FileUploader to use generated batch ID during uploads
This commit is contained in:
Greirson Lee-Thorp
2025-02-03 16:56:30 -08:00
parent dac7143a19
commit 140d58cdc3
2 changed files with 27 additions and 7 deletions

View File

@@ -61,9 +61,15 @@
const MAX_RETRIES = 3;
const RETRY_DELAY = 1000;
// Utility function to generate a unique batch ID
function generateBatchId() {
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
class FileUploader {
constructor(file) {
constructor(file, batchId) {
this.file = file;
this.batchId = batchId;
this.uploadId = null;
this.position = 0;
this.progressElement = null;
@@ -90,7 +96,7 @@
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Batch-ID': this.file.batchId || Date.now().toString()
'X-Batch-ID': this.batchId
},
body: JSON.stringify({
filename: uploadPath,
@@ -233,7 +239,7 @@
// Helper function to process directory entries
async function getAllFileEntries(dataTransferItems) {
let fileEntries = [];
const batchId = Date.now().toString();
const batchId = generateBatchId();
async function traverseEntry(entry, path = '') {
if (entry.isFile) {
@@ -317,7 +323,7 @@
}
function handleFolders(e) {
const batchId = Date.now().toString();
const batchId = generateBatchId();
files = [...e.target.files];
files.forEach(file => {
const pathParts = file.webkitRelativePath.split('/');
@@ -361,11 +367,13 @@
document.getElementById('uploadProgress').innerHTML = '';
const groupedItems = groupFilesByFolder(files);
const batchId = generateBatchId(); // Generate a single batch ID for all files
const results = await Promise.all(
groupedItems.map(async item => {
let success = true;
for (const file of item.files) {
const uploader = new FileUploader(file);
const uploader = new FileUploader(file, batchId);
if (!await uploader.start()) {
success = false;
}

View File

@@ -251,10 +251,22 @@ function getUniqueFolderPath(folderPath) {
return newPath;
}
// Validate batch ID format
function isValidBatchId(batchId) {
// Batch ID should be in format: timestamp-randomstring
return /^\d+-[a-z0-9]{9}$/.test(batchId);
}
// Routes
app.post('/upload/init', async (req, res) => {
const { filename, fileSize } = req.body;
const batchId = req.headers['x-batch-id'] || Date.now().toString();
const batchId = req.headers['x-batch-id'];
// Validate batch ID
if (!batchId || !isValidBatchId(batchId)) {
log.error('Invalid or missing batch ID');
return res.status(400).json({ error: 'Invalid or missing batch ID' });
}
const safeFilename = path.normalize(filename).replace(/^(\.\.(\/|\\|$))+/, '');
@@ -268,7 +280,7 @@ app.post('/upload/init', async (req, res) => {
});
}
const uploadId = Date.now().toString();
const uploadId = crypto.randomBytes(16).toString('hex');
let filePath = path.join(uploadDir, safeFilename);
try {