// scripts/decrypt_pdf.ts import * as fs from 'fs' import * as path from 'path' import * as crypto from 'crypto' import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const PDF_DIR = path.resolve(__dirname, '../../public/pdf') function getKey(password: string): Buffer { return crypto.createHash('sha256').update(password).digest() } function decryptGCM(inputPath: string, outputPath: string): void { const input = fs.readFileSync(inputPath) const iv = input.subarray(0, 12) const lenBuf = input.subarray(input.length - 4) const pLen = lenBuf.readUint32BE() const passwordBuffer = input.subarray(input.length - pLen - 4, input.length - 4) const password = passwordBuffer.toString('base64') const authTag = input.subarray(input.length - pLen - 4 - 16, input.length - pLen - 4) const encrypted = input.subarray(12, input.length - pLen - 4 - 16) const key = getKey(password) const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv) decipher.setAuthTag(authTag) const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]) fs.writeFileSync(outputPath, Buffer.from(decrypted)) console.log(`✔ Decrypted (GCM): ${path.basename(inputPath)}`) } function decryptAllPDFs(): void { const files = fs.readdirSync(PDF_DIR) for (const file of files) { const fullPath = path.join(PDF_DIR, file) if (!fs.statSync(fullPath).isFile() || !file.endsWith('.enc')) continue const decPath = fullPath + '.dec' if (fs.existsSync(decPath)) { console.log(`⏭ Skipped (already decrypted): ${file}`) continue } decryptGCM(fullPath, decPath) } } decryptAllPDFs()