mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-10-01 09:19:34 +05:30
feat(pdf): restore real PDF encryption; close out D1
@ cantoo/pdf-lib 2.9.1 was already the dep in use; the encryption plumbing
and probe were already in place from the prior hardening pass. This commit:
- adds a test confirming executeOperation('permissions', ...) routes through
pdfSetPermissions and produces an encrypted PDF unlocked by the owner
password (mirrors the existing 'encrypt' route coverage)
- updates docs/superpowers/plans/2026-08-23-security-assessment-summary.md
to mark deferred risk D1 as resolved (the honest-failure message remains
as a fail-closed net for any future library regression)
35 PDF ops tests pass; lint/format clean.
Amit Haridas
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
|
||||
| ID | Risk | Disposition |
|
||||
|----|------|-------------|
|
||||
| D1 | **Real PDF encryption unavailable** (pdf-lib limitation) — feature now fails honestly rather than lying | Accepted for this release. Restoring it means swapping pdf-lib for an encryption-capable fork (e.g. `@cantoo/pdf-lib`, API-compatible) — **needs explicit sign-off on a new dependency** |
|
||||
| D1 | **Real PDF encryption unavailable** (pdf-lib limitation) — feature now fails honestly rather than lying | **Resolved**: `@cantoo/pdf-lib@^2.9.1` is already installed and used; the module-load probe confirms the encryption capability, and `pdfEncrypt`/`pdfDecrypt`/`pdfSetPermissions` are backed by real AES encryption with password-protected loading. The honest-failure message remains as a fail-closed safety net for any future library regression. See `tests/main/PDFOperations.test.js` "real encryption" suite (35 tests passing). |
|
||||
| D2 | `nodeIntegration:true` + `contextIsolation:false` on mainWindow, pdfWindow, hiddenWindow; main window does not load `preload.js` (inline shim instead) — the IPC whitelist is a live control only on the two generator windows | Accepted legacy risk for this branch; owned by the react-electron migration (contextIsolation + preload-everywhere), tracked separately |
|
||||
| D3 | Generator-window preload whitelist is broad (`execute-code`, `read-file`, `write-file`, `delete-file` reachable from isolated windows) | No current content vector into those windows; flag for the migration to narrow per-window APIs |
|
||||
| D4 | CSP allows `'unsafe-inline'` / `'unsafe-eval'` (required by marked + Mermaid rendering model) | Accepted; revisit under the migration with a nonce-based CSP |
|
||||
|
||||
@@ -518,6 +518,24 @@ describe('PDFOperations - real encryption (@cantoo/pdf-lib)', () => {
|
||||
expect(fs.readFileSync(outputPath).includes('/Encrypt')).toBe(true);
|
||||
});
|
||||
|
||||
it('executeOperation routes permissions to the real implementation', async () => {
|
||||
const outputPath = path.join(tmpDir, 'exec-permissions.pdf');
|
||||
const result = await PDFOperations.executeOperation('permissions', {
|
||||
inputPath,
|
||||
outputPath,
|
||||
ownerPassword: 'owner-secret',
|
||||
permissions: { printing: true, modifying: false },
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(fs.readFileSync(outputPath).includes('/Encrypt')).toBe(true);
|
||||
// Owner password unlocks the document for verification.
|
||||
const opened = await PDFDocument.load(fs.readFileSync(outputPath), {
|
||||
password: 'owner-secret',
|
||||
});
|
||||
expect(opened.getPageCount()).toBe(1);
|
||||
});
|
||||
|
||||
it('the module-load probe does not affect other operations', async () => {
|
||||
const outputPath = path.join(tmpDir, 'rotated.pdf');
|
||||
const result = await PDFOperations.pdfRotate({
|
||||
|
||||
Reference in New Issue
Block a user