mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-03 02:11:07 +05:30
fix: resolve 12 critical runtime failures, security issue, and dead code
CRITICAL fixes:
- GitStatusPanel: use ipc.file.gitStage/gitCommit instead of non-existent top-level methods
- HeaderFooterDialog: use send/on channels instead of non-existent headerFooter namespace
- CodeMirrorEditor: use invoke('save-pasted-image') instead of non-existent savePastedImage
- ipc.ts: map to correct preload namespaces (git.status, git.stage, git.commit)
- Add pick-folder/pick-file to ALLOWED_SEND_CHANNELS whitelist
- Add git convenience namespace to preload (git.status/stage/commit/log/diff)
HIGH fixes:
- FindReplaceBar: replace broken match count stub with regex-based counter
- PDF export window: disable nodeIntegration, enable contextIsolation + sandbox
- Git handler: accept rootPath argument from renderer
- Add git-diff IPC handler + GitOperations.diff()
MEDIUM fixes:
- Remove 4 dead functions: checkPandocAvailable, safeExecFile, runPandoc, openPDFFile, exportWithPandocPDF
- Remove stale ODT header/footer console.log stub
- Rewrite electron.d.ts to match actual preload API shape
This commit is contained in:
@@ -41,4 +41,14 @@ async function log(dir, maxCount = 20) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getStatus, stage, commit, log };
|
||||
async function diff(dir, filePath) {
|
||||
try {
|
||||
const git = getGitInstance(dir);
|
||||
const args = filePath ? ['--', filePath] : [];
|
||||
return await git.diff(args);
|
||||
} catch (err) {
|
||||
return { error: err.message };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getStatus, stage, commit, log, diff };
|
||||
|
||||
+25
-16
@@ -4,33 +4,42 @@ const { ipcMain } = require('electron');
|
||||
const GitOperations = require('../GitOperations');
|
||||
|
||||
function register(currentFileRef) {
|
||||
ipcMain.handle('git-status', async () => {
|
||||
const dir = currentFileRef.current
|
||||
? require('path').dirname(currentFileRef.current)
|
||||
: process.cwd();
|
||||
ipcMain.handle('git-status', async (_event, rootPath) => {
|
||||
const dir =
|
||||
rootPath ||
|
||||
(currentFileRef.current ? require('path').dirname(currentFileRef.current) : process.cwd());
|
||||
return GitOperations.getStatus(dir);
|
||||
});
|
||||
|
||||
ipcMain.handle('git-stage', async (_event, { files }) => {
|
||||
const dir = currentFileRef.current
|
||||
? require('path').dirname(currentFileRef.current)
|
||||
: process.cwd();
|
||||
ipcMain.handle('git-stage', async (_event, { rootPath, files }) => {
|
||||
const dir =
|
||||
rootPath ||
|
||||
(currentFileRef.current ? require('path').dirname(currentFileRef.current) : process.cwd());
|
||||
return GitOperations.stage(dir, files);
|
||||
});
|
||||
|
||||
ipcMain.handle('git-commit', async (_event, { message }) => {
|
||||
const dir = currentFileRef.current
|
||||
? require('path').dirname(currentFileRef.current)
|
||||
: process.cwd();
|
||||
ipcMain.handle('git-commit', async (_event, { rootPath, message }) => {
|
||||
const dir =
|
||||
rootPath ||
|
||||
(currentFileRef.current ? require('path').dirname(currentFileRef.current) : process.cwd());
|
||||
return GitOperations.commit(dir, message);
|
||||
});
|
||||
|
||||
ipcMain.handle('git-log', async () => {
|
||||
const dir = currentFileRef.current
|
||||
? require('path').dirname(currentFileRef.current)
|
||||
: process.cwd();
|
||||
ipcMain.handle('git-log', async (_event, rootPath) => {
|
||||
const dir =
|
||||
rootPath ||
|
||||
(currentFileRef.current ? require('path').dirname(currentFileRef.current) : process.cwd());
|
||||
return GitOperations.log(dir);
|
||||
});
|
||||
|
||||
ipcMain.handle('git-diff', async (_event, filePath) => {
|
||||
const dir = filePath
|
||||
? require('path').dirname(filePath)
|
||||
: currentFileRef.current
|
||||
? require('path').dirname(currentFileRef.current)
|
||||
: process.cwd();
|
||||
return GitOperations.diff(dir, filePath);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { register };
|
||||
|
||||
+5
-95
@@ -57,41 +57,6 @@ function getFFmpegPath() {
|
||||
return process.platform === 'win32' ? 'ffmpeg' : 'ffmpeg';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function checkPandocAvailable() {
|
||||
return new Promise((resolve) => {
|
||||
const pandocPath = getPandocPath();
|
||||
execFile(pandocPath, ['--version'], (error) => {
|
||||
resolve(!error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe command execution using execFile (no shell injection risk)
|
||||
* @param {string} command - The command to execute
|
||||
* @param {string[]} args - Array of arguments
|
||||
* @param {object} options - Options for execFile
|
||||
* @returns {Promise<{stdout: string, stderr: string}>}
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function safeExecFile(command, args, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
execFile(
|
||||
command,
|
||||
args,
|
||||
{ maxBuffer: 10 * 1024 * 1024, ...options },
|
||||
(error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject({ error, stdout, stderr });
|
||||
} else {
|
||||
resolve({ stdout, stderr });
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// File size validation
|
||||
const MAX_FILE_SIZE_MB = 50;
|
||||
const MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024;
|
||||
@@ -134,17 +99,6 @@ function convertDataToMarkdown(content, format) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Pandoc command safely with execFile
|
||||
* @param {string[]} args - Pandoc arguments array
|
||||
* @param {Function} callback - Callback function (error, stdout, stderr)
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function runPandoc(args, callback) {
|
||||
const pandocPath = getPandocPath();
|
||||
execFile(pandocPath, args, { maxBuffer: 10 * 1024 * 1024 }, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a Pandoc command string safely using execFile
|
||||
* Parses the command string and uses execFile to prevent shell injection
|
||||
@@ -593,23 +547,6 @@ function showDependenciesDialog() {
|
||||
depsWindow.setMenuBarVisibility(false);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function openPDFFile() {
|
||||
const files = dialog.showOpenDialogSync(mainWindow, {
|
||||
properties: ['openFile'],
|
||||
filters: [{ name: 'PDF Files', extensions: ['pdf'] }],
|
||||
});
|
||||
|
||||
if (files && files[0]) {
|
||||
const stats = fs.statSync(files[0]);
|
||||
if (stats.size > MAX_FILE_SIZE) {
|
||||
dialog.showErrorBox('File Too Large', `File exceeds the ${MAX_FILE_SIZE_MB}MB size limit.`);
|
||||
return;
|
||||
}
|
||||
mainWindow.webContents.send('open-pdf-viewer', files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function openFile() {
|
||||
const files = dialog.showOpenDialogSync(mainWindow, {
|
||||
properties: ['openFile'],
|
||||
@@ -1958,42 +1895,14 @@ function exportWithPandoc(pandocCmd, outputFile, format) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add headers/footers to ODT if enabled
|
||||
if (format === 'odt' && headerFooterSettings.enabled) {
|
||||
// ODT format is similar to DOCX in structure, we could implement this
|
||||
console.log('ODT header/footer support not yet implemented');
|
||||
}
|
||||
// ODT header/footer is not supported by Pandoc's ODT output
|
||||
// Headers/footers are applied only for DOCX format
|
||||
|
||||
showExportSuccess(outputFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to export PDF with pandoc (with fallbacks) - uses runPandocCmd for safety
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function exportWithPandocPDF(pandocCmd, outputFile) {
|
||||
runPandocCmd(pandocCmd, (error, _stdout, _stderr) => {
|
||||
if (error) {
|
||||
console.log('XeLaTeX failed, trying PDFLaTeX...');
|
||||
// Fallback to pdflatex
|
||||
const fallbackCmd = pandocCmd.replace('--pdf-engine=xelatex', '--pdf-engine=pdflatex');
|
||||
runPandocCmd(fallbackCmd, (fallbackError, _fallbackStdout, _fallbackStderr) => {
|
||||
if (fallbackError) {
|
||||
console.log('PDFLaTeX failed, trying Electron PDF...');
|
||||
// Final fallback to Electron PDF
|
||||
exportToPDFElectron(outputFile);
|
||||
} else {
|
||||
console.log('Successfully exported PDF with PDFLaTeX');
|
||||
showExportSuccess(outputFile);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('Successfully exported PDF with XeLaTeX');
|
||||
showExportSuccess(outputFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Export to HTML using marked (no pandoc required)
|
||||
function exportToHTML(outputFile) {
|
||||
try {
|
||||
@@ -2219,8 +2128,9 @@ function exportToPDFElectron(outputFile) {
|
||||
const pdfWindow = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
sandbox: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user