diff --git a/apps/OpenSign/package.json b/apps/OpenSign/package.json index b77c268de..80baff0ab 100644 --- a/apps/OpenSign/package.json +++ b/apps/OpenSign/package.json @@ -48,7 +48,7 @@ }, "scripts": { "start": "serve -s build", - "start-dev" :"react-scripts start", + "start-dev": "react-scripts start", "version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt", "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\"", "build": "npm run version && react-scripts build", diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js index 85d56af52..166f4449e 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/PDF.min.js @@ -1,7 +1,8 @@ import SignPDF from './SignPDF.min.cjs'; import fs from 'node:fs'; import axios from 'axios'; -import { plainAddPlaceholder } from 'node-signpdf/dist/helpers/index.js'; +import { pdflibAddPlaceholder } from './customSignPdf/pdflibplaceholder.min.js'; +import { PDFDocument } from 'pdf-lib'; const serverUrl = process.env.SERVER_URL, APPID = process.env.APP_ID, masterKEY = process.env.MASTER_KEY; @@ -15,20 +16,20 @@ async function uploadFile(e, a) { console.log('Err ', e), fs.unlinkSync(a); } } -async function updateDoc(t, s, r, i, n, o) { +async function updateDoc(t, s, r, i, o, n) { try { var d = { - UserPtr: { __type: 'Pointer', className: o, objectId: r }, + UserPtr: { __type: 'Pointer', className: n, objectId: r }, SignedUrl: s, Activity: 'Signed', ipAddress: i, }; let e; - var l = (e = n.AuditTrail && 0 < n.AuditTrail.length ? [...n.AuditTrail, d] : [d]).filter( + var l = (e = o.AuditTrail && 0 < o.AuditTrail.length ? [...o.AuditTrail, d] : [d]).filter( e => 'Signed' === e.Activity ); let a = !1; - !((n.Signers && 0 < n.Signers.length && l.length !== n.Signers.length) || !(a = !0)); + !((o.Signers && 0 < o.Signers.length && l.length !== o.Signers.length) || !(a = !0)); var c = { SignedUrl: s, AuditTrail: e, IsCompleted: a }; await axios.put(serverUrl + '/classes/contracts_Document/' + t, c, { headers: { @@ -150,9 +151,8 @@ async function sendDoctoWebhook(t, e, a, s) { } })); } -async function PDF(i, n) { +async function PDF(i) { try { - i.params.sign; var e = i.params.docId, a = i.params.userId, o = await axios.get( @@ -173,125 +173,136 @@ async function PDF(i, n) { }); if (!t.data || !t.data.objectId) return { status: 'error', message: 'this user not allowed!' }; { - var d, + var n, + d, l, - c, - p = JSON.stringify({ objectId: a }); + c = JSON.stringify({ objectId: a }); let s, r; r = a - ? (d = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + p, { + ? (n = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + c, { headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Session-Token': i.headers.sessiontoken, }, - })).data && 0 < d.data.results.length - ? ((s = d), 'contracts_Contactbook') - : ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + p, { + })).data && 0 < n.data.results.length + ? ((s = n), 'contracts_Contactbook') + : ((s = await axios.get(serverUrl + '/classes/contracts_Users?where=' + c, { headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY }, })), 'contracts_Users') - : ((l = JSON.stringify({ + : ((d = JSON.stringify({ UserId: { __type: 'Pointer', className: '_User', objectId: t.data.objectId }, })), - (c = await axios.get(serverUrl + '/classes/contracts_Users?where=' + l, { + (l = await axios.get(serverUrl + '/classes/contracts_Users?where=' + d, { headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Master-Key': masterKEY }, - })).data && 0 < c.data.results.length - ? ((s = c), 'contracts_Users') - : ((s = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + l, { + })).data && 0 < l.data.results.length + ? ((s = l), 'contracts_Users') + : ((s = await axios.get(serverUrl + '/classes/contracts_Contactbook?where=' + d, { headers: { 'X-Parse-Application-Id': APPID, 'X-Parse-Session-Token': i.headers.sessiontoken, }, })), 'contracts_Contactbook')); - var m = s.data.results[0].Name, - g = s.data.results[0].Email; + var p = s.data.results[0].Name, + m = s.data.results[0].Email; if (!i.params.pdfFile) return { status: 'error', message: 'pdf file not present!' }; { let e = Buffer.from(i.params.pdfFile, 'base64'); - var h = process.env.PFX_BASE64, - u = Buffer.from(h, 'base64'), - f = { + var g = process.env.PFX_BASE64, + h = Buffer.from(g, 'base64'), + u = { UserPtr: { __type: 'Pointer', className: r, objectId: s.data.results[0].objectId }, SignedUrl: '', Activity: 'Signed', ipAddress: i.headers['x-real-ip'], }; let a; - var y = (a = + var f = (a = o.data.AuditTrail && 0 < o.data.AuditTrail.length - ? [...o.data.AuditTrail, f] - : [f]).filter(e => 'Signed' === e.Activity); + ? [...o.data.AuditTrail, u] + : [u]).filter(e => 'Signed' === e.Activity); let t = !1; !( - (o.data.Signers && 0 < o.data.Signers.length && y.length !== o.data.Signers.length) || + (o.data.Signers && 0 < o.data.Signers.length && f.length !== o.data.Signers.length) || !(t = !0) ); - var v, + var y, P, - b = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`, - x = './exports/' + b, - U = + v, + b, + x, + w, + U, + I, + S, + A = `exported_file_${Math.floor(5e3 * Math.random())}.pdf`, + D = './exports/' + A, + E = (t - ? ((v = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), + ? ((y = o.data.Signers?.map(e => e.Name + ' <' + e.Email + '>')), (e = - v && 0 < v.length - ? plainAddPlaceholder({ - pdfBuffer: e, - reason: 'Digitally signed by OpenSign for ' + v?.join(', '), + y && 0 < y.length + ? ((P = await PDFDocument.load(e)), + pdflibAddPlaceholder({ + pdfDoc: P, + reason: 'Digitally signed by OpenSign for ' + y?.join(', '), location: 'location', - signatureLength: 1e4, - }) - : plainAddPlaceholder({ - pdfBuffer: e, - reason: 'Digitally signed by OpenSign for ' + m + ' <' + g + '>', + signatureLength: 15e3, + }), + (v = await P.save()), + Buffer.from(v)) + : ((b = await PDFDocument.load(e)), + pdflibAddPlaceholder({ + pdfDoc: b, + reason: 'Digitally signed by OpenSign for ' + p + ' <' + m + '>', location: 'location', - signatureLength: 1e4, - })), - (P = await new SignPDF(e, u).signPDF()), - fs.writeFileSync(x, P)) - : fs.writeFileSync(x, e), - await uploadFile(b, x)); - if (U && U.imageUrl) { - const n = await updateDoc( - i.params.docId, - U.imageUrl, - s.data.results[0].objectId, - i.headers['x-real-ip'], - o.data, - r - ); - var I, - w = { - url: U.imageUrl, + signatureLength: 15e3, + }), + (x = await b.save()), + Buffer.from(x))), + (w = await new SignPDF(e, h).signPDF()), + fs.writeFileSync(D, w)) + : fs.writeFileSync(D, e), + await uploadFile(A, D)); + if (E && E.imageUrl) + return ( + (U = await updateDoc( + i.params.docId, + E.imageUrl, + s.data.results[0].objectId, + i.headers['x-real-ip'], + o.data, + r + )), + (I = { + url: E.imageUrl, sender: { Mail: o.data.ExtUserPtr.Email, Name: o.data.ExtUserPtr.Name }, pdfName: o.data.Name, - receiver: g, - }; - return ( + receiver: m, + }), o.data.IsSendMail && !1 === o.data.IsSendMail ? console.log("don't send mail") - : sendMail(w), - sendDoctoWebhook(o, U.imageUrl, 'signed', s?.data.results?.[0]), - n && - n.isCompleted && - ((I = { - url: U.imageUrl, + : sendMail(I), + sendDoctoWebhook(o, E.imageUrl, 'signed', s?.data.results?.[0]), + U && + U.isCompleted && + ((S = { + url: E.imageUrl, sender: { Mail: o.data.ExtUserPtr.Email, Name: 'OpenSign™' }, pdfName: o.data.Name, receiver: o.data.ExtUserPtr.Email, }), o.data.IsSendMail && !1 === o.data.IsSendMail ? console.log("don't send mail") - : sendCompletedMail(I), - sendDoctoWebhook(o, U.imageUrl, 'completed')), - fs.unlinkSync(x), - console.log('New Signed PDF created called: ' + x), - 'success' === n.message - ? { status: 'success', data: U.imageUrl } + : sendCompletedMail(S), + sendDoctoWebhook(o, E.imageUrl, 'completed')), + fs.unlinkSync(D), + console.log('New Signed PDF created called: ' + D), + 'success' === U.message + ? { status: 'success', data: E.imageUrl } : { status: 'error', message: 'please provide required parameters!' } ); - } } } } catch (e) { diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/customSignPdf/SignPdfError.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/customSignPdf/SignPdfError.min.js index 54ea42ede..4557aca9f 100644 --- a/apps/OpenSignServer/cloud/parsefunction/pdf/customSignPdf/SignPdfError.min.js +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/customSignPdf/SignPdfError.min.js @@ -1 +1,20 @@ -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}; \ No newline at end of file +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 { + ERROR_TYPE_UNKNOWN, + ERROR_TYPE_INPUT, + ERROR_TYPE_PARSE, + ERROR_VERIFY_SIGNATURE, + SignPdfError, +}; diff --git a/apps/OpenSignServer/cloud/parsefunction/pdf/customSignPdf/pdflibplaceholder.min.js b/apps/OpenSignServer/cloud/parsefunction/pdf/customSignPdf/pdflibplaceholder.min.js new file mode 100644 index 000000000..610e5012d --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/pdf/customSignPdf/pdflibplaceholder.min.js @@ -0,0 +1,87 @@ +import { + DEFAULT_BYTE_RANGE_PLACEHOLDER, + DEFAULT_SIGNATURE_LENGTH, + SUBFILTER_ADOBE_PKCS7_DETACHED, +} from './const.min.js'; +import { SignPdfError } from './SignPdfError.min.js'; +import { + PDFArray, + PDFDict, + PDFHexString, + PDFName, + PDFNumber, + PDFInvalidObject, + PDFString, +} from 'pdf-lib'; +const pdflibAddPlaceholder = ({ + pdfDoc: e = void 0, + pdfPage: o = void 0, + reason: t, + contactInfo: r = 'emailfromp1289@gmail.com', + name: i = 'Name from p12', + location: n, + signingTime: a = void 0, + signatureLength: P = DEFAULT_SIGNATURE_LENGTH, + byteRangePlaceholder: F = DEFAULT_BYTE_RANGE_PLACEHOLDER, + subFilter: D = SUBFILTER_ADOBE_PKCS7_DETACHED, + widgetRect: f = [0, 0, 0, 0], + appName: g = void 0, +}) => { + if (void 0 === e && void 0 === o) + throw new SignPdfError('PDFDoc or PDFPage must be set.', SignPdfError.TYPE_INPUT); + var e = e ?? o.doc, + o = o ?? e.getPages()[0], + m = PDFArray.withContext(e.context), + F = + (m.push(PDFNumber.of(0)), + m.push(PDFName.of(F)), + m.push(PDFName.of(F)), + m.push(PDFName.of(F)), + PDFHexString.of(String.fromCharCode(0).repeat(P))), + P = g ? { App: { Name: g } } : {}, + g = e.context.obj({ + Type: 'Sig', + Filter: 'Adobe.PPKLite', + SubFilter: D, + ByteRange: m, + Contents: F, + Reason: PDFString.of(t), + M: PDFString.fromDate(a ?? new Date()), + ContactInfo: PDFString.of(r), + Name: PDFString.of(i), + Location: PDFString.of(n), + Prop_Build: { Filter: { Name: 'Adobe.PPKLite' }, ...P }, + }), + D = new Uint8Array(g.sizeInBytes()), + m = (g.copyBytesInto(D, 0), PDFInvalidObject.of(D)), + F = e.context.register(m); + const s = PDFArray.withContext(e.context); + f.forEach(e => s.push(PDFNumber.of(e))); + (t = e.context.formXObject([], { BBox: f, Resources: {} })), + (a = e.context.obj({ + Type: 'Annot', + Subtype: 'Widget', + FT: 'Sig', + Rect: s, + V: F, + T: PDFString.of('Signature1'), + F: 4, + P: o.ref, + AP: { N: e.context.register(t) }, + })), + (r = e.context.register(a)); + let c = o.node.lookupMaybe(PDFName.of('Annots'), PDFArray), + d = + ((c = void 0 === c ? e.context.obj([]) : c).push(r), + o.node.set(PDFName.of('Annots'), c), + e.catalog.lookupMaybe(PDFName.of('AcroForm'), PDFDict)); + void 0 === d && + ((d = e.context.obj({ Fields: [] })), + (i = e.context.register(d)), + e.catalog.set(PDFName.of('AcroForm'), i)); + let N; + N = d.has(PDFName.of('SigFlags')) ? d.get(PDFName.of('SigFlags')) : PDFNumber.of(0); + n = PDFNumber.of(3 | N.asNumber()); + d.set(PDFName.of('SigFlags'), n), d.get(PDFName.of('Fields')).push(r); +}; +export { pdflibAddPlaceholder }; diff --git a/apps/OpenSignServer/package-lock.json b/apps/OpenSignServer/package-lock.json index e32a872a0..ff47aa212 100644 --- a/apps/OpenSignServer/package-lock.json +++ b/apps/OpenSignServer/package-lock.json @@ -32,7 +32,7 @@ "parse-server-api-mail-adapter": "^3.1.1", "parse-server-fs-adapter": "1.0.1", "parse-server-s3-adapter": "^1.2.0", - "pdf-lib": "^1.16.0", + "pdf-lib": "^1.17.1", "pdfkit": "^0.13.0", "posthog-node": "^3.6.2", "razorpay": "^2.8.6", @@ -7025,9 +7025,9 @@ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/pdf-lib": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.16.0.tgz", - "integrity": "sha512-P/1SSmElOBKrPlbc+Sn7UxikRQbzVA64+4Dh6/uczPscvq/NatP9eryoOguyBTpTnzICNiG8EnMH4Ziqp2TnFA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz", + "integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==", "dependencies": { "@pdf-lib/standard-fonts": "^1.0.0", "@pdf-lib/upng": "^1.0.1", diff --git a/apps/OpenSignServer/package.json b/apps/OpenSignServer/package.json index c5cb6d1b7..c3c8dd7e5 100644 --- a/apps/OpenSignServer/package.json +++ b/apps/OpenSignServer/package.json @@ -41,7 +41,7 @@ "parse-server-api-mail-adapter": "^3.1.1", "parse-server-fs-adapter": "1.0.1", "parse-server-s3-adapter": "^1.2.0", - "pdf-lib": "^1.16.0", + "pdf-lib": "^1.17.1", "pdfkit": "^0.13.0", "posthog-node": "^3.6.2", "razorpay": "^2.8.6",