mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-26 17:42:33 +02:00
@@ -2,6 +2,8 @@ import express from 'express';
|
||||
import cors from 'cors';
|
||||
import dotenv from 'dotenv';
|
||||
import uploadFile from './uploadFile.js';
|
||||
import docxtopdf, { upload as docxUpload } from './docxtopdf.js';
|
||||
import decryptpdf, { upload as decryptUpload } from './decryptpdf.js';
|
||||
|
||||
export const app = express();
|
||||
|
||||
@@ -11,4 +13,5 @@ app.use(express.json({ limit: '50mb' }));
|
||||
app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
||||
|
||||
app.post('/file_upload', uploadFile);
|
||||
|
||||
app.post('/docxtopdf', docxUpload.single('file'), docxtopdf);
|
||||
app.post('/decryptpdf', decryptUpload.single('file'), decryptpdf);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import fs from 'node:fs';
|
||||
import multer from 'multer';
|
||||
import Coherentpdf from 'coherentpdf';
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination(req, file, cb) {
|
||||
cb(null, 'exports');
|
||||
},
|
||||
filename(req, file, cb) {
|
||||
cb(null, file.originalname);
|
||||
},
|
||||
});
|
||||
|
||||
export const upload = multer({ storage });
|
||||
|
||||
export default async function decryptpdf(req, res) {
|
||||
const inputPath = req.file.path;
|
||||
const outputPath = './exports/out.pdf';
|
||||
const password = req.body.password || '';
|
||||
try {
|
||||
const file = fs.readFileSync(inputPath);
|
||||
const pdf = await Coherentpdf.fromMemory(file, password);
|
||||
await Coherentpdf.decryptPdf(pdf, password);
|
||||
await Coherentpdf.toFile(pdf, outputPath, false, false);
|
||||
const buffer = fs.readFileSync(outputPath);
|
||||
res.set('Content-Type', 'application/pdf');
|
||||
res.send(buffer);
|
||||
fs.unlink(inputPath, () => {});
|
||||
} catch (err) {
|
||||
fs.unlink(inputPath, () => {});
|
||||
console.log('Error in decrypt file: ', err);
|
||||
let code = err?.code ? err.code : 400;
|
||||
let message = err?.[2]?.c ? err[2].c : 'Something went wrong.';
|
||||
if (err?.[2]?.c?.includes('Bad password') || err?.[2]?.c?.includes('decrypt_pdf_inner')) {
|
||||
code = 401;
|
||||
message = 'Incorrect password.';
|
||||
}
|
||||
return res.status(code).json({ error: message });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
import fs from 'node:fs';
|
||||
import axios from 'axios';
|
||||
import multer from 'multer';
|
||||
import libre from 'libreoffice-convert';
|
||||
import util from 'node:util';
|
||||
import { cloudServerUrl, getSecureUrl } from '../../Utils.js';
|
||||
|
||||
libre.convertAsync = util.promisify(libre.convert);
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination(req, file, cb) {
|
||||
cb(null, 'exports');
|
||||
},
|
||||
filename(req, file, cb) {
|
||||
cb(null, file.originalname);
|
||||
},
|
||||
});
|
||||
|
||||
export const upload = multer({ storage });
|
||||
|
||||
function generatePdfName(length) {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export default async function docxtopdf(req, res) {
|
||||
const serverUrl = cloudServerUrl;
|
||||
const appId = process.env.APP_ID;
|
||||
const masterKey = process.env.MASTER_KEY;
|
||||
const inputPath = req.file.path;
|
||||
const name = generatePdfName(16);
|
||||
const fileName = `${name}.pdf`;
|
||||
const outputPath = './exports/output.pdf';
|
||||
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': req.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = JSON.stringify({
|
||||
UserId: {
|
||||
__type: 'Pointer',
|
||||
className: '_User',
|
||||
objectId: userRes.data.objectId,
|
||||
},
|
||||
});
|
||||
const resUser = await axios.get(
|
||||
serverUrl + `/classes/contracts_Users?where=${userId}&limit=1&include=TenantId`,
|
||||
{
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Master-Key': masterKey,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (resUser?.data?.results?.length > 0) {
|
||||
const tenantId = resUser.data.results[0].TenantId?.objectId;
|
||||
const ext = '.pdf';
|
||||
const outPath = `./exports/output${ext}`;
|
||||
const docxBuf = fs.readFileSync(inputPath);
|
||||
const pdfBuffer = await libre.convertAsync(docxBuf, ext, undefined);
|
||||
fs.writeFileSync(outPath, pdfBuffer);
|
||||
const file = fs.readFileSync(outPath);
|
||||
const size = fs.statSync(outPath).size;
|
||||
const PartnersTenant = JSON.stringify({
|
||||
PartnersTenant: {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: tenantId,
|
||||
},
|
||||
});
|
||||
const resTenantCredit = await axios.get(
|
||||
serverUrl + `/classes/partners_TenantCredits?where=${PartnersTenant}&limit=1`,
|
||||
{
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Master-Key': masterKey,
|
||||
},
|
||||
}
|
||||
);
|
||||
if (resTenantCredit.data?.results?.length > 0) {
|
||||
const tenantCreditsId = resTenantCredit.data.results[0].objectId;
|
||||
const activeFileAdapter = resUser.data.results[0].TenantId?.ActiveFileAdapter;
|
||||
let fileUrl;
|
||||
if (activeFileAdapter) {
|
||||
const params = {
|
||||
fileBase64: file.toString('base64'),
|
||||
fileName,
|
||||
id: activeFileAdapter,
|
||||
};
|
||||
const url = serverUrl + '/functions/savetofileadapter';
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': req.headers['sessiontoken'],
|
||||
};
|
||||
try {
|
||||
const savetos3 = await axios.post(url, params, { headers });
|
||||
fileUrl = savetos3?.data?.result?.url;
|
||||
} catch (err) {
|
||||
console.log('err in save to customfile', err);
|
||||
}
|
||||
} else {
|
||||
const parsefile = await axios.post(serverUrl + `/files/${fileName}`, file, {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Master-Key': masterKey,
|
||||
'Content-Type': 'application/pdf',
|
||||
},
|
||||
});
|
||||
const fileRes = getSecureUrl(parsefile.data.url);
|
||||
fileUrl = fileRes.url;
|
||||
}
|
||||
const usedStorage = resTenantCredit.data.results[0].usedStorage
|
||||
? resTenantCredit.data.results[0].usedStorage + size
|
||||
: size;
|
||||
await axios.put(
|
||||
serverUrl + `/classes/partners_TenantCredits/${tenantCreditsId}`,
|
||||
{ usedStorage },
|
||||
{
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Master-Key': masterKey,
|
||||
},
|
||||
}
|
||||
);
|
||||
await axios.post(
|
||||
serverUrl + '/classes/partners_DataFiles',
|
||||
{
|
||||
FileSize: size,
|
||||
FileUrl: fileUrl,
|
||||
TenantPtr: {
|
||||
__type: 'Pointer',
|
||||
className: 'partners_Tenant',
|
||||
objectId: tenantId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Master-Key': masterKey,
|
||||
},
|
||||
}
|
||||
);
|
||||
[inputPath, outPath].forEach(p => fs.existsSync(p) && fs.unlinkSync(p));
|
||||
return res.status(200).json({ message: 'success.', url: fileUrl });
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
[inputPath, outputPath].forEach(p => fs.existsSync(p) && fs.unlinkSync(p));
|
||||
const msg =
|
||||
err?.response?.data?.error || err?.response?.data || err?.message || 'Something went wrong.';
|
||||
console.log(`Error converting file: ${msg}`);
|
||||
|
||||
const message =
|
||||
'We are currently experiencing some issues with processing DOCX files. Please upload the PDF version or contact us on support@opensignlabs.com';
|
||||
return res.status(400).json({ error: message });
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,6 @@ async function deductcount(docsCount, extUserId) {
|
||||
async function sendMail(document, publicUrl) {
|
||||
//sessionToken
|
||||
const baseUrl = new URL(publicUrl);
|
||||
|
||||
// console.log("pdfDetails", pdfDetails);
|
||||
const timeToCompleteDays = document?.TimeToCompleteDays || 15;
|
||||
const ExpireDate = new Date(document.createdAt);
|
||||
ExpireDate.setDate(ExpireDate.getDate() + timeToCompleteDays);
|
||||
@@ -168,9 +166,9 @@ async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) {
|
||||
})),
|
||||
ACL: Acl,
|
||||
SentToOthers: true,
|
||||
RemindOnceInEvery: x.RemindOnceInEvery || 5,
|
||||
RemindOnceInEvery: x.RemindOnceInEvery ? parseInt(x.RemindOnceInEvery) : 5,
|
||||
AutomaticReminders: x.AutomaticReminders || false,
|
||||
TimeToCompleteDays: x.TimeToCompleteDays || 15,
|
||||
TimeToCompleteDays: x.TimeToCompleteDays ? parseInt(x.TimeToCompleteDays) : 15,
|
||||
OriginIp: Ip,
|
||||
DocSentAt: { __type: 'Date', iso: isoDate },
|
||||
IsEnableOTP: x?.IsEnableOTP || false,
|
||||
@@ -231,6 +229,7 @@ export default async function createBatchDocs(request) {
|
||||
const sessionToken = request.headers?.sessiontoken;
|
||||
const type = request.headers?.type || 'quicksend';
|
||||
const Documents = JSON.parse(strDocuments);
|
||||
|
||||
const Ip = request?.headers?.['x-real-ip'] || '';
|
||||
// Access the host from the headers
|
||||
const publicUrl = request.headers.public_url;
|
||||
|
||||
@@ -65,7 +65,7 @@ export default async function generateCertificatebydocId(req) {
|
||||
const certificate = await GenerateCertificate(doc);
|
||||
const certificatePdf = await PDFDocument.load(certificate);
|
||||
const p12 = new P12Signer(P12Buffer, { passphrase: process.env.PASS_PHRASE || null });
|
||||
// `pdflibAddPlaceholder` is used to add code of only digitial sign in certificate
|
||||
// `pdflibAddPlaceholder` is used to add code of only digital sign in certificate
|
||||
pdflibAddPlaceholder({
|
||||
pdfDoc: certificatePdf,
|
||||
reason: `Digitally signed by ${eSignName}.`,
|
||||
|
||||
@@ -2,19 +2,26 @@ import { cloudServerUrl } from '../../Utils.js';
|
||||
import reportJson from './reportsJson.js';
|
||||
import axios from 'axios';
|
||||
|
||||
// Escape regex special characters. Copied from filterDocs.js
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
export default async function getReport(request) {
|
||||
const reportId = request.params.reportId;
|
||||
const limit = request.params.limit;
|
||||
const skip = request.params.skip;
|
||||
const searchTerm = request.params.searchTerm || '';
|
||||
|
||||
const serverUrl = cloudServerUrl; //process.env.SERVER_URL;
|
||||
const appId = process.env.APP_ID;
|
||||
const masterKey = process.env.MASTER_KEY;
|
||||
const sessionToken = request.headers['sessiontoken'] || request.headers['x-parse-session-token'];
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': appId,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
'X-Parse-Session-Token': sessionToken,
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
@@ -25,7 +32,7 @@ export default async function getReport(request) {
|
||||
const { params, keys } = json;
|
||||
const orderBy = '-updatedAt';
|
||||
const strKeys = keys.join();
|
||||
let strParams = JSON.stringify(params);
|
||||
let paramsObj = { ...params };
|
||||
if (reportId == '6TeaPr321t') {
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('Email', userRes.data.email);
|
||||
@@ -36,8 +43,8 @@ export default async function getReport(request) {
|
||||
if (_extUser?.TeamIds && _extUser.TeamIds?.length > 0) {
|
||||
let teamArr = [];
|
||||
_extUser?.TeamIds?.forEach(x => (teamArr = [...teamArr, ...x.Ancestors]));
|
||||
strParams = JSON.stringify({
|
||||
...params,
|
||||
paramsObj = {
|
||||
...paramsObj,
|
||||
$or: [
|
||||
{ SharedWith: { $in: teamArr } },
|
||||
{
|
||||
@@ -55,15 +62,23 @@ export default async function getReport(request) {
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
} else {
|
||||
strParams = JSON.stringify({
|
||||
...params,
|
||||
paramsObj = {
|
||||
...paramsObj,
|
||||
CreatedBy: { __type: 'Pointer', className: '_User', objectId: userId },
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (searchTerm) {
|
||||
const escaped = escapeRegExp(searchTerm);
|
||||
paramsObj = {
|
||||
...paramsObj,
|
||||
Name: { $regex: `.*${escaped}.*`, $options: 'i' },
|
||||
};
|
||||
}
|
||||
const strParams = JSON.stringify(paramsObj);
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': appId,
|
||||
|
||||
@@ -14,11 +14,14 @@ export default async function recreateDocument(request) {
|
||||
if (!doc) {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Document not found');
|
||||
}
|
||||
if (doc?.get('IsSignyourself')) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Signyourself Document not allowed');
|
||||
}
|
||||
const _docRes = doc?.toJSON();
|
||||
const { objectId, SignedUrl, AuditTrail, ACL, DeclineBy, DeclineReason, ...docRes } = _docRes;
|
||||
const createDoc = new Parse.Object('contracts_Document');
|
||||
Object.entries(docRes).forEach(([key, value]) => {
|
||||
if (key === 'IsDeclined') {
|
||||
if (key === 'IsDeclined' || key === 'IsCompleted') {
|
||||
createDoc.set(key, false);
|
||||
} else {
|
||||
createDoc.set(key, value);
|
||||
|
||||
@@ -55,7 +55,7 @@ export default function reportJson(id, userId) {
|
||||
'ExpiryDate',
|
||||
],
|
||||
};
|
||||
// In progess report
|
||||
// In progress report
|
||||
case '1MwEuxLEkF':
|
||||
return {
|
||||
reportName: 'In-progress documents',
|
||||
@@ -123,6 +123,8 @@ export default function reportJson(id, userId) {
|
||||
'TimeToCompleteDays',
|
||||
'IsSignyourself',
|
||||
'IsCompleted',
|
||||
'ExpiryDate',
|
||||
'IsSignyourself',
|
||||
],
|
||||
};
|
||||
// declined documents report
|
||||
|
||||
@@ -51,6 +51,17 @@ export default async function saveAsTemplate(request) {
|
||||
|
||||
if (_docRes?.Placeholders?.length > 0) {
|
||||
if (_docRes?.IsSignyourself) {
|
||||
//add required option for all widget when save as template using signyour-self draft document
|
||||
const updatedPlaceholder = _docRes?.Placeholders.map(pageItem => ({
|
||||
...pageItem,
|
||||
pos: pageItem.pos.map(p => ({
|
||||
...p,
|
||||
options: {
|
||||
...p.options,
|
||||
status: 'required',
|
||||
},
|
||||
})),
|
||||
}));
|
||||
const placeHolders = {
|
||||
signerObjId: '',
|
||||
signerPtr: {},
|
||||
@@ -58,7 +69,7 @@ export default async function saveAsTemplate(request) {
|
||||
blockColor: '#93a3db',
|
||||
Role: 'Role 1',
|
||||
email: '',
|
||||
placeHolder: _docRes?.Placeholders,
|
||||
placeHolder: updatedPlaceholder,
|
||||
};
|
||||
templateCls.set('Placeholders', [placeHolders]);
|
||||
} else {
|
||||
|
||||
@@ -53,10 +53,16 @@ const makeEmail = async (
|
||||
const isSecure =
|
||||
new URL(url)?.protocol === 'https:' && new URL(url)?.hostname !== 'localhost';
|
||||
if (isSecure) {
|
||||
https.get(url, async function (response) {
|
||||
response.pipe(Pdf);
|
||||
response.on('end', () => resolve('success'));
|
||||
});
|
||||
https
|
||||
.get(url, async function (response) {
|
||||
response.pipe(Pdf);
|
||||
Pdf.on('finish', () => resolve('success'));
|
||||
Pdf.on('error', () => resolve('error'));
|
||||
})
|
||||
.on('error', e => {
|
||||
console.error(`error: ${e.message}`);
|
||||
resolve('error');
|
||||
});
|
||||
} else {
|
||||
const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Disable SSL validation
|
||||
axios
|
||||
|
||||
Reference in New Issue
Block a user