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
This commit is contained in:
abdullahalam123
2025-10-24 11:37:15 +05:30
parent e0d3075609
commit e3468e3aaa
4 changed files with 47 additions and 89 deletions

View File

@@ -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 {

View File

@@ -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];

View File

@@ -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);

View File

@@ -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;
}