diff --git a/packages/lib/server-only/document/seal-document.ts b/packages/lib/server-only/document/seal-document.ts index a5a1c1079..357bf61e3 100644 --- a/packages/lib/server-only/document/seal-document.ts +++ b/packages/lib/server-only/document/seal-document.ts @@ -6,8 +6,12 @@ import PostHogServerClient from '@documenso/lib/server-only/feature-flags/get-po import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs'; import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs'; import { prisma } from '@documenso/prisma'; -import { DocumentStatus, RecipientRole, SigningStatus } from '@documenso/prisma/client'; -import { WebhookTriggerEvents } from '@documenso/prisma/client'; +import { + DocumentStatus, + RecipientRole, + SigningStatus, + WebhookTriggerEvents, +} from '@documenso/prisma/client'; import { signPdf } from '@documenso/signing'; import { ZWebhookDocumentSchema } from '../../types/webhook-payload'; diff --git a/packages/lib/server-only/document/send-document.tsx b/packages/lib/server-only/document/send-document.tsx index 791d80938..cdea1fcd0 100644 --- a/packages/lib/server-only/document/send-document.tsx +++ b/packages/lib/server-only/document/send-document.tsx @@ -9,8 +9,8 @@ import { RecipientRole, SendStatus, SigningStatus, + WebhookTriggerEvents, } from '@documenso/prisma/client'; -import { WebhookTriggerEvents } from '@documenso/prisma/client'; import { jobs } from '../../jobs/client'; import { extractDerivedDocumentEmailSettings } from '../../types/document-email'; diff --git a/packages/lib/server-only/pdf/flatten-form.ts b/packages/lib/server-only/pdf/flatten-form.ts index d3b0d42ae..fd2c981ec 100644 --- a/packages/lib/server-only/pdf/flatten-form.ts +++ b/packages/lib/server-only/pdf/flatten-form.ts @@ -1,9 +1,11 @@ import type { PDFField, PDFWidgetAnnotation } from 'pdf-lib'; -import { PDFCheckBox, PDFRadioGroup, PDFRef } from 'pdf-lib'; import { + PDFCheckBox, PDFDict, type PDFDocument, PDFName, + PDFRadioGroup, + PDFRef, drawObject, popGraphicsState, pushGraphicsState, @@ -11,7 +13,18 @@ import { translate, } from 'pdf-lib'; +export const removeOptionalContentGroups = (document: PDFDocument) => { + const context = document.context; + const catalog = context.lookup(context.trailerInfo.Root); + + if (catalog instanceof PDFDict) { + catalog.delete(PDFName.of('OCProperties')); + } +}; + export const flattenForm = (document: PDFDocument) => { + removeOptionalContentGroups(document); + const form = document.getForm(); form.updateFieldAppearances(); diff --git a/packages/lib/universal/upload/put-file.ts b/packages/lib/universal/upload/put-file.ts index 2b2132e0d..c7bbf9c05 100644 --- a/packages/lib/universal/upload/put-file.ts +++ b/packages/lib/universal/upload/put-file.ts @@ -8,6 +8,7 @@ import { DocumentDataType } from '@documenso/prisma/client'; import { AppError } from '../../errors/app-error'; import { createDocumentData } from '../../server-only/document-data/create-document-data'; +import { removeOptionalContentGroups } from '../../server-only/pdf/flatten-form'; type File = { name: string; @@ -24,20 +25,25 @@ export const putPdfFile = async (file: File) => { () => false, ); - // This will prevent uploading encrypted PDFs or anything that can't be opened. - if (!isEncryptedDocumentsAllowed) { - await PDFDocument.load(await file.arrayBuffer()).catch((e) => { - console.error(`PDF upload parse error: ${e.message}`); + const pdf = await PDFDocument.load(await file.arrayBuffer()).catch((e) => { + console.error(`PDF upload parse error: ${e.message}`); - throw new AppError('INVALID_DOCUMENT_FILE'); - }); + throw new AppError('INVALID_DOCUMENT_FILE'); + }); + + if (!isEncryptedDocumentsAllowed && pdf.isEncrypted) { + throw new AppError('INVALID_DOCUMENT_FILE'); } if (!file.name.endsWith('.pdf')) { file.name = `${file.name}.pdf`; } - const { type, data } = await putFile(file); + removeOptionalContentGroups(pdf); + + const bytes = await pdf.save(); + + const { type, data } = await putFile(new File([bytes], file.name, { type: 'application/pdf' })); return await createDocumentData({ type, data }); };