Merge pull request #13 from OpenSignLabs/staging

sync fork
This commit is contained in:
prafull-opensignlabs
2023-11-13 16:00:03 +05:30
committed by GitHub
13 changed files with 131 additions and 58 deletions
+2 -1
View File
@@ -23,4 +23,5 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
apps/OpenSign/public/mfbuild/*
microfrontends/SignDocuments/build/*
microfrontends/SignDocuments/build/*
apps/OpenSignServer/files/files/*
+4 -1
View File
@@ -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`
+6
View File
@@ -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
+12 -8
View File
@@ -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.
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/b37ff443-7099-4273-9aeb-21c46d7154cf height='200'>
<img src=https://github.com/OpenSignLabs/OpenSign/assets/5486116/86db91b7-6c2f-4885-a33c-58f4fd35ec89 height='200'>
+1 -1
View File
@@ -21,5 +21,5 @@ EXPOSE 3000
# ENV NODE_ENV production
# Run the application
CMD ["npm", "start"]
ENTRYPOINT npm run start-dev
+9 -8
View File
@@ -1154,7 +1154,7 @@ function Login(props) {
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Login form</h5>
<h5 className="modal-title font-semibold">Additional Info</h5>
<span>
<span></span>
</span>
@@ -1210,18 +1210,19 @@ function Login(props) {
<div className="mt-4">
<button
type="button"
className="bg-[#6c757d] text-sm p-2 text-white rounded uppercase"
onClick={handleCloseModal}
style={{ marginRight: 10, width: 90 }}
className="bg-[#17a2b8] text-sm p-2 text-white rounded uppercase"
onClick={(e) => handleSubmitbtn(e)}
style={{ marginRight: 10 }}
>
Cancel
Login
</button>
<button
type="button"
className="bg-[#17a2b8] text-sm p-2 text-white rounded uppercase"
onClick={(e) => handleSubmitbtn(e)}
className="bg-[#6c757d] text-sm p-2 text-white rounded uppercase"
onClick={handleCloseModal}
style={{ width: 90 }}
>
Login
Cancel
</button>
</div>
</form>
+1 -1
View File
@@ -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!");
}
}
);
@@ -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);
@@ -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);
@@ -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" */}
@@ -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 (
<div>
{/* isEmail */}
@@ -248,13 +253,13 @@ function EmailComponent({
style={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap"
}}
>
{emailCount.map((data, ind) => {
return (
<div className="emailChip"
<div className="emailChip"
style={{display:"flex", flexDirection:"row", alignItems:"center"}}
key={ind}>
<span
@@ -76,9 +76,15 @@ function Header({
const handleDownloadPdf = () => {
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 (
<div
style={{ padding: !isGuestSigner && "5px 0px 5px 0px" }}
@@ -217,7 +223,7 @@ function Header({
</DropdownMenu.Root>
) : (
<div style={{ display: "flex", justifyContent: "space-around" }}>
{/* 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 && (