Skip to content

Commit b675254

Browse files
Merge pull request #484 from OpenSignLabs/fix_e_sign
fix: E-sign is not available in completed document
2 parents 73c219f + 51505af commit b675254

File tree

6 files changed

+200
-83
lines changed

6 files changed

+200
-83
lines changed

apps/OpenSign/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
},
4949
"scripts": {
5050
"start": "serve -s build",
51-
"start-dev" :"react-scripts start",
51+
"start-dev": "react-scripts start",
5252
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
5353
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
5454
"build": "npm run version && react-scripts build",

apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js

Lines changed: 87 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import SignPDF from './SignPDF.min.cjs';
22
import fs from 'node:fs';
33
import axios from 'axios';
4-
import { plainAddPlaceholder } from 'node-signpdf/dist/helpers/index.js';
4+
import { pdflibAddPlaceholder } from './customSignPdf/pdflibplaceholder.min.js';
5+
import { PDFDocument } from 'pdf-lib';
56
const serverUrl = process.env.SERVER_URL,
67
APPID = process.env.APP_ID,
78
masterKEY = process.env.MASTER_KEY;
@@ -15,20 +16,20 @@ async function uploadFile(e, a) {
1516
console.log('Err ', e), fs.unlinkSync(a);
1617
}
1718
}
18-
async function updateDoc(t, s, r, i, n, o) {
19+
async function updateDoc(t, s, r, i, o, n) {
1920
try {
2021
var d = {
21-
UserPtr: { __type: 'Pointer', className: o, objectId: r },
22+
UserPtr: { __type: 'Pointer', className: n, objectId: r },
2223
SignedUrl: s,
2324
Activity: 'Signed',
2425
ipAddress: i,
2526
};
2627
let e;
27-
var l = (e = n.AuditTrail && 0 < n.AuditTrail.length ? [...n.AuditTrail, d] : [d]).filter(
28+
var l = (e = o.AuditTrail && 0 < o.AuditTrail.length ? [...o.AuditTrail, d] : [d]).filter(
2829
e => 'Signed' === e.Activity
2930
);
3031
let a = !1;
31-
!((n.Signers && 0 < n.Signers.length && l.length !== n.Signers.length) || !(a = !0));
32+
!((o.Signers && 0 < o.Signers.length && l.length !== o.Signers.length) || !(a = !0));
3233
var c = { SignedUrl: s, AuditTrail: e, IsCompleted: a };
3334
await axios.put(serverUrl + '/classes/contracts_Document/' + t, c, {
3435
headers: {
@@ -150,9 +151,8 @@ async function sendDoctoWebhook(t, e, a, s) {
150151
}
151152
}));
152153
}
153-
async function PDF(i, n) {
154+
async function PDF(i) {
154155
try {
155-
i.params.sign;
156156
var e = i.params.docId,
157157
a = i.params.userId,
158158
o = await axios.get(
@@ -173,125 +173,136 @@ async function PDF(i, n) {
173173
});
174174
if (!t.data || !t.data.objectId) return { status: 'error', message: 'this user not allowed!' };
175175
{
176-
var d,
176+
var n,
177+
d,
177178
l,
178-
c,
179-
p = JSON.stringify({ objectId: a });
179+
c = JSON.stringify({ objectId: a });
180180
let s, r;
181181
r = a
182-
? (d = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + p, {
182+
? (n = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + c, {
183183
headers: {
184184
'X-Parse-Application-Id': APPID,
185185
'X-Parse-Session-Token': i.headers.sessiontoken,
186186
},
187-
})).data && 0 < d.data.results.length
188-
? ((s = d), 'contracts_Contactbook')
189-
: ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + p, {
187+
})).data && 0 < n.data.results.length
188+
? ((s = n), 'contracts_Contactbook')
189+
: ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + c, {
190190
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
191191
})),
192192
'contracts_Users')
193-
: ((l = JSON.stringify({
193+
: ((d = JSON.stringify({
194194
UserId: { __type: 'Pointer', className: '_User', objectId: t.data.objectId },
195195
})),
196-
(c = await axios.get(serverUrl + '/classes/contracts_Users?where=' + l, {
196+
(l = await axios.get(serverUrl + '/classes/contracts_Users?where=' + d, {
197197
headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY },
198-
})).data && 0 < c.data.results.length
199-
? ((s = c), 'contracts_Users')
200-
: ((s = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + l, {
198+
})).data && 0 < l.data.results.length
199+
? ((s = l), 'contracts_Users')
200+
: ((s = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + d, {
201201
headers: {
202202
'X-Parse-Application-Id': APPID,
203203
'X-Parse-Session-Token': i.headers.sessiontoken,
204204
},
205205
})),
206206
'contracts_Contactbook'));
207-
var m = s.data.results[0].Name,
208-
g = s.data.results[0].Email;
207+
var p = s.data.results[0].Name,
208+
m = s.data.results[0].Email;
209209
if (!i.params.pdfFile) return { status: 'error', message: 'pdf file not present!' };
210210
{
211211
let e = Buffer.from(i.params.pdfFile, 'base64');
212-
var h = process.env.PFX_BASE64,
213-
u = Buffer.from(h, 'base64'),
214-
f = {
212+
var g = process.env.PFX_BASE64,
213+
h = Buffer.from(g, 'base64'),
214+
u = {
215215
UserPtr: { __type: 'Pointer', className: r, objectId: s.data.results[0].objectId },
216216
SignedUrl: '',
217217
Activity: 'Signed',
218218
ipAddress: i.headers['x-real-ip'],
219219
};
220220
let a;
221-
var y = (a =
221+
var f = (a =
222222
o.data.AuditTrail && 0 < o.data.AuditTrail.length
223-
? [...o.data.AuditTrail, f]
224-
: [f]).filter(e => 'Signed' === e.Activity);
223+
? [...o.data.AuditTrail, u]
224+
: [u]).filter(e => 'Signed' === e.Activity);
225225
let t = !1;
226226
!(
227-
(o.data.Signers && 0 < o.data.Signers.length && y.length !== o.data.Signers.length) ||
227+
(o.data.Signers && 0 < o.data.Signers.length && f.length !== o.data.Signers.length) ||
228228
!(t = !0)
229229
);
230-
var v,
230+
var y,
231231
P,
232-
b = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
233-
x = './exports/' + b,
234-
U =
232+
v,
233+
b,
234+
x,
235+
w,
236+
U,
237+
I,
238+
S,
239+
A = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`,
240+
D = './exports/' + A,
241+
E =
235242
(t
236-
? ((v = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
243+
? ((y = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')),
237244
(e =
238-
v && 0 < v.length
239-
? plainAddPlaceholder({
240-
pdfBuffer: e,
241-
reason: 'Digitally signed by OpenSign for ' + v?.join(', '),
245+
y && 0 < y.length
246+
? ((P = await PDFDocument.load(e)),
247+
pdflibAddPlaceholder({
248+
pdfDoc: P,
249+
reason: 'Digitally signed by OpenSign for ' + y?.join(', '),
242250
location: 'location',
243-
signatureLength: 1e4,
244-
})
245-
: plainAddPlaceholder({
246-
pdfBuffer: e,
247-
reason: 'Digitally signed by OpenSign for ' + m + ' <' + g + '>',
251+
signatureLength: 15e3,
252+
}),
253+
(v = await P.save()),
254+
Buffer.from(v))
255+
: ((b = await PDFDocument.load(e)),
256+
pdflibAddPlaceholder({
257+
pdfDoc: b,
258+
reason: 'Digitally signed by OpenSign for ' + p + ' <' + m + '>',
248259
location: 'location',
249-
signatureLength: 1e4,
250-
})),
251-
(P = await new SignPDF(e, u).signPDF()),
252-
fs.writeFileSync(x, P))
253-
: fs.writeFileSync(x, e),
254-
await uploadFile(b, x));
255-
if (U && U.imageUrl) {
256-
const n = await updateDoc(
257-
i.params.docId,
258-
U.imageUrl,
259-
s.data.results[0].objectId,
260-
i.headers['x-real-ip'],
261-
o.data,
262-
r
263-
);
264-
var I,
265-
w = {
266-
url: U.imageUrl,
260+
signatureLength: 15e3,
261+
}),
262+
(x = await b.save()),
263+
Buffer.from(x))),
264+
(w = await new SignPDF(e, h).signPDF()),
265+
fs.writeFileSync(D, w))
266+
: fs.writeFileSync(D, e),
267+
await uploadFile(A, D));
268+
if (E && E.imageUrl)
269+
return (
270+
(U = await updateDoc(
271+
i.params.docId,
272+
E.imageUrl,
273+
s.data.results[0].objectId,
274+
i.headers['x-real-ip'],
275+
o.data,
276+
r
277+
)),
278+
(I = {
279+
url: E.imageUrl,
267280
sender: { Mail: o.data.ExtUserPtr.Email, Name: o.data.ExtUserPtr.Name },
268281
pdfName: o.data.Name,
269-
receiver: g,
270-
};
271-
return (
282+
receiver: m,
283+
}),
272284
o.data.IsSendMail && !1 === o.data.IsSendMail
273285
? console.log("don't send mail")
274-
: sendMail(w),
275-
sendDoctoWebhook(o, U.imageUrl, 'signed', s?.data.results?.[0]),
276-
n &&
277-
n.isCompleted &&
278-
((I = {
279-
url: U.imageUrl,
286+
: sendMail(I),
287+
sendDoctoWebhook(o, E.imageUrl, 'signed', s?.data.results?.[0]),
288+
U &&
289+
U.isCompleted &&
290+
((S = {
291+
url: E.imageUrl,
280292
sender: { Mail: o.data.ExtUserPtr.Email, Name: 'OpenSign™' },
281293
pdfName: o.data.Name,
282294
receiver: o.data.ExtUserPtr.Email,
283295
}),
284296
o.data.IsSendMail && !1 === o.data.IsSendMail
285297
? console.log("don't send mail")
286-
: sendCompletedMail(I),
287-
sendDoctoWebhook(o, U.imageUrl, 'completed')),
288-
fs.unlinkSync(x),
289-
console.log('New Signed PDF created called: ' + x),
290-
'success' === n.message
291-
? { status: 'success', data: U.imageUrl }
298+
: sendCompletedMail(S),
299+
sendDoctoWebhook(o, E.imageUrl, 'completed')),
300+
fs.unlinkSync(D),
301+
console.log('New Signed PDF created called: ' + D),
302+
'success' === U.message
303+
? { status: 'success', data: E.imageUrl }
292304
: { status: 'error', message: 'please provide required parameters!' }
293305
);
294-
}
295306
}
296307
}
297308
} catch (e) {
Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,20 @@
1-
const ERROR_TYPE_UNKNOWN=1,ERROR_TYPE_INPUT=2,ERROR_TYPE_PARSE=3,ERROR_VERIFY_SIGNATURE=4;class SignPdfError extends Error{constructor(R,E=ERROR_TYPE_UNKNOWN){super(R),this.type=E}}SignPdfError.TYPE_UNKNOWN=ERROR_TYPE_UNKNOWN,SignPdfError.TYPE_INPUT=ERROR_TYPE_INPUT,SignPdfError.TYPE_PARSE=ERROR_TYPE_PARSE,SignPdfError.VERIFY_SIGNATURE=ERROR_VERIFY_SIGNATURE;export default SignPdfError;export{ERROR_TYPE_UNKNOWN,ERROR_TYPE_INPUT,ERROR_TYPE_PARSE,ERROR_VERIFY_SIGNATURE};
1+
const ERROR_TYPE_UNKNOWN = 1,
2+
ERROR_TYPE_INPUT = 2,
3+
ERROR_TYPE_PARSE = 3,
4+
ERROR_VERIFY_SIGNATURE = 4;
5+
class SignPdfError extends Error {
6+
constructor(R, E = ERROR_TYPE_UNKNOWN) {
7+
super(R), (this.type = E);
8+
}
9+
}
10+
(SignPdfError.TYPE_UNKNOWN = ERROR_TYPE_UNKNOWN),
11+
(SignPdfError.TYPE_INPUT = ERROR_TYPE_INPUT),
12+
(SignPdfError.TYPE_PARSE = ERROR_TYPE_PARSE),
13+
(SignPdfError.VERIFY_SIGNATURE = ERROR_VERIFY_SIGNATURE);
14+
export {
15+
ERROR_TYPE_UNKNOWN,
16+
ERROR_TYPE_INPUT,
17+
ERROR_TYPE_PARSE,
18+
ERROR_VERIFY_SIGNATURE,
19+
SignPdfError,
20+
};
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import {
2+
DEFAULT_BYTE_RANGE_PLACEHOLDER,
3+
DEFAULT_SIGNATURE_LENGTH,
4+
SUBFILTER_ADOBE_PKCS7_DETACHED,
5+
} from './const.min.js';
6+
import { SignPdfError } from './SignPdfError.min.js';
7+
import {
8+
PDFArray,
9+
PDFDict,
10+
PDFHexString,
11+
PDFName,
12+
PDFNumber,
13+
PDFInvalidObject,
14+
PDFString,
15+
} from 'pdf-lib';
16+
const pdflibAddPlaceholder = ({
17+
pdfDoc: e = void 0,
18+
pdfPage: o = void 0,
19+
reason: t,
20+
contactInfo: r = '[email protected]',
21+
name: i = 'Name from p12',
22+
location: n,
23+
signingTime: a = void 0,
24+
signatureLength: P = DEFAULT_SIGNATURE_LENGTH,
25+
byteRangePlaceholder: F = DEFAULT_BYTE_RANGE_PLACEHOLDER,
26+
subFilter: D = SUBFILTER_ADOBE_PKCS7_DETACHED,
27+
widgetRect: f = [0, 0, 0, 0],
28+
appName: g = void 0,
29+
}) => {
30+
if (void 0 === e && void 0 === o)
31+
throw new SignPdfError('PDFDoc or PDFPage must be set.', SignPdfError.TYPE_INPUT);
32+
var e = e ?? o.doc,
33+
o = o ?? e.getPages()[0],
34+
m = PDFArray.withContext(e.context),
35+
F =
36+
(m.push(PDFNumber.of(0)),
37+
m.push(PDFName.of(F)),
38+
m.push(PDFName.of(F)),
39+
m.push(PDFName.of(F)),
40+
PDFHexString.of(String.fromCharCode(0).repeat(P))),
41+
P = g ? { App: { Name: g } } : {},
42+
g = e.context.obj({
43+
Type: 'Sig',
44+
Filter: 'Adobe.PPKLite',
45+
SubFilter: D,
46+
ByteRange: m,
47+
Contents: F,
48+
Reason: PDFString.of(t),
49+
M: PDFString.fromDate(a ?? new Date()),
50+
ContactInfo: PDFString.of(r),
51+
Name: PDFString.of(i),
52+
Location: PDFString.of(n),
53+
Prop_Build: { Filter: { Name: 'Adobe.PPKLite' }, ...P },
54+
}),
55+
D = new Uint8Array(g.sizeInBytes()),
56+
m = (g.copyBytesInto(D, 0), PDFInvalidObject.of(D)),
57+
F = e.context.register(m);
58+
const s = PDFArray.withContext(e.context);
59+
f.forEach(e => s.push(PDFNumber.of(e)));
60+
(t = e.context.formXObject([], { BBox: f, Resources: {} })),
61+
(a = e.context.obj({
62+
Type: 'Annot',
63+
Subtype: 'Widget',
64+
FT: 'Sig',
65+
Rect: s,
66+
V: F,
67+
T: PDFString.of('Signature1'),
68+
F: 4,
69+
P: o.ref,
70+
AP: { N: e.context.register(t) },
71+
})),
72+
(r = e.context.register(a));
73+
let c = o.node.lookupMaybe(PDFName.of('Annots'), PDFArray),
74+
d =
75+
((c = void 0 === c ? e.context.obj([]) : c).push(r),
76+
o.node.set(PDFName.of('Annots'), c),
77+
e.catalog.lookupMaybe(PDFName.of('AcroForm'), PDFDict));
78+
void 0 === d &&
79+
((d = e.context.obj({ Fields: [] })),
80+
(i = e.context.register(d)),
81+
e.catalog.set(PDFName.of('AcroForm'), i));
82+
let N;
83+
N = d.has(PDFName.of('SigFlags')) ? d.get(PDFName.of('SigFlags')) : PDFNumber.of(0);
84+
n = PDFNumber.of(3 | N.asNumber());
85+
d.set(PDFName.of('SigFlags'), n), d.get(PDFName.of('Fields')).push(r);
86+
};
87+
export { pdflibAddPlaceholder };

apps/OpenSignServer/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)