mirror of
				https://github.com/DumbWareio/DumbDrop.git
				synced 2025-11-03 21:43:26 +00:00 
			
		
		
		
	feat: Enhance folder upload handling and filename sanitation
- Added support for checking webkitRelativePath in folder uploads, alerting users if their browser does not support this feature. - Introduced sanitizePathPreserveDirs function to sanitize filenames while preserving directory structure. - Updated upload route to utilize the new sanitation function and ensure consistent folder naming during uploads. Fixes #45
This commit is contained in:
		@@ -516,6 +516,15 @@
 | 
			
		||||
            // Reset the input to allow selecting the same folder again
 | 
			
		||||
            const input = e.target;
 | 
			
		||||
            files = [...input.files];
 | 
			
		||||
            // Check for webkitRelativePath support
 | 
			
		||||
            const missingRelPath = files.some(f => !('webkitRelativePath' in f) || !f.webkitRelativePath);
 | 
			
		||||
            if (missingRelPath) {
 | 
			
		||||
                alert('Your browser does not support folder uploads with structure. Please use a modern browser like Chrome or Edge.');
 | 
			
		||||
                files = [];
 | 
			
		||||
                updateFileList();
 | 
			
		||||
                input.value = '';
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            console.log('Folder selection files:', files.map(f => ({
 | 
			
		||||
                name: f.name,
 | 
			
		||||
                path: f.webkitRelativePath,
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ const crypto = require('crypto');
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const { config } = require('../config');
 | 
			
		||||
const logger = require('../utils/logger');
 | 
			
		||||
const { getUniqueFilePath, getUniqueFolderPath, sanitizeFilename } = require('../utils/fileUtils');
 | 
			
		||||
const { getUniqueFilePath, getUniqueFolderPath, sanitizeFilename, sanitizePathPreserveDirs } = require('../utils/fileUtils');
 | 
			
		||||
const { sendNotification } = require('../services/notifications');
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
const { cleanupIncompleteUploads } = require('../utils/cleanup');
 | 
			
		||||
@@ -174,8 +174,8 @@ router.post('/init', async (req, res) => {
 | 
			
		||||
    // Update batch activity
 | 
			
		||||
    batchActivity.set(batchId, Date.now());
 | 
			
		||||
 | 
			
		||||
    // Sanitize filename and convert to forward slashes
 | 
			
		||||
    const sanitizedFilename = sanitizeFilename(filename);
 | 
			
		||||
    // Sanitize filename and convert to forward slashes, preserving directory structure
 | 
			
		||||
    const sanitizedFilename = sanitizePathPreserveDirs(filename);
 | 
			
		||||
    const safeFilename = path.normalize(sanitizedFilename)
 | 
			
		||||
      .replace(/^(\.\.(\/|\\|$))+/, '')
 | 
			
		||||
      .replace(/\\/g, '/')
 | 
			
		||||
@@ -205,35 +205,36 @@ router.post('/init', async (req, res) => {
 | 
			
		||||
      const pathParts = safeFilename.split('/').filter(Boolean); // Remove empty parts
 | 
			
		||||
      
 | 
			
		||||
      if (pathParts.length > 1) {
 | 
			
		||||
        // Handle files within folders
 | 
			
		||||
        // The first part is the root folder name from the client
 | 
			
		||||
        const originalFolderName = pathParts[0];
 | 
			
		||||
        const folderPath = path.join(config.uploadDir, originalFolderName);
 | 
			
		||||
        // Always use a consistent mapping for this batch to avoid collisions
 | 
			
		||||
        // This ensures all files in the batch go into the same (possibly renamed) root folder
 | 
			
		||||
        let newFolderName = folderMappings.get(`${originalFolderName}-${batchId}`);
 | 
			
		||||
        
 | 
			
		||||
        const folderPath = path.join(config.uploadDir, newFolderName || originalFolderName);
 | 
			
		||||
        if (!newFolderName) {
 | 
			
		||||
          try {
 | 
			
		||||
            // First ensure parent directories exist
 | 
			
		||||
            // Ensure parent directories exist
 | 
			
		||||
            await fs.promises.mkdir(path.dirname(folderPath), { recursive: true });
 | 
			
		||||
            // Then try to create the target folder
 | 
			
		||||
            // Try to create the target folder
 | 
			
		||||
            await fs.promises.mkdir(folderPath, { recursive: false });
 | 
			
		||||
            newFolderName = originalFolderName;
 | 
			
		||||
          } catch (err) {
 | 
			
		||||
            if (err.code === 'EEXIST') {
 | 
			
		||||
              // If the folder exists, generate a unique folder name for this batch
 | 
			
		||||
              const uniqueFolderPath = await getUniqueFolderPath(folderPath);
 | 
			
		||||
              newFolderName = path.basename(uniqueFolderPath);
 | 
			
		||||
              logger.info(`Folder "${originalFolderName}" exists, using "${newFolderName}"`);
 | 
			
		||||
              logger.info(`Folder "${originalFolderName}" exists, using "${newFolderName}" for batch ${batchId}`);
 | 
			
		||||
            } else {
 | 
			
		||||
              throw err;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          
 | 
			
		||||
          // Store the mapping for this batch
 | 
			
		||||
          folderMappings.set(`${originalFolderName}-${batchId}`, newFolderName);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Always apply the mapping for this batch
 | 
			
		||||
        pathParts[0] = newFolderName;
 | 
			
		||||
        filePath = path.join(config.uploadDir, ...pathParts);
 | 
			
		||||
        
 | 
			
		||||
        // Ensure all parent directories exist
 | 
			
		||||
        // Ensure all parent directories exist for the file
 | 
			
		||||
        await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -165,11 +165,20 @@ function sanitizeFilename(fileName) {
 | 
			
		||||
  return sanitized;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sanitizePathPreserveDirs(filePath) {
 | 
			
		||||
  // Split on forward slashes, sanitize each part, and rejoin
 | 
			
		||||
  return filePath
 | 
			
		||||
    .split('/')
 | 
			
		||||
    .map(part => sanitizeFilename(part))
 | 
			
		||||
    .join('/');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  formatFileSize,
 | 
			
		||||
  calculateDirectorySize,
 | 
			
		||||
  ensureDirectoryExists,
 | 
			
		||||
  getUniqueFilePath,
 | 
			
		||||
  getUniqueFolderPath,
 | 
			
		||||
  sanitizeFilename
 | 
			
		||||
  sanitizeFilename,
 | 
			
		||||
  sanitizePathPreserveDirs
 | 
			
		||||
}; 
 | 
			
		||||
		Reference in New Issue
	
	Block a user