UNPKG

@foreverrbum/ethsign

Version:

This package will allow you to electronically sign documents within your application

229 lines (207 loc) 10.1 kB
import { ethers } from 'ethers'; import { storeNotif } from './dashboard'; import {setDocumentCommentsForSigner, getEncryptedStringFromFile, docUpload, aggregateNewBasicDocumentAndSetStorage} from './newdocument'; const emptyHex = '0x0000000000000000000000000000000000000000000000000000000000000000'; export const createAndSign = async (provider, ethAccount, instance, signaturesToSave, formatMessage, contract, handleSaveStatus, password, docName, initialSigners, bar, handleProgress, user, networkId, callback, errorCallback, handleSavedAnnotations, handleNewChanges) => { // 1-docUpload // 2-setDocStorage // 3-addSignersAndNumofSigFields // 4-signMessage // 5-saveSigsAndSaveComment const {docViewer} = instance; let key, storageHash; const expiration = 0; let storageProvider = "FL" const doc = docViewer.getDocument(); const fileData = await doc.getFileData(); const buffer = new Uint8Array(fileData); const blob = new Blob([buffer], { type: 'application/pdf' }); const encryptedFile = await getEncryptedStringFromFile(blob, password) try{ const {documentKey, hash, storage_provider} = await docUpload(formatMessage, encryptedFile, contract, handleSaveStatus, storageProvider) key = documentKey storageHash = hash storageProvider = storage_provider }catch(err){ console.log(err) storeNotif(formatMessage({id: 'FILE_UPLOAD_ERROR'}),formatMessage({id: 'FILE_UPLOAD_ERROR_MESSAGE'}, {button: bar.button2} ), 'danger') handleSaveStatus(null) if(errorCallback){ errorCallback(); } return; } handleProgress(1) const docuStorageHash = [storageHash, emptyHex, emptyHex, emptyHex, emptyHex, emptyHex] const {annotManager} = instance; const x = annotManager.getAnnotationsList().filter(a=> a.Subject == "Widget" && a.Signer != null).length const signers = [ethAccount, ...initialSigners] const signerFieldCount = [x] initialSigners.map(a=>{ signerFieldCount.push(1) }) const created = await aggregateNewBasicDocumentAndSetStorage (provider, contract, key, docName, expiration, storageProvider, docuStorageHash, signers, signerFieldCount, handleSaveStatus, formatMessage, async (tx)=>{ const networkId = (await provider.getNetwork()).chainId; await tx.wait(networkId == 1287 ? 2 : 1).then((receipt) => { handleProgress(2); }); }, ()=>{ handleSaveStatus(null); if(errorCallback){ errorCallback(); } }, bar.button2 ) if(created){ const doc = { documentKey: key, storageProvider: storageProvider, } await signAndSaveComments(annotManager, signaturesToSave, provider, ethAccount, contract, doc, password, user, callback, errorCallback, formatMessage, handleSaveStatus, handleSavedAnnotations, handleNewChanges, 2, handleProgress) } } export const signAndSaveComments = async (annotManager, signaturesToSave, provider, ethAccount, contract, doc, password, user, callback, errorCallback, formatMessage, handleSaveStatus, handleSavedAnnotations, handleNewChanges, progress, handleProgress) => { const annotSignatures = [] // exporting and setting custom Data const signedIndices = [] const ec_signatures = []; const signatures = [] const signer = provider.getSigner(); const instance = contract.connect(signer); if (signaturesToSave.length>0){ handleSaveStatus(formatMessage({id: 'REQUESTING_SIGNATURES'})) try{ // get signature await Promise.all( signaturesToSave.map(async (annot) => { annot.annot.setCustomData('Signer', annot.Signer) annot.annot.setCustomData('Index', annot.Index) signedIndices.push(annot.Index) annotSignatures.push(annot.annot) // const hash = await contract.hashDocumentKey(doc.ipfsHash + doc.metaHash + `${annot.Index}`); const hash = await instance.hashSaltedAddressWithIndexMappingKeyAsSigner(doc.documentKey, annot.Index); const hashArray = ethers.utils.arrayify(hash); const ec_signature = await signer.signMessage(hashArray); ec_signatures.push(ec_signature); signatures.push(annot.annot) }) ); handleProgress(progress+1); }catch(err){ signaturesToSave.map(async (annot) => { annot.annot.setCustomData('Signer', null) annot.annot.setCustomData('Index', null) }) console.log(err) handleSaveStatus(null) if(errorCallback){ errorCallback(); } storeNotif(formatMessage({id: 'TRANSACTION_ERROR'}), formatMessage({id: 'YOU_REJECTED_TRANSACTION'}), "danger") return; } } handleSaveStatus(formatMessage({id: 'ENCRYPTING_ANNOTATIONS'})) // deleting those Ethsign Signature Fields (orange) widgets that are not signed const annotsToDelete = annotManager.getAnnotationsList().filter((annot) => (annot.Subject == "SignatureField" || annot.Subject == "Widget") && annot.Signer != null && annot.annot == null) await annotManager.deleteAnnotations(annotsToDelete, null, true); const xfdfStringAnnotations = await annotManager.exportAnnotations(); const commentsToSave = [...annotManager.getAnnotationsList()] await annotManager.addAnnotations(annotsToDelete); await annotManager.drawAnnotationsFromList(annotsToDelete); var annotationsFile = new Blob([xfdfStringAnnotations], {type: 'text/plain'}); const encryptedAnnotations = await getEncryptedStringFromFile(annotationsFile, password) if (await setDocumentCommentsForSigner(provider, contract, ethAccount, doc.storageProvider, doc.documentKey, signedIndices, ec_signatures, encryptedAnnotations, formatMessage, callback, errorCallback, handleSaveStatus, signaturesToSave.length)){ handleProgress(progress + 2); signatures.map(async (annot) => { annot.ReadOnly = true; }) handleSavedAnnotations(commentsToSave) var newChanges = annotManager.getAnnotationsList().filter((annot) => annot.Subject != "SignatureField" && annot.Subject != "Widget" && annot.Author == user) _.pullAll(newChanges, commentsToSave); handleNewChanges(newChanges.length > 0) }else{ signatures.map(async (annot) => { annot.setCustomData('Signer', null) annot.setCustomData('Index', null) }) } return; } export const makeSignaturesReadOnly = (signatures) => { signatures.map(annot => { annot.ReadOnly = true; }) } export const aggregateSetSigFieldAsSignerForDocument = async (ethAccount, contract, provider, documentKey, indices, r, s, v, handleSaveStatus, commentsLength, formatMessage) => { try { const signer = provider.getSigner(); const instance = await contract.connect(signer); const saltedAddressMappingKey = await contract.hashSaltedAddressMappingKey(documentKey, ethAccount); const saltedMetaDocumentMappingKey = await contract.hashSaltedMetaDocumentMappingKey(documentKey); // Sign it let tx = await instance.aggregateSetSigFieldAsSignerForDocument(documentKey, indices, saltedAddressMappingKey, saltedMetaDocumentMappingKey, r, s, v); handleSaveStatus(formatMessage({id: 'WAITING_FOR_CONFIRMATIONS_FROM_NEWWORK'})) const networkId = (await provider.getNetwork()).chainId; await tx.wait(networkId == 1287 ? 2 : 1).then((receipt) => { console.log(receipt) if(commentsLength==0){ handleSaveStatus(null) storeNotif(formatMessage({id: 'SIGNATURE_APPLIED'}), formatMessage({id: 'SUCCESSFULLY_SIGNED_CONTRACT'}), 'success') } }) } catch (err) { console.log(err) return false; } return true; } // Signing a particular field in a specific version of the document export const signDocumentAtIndex = async (contract, provider, documentKey, doc_storage_id, metadata_storage_id, index, handleSubmitButton, formatMessage) => { try { const signer = provider.getSigner(); const instance = await contract.connect(signer); const ethAccount = await signer.getAddress(); // Sign it // const hash = await instance.hashDocumentKey(doc_storage_id + metadata_storage_id + `${index}`); const hash = await instance.hashSaltedAddressWithMappingKeyAsSigner(documentKey, index); const hashArray = ethers.utils.arrayify(hash); const ec_signature = await signer.signMessage(hashArray); let tx = await instance.aggregateSetSigFieldForDocument(documentKey, ethAccount, [index], ec_signature); if(handleSubmitButton) { handleSubmitButton(formatMessage({id: 'WAITING_FOR_CONFIRMATIONS_FROM_NEWWORK'})); } const networkId = (await provider.getNetwork()).chainId; await tx.wait(networkId == 1287 ? 2 : 1).then((receipt) => { console.log(receipt) storeNotif(formatMessage({id: 'SIGNATURE_APPLIED'}), formatMessage({id: 'SUCCESSFULLY_SIGNED_CONTRACT'}), 'success') }) } catch (err) { console.log(err) return false; } return true; } export const getDocumentSignatureAtIndex = async (contract, doc, index, signerAddress) => { let legit; try { const signatureArray = await contract.getDocumentECSignatureForSignerAtIndex(signerAddress, doc.documentKey, index); let ec_signature = ethers.utils.joinSignature({ "r": signatureArray.r, "s": signatureArray.s, "v": signatureArray.v }); const hash = await contract.hashDocumentKey(doc.ipfsHash + doc.metaHash + `${index}`); const hashArray = ethers.utils.arrayify(hash); legit = ethers.utils.verifyMessage(hashArray, ec_signature) } catch (err) { console.log(err); return false; } // Compare, ignoring lowercase/uppercase if (legit.localeCompare(signerAddress, undefined, { sensitivity: 'accent' }) === 0) { return true; } else { return false; } } export default { getDocumentSignatureAtIndex, signDocumentAtIndex, signAndSaveComments, makeSignaturesReadOnly }