pdf-password-protector
Version:
A Node.js package to password protect PDF files using Java PDFBox
128 lines (112 loc) • 3.87 kB
JavaScript
const { spawn } = require('child_process');
const fs = require('fs').promises;
const path = require('path');
class PdfPasswordProtector {
/**
* Get the path to the JAR file
* @private
* @returns {string} Path to the JAR file
*/
static _getJarPath() {
return path.join(__dirname, 'lib', 'pdf-password-protector.jar');
}
/**
* Execute the Java command
* @private
* @param {string[]} args Command line arguments
* @returns {Promise<string>} Command output
*/
static _executeJavaCommand(args) {
return new Promise((resolve, reject) => {
const java = spawn('java', ['-jar', this._getJarPath(), ...args]);
let output = '';
let error = '';
java.stdout.on('data', (data) => {
output += data.toString();
});
java.stderr.on('data', (data) => {
error += data.toString();
});
java.on('close', (code) => {
if (code === 0 && output.includes('SUCCESS')) {
resolve(output);
} else {
reject(new Error(error || 'Failed to execute Java command'));
}
});
});
}
/**
* Protects a PDF file with a password
* @param {string|Buffer} input - Path to the PDF file or Buffer containing PDF data
* @param {string} outputPath - Path where the protected PDF will be saved
* @param {string} password - Password to protect the PDF
* @param {Object} options - Additional options
* @param {string} options.ownerPassword - Set a different owner password (defaults to same as user password)
* @returns {Promise<void>}
*/
static async protect(input, outputPath, password, options = {}) {
try {
// If input is a Buffer, write it to a temporary file
let inputPath = input;
let tempFile = null;
if (Buffer.isBuffer(input)) {
tempFile = path.join(__dirname, `temp_${Date.now()}.pdf`);
await fs.writeFile(tempFile, input);
inputPath = tempFile;
} else if (typeof input !== 'string') {
throw new Error('Input must be a file path (string) or Buffer');
}
// Prepare arguments for Java command
const args = [
inputPath,
outputPath,
password
];
// Add owner password if specified
if (options.ownerPassword) {
args.push(options.ownerPassword);
}
// Execute Java command
await this._executeJavaCommand(args);
// Clean up temporary file if created
if (tempFile) {
await fs.unlink(tempFile);
}
} catch (error) {
throw new Error(`Failed to protect PDF: ${error.message}`);
}
}
/**
* Checks if a PDF is password protected
* @param {string|Buffer} input - Path to the PDF file or Buffer containing PDF data
* @returns {Promise<boolean>}
*/
static async isProtected(input) {
try {
// If input is a Buffer, write it to a temporary file
let inputPath = input;
let tempFile = null;
if (Buffer.isBuffer(input)) {
tempFile = path.join(__dirname, `temp_${Date.now()}.pdf`);
await fs.writeFile(tempFile, input);
inputPath = tempFile;
} else if (typeof input !== 'string') {
throw new Error('Input must be a file path (string) or Buffer');
}
try {
// Try to load the PDF with PDFBox
const output = await this._executeJavaCommand(['--check', inputPath]);
return output.includes('PROTECTED');
} finally {
// Clean up temporary file if created
if (tempFile) {
await fs.unlink(tempFile);
}
}
} catch (error) {
throw new Error(`Failed to check PDF protection: ${error.message}`);
}
}
}
module.exports = PdfPasswordProtector;