fix: resolve build failures, security issues, and architectural improvements
Critical Fixes: - Remove missing sw_combine.js from prebuild script and all documentation - Remove missing test-safety-check.sh from test:all script - Add build:web:build alias to fix docker commands - Fix syntax errors in validate-critical-files.sh script Security: - Fix Electron path traversal vulnerability in export-data-to-downloads handler - Sanitize file names using basename() to prevent directory traversal - Enforce allowed file extensions (.json, .txt, .csv, .md, .log) - Add validation for empty names, path separators, and length limits Architecture Improvements: - Add queue size guard to CapacitorPlatformService (max 1000 operations) - Fail-fast when queue is full to prevent memory exhaustion - Add warning at 80% capacity - Add getQueueTelemetry() method for monitoring queue health - Track peak queue size for diagnostics - Standardize environment variable usage in PlatformServiceFactory - Prefer import.meta.env.VITE_PLATFORM (standard Vite pattern) - Maintain backward compatibility with process.env fallback Documentation: - Clarify PWA status: remove misleading VitePWA comments - Update BUILDING.md to reflect removed sw_combine.js step - Update build-arch-guard.sh to remove sw_combine.js from protected files All changes maintain backward compatibility and improve code quality.
This commit is contained in:
@@ -6,7 +6,7 @@ import electronIsDev from 'electron-is-dev';
|
||||
import unhandled from 'electron-unhandled';
|
||||
// import { autoUpdater } from 'electron-updater';
|
||||
import { promises as fs } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { join, basename } from 'path';
|
||||
|
||||
import { ElectronCapacitorApp, setupContentSecurityPolicy, setupReloadWatcher } from './setup';
|
||||
|
||||
@@ -151,15 +151,47 @@ app.on('activate', async function () {
|
||||
* This provides a secure, native way to save files directly to the Downloads
|
||||
* directory using the main process's file system access.
|
||||
*
|
||||
* Security: File names are sanitized to prevent path traversal attacks.
|
||||
* Only safe file extensions are allowed (.json, .txt, .csv, .md).
|
||||
*
|
||||
* @param fileName - The name of the file to save (including extension)
|
||||
* @param data - The data to write to the file (string or buffer)
|
||||
* @returns Promise<{success: boolean, path?: string, error?: string}>
|
||||
*/
|
||||
ipcMain.handle('export-data-to-downloads', async (_event, fileName: string, data: string) => {
|
||||
try {
|
||||
// Security: Sanitize file name to prevent path traversal
|
||||
// 1. Extract only the basename (removes any directory components)
|
||||
const sanitizedBaseName = basename(fileName);
|
||||
|
||||
// 2. Reject if still contains path separators (shouldn't happen after basename, but double-check)
|
||||
if (sanitizedBaseName.includes('/') || sanitizedBaseName.includes('\\')) {
|
||||
throw new Error('Invalid file name: path separators not allowed');
|
||||
}
|
||||
|
||||
// 3. Enforce allowed file extensions for security
|
||||
const allowedExtensions = ['.json', '.txt', '.csv', '.md', '.log'];
|
||||
const hasAllowedExtension = allowedExtensions.some(ext =>
|
||||
sanitizedBaseName.toLowerCase().endsWith(ext.toLowerCase())
|
||||
);
|
||||
|
||||
if (!hasAllowedExtension) {
|
||||
throw new Error(`Invalid file extension. Allowed: ${allowedExtensions.join(', ')}`);
|
||||
}
|
||||
|
||||
// 4. Additional validation: reject empty or suspicious names
|
||||
if (!sanitizedBaseName || sanitizedBaseName.trim().length === 0) {
|
||||
throw new Error('File name cannot be empty');
|
||||
}
|
||||
|
||||
// 5. Reject names that are too long (prevent potential filesystem issues)
|
||||
if (sanitizedBaseName.length > 255) {
|
||||
throw new Error('File name too long (max 255 characters)');
|
||||
}
|
||||
|
||||
// Get the user's Downloads directory path
|
||||
const downloadsDir = app.getPath('downloads');
|
||||
const filePath = join(downloadsDir, fileName);
|
||||
const filePath = join(downloadsDir, sanitizedBaseName);
|
||||
|
||||
// Write the file to the Downloads directory
|
||||
await fs.writeFile(filePath, data, 'utf-8');
|
||||
|
||||
Reference in New Issue
Block a user