Delete apps/OpenSignServer/package-lock.json

This commit is contained in:
prafull-opensignlabs
2026-02-06 12:45:57 +00:00
parent f1278d32a8
commit 336cfb3482
59 changed files with 3201 additions and 33098 deletions
@@ -1,7 +1,6 @@
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';
@@ -16,7 +15,6 @@ app.use(cors());
app.use(express.json({ limit: '100mb' }));
app.use(express.urlencoded({ limit: '100mb', extended: true }));
app.post('/file_upload', uploadFile);
app.post('/docxtopdf', docxUpload.single('file'), docxtopdf);
app.post('/decryptpdf', decryptUpload.single('file'), decryptpdf);
app.get('/delete-account/:userId', deleteUserGet);
@@ -1,8 +1,31 @@
import axios from 'axios';
import multer from 'multer';
import libre from 'libreoffice-convert';
import { exec } from 'child_process';
import { promisify } from 'util';
import { cloudServerUrl, getSecureUrl, serverAppId } from '../../Utils.js';
const execAsync = promisify(exec);
// -------------------- Process Management --------------------
/**
* Kill stuck LibreOffice processes
*/
async function killStuckProcesses() {
try {
// Kill soffice processes older than 2 minutes
if (process.platform === 'linux' || process.platform === 'darwin') {
await execAsync("pkill -9 -f 'soffice.*--headless' || true");
console.log('[DOCX2PDF] Cleaned up stuck processes');
} else if (process.platform === 'win32') {
await execAsync('taskkill /F /IM soffice.bin /T || exit 0');
console.log('[DOCX2PDF] Cleaned up stuck processes (Windows)');
}
} catch (err) {
console.error('[DOCX2PDF] Error killing processes:', err.message);
}
}
/** @returns {Promise<Buffer>} */
async function convertLibre(input, ext, opts) {
return await new Promise((resolve, reject) => {
@@ -14,7 +37,7 @@ async function convertLibre(input, ext, opts) {
});
}
// -------------------- Concurrency limiter --------------------
// -------------------- Concurrency limiter with queue limits --------------------
// CRITICAL FIX: Reduced to 1 for CPU-intensive LibreOffice conversions
const MAX_CONCURRENCY = Number(process.env.DOCX2PDF_CONCURRENCY || 1);
let active = 0;
@@ -22,22 +45,27 @@ const queue = [];
function runWithLimit(task) {
return new Promise((resolve, reject) => {
const run = () => {
const run = async () => {
active++;
Promise.resolve()
.then(task)
.then(resolve, reject)
.finally(() => {
active--;
if (queue.length) queue.shift()();
});
try {
const result = await task();
resolve(result);
} catch (error) {
reject(error);
} finally {
active--;
if (queue.length) {
const next = queue.shift();
next();
}
}
};
if (active < MAX_CONCURRENCY) run();
else queue.push(run);
});
}
// -------------------- Timeout helper --------------------
// -------------------- Timeout helper with cleanup --------------------
/**
* @template T
* @param {Promise<T>} promise
@@ -49,7 +77,11 @@ export async function withTimeout(promise, ms, label = 'operation') {
let timer;
try {
const timeout = new Promise((_, reject) => {
timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
timer = setTimeout(async () => {
// Kill stuck processes on timeout
await killStuckProcesses();
reject(new Error(`${label} timed out after ${ms}ms`));
}, ms);
});
return await Promise.race([promise, timeout]);
} finally {
@@ -116,22 +148,29 @@ export default async function docxtopdf(req, res) {
// ---- DOCX -> PDF conversion with concurrency control and timeout ----
const fileName = `${generatePdfName(16)}.pdf`;
// FIX: Increased timeout to 90s for large files, added nice priority
// Adjust timeout based on file size
const timeoutMs = uploadedSizeBytes > 10 * 1024 * 1024 ? 120_000 : 90_000;
// FIX: Increased timeout for large files, added nice priority
const pdfBuffer = await runWithLimit(async () => {
// Log for monitoring
console.log(`[DOCX2PDF] Starting conversion, active: ${active}, queued: ${queue.length}`);
console.log(
`[DOCX2PDF] Starting conversion, size: ${(uploadedSizeBytes / 1024 / 1024).toFixed(2)}MB, active: ${active}, queued: ${queue.length}`
);
const startTime = Date.now();
try {
const result = await withTimeout(
convertLibre(req.file.buffer, '.pdf', undefined),
90_000, // Increased from 60s to 90s
timeoutMs,
'DOCX->PDF'
);
console.log(`[DOCX2PDF] Completed in ${Date.now() - startTime}ms`);
return result;
} catch (error) {
console.error(`[DOCX2PDF] Failed after ${Date.now() - startTime}ms:`, error.message);
// Clean up on error
await killStuckProcesses();
throw error;
}
});
@@ -1,168 +0,0 @@
// npm packages
import multer from 'multer';
import multerS3 from 'multer-s3';
import aws from 'aws-sdk';
import dotenv from 'dotenv';
import { cloudServerUrl, serverAppId, useLocal } from '../../Utils.js';
dotenv.config({ quiet: true });
function sanitizeFileName(fileName) {
// Remove spaces and invalid characters
return fileName.replace(/[^a-zA-Z0-9._-]/g, '');
}
async function uploadFile(req, res) {
try {
//--size extended to 100 mb
const size = 100 * 1024 * 1024;
//console.log(size);
const accepted_extensions = [
'jpg',
'png',
'gif',
'mp4',
'mp3',
'pdf',
'jpeg',
'dwg',
'dxf',
'zip',
'rar',
'txt',
'doc',
'docx',
'pptx',
'ppt',
'xlsx',
'xlsm',
'xlsb',
'xltx',
'xml',
'xls',
'xla',
'xlx',
];
const DO_ENDPOINT = process.env.DO_ENDPOINT;
const DO_ACCESS_KEY_ID = process.env.DO_ACCESS_KEY_ID;
const DO_SECRET_ACCESS_KEY = process.env.DO_SECRET_ACCESS_KEY;
const DO_SPACE = process.env.DO_SPACE;
const parseBaseUrl = cloudServerUrl; //process.env.SERVER_URL;
const parseAppId = serverAppId;
let fileStorage;
if (useLocal === 'true') {
fileStorage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'files/files');
},
metadata: function (req, file, cb) {
cb(null, { fieldName: 'OPENSIGN_METADATA' });
},
filename: function (req, file, cb) {
let filename = file.originalname;
let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1];
newFileName = sanitizeFileName(
newFileName + '_' + new Date().toISOString() + '.' + extension
);
// console.log(newFileName);
cb(null, newFileName);
},
});
} else {
try {
const spacesEndpoint = new aws.Endpoint(DO_ENDPOINT);
const s3 = new aws.S3({
endpoint: spacesEndpoint,
accessKeyId: DO_ACCESS_KEY_ID,
secretAccessKey: DO_SECRET_ACCESS_KEY,
signatureVersion: 'v4',
region: process.env.DO_REGION,
});
fileStorage = multerS3({
acl: 'public-read',
s3,
bucket: DO_SPACE,
metadata: function (req, file, cb) {
cb(null, { fieldName: 'OPENSIGN_METADATA' });
},
key: function (req, file, cb) {
//console.log(file);
let filename = file.originalname;
let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1];
newFileName = sanitizeFileName(
newFileName + '_' + new Date().toISOString() + '.' + extension
);
// console.log(newFileName);
cb(null, newFileName);
},
});
} catch (err) {
fileStorage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'files/files');
},
metadata: function (req, file, cb) {
cb(null, { fieldName: 'OPENSIGN_METADATA' });
},
filename: function (req, file, cb) {
let filename = file.originalname;
let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1];
newFileName = sanitizeFileName(
newFileName + '_' + new Date().toISOString() + '.' + extension
);
// console.log(newFileName);
cb(null, newFileName);
},
});
}
}
// const s3 = new aws.S3();
const upload = multer({
fileFilter: function (req, file, cb) {
if (accepted_extensions.some(ext => file.originalname.toLowerCase().endsWith('.' + ext))) {
return cb(null, true);
}
// otherwise, return error
return cb('Only ' + accepted_extensions.join(', ') + ' files are allowed!');
},
storage: fileStorage,
limits: { fileSize: size },
}).single('file');
//--call upload function--
upload(req, res, function (err, some) {
if (err) {
console.log(err);
const status = 'Error';
const message = err;
const returnCode = 1029;
return res.send({ status, returnCode, message });
}
const status = 'Success';
//res.header("Access-Control-Allow-Headers", "Content-Type");
//res.setHeader("Access-Control-Allow-Origin", "*");
if (useLocal === 'true') {
// console.log(req.file);
var fileUrl = `${parseBaseUrl}/files/${parseAppId}/${req.file.filename}`;
} else {
var fileUrl = req.file.location;
}
return res.json({ status, imageUrl: fileUrl });
});
} catch (err) {
console.log('Exeption in query ' + err.stack);
const status = 'Error';
const returnCode = 1021;
const message = 'Some error occurred';
return res.send({ status, returnCode, message });
}
}
export default uploadFile;
@@ -25,7 +25,7 @@ async function sendMail(document, publicUrl) {
month: 'long',
year: 'numeric',
});
let signerMail = document.Placeholders;
let signerMail = document.Placeholders?.filter(x => x?.Role !== 'prefill');
const senderName = document.ExtUserPtr.Name;
const senderEmail = document.ExtUserPtr.Email;
@@ -109,9 +109,12 @@ async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) {
try {
const requests = Documents.map(x => {
const Signers = x.Signers;
const allSigner = x?.Placeholders?.map(
item => Signers?.find(e => item?.signerPtr?.objectId === e?.objectId) || item?.signerPtr
).filter(signer => Object.keys(signer).length > 0);
const placeholders = x?.Placeholders?.filter(p => p?.Role !== 'prefill');
const allSigner = placeholders
?.map(
item => Signers?.find(e => item?.signerPtr?.objectId === e?.objectId) || item?.signerPtr
)
.filter(signer => Object.keys(signer).length > 0);
const date = new Date();
const isoDate = date.toISOString();
let Acl = { [x.CreatedBy.objectId]: { read: true, write: true } };
@@ -140,7 +143,7 @@ async function batchQuery(userId, Documents, Ip, parseConfig, type, publicUrl) {
className: x.ExtUserPtr.className,
objectId: x.ExtUserPtr?.objectId,
},
Placeholders: x.Placeholders.map(y =>
Placeholders: placeholders.map(y =>
y?.signerPtr?.objectId
? {
...y,
@@ -2,7 +2,6 @@ import { SignPdf } from '@signpdf/signpdf';
import { P12Signer } from '@signpdf/signer-p12';
import { pdflibAddPlaceholder } from '@signpdf/placeholder-pdf-lib';
import { PDFDocument } from 'pdf-lib';
import Parse from 'parse/node.js';
import fs from 'node:fs';
import dotenv from 'dotenv';
import GenerateCertificate from './pdf/GenerateCertificate.js';
@@ -2,6 +2,7 @@ import AWS from 'aws-sdk';
import { useLocal } from '../../Utils.js';
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
import { isAuthenticated } from '../../utils/AuthUtils.js';
dotenv.config({ quiet: true });
export default function getPresignedUrl(url) {
@@ -42,6 +43,7 @@ export async function getSignedUrl(request) {
const docId = request.params.docId || '';
const templateId = request.params.templateId || '';
const url = request.params.url;
if (docId || templateId) {
try {
if (url?.includes('files')) {
@@ -56,8 +58,14 @@ export async function getSignedUrl(request) {
const _resDoc = res?.toJSON();
// Ensure user is authenticated if OTP is required
if (_resDoc?.IsEnableOTP && !request?.user) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
if (_resDoc?.IsEnableOTP) {
const isAuth = await isAuthenticated(request?.user);
if (!isAuth) {
throw new Parse.Error(
Parse.Error.INVALID_SESSION_TOKEN,
'User is not authenticated.'
);
}
}
const presignedUrl = getPresignedUrl(url);
@@ -70,7 +78,8 @@ export async function getSignedUrl(request) {
throw err;
}
} else {
if (!request?.user) {
const isAuth = await isAuthenticated(request?.user);
if (!isAuth) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'User is not authenticated.');
} else {
if (url?.includes('files')) {
@@ -56,6 +56,7 @@ export default async function saveAsTemplate(request) {
pos: pageItem.pos.map(p => ({
...p,
type: p.type === 'text' ? 'text input' : p.type,
signatureType: '',
options: {
...p.options,
status: 'required',
@@ -92,6 +93,7 @@ export default async function saveAsTemplate(request) {
if (widget.options && widget.options.defaultValue !== undefined) {
return {
...widget,
signatureType: '',
options: {
...widget.options,
defaultValue: '',