From e3468e3aaa74a5870dad79193c46683e49b4568b Mon Sep 17 00:00:00 2001 From: abdullahalam123 Date: Fri, 24 Oct 2025 11:37:15 +0530 Subject: [PATCH] refactor(qpdf): move initialization logic to helpers module Consolidate qpdf initialization code into helpers.ts to avoid duplication Improve error message for password protected PDFs Fortify encryption logic by auto-filling owner password when empty --- src/js/logic/change-permissions.ts | 29 ++---------------- src/js/logic/decrypt.ts | 27 +--------------- src/js/logic/encrypt.ts | 49 ++++++++---------------------- src/js/utils/helpers.ts | 31 +++++++++++++++++++ 4 files changed, 47 insertions(+), 89 deletions(-) diff --git a/src/js/logic/change-permissions.ts b/src/js/logic/change-permissions.ts index 8871044..7a42992 100644 --- a/src/js/logic/change-permissions.ts +++ b/src/js/logic/change-permissions.ts @@ -1,31 +1,6 @@ import { showLoader, hideLoader, showAlert } from '../ui.js'; -import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { downloadFile, initializeQpdf, readFileAsArrayBuffer } from '../utils/helpers.js'; import { state } from '../state.js'; -import createModule from '@neslinesli93/qpdf-wasm'; - -let qpdfInstance: any = null; - -async function initializeQpdf() { - if (qpdfInstance) { - return qpdfInstance; - } - showLoader('Initializing PDF engine...'); - try { - qpdfInstance = await createModule({ - locateFile: () => '/qpdf.wasm', - }); - } catch (error) { - console.error('Failed to initialize qpdf-wasm:', error); - showAlert( - 'Initialization Error', - 'Could not load the PDF engine. Please refresh the page and try again.' - ); - throw error; - } finally { - hideLoader(); - } - return qpdfInstance; -} export async function changePermissions() { const file = state.files[0]; @@ -156,7 +131,7 @@ export async function changePermissions() { } else { showAlert( 'Processing Failed', - `An error occurred: ${error.message || 'The PDF might be corrupted.'}` + `An error occurred: ${error.message || 'The PDF might be corrupted or password protected.'}` ); } } finally { diff --git a/src/js/logic/decrypt.ts b/src/js/logic/decrypt.ts index ed1008f..21c3cbb 100644 --- a/src/js/logic/decrypt.ts +++ b/src/js/logic/decrypt.ts @@ -1,31 +1,6 @@ import { showLoader, hideLoader, showAlert } from '../ui.js'; -import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { downloadFile, initializeQpdf, readFileAsArrayBuffer } from '../utils/helpers.js'; import { state } from '../state.js'; -import createModule from '@neslinesli93/qpdf-wasm'; - -let qpdfInstance: any = null; - -async function initializeQpdf() { - if (qpdfInstance) { - return qpdfInstance; - } - showLoader('Initializing decryption engine...'); - try { - qpdfInstance = await createModule({ - locateFile: () => '/qpdf.wasm', - }); - } catch (error) { - console.error('Failed to initialize qpdf-wasm:', error); - showAlert( - 'Initialization Error', - 'Could not load the decryption engine. Please refresh the page and try again.' - ); - throw error; - } finally { - hideLoader(); - } - return qpdfInstance; -} export async function decrypt() { const file = state.files[0]; diff --git a/src/js/logic/encrypt.ts b/src/js/logic/encrypt.ts index 26717ef..a2b5c1f 100644 --- a/src/js/logic/encrypt.ts +++ b/src/js/logic/encrypt.ts @@ -1,38 +1,13 @@ import { showLoader, hideLoader, showAlert } from '../ui.js'; -import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { downloadFile, initializeQpdf, readFileAsArrayBuffer } from '../utils/helpers.js'; import { state } from '../state.js'; -import createModule from '@neslinesli93/qpdf-wasm'; - -let qpdfInstance: any = null; - -async function initializeQpdf() { - if (qpdfInstance) { - return qpdfInstance; - } - showLoader('Initializing encryption engine...'); - try { - qpdfInstance = await createModule({ - locateFile: () => '/qpdf.wasm', - }); - } catch (error) { - console.error('Failed to initialize qpdf-wasm:', error); - showAlert( - 'Initialization Error', - 'Could not load the encryption engine. Please refresh the page and try again.' - ); - throw error; - } finally { - hideLoader(); - } - return qpdfInstance; -} export async function encrypt() { const file = state.files[0]; const userPassword = (document.getElementById('user-password-input') as HTMLInputElement) ?.value || ''; - const ownerPassword = + const ownerPasswordInput = (document.getElementById('owner-password-input') as HTMLInputElement) ?.value || ''; @@ -41,6 +16,9 @@ export async function encrypt() { return; } + const ownerPassword = ownerPasswordInput || userPassword; + const hasDistinctOwnerPassword = ownerPasswordInput !== ''; + const inputPath = '/input.pdf'; const outputPath = '/output.pdf'; let qpdf: any; @@ -61,11 +39,12 @@ export async function encrypt() { inputPath, '--encrypt', userPassword, - ownerPassword, // Can be empty + ownerPassword, '256', ]; - if (ownerPassword) { + // Only add restrictions if a distinct owner password was provided + if (hasDistinctOwnerPassword) { args.push( '--modify=none', '--extract=n', @@ -78,12 +57,10 @@ export async function encrypt() { ); } - if (!ownerPassword) { - args.push('--allow-insecure'); - } - args.push('--', outputPath); + console.log(args); + try { qpdf.callMain(args); } catch (qpdfError: any) { @@ -106,9 +83,9 @@ export async function encrypt() { hideLoader(); let successMessage = 'PDF encrypted successfully with 256-bit AES!'; - if (!ownerPassword) { + if (!hasDistinctOwnerPassword) { successMessage += - ' Note: Without an owner password, the PDF has no usage restrictions.'; + ' Note: Without a separate owner password, the PDF has no usage restrictions.'; } showAlert('Success', successMessage); @@ -137,4 +114,4 @@ export async function encrypt() { console.warn('Failed to cleanup WASM FS:', cleanupError); } } -} +} \ No newline at end of file diff --git a/src/js/utils/helpers.ts b/src/js/utils/helpers.ts index affb8f6..3727fec 100644 --- a/src/js/utils/helpers.ts +++ b/src/js/utils/helpers.ts @@ -1,3 +1,6 @@ +import createModule from '@neslinesli93/qpdf-wasm'; +import { showLoader, hideLoader, showAlert } from '../ui'; + const STANDARD_SIZES = { A4: { width: 595.28, height: 841.89 }, Letter: { width: 612, height: 792 }, @@ -146,3 +149,31 @@ export function formatIsoDate(isoDateString) { return isoDateString; // Return original string on any error } } + +let qpdfInstance: any = null; + +/** + * Initialize qpdf-wasm singleton. + * Subsequent calls return the same instance. + */ +export async function initializeQpdf() { + if (qpdfInstance) return qpdfInstance; + + showLoader('Initializing PDF engine...'); + try { + qpdfInstance = await createModule({ + locateFile: () => '/qpdf.wasm', + }); + } catch (error) { + console.error('Failed to initialize qpdf-wasm:', error); + showAlert( + 'Initialization Error', + 'Could not load the PDF engine. Please refresh the page and try again.' + ); + throw error; + } finally { + hideLoader(); + } + + return qpdfInstance; +} \ No newline at end of file