diff --git a/.gitignore b/.gitignore index 8e62b9ce7..b6dcebdf3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* apps/OpenSign/public/mfbuild/* -microfrontends/SignDocuments/build/* \ No newline at end of file +microfrontends/SignDocuments/build/* +apps/OpenSignServer/files/files/* \ No newline at end of file diff --git a/INSTALLATION.md b/INSTALLATION.md index 6cebe94b8..86a9fb8e6 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -143,5 +143,8 @@ In order to address this, your document storage system must be instructed to acc # Build Local Environment -Below are the steps to follow - +Command to build project - - Execute `make build` + +Command to run project - +- Execute `make run` \ No newline at end of file diff --git a/Makefile b/Makefile index 35fa55901..d44c064b7 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,9 @@ build: + cp .env.local_dev .env + rm -rf apps/OpenSign/public/mfbuild + cd microfrontends/SignDocuments && npm install && npm run build + docker compose up --build --force-recreate + +run: cp .env.local_dev .env docker compose up -d \ No newline at end of file diff --git a/README.md b/README.md index 200487ed5..fe1f2b8e6 100644 --- a/README.md +++ b/README.md @@ -48,14 +48,18 @@ Welcome to OpenSign, an open-source document e-signing solution designed to prov ### Features -- **Secure Signing**: Utilizes state-of-the-art cryptographic algorithms to ensure the security & integrity of your documents. -- **User-Friendly Interface**: Designed with usability in mind, making it easy for both technical and non-technical users. -- **Multi-Platform Support**: Compatible with various browsers and devices. -- **Invite & collaborate users**: Bring multiple people from your team into the signing process, all within your own infrastructure. -- **Secure**: Allows for the easy, secure and seamless organization of your documents using 'OpenSigDrive'. -- **Audit Trails**: Keeps a detailed log of all activities related to the document signing process including IP addresses and access timings. -- **Completion Certificate**: Generate secure completion certificate as soon as a document is signed by all participants. -- **API Support**: Provides a robust API for integration into other software and services. +- **Secure PDF E-Signing:** With the help of Robust encryption algorithms, OpenSign™ ensures maximum security, privacy & compatibility. +- **Annotate Documents:** OpenSign™ allows you to annotate PDF documents with an advanced signing pad that comes with hand drawn signatures support as well as uploaded images & saved signatures for the simplest signing experience. +- **User-Friendly Interface:** OpenSign™ was built while keeping Intuitive design in mind for ease of use. Features like "Sign yourself", "One click signatures" and "OpenSign Drive" makes it stand out of the crowd and even makes it better than a lot of so-called industry leaders. +- **Multi-signer Support:** OpenSign's ability to invite multiple signers for signing along with the ability to invite witnesses & being able to enforce signing in a sequence makes it the only open source solution that is fully loaded and allows it to compete head-to-head with established players. +- **Email Unique Code(OTP) verification support for guest signers:** With OpenSign™, your documents are fully secure even when being signed by guest users. Guest signers can only sign the document after entering a unique code sent to their email address.  +- **"Expiring Docs" & "Rejection":** You can set documents to expire after certain number of days after which nobody will be able to sign it. Not just this, OpenSign also allows signers to reject signing a document. +- **Beautiful email templates:** All document signing invitations, completion notifications & reminders are formatted using great looking email templates. +- **PDF Template Creation(coming soon):** OpenSign™ allows you to create and store PDF document templates for repeated use thereby saving you a lot of time. +- **OpenSign™ Drive:** It is a centralised secure vault for your signed documents that makes storing, signing, organizing, sharing & achieving your docs a breeze. +- **Audit Trails & completion certificate:** Being a security focused solution, OpenSign™ makes it a top priority to save detailed logs for tracking document activities along with time-stamps, IP addresses, email IDs & phone numbers. A completion certificate is generated as soon as document is completed which contains all the document related logs for added safety. +- **API Support(coming soon):** OpenSign™ API allows seamless integration into existing systems and software. APIs will soon be available as a cloud hosted solution. +- **Integrations:** Seamless integrations with various Cloud storage systems, CRMs & enterprise platforms is coming soon. diff --git a/apps/OpenSign/Dockerfile b/apps/OpenSign/Dockerfile index 7d8542bf6..57c815846 100644 --- a/apps/OpenSign/Dockerfile +++ b/apps/OpenSign/Dockerfile @@ -21,5 +21,5 @@ EXPOSE 3000 # ENV NODE_ENV production # Run the application -CMD ["npm", "start"] +ENTRYPOINT npm run start-dev diff --git a/apps/OpenSign/public/mfbuild/.gitkeep b/apps/OpenSign/public/mfbuild/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/OpenSign/src/routes/Login.js b/apps/OpenSign/src/routes/Login.js index 509dc0efd..25ea70907 100644 --- a/apps/OpenSign/src/routes/Login.js +++ b/apps/OpenSign/src/routes/Login.js @@ -1154,7 +1154,7 @@ function Login(props) {
-
Login form
+
Additional Info
@@ -1210,18 +1210,19 @@ function Login(props) {
diff --git a/apps/OpenSign/src/routes/Signup.js b/apps/OpenSign/src/routes/Signup.js index 31c26f566..137c76b21 100644 --- a/apps/OpenSign/src/routes/Signup.js +++ b/apps/OpenSign/src/routes/Signup.js @@ -117,7 +117,7 @@ const Signup = (props) => { await Parse.User.requestPasswordReset(email).then( async function (res1) { if (res1.data === undefined) { - alert("Email has been sent to your mail!"); + alert("Verification mail has been sent to your E-mail!"); } } ); diff --git a/apps/OpenSignServer/cloud/customRoute/uploadFile.js b/apps/OpenSignServer/cloud/customRoute/uploadFile.js index 34abc14d0..b0152e1bd 100644 --- a/apps/OpenSignServer/cloud/customRoute/uploadFile.js +++ b/apps/OpenSignServer/cloud/customRoute/uploadFile.js @@ -4,6 +4,12 @@ import multerS3 from 'multer-s3'; import aws from 'aws-sdk'; import dotenv from 'dotenv'; dotenv.config(); + +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 @@ -50,16 +56,28 @@ async function uploadFile(req, res) { region: process.env.DO_REGION, }); - // 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); + const parseBaseUrl = process.env.SERVER_URL; + const parseAppId = process.env.APP_ID; + + if (process.env.USE_LOCAL == "TRUE") { + var 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); } - // otherwise, return error - return cb('Only ' + accepted_extensions.join(', ') + ' files are allowed!'); - }, - storage: multerS3({ + }); + } else { + var fileStorage = multerS3({ acl: 'public-read', s3, bucket: DO_SPACE, @@ -69,14 +87,25 @@ async function uploadFile(req, res) { key: function (req, file, cb) { //console.log(file); let filename = file.originalname; - let filenam = filename.split('.')[0]; + let newFileName = filename.split('.')[0]; let extension = filename.split('.')[1]; - filenam = filenam + '_' + new Date().toISOString() + '.' + extension; - console.log(filenam); - cb(null, filenam); - }, - }), + 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'); @@ -93,7 +122,14 @@ async function uploadFile(req, res) { const status = 'Success'; //res.header("Access-Control-Allow-Headers", "Content-Type"); //res.setHeader("Access-Control-Allow-Origin", "*"); - return res.json({ status, imageUrl: req.file.location }); + if (process.env.USE_LOCAL == "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); diff --git a/microfrontends/SignDocuments/src/Component/LegaDrive/FolderDrive/legaDriveComponent.js b/microfrontends/SignDocuments/src/Component/LegaDrive/FolderDrive/legaDriveComponent.js index ab7d1bd4c..df62c822d 100644 --- a/microfrontends/SignDocuments/src/Component/LegaDrive/FolderDrive/legaDriveComponent.js +++ b/microfrontends/SignDocuments/src/Component/LegaDrive/FolderDrive/legaDriveComponent.js @@ -99,7 +99,7 @@ function PdfFileComponent({ //function for navigate user to microapp-signature component const checkPdfStatus = async (data) => { - + const hostUrl = getHostUrl(); const expireDate = data.ExpiryDate.iso; const expireUpdateDate = new Date(expireDate).getTime(); @@ -221,13 +221,19 @@ function PdfFileComponent({ // console.log("download") const pdfName = data && data.Name; const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL; - saveAs(pdfUrl, `${pdfName}_signed_by_OpenSign™.pdf`); + saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`); } else if (selectType === "Rename") { // console.log("rename") setRenameValue(data.Name); setRename(data.objectId); } }; + + const sanitizeFileName = (pdfName) => { + // Replace spaces with underscore + return pdfName.replace(/ /g, '_'); + } + const handleEnterPress = (e, data) => { if (e.key === "Enter") { handledRenameDoc(data); diff --git a/microfrontends/SignDocuments/src/Component/SignYourselfPdf.js b/microfrontends/SignDocuments/src/Component/SignYourselfPdf.js index 92eec4b8f..d4cb37df9 100644 --- a/microfrontends/SignDocuments/src/Component/SignYourselfPdf.js +++ b/microfrontends/SignDocuments/src/Component/SignYourselfPdf.js @@ -500,7 +500,6 @@ function SignYourSelf() { removeBase64Fromjpeg, "" ); - //function for call to embed signature in pdf and get digital signature pdf signPdfFun(newImgUrl, documentId, data, pdfBase64, pageNo); }) @@ -575,14 +574,18 @@ function SignYourSelf() { const scale = isMobile ? pdfOriginalWidth / newWidth : 1; const posY = () => { - if (id === 0) { - return ( - page.getHeight() - - imgUrlList[id].yPosition * scale - - imgHeight - ); - } else if (id > 0) { - return page.getHeight() - imgUrlList[id].yPosition * scale; + if (isMobile) { + if (id === 0) { + return ( + page.getHeight() - + imgUrlList[id].yPosition * scale - + imgHeight + ); + } else if (id > 0) { + return page.getHeight() - imgUrlList[id].yPosition * scale; + } + } else { + return page.getHeight() - imgUrlList[id].yPosition - imgHeight; } }; page.drawImage(img, { @@ -596,7 +599,6 @@ function SignYourSelf() { }); } const pdfBytes = await pdfDoc.saveAsBase64({ useObjectStreams: false }); - signPdfFun(pdfBytes, documentId); } setIsSignPad(false); @@ -615,10 +617,11 @@ function SignYourSelf() { pageNo ) => { let singleSign; + const isMobile = window.innerWidth < 767; const newWidth = window.innerWidth; const scale = isMobile ? pdfOriginalWidth / newWidth : 1; - const imgWidth = xyPosData.Width.Width ? xyPosData.Width.Width : 150; + const imgWidth = xyPosData ? xyPosData.Width : 150; if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) { const height = xyPosData.Height ? xyPosData.Height : 60; const bottomY = xyPosData.isDrag @@ -1115,6 +1118,8 @@ function SignYourSelf() { pdfDetails={pdfDetails} isShowHeader={true} currentSigner={true} + alreadySign={pdfUrl ? true : false} + isSignYourself={true} /> {/* className="hidePdf" */} diff --git a/microfrontends/SignDocuments/src/Component/component/emailComponent.js b/microfrontends/SignDocuments/src/Component/component/emailComponent.js index 5892c8ef5..532b3be4e 100644 --- a/microfrontends/SignDocuments/src/Component/component/emailComponent.js +++ b/microfrontends/SignDocuments/src/Component/component/emailComponent.js @@ -28,9 +28,9 @@ function EmailComponent({ setIsLoading(true); let sendMail; for (let i = 0; i < emailCount.length; i++) { - + try { - + const imgPng = "https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"; // "https://qikinnovation.ams3.digitaloceanspaces.com/mailLogo_2023-08-18T12%3A51%3A31.573Z.png"; @@ -41,7 +41,7 @@ function EmailComponent({ "X-Parse-Application-Id": localStorage.getItem("parseAppId"), sessionToken: localStorage.getItem("accesstoken") }; - + const themeBGcolor = themeColor(); let params = { pdfName: pdfName, @@ -125,12 +125,17 @@ function EmailComponent({ //handle download signed pdf const handleDownloadPdf = () => { - saveAs(pdfUrl, `${pdfName}_signed_by_OpenSign™.pdf`); + saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`); }; + const sanitizeFileName = (pdfName) => { + // Replace spaces with underscore + return pdfName.replace(/ /g, '_'); + } + const isAndroid = /Android/i.test(navigator.userAgent); - + return (
{/* isEmail */} @@ -248,13 +253,13 @@ function EmailComponent({ style={{ display: "flex", flexDirection: "row", - + flexWrap: "wrap" }} > {emailCount.map((data, ind) => { return ( -
{ const pdfName = pdfDetails[0] && pdfDetails[0].Name; - saveAs(pdfUrl, `${pdfName}_signed_by_OpenSign™.pdf`); + saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`); }; + const sanitizeFileName = (pdfName) => { + // Replace spaces with underscore + return pdfName.replace(/ /g, '_'); + } + + return (
) : (
- {/* current signer is checking user send request and check status of pdf sign than if current + {/* current signer is checking user send request and check status of pdf sign than if current user exist than show finish button else no */} {currentSigner && (