mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 18:10:18 +05:30
fix(security): address supply-chain + resource-leak findings
- PdfFontHeader: use mkdtempSync for exclusive temp dir; caller unlinks after pandoc consumes (cleanup wired into exportWithPandoc callback) - download-tools: pin FiraCode to immutable release v6.2 with SHA-256 digests verified before atomic rename; refuse download on mismatch - Vendor missing FiraCode-Bold.ttf + JetBrainsMono-Regular.ttf
This commit is contained in:
@@ -4,6 +4,14 @@ const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Build a xelatex/lualatex fontspec header referencing the bundled TTF.
|
||||
*
|
||||
* Uses an exclusive temp directory (mkdtempSync) to avoid the racy
|
||||
* Date.now()+pid filename pattern. Returns the directory along with the
|
||||
* header path; callers MUST `unlinkSync(headerPath)` and `rmdirSync(dir)`
|
||||
* after pandoc consumes the file.
|
||||
*/
|
||||
function buildPdfFontHeader(settings, ttfPath, fontFamily) {
|
||||
if (!ttfPath || !fs.existsSync(ttfPath)) {
|
||||
throw new Error(`PdfFontHeader: TTF not found at ${ttfPath}`);
|
||||
@@ -21,9 +29,10 @@ function buildPdfFontHeader(settings, ttfPath, fontFamily) {
|
||||
` Scale = 0.9]`,
|
||||
`{${fontFamily}}`,
|
||||
].filter(Boolean);
|
||||
const headerPath = path.join(os.tmpdir(), `monospace-pdf-${Date.now()}-${process.pid}.tex`);
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'mono-pdf-'));
|
||||
const headerPath = path.join(dir, 'monospace.tex');
|
||||
fs.writeFileSync(headerPath, lines.join('\n'), 'utf-8');
|
||||
return { headerPath, familyName: fontFamily };
|
||||
return { headerPath, dir, familyName: fontFamily };
|
||||
}
|
||||
|
||||
module.exports = { buildPdfFontHeader };
|
||||
|
||||
+20
-2
@@ -1600,14 +1600,16 @@ function performExportWithOptions(format, options) {
|
||||
// active monospace font (xelatex fontspec) so ASCII art renders
|
||||
// identically across machines.
|
||||
const monoCtx = getActiveMonospaceContext();
|
||||
let monoPdfHeaderDir = null;
|
||||
if (monoCtx.ttf) {
|
||||
try {
|
||||
const { headerPath } = buildPdfFontHeader(
|
||||
const built = buildPdfFontHeader(
|
||||
monoCtx.settings,
|
||||
monoCtx.ttf,
|
||||
MonospaceFontConfig.getActiveFamily(monoCtx.settings)
|
||||
);
|
||||
pandocCmd += ` --include-in-header="${headerPath}"`;
|
||||
pandocCmd += ` --include-in-header="${built.headerPath}"`;
|
||||
monoPdfHeaderDir = built.dir;
|
||||
} catch (e) {
|
||||
console.error('[monospace] PDF header build failed (non-fatal):', e.message);
|
||||
}
|
||||
@@ -1869,6 +1871,19 @@ function showExportSuccess(outputFile) {
|
||||
// Helper function to export with pandoc (general) - uses runPandocCmd for safety
|
||||
function exportWithPandoc(pandocCmd, outputFile, format) {
|
||||
console.log(`Executing Pandoc command: ${pandocCmd}`);
|
||||
// Track the temp directory (if any) created by buildPdfFontHeader so we can
|
||||
// clean it up after pandoc finishes — regardless of success or failure.
|
||||
const headerDirMatch = pandocCmd.match(/--include-in-header="([^"]+)"/);
|
||||
const monoPdfHeaderDir = headerDirMatch ? path.dirname(headerDirMatch[1]) : null;
|
||||
const cleanupMonoHeader = () => {
|
||||
if (monoPdfHeaderDir && monoPdfHeaderDir.includes('mono-pdf-')) {
|
||||
try {
|
||||
fs.rmSync(monoPdfHeaderDir, { recursive: true, force: true });
|
||||
} catch (_) {
|
||||
/* best-effort cleanup */
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
runPandocCmd(pandocCmd, async (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
@@ -1971,6 +1986,9 @@ function exportWithPandoc(pandocCmd, outputFile, format) {
|
||||
// Headers/footers are applied only for DOCX format
|
||||
|
||||
showExportSuccess(outputFile);
|
||||
cleanupMonoHeader();
|
||||
} else {
|
||||
cleanupMonoHeader();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user