fix: prevent hidden layers from being toggled in pdf viewers (#1528)

https://github.com/user-attachments/assets/e10194ca-212b-40ee-b9a1-85ef54829a40

---------

Co-authored-by: Mythie <me@lucasjamessmith.me>
This commit is contained in:
Ephraim Duncan
2024-12-13 03:19:55 +00:00
committed by GitHub
parent 10b8e785e0
commit 4ad46b81c9
4 changed files with 34 additions and 11 deletions

View File

@ -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 { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs'; import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma'; import { prisma } from '@documenso/prisma';
import { DocumentStatus, RecipientRole, SigningStatus } from '@documenso/prisma/client'; import {
import { WebhookTriggerEvents } from '@documenso/prisma/client'; DocumentStatus,
RecipientRole,
SigningStatus,
WebhookTriggerEvents,
} from '@documenso/prisma/client';
import { signPdf } from '@documenso/signing'; import { signPdf } from '@documenso/signing';
import { ZWebhookDocumentSchema } from '../../types/webhook-payload'; import { ZWebhookDocumentSchema } from '../../types/webhook-payload';

View File

@ -9,8 +9,8 @@ import {
RecipientRole, RecipientRole,
SendStatus, SendStatus,
SigningStatus, SigningStatus,
WebhookTriggerEvents,
} from '@documenso/prisma/client'; } from '@documenso/prisma/client';
import { WebhookTriggerEvents } from '@documenso/prisma/client';
import { jobs } from '../../jobs/client'; import { jobs } from '../../jobs/client';
import { extractDerivedDocumentEmailSettings } from '../../types/document-email'; import { extractDerivedDocumentEmailSettings } from '../../types/document-email';

View File

@ -1,9 +1,11 @@
import type { PDFField, PDFWidgetAnnotation } from 'pdf-lib'; import type { PDFField, PDFWidgetAnnotation } from 'pdf-lib';
import { PDFCheckBox, PDFRadioGroup, PDFRef } from 'pdf-lib';
import { import {
PDFCheckBox,
PDFDict, PDFDict,
type PDFDocument, type PDFDocument,
PDFName, PDFName,
PDFRadioGroup,
PDFRef,
drawObject, drawObject,
popGraphicsState, popGraphicsState,
pushGraphicsState, pushGraphicsState,
@ -11,7 +13,18 @@ import {
translate, translate,
} from 'pdf-lib'; } 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) => { export const flattenForm = (document: PDFDocument) => {
removeOptionalContentGroups(document);
const form = document.getForm(); const form = document.getForm();
form.updateFieldAppearances(); form.updateFieldAppearances();

View File

@ -8,6 +8,7 @@ import { DocumentDataType } from '@documenso/prisma/client';
import { AppError } from '../../errors/app-error'; import { AppError } from '../../errors/app-error';
import { createDocumentData } from '../../server-only/document-data/create-document-data'; import { createDocumentData } from '../../server-only/document-data/create-document-data';
import { removeOptionalContentGroups } from '../../server-only/pdf/flatten-form';
type File = { type File = {
name: string; name: string;
@ -24,20 +25,25 @@ export const putPdfFile = async (file: File) => {
() => false, () => false,
); );
// This will prevent uploading encrypted PDFs or anything that can't be opened. const pdf = await PDFDocument.load(await file.arrayBuffer()).catch((e) => {
if (!isEncryptedDocumentsAllowed) { console.error(`PDF upload parse error: ${e.message}`);
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')) { if (!file.name.endsWith('.pdf')) {
file.name = `${file.name}.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 }); return await createDocumentData({ type, data });
}; };