vbuch / node-signpdf

Simple signing of PDFs in node.
MIT License
719 stars 178 forks source link

How to properly signing a signature form field? #104

Closed NoahCardoza closed 3 years ago

NoahCardoza commented 4 years ago

Sifting through the issues I've found https://github.com/vbuch/node-signpdf/issues/22 and https://github.com/vbuch/node-signpdf/issues/39. The latter being a little hard to follow.

I'm trying to sign a PDF with form fields, some of which are meant for signatures. Is there a "special" way to sign the document and overlay an image of the user's written signature/time stamp in which Acrobat will properly identify it?

E.G. Let the user hover over the form and show the details of the signature?

image

NoahCardoza commented 4 years ago

After some digging it seems that I don't want to use plainAddPlaceholder because it adds a new form field and links that to the signature, where as I was to link it to an existing field.

I think I've identified the code that would need to be modified:

    const widget = pdf.ref({
        Type: 'Annot',
        Subtype: 'Widget',
        FT: 'Sig',
        Rect: [0, 0, 0, 0],
        V: signature,
        T: new String(signatureName + (fieldIds.length + 1)), // eslint-disable-line no-new-wrappers
        F: 4,
        P: pdf.page.dictionary, // eslint-disable-line no-underscore-dangle
    });
    pdf.page.dictionary.data.Annots = [widget];
    // Include the widget in a page
    let form;

    if (!isAcroFormExists) {
        // Create a form (with the widget) and link in the _root
        form = pdf.ref({
            Type: 'AcroForm',
            SigFlags: 3,
            Fields: [...fieldIds, widget],
        });
    } else {
        // Use existing acroform and extend the fields with newly created widgets
        form = pdf.ref({
            Type: 'AcroForm',
            SigFlags: 3,
            Fields: [...fieldIds, widget],
        }, acroFormId);
    }
    pdf._root.data.AcroForm = form;

I think adding a widgetId option to the function and then optionally creating a widget if no existing widgetId was passed should work?

Is there anything I'm missing?

NoahCardoza commented 4 years ago

For reference the version of the PDF I'm working on currently is 1.6. I noticed it wasn't finding any existing form, and it looks like it's because

const acroFormPosition = pdfBuffer.lastIndexOf('/Type /AcroForm');

fails to find /Type /AcroForm. It looks like the only mention of AcroForm is in the first object of the PDF:

%PDF-1.6
%<E2><E3><CF><D3>
1 0 obj 
<<
/Metadata 2 0 R
/AcroForm 3 0 R
/MarkInfo 
<<
/Marked true
>>
/Type /Catalog
/Names 4 0 R
/Pages 5 0 R
/StructTreeRoot 6 0 R
/Perms 7 0 R
>>
endobj

It looks like the form field refs are stored here:

352 0 obj [304 0 R 305 0 R 306 0 R 303 0 R 284 0 R 277 0 R 270 0 R 263 0 R 250 0 R 245 0 R 236 0
 R 231 0 R 226 0 R 221 0 R 217 0 R 216 0 R 215 0 R 197 0 R 196 0 R 195 0 R 174 0 R 165 0 R 156 0
 R 145 0 R 142 0 R 127 0 R 118 0 R 115 0 R 102 0 R 99 0 R 90 0 R 385 0 R 386 0 R 387 0 R 388 0 R
 389 0 R 390 0 R 391 0 R 392 0 R 393 0 R 394 0 R 395 0 R 396 0 R 397 0 R 398 0 R 399 0 R 400 0 R
 401 0 R 402 0 R 403 0 R]
endobj

Which is referenced here:

9 0 obj 
<<
/Annots 352 0 R
/StructParents 0
/Rotate 0
/Resources 
<<
/Font 
<<
/TT2 353 0 R
/TT1 354 0 R
/TT0 355 0 R
>>
/ProcSet [/PDF /Text]
>>
/Type /Page
/Parent 5 0 R
/Contents [356 0 R 357 0 R 358 0 R 359 0 R 360 0 R 361 0 R 362 0 R 363 0 R]
/MediaBox [0.0 0.0 612.0 792.0]
/CropBox [0.0 0.0 612.0 792.0]
>>
endobj

The problem is I can't figure out how to connect the two...

Any ideas?

vbuch commented 4 years ago

https://github.com/vbuch/node-signpdf#append-a-signature-placeholder

What's needed is a Sig element and a Widget that is also linked in a Form. The form needs to be referenced in the root descriptor of the PDF as well. A (hopefully) readable sample is available in the helpers. Note the Contents descriptor of the Sig where zeros are placed that will later be replaced with the actual signature.

That's how it is in a PDF 1.3. Where is the root descriptor of latter version, i have no clue.

NoahCardoza commented 4 years ago

Ah I see... it’s a mystery isn’t it 😂 Currently I’m trying to convince the client that using JWS will be easier and more efficient and we can generate a PDF from the end product after the fact, but use JWS to store the audit trail and provide non-reputation. Wish me luck! 💀

Sent with GitHawk

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had activity in the past 90 days. It will be closed if no further activity occurs. Thank you for your contributions.

Dhopal commented 1 year ago

Hi @NoahCardoza, were you able to add the hover functionality? Can you share how did you do it.