Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
vbuch committed Nov 14, 2023
1 parent 209edba commit a1b9528
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 33 deletions.
180 changes: 170 additions & 10 deletions packages/placeholder-pdf-lib/src/pdflibAddPlaceholder.test.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import {PDFDocument} from 'pdf-lib';
import {
PDFArray, PDFDict, PDFDocument, PDFName, PDFString,
} from 'pdf-lib';
import {readTestResource} from '@signpdf/internal-utils';
import {SUBFILTER_ETSI_CADES_DETACHED} from '@signpdf/utils';
import {DEFAULT_BYTE_RANGE_PLACEHOLDER, SUBFILTER_ETSI_CADES_DETACHED} from '@signpdf/utils';
import {pdflibAddPlaceholder} from './pdflibAddPlaceholder';

describe(pdflibAddPlaceholder, () => {
const defaults = {
reason: 'Because I can',
contactInfo: '[email protected]',
name: 'test name',
location: 'test Location',
};

it('adds placeholder to a prepared document', async () => {
const input = readTestResource('w3dummy.pdf');
expect(input.indexOf('/ByteRange')).toBe(-1);
const pdfDoc = await PDFDocument.load(input);

pdflibAddPlaceholder({
pdfDoc,
reason: 'Because I can',
location: 'some place',
name: 'example name',
contactInfo: '[email protected]',
...defaults,
});
// Convert the PDFDocument to bytes
const pdfBytes = await pdfDoc.save({useObjectStreams: false});
Expand All @@ -34,10 +40,7 @@ describe(pdflibAddPlaceholder, () => {

pdflibAddPlaceholder({
pdfDoc,
reason: 'Because I can',
location: 'some place',
name: 'example name',
contactInfo: '[email protected]',
...defaults,
subFilter: SUBFILTER_ETSI_CADES_DETACHED,
});
// Convert the PDFDocument to bytes
Expand All @@ -48,4 +51,161 @@ describe(pdflibAddPlaceholder, () => {
expect(buffer).toBeInstanceOf(Buffer);
expect(buffer.indexOf(`/SubFilter /${SUBFILTER_ETSI_CADES_DETACHED}`)).not.toBe(-1);
});

it('placeholder contains reason, contactInfo, name, location', async () => {
const input = readTestResource('w3dummy.pdf');
expect(input.indexOf('/ByteRange')).toBe(-1);
const pdfDoc = await PDFDocument.load(input);

pdflibAddPlaceholder({
pdfDoc,
...defaults,
});

/**
* @type {PDFArray}
*/
const annots = pdfDoc.getPage(0).node.lookup(PDFName.of('Annots'));

/**
* @type {PDFDict}
*/
const widget = annots.lookup(annots.size() - 1, PDFDict);

/**
* @type {PDFDict}
*/
const widgetData = widget.lookup(PDFName.of('V'));

expect(widget.get(PDFName.of('Subtype'))).toEqual(PDFName.of('Widget'));
expect(widgetData.get(PDFName.of('Reason'))).toEqual(PDFString.of(defaults.reason));
expect(widgetData.get(PDFName.of('ContactInfo'))).toEqual(PDFString.of(defaults.contactInfo));
expect(widgetData.get(PDFName.of('Location'))).toEqual(PDFString.of(defaults.location));
expect(widgetData.get(PDFName.of('Name'))).toEqual(PDFString.of(defaults.name));
});

it('sets the widget rectange to invisible by default', async () => {
const input = readTestResource('w3dummy.pdf');
expect(input.indexOf('/ByteRange')).toBe(-1);
const pdfDoc = await PDFDocument.load(input);

pdflibAddPlaceholder({
pdfDoc,
...defaults,
});

/**
* @type {PDFArray}
*/
const annots = pdfDoc.getPage(0).node.lookup(PDFName.of('Annots'));

/**
* @type {PDFDict}
*/
const widget = annots.lookup(annots.size() - 1, PDFDict);

/**
* @type {PDFArray}
*/
const rect = widget.get(PDFName.of('Rect'));
expect(rect).toBeInstanceOf(PDFArray);
expect(rect.toString()).toEqual('[ 0 0 0 0 ]');
});

it('allows defining widget rectange', async () => {
const input = readTestResource('w3dummy.pdf');
expect(input.indexOf('/ByteRange')).toBe(-1);
const pdfDoc = await PDFDocument.load(input);
const widgetRect = [100, 100, 200, 200];

pdflibAddPlaceholder({
pdfDoc,
...defaults,
widgetRect,
});

/**
* @type {PDFArray}
*/
const annots = pdfDoc.getPage(0).node.lookup(PDFName.of('Annots'));

/**
* @type {PDFDict}
*/
const widget = annots.lookup(annots.size() - 1, PDFDict);

/**
* @type {PDFArray}
*/
const rect = widget.get(PDFName.of('Rect'));
expect(rect).toBeInstanceOf(PDFArray);
expect(rect.toString()).toEqual('[ 100 100 200 200 ]');
});

it('does not overwrite the AcroForm when it was already there', async () => {
const input = readTestResource('signed-once.pdf');
expect(input.indexOf('/ByteRange')).not.toBe(-1);
const pdfDoc = await PDFDocument.load(input);
const existingAcroFormTag = pdfDoc.catalog.get(PDFName.of('AcroForm')).tag;

pdflibAddPlaceholder({
pdfDoc,
...defaults,
});

const newAcroFormRef = pdfDoc.catalog.get(PDFName.of('AcroForm'));
expect(newAcroFormRef.tag).toBe(existingAcroFormTag);
});

it('does not overwrite page annotations when there already were some', async () => {
const input = readTestResource('signed-once.pdf');
expect(input.indexOf('/ByteRange')).not.toBe(-1);
const pdfDoc = await PDFDocument.load(input);
const existingAnnotations = pdfDoc
.getPage(0).node
.lookup(PDFName.of('Annots'), PDFArray)
.asArray().map((v) => v.toString());

pdflibAddPlaceholder({
pdfDoc,
...defaults,
});

const newAnnotations = pdfDoc
.getPage(0).node
.lookup(PDFName.of('Annots'), PDFArray)
.asArray().map((v) => v.toString());
expect(newAnnotations).toEqual(expect.arrayContaining(existingAnnotations));
expect(newAnnotations).toHaveLength(existingAnnotations.length + 1);
});

it('adds placeholder to PDFDocument document when AcroForm is already there', async () => {
const input = readTestResource('signed-once.pdf');
expect(input.indexOf('/ByteRange')).not.toBe(-1);
const pdfDoc = await PDFDocument.load(input);

pdflibAddPlaceholder({
pdfDoc,
...defaults,
});

const annotations = pdfDoc
.getPage(0).node
.lookup(PDFName.of('Annots'), PDFArray);
const widgetDict = annotations.lookup(annotations.size() - 1, PDFDict);
expect(widgetDict.get(PDFName.of('Subtype'))).toEqual(PDFName.of('Widget'));

const byteRange = widgetDict
.lookup(PDFName.of('V'), PDFDict)
.lookup(PDFName.of('ByteRange'), PDFArray)
.asArray()
.map((v) => v.toString());

expect(byteRange).toEqual([
'0',
PDFName.of(DEFAULT_BYTE_RANGE_PLACEHOLDER).asString(),
PDFName.of(DEFAULT_BYTE_RANGE_PLACEHOLDER).asString(),
PDFName.of(DEFAULT_BYTE_RANGE_PLACEHOLDER).asString(),
]);
});
});
23 changes: 0 additions & 23 deletions packages/placeholder-pdfkit010/src/pdfkitAddPlaceholder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,6 @@ describe(pdfkitAddPlaceholder, () => {
it('placeholder contains reason, contactInfo, name, location', () => {
const {pdf} = createPdfkitDocument();

const refs = pdfkitAddPlaceholder({
pdf,
pdfBuffer: Buffer.from([pdf]),
reason: 'test reason',
...defaults,
});
expect(Object.keys(refs)).toEqual(expect.arrayContaining([
'signature',
'form',
'widget',
]));
expect(pdf.page.dictionary.data.Annots).toHaveLength(1);
expect(pdf.page.dictionary.data.Annots[0].data.Subtype).toEqual('Widget');
const widgetData = pdf.page.dictionary.data.Annots[0].data.V.data;
expect(PDFObject.convert(widgetData.Reason)).toEqual('(test reason)');
expect(PDFObject.convert(widgetData.ContactInfo)).toEqual('([email protected])');
expect(PDFObject.convert(widgetData.Name)).toEqual('(test name)');
expect(PDFObject.convert(widgetData.Location)).toEqual('(test Location)');
});

it('placeholder contains default values for contactInfo, name, location', () => {
const {pdf} = createPdfkitDocument();

const refs = pdfkitAddPlaceholder({
...defaults,
pdf,
Expand Down

0 comments on commit a1b9528

Please sign in to comment.