@foreverrbum/ethsign
Version:
This package will allow you to electronically sign documents within your application
798 lines (729 loc) • 32.3 kB
JavaScript
import bs58 from 'bs58';
import { store } from 'react-notifications-component';
import { isFileWithPassword } from './download';
import Fortmatic from 'fortmatic';
import Torus from '@toruslabs/torus-embed';
import Ethsign from '../artifacts/EthSign.json';
import jsPDF from "jspdf";
import "jspdf-autotable";
import logo from '../assets/logo.png';
import moment from 'moment';
import request from 'request';
// New imports
import { ethers } from 'ethers';
import { v4 } from 'uuid';
import _ from 'lodash';
import { getTimestampOfFutureBlock } from './block';
import { getChain, getFortmaticChainOptions, getTorusChainOptions, isTestnet } from './chains';
import { Biconomy } from '@biconomy/mexa'
import MetaMaskLogo from '../assets/metamask.svg';
import FortmaticLogo from '../assets/fortmatic.svg';
import TorusLogo from '../assets/torus.svg';
import imTokenLogo from '../assets/imtoken.svg';
// const fromAscii = ethers.utils.formatBytes32String;
const toAscii = ethers.utils.parseBytes32String;
const fortmatic_key = 'pk_live_6D2FFF6E41301BF0';
const fortmatic_test_key = 'pk_test_F4BDDED1F885923E';
export const getLoggedOutWeb3Credentials = async (networkId) => {
let provider = new ethers.providers.JsonRpcProvider(getChain(networkId).rpc[0]);
const deployedNetwork = Ethsign.networks[networkId];
let contract = new ethers.Contract(deployedNetwork.address, Ethsign.abi, provider);
return {
networkId: networkId,
provider: provider,
contract: contract,
}
}
export const getWeb3Credentials = async (web3Case, preferredNetwork, location, history, _provider) => {
let fm = null;
let biconomy = null;
let torus = null;
let innerNetwork = preferredNetwork;
// Detect case if none provided
if(web3Case == null) {
innerNetwork = location.state?.networkId;
if(location.state !== undefined && location.state.fortmatic && location.state?.networkId) {
web3Case = 1;
} else if(location.state !== undefined && location.state.torus && location.state?.networkId) {
web3Case = 4;
} else if(window.ethereum) {
web3Case = 2;
} else {
window.alert('No wallet detected!');
history.goBack();
return;
}
}
// Init biconomy/provider/other instance variables
if (web3Case == 1) {
if(innerNetwork == 1) {
fm = new Fortmatic(fortmatic_key);
} else {
fm = new Fortmatic(isTestnet(innerNetwork) ? fortmatic_test_key : fortmatic_key, getFortmaticChainOptions(innerNetwork))
}
if(getChain(innerNetwork).biconomySupport) {
let originalProvider = new ethers.providers.Web3Provider(fm.getProvider());
biconomy = new Biconomy(originalProvider, { apiKey: getChain(innerNetwork).biconomyKey, strictMode: false });
_provider = new ethers.providers.Web3Provider(biconomy);
} else {
_provider = new ethers.providers.Web3Provider(fm.getProvider());
}
} else if(web3Case == 4) {
torus = new Torus();
await torus.init(getTorusChainOptions(innerNetwork));
await torus.ethereum.enable();
torus.ethereum.isStatus = true;
if(getChain(innerNetwork).biconomySupport) {
let originalProvider = new ethers.providers.Web3Provider(torus.ethereum);
biconomy = new Biconomy(originalProvider, { apiKey: getChain(innerNetwork).biconomyKey, strictMode: false });
_provider = new ethers.providers.Web3Provider(biconomy);
} else {
_provider = new ethers.providers.Web3Provider(torus.ethereum);
}
} else if (web3Case == 2) {
if(getChain(await window.ethereum.request({ method: 'eth_chainId' })).biconomySupport) {
let originalProvider = new ethers.providers.Web3Provider(window.ethereum);
biconomy = new Biconomy(originalProvider, { apiKey: getChain(await window.ethereum.request({ method: 'eth_chainId' })).biconomyKey, strictMode: false });
_provider = new ethers.providers.Web3Provider(biconomy);
} else {
_provider = new ethers.providers.Web3Provider(window.ethereum);
}
}
const signer = await _provider.getSigner(); // signer == current logged in user
const account = await signer.getAddress();
const networkId = (await _provider.getNetwork()).chainId;
const deployedNetwork = Ethsign.networks[networkId];
let contract = null;
if (biconomy == null) {
contract = new ethers.Contract(deployedNetwork.address, Ethsign.abi, _provider);
console.log("EthSign: Initialized normally.")
} else {
await new Promise((resolve, reject) => {
biconomy.onEvent(biconomy.READY, async () => {
contract = new ethers.Contract(
deployedNetwork.address,
Ethsign.abi,
biconomy.getSignerByAddress(account)
);
console.log("EthSign: Initialized with Mexa.")
resolve();
}).onEvent(biconomy.ERROR, (error, message) => {
console.log("EthSign: Failed to initialize with Mexa.")
console.log(message);
console.log(error);
reject();
});
});
}
return ({
web3: _provider,
fm: fm,
torus: torus,
ethAccount: account?.toLowerCase(),
networkId: networkId,
contract: contract,
web3Case: web3Case
})
}
export const timer = ms => new Promise(res => setTimeout(res, ms));
export const getSignInWalletLogo = (walletName) => {
switch(walletName) {
case 'Metamask':
return MetaMaskLogo;
case 'Fortmatic':
return FortmaticLogo;
case 'Torus':
return TorusLogo;
case 'imToken':
return imTokenLogo;
default:
return null;
}
}
const getPastEvents = async (provider, contract, filter, fromBlock) => {
const latest = await provider.getBlockNumber();
const networkId = (await provider.getNetwork()).chainId;
let contractBirth;
if (fromBlock != null) contractBirth = fromBlock;
else {
const contractBirthTxHash = Ethsign.networks[networkId].transactionHash;
contractBirth = (await provider.getTransaction(contractBirthTxHash)).blockNumber;
}
let events = [];
if (networkId == 56 || networkId == 1) {
let i_increment;
if (networkId == "56") i_increment = 4999;
else if (networkId == "1") i_increment = 511;
for (let i = contractBirth; i < latest; i += i_increment) {
let toBlock;
if (i + i_increment > latest) {
toBlock = latest;
} else {
toBlock = i + i_increment;
}
const slicedEvents = await contract.queryFilter(filter, i, toBlock);
events.push.apply(events, slicedEvents);
}
} else {
events = await contract.queryFilter(filter, contractBirth, latest);
}
console.log(events);
return events;
}
export function getIpfsHashFromBytes32(bytes32Hex) {
if (
bytes32Hex == null ||
bytes32Hex === '' ||
bytes32Hex ===
'0x0000000000000000000000000000000000000000000000000000000000000000'
)
return "";
// Add our default ipfs values for first 2 bytes:
// function:0x12=sha2, size:0x20=256 bits
// and cut off leading "0x"
const hashHex = '1220' + bytes32Hex.slice(2);
const hashBytes = Buffer.from(hashHex, 'hex');
const hashStr = bs58.encode(hashBytes);
return hashStr;
}
export const getDocumentDetails = async (documentKey, documentBasicInfo, contract, provider) => {
const signer = provider.getSigner();
const signerAddress = (await signer.getAddress())?.toLowerCase();
const instance = await contract.connect(signer);
const { name, birth, expiration, numOfSigners, initiator } = documentBasicInfo;
const created_at = await provider.getBlock(birth);
const currentBlock = await getCurrentBlockNumber(provider);
let expire_at = null, expiration_block = expiration;
if (expiration !== 0) {
const estimateDate = await getTimestampOfFutureBlock(expiration, currentBlock, provider)
expire_at = estimateDate ? moment(estimateDate).unix() : null
} else {
expiration_block = 'Never'
}
// Check document current status
const { docStorageProvider, docStorage_id0, docStorage_id1 } = await instance.getDocumentDocStorageInfo(documentKey);
// const saltedAddressMappingKey = await instance.hashSaltedAddressMappingKey(documentKey, signerAddress);
const { metaStorageProvider, metaStorage_id0, metaStorage_id1 } = await instance.getDocumentMetaStorageInfo(documentKey);
let docHash = getIpfsHashFromBytes32(docStorage_id0) + getIpfsHashFromBytes32(docStorage_id1);
let metaHash = getIpfsHashFromBytes32(metaStorage_id0) + getIpfsHashFromBytes32(metaStorage_id1);
let commentDataRaw = await instance.aggregateGetAllCommentsOfAllSigners(documentKey);
let commentData=[]
commentDataRaw.map((data)=>{
const {signer, commentStorageInfo} = data
const {storage_id0, storage_id1, provider} = commentStorageInfo;
const commentHash = getIpfsHashFromBytes32(storage_id0) + getIpfsHashFromBytes32(storage_id1);
if (commentHash != ""){
commentData.push({
address: signer.toLowerCase(),
provider: safeToAscii(provider),
commentHash: commentHash
})
}
})
/*
* Statuses:
* 0: 'PDF Not Uploaded'
* 1: 'More Signers Needed'
* 2: 'Pending Signatures'
* 3: 'All Signed'
* 4: 'Waiting For Others'
* 5: 'Need More Signers'
*/
let voteStatus = 2;
if (docStorageProvider == 0) {
// console.log("Document suspended: PDF needs to be uploaded");
voteStatus = 0;
}
const signatureDataRaw = await instance.aggregateGetIsSignedForAllSignatureFields(documentKey);
let signatureData = []
let numAllSignersTotalSigned = 0;
let numAllSignersTotalFields = 0;
let signers = []
signatureDataRaw.map((data)=>{
var {signer, fieldSigned} = data
const signed = fieldSigned.filter(field => field == true);
const numSignedFields = signed.length;
const numTotalFields = fieldSigned.length;
if(signer == signerAddress && numSignedFields == numTotalFields){
voteStatus = 4; // user signed all his fields
}
numAllSignersTotalSigned = numAllSignersTotalSigned + numSignedFields;
numAllSignersTotalFields = numAllSignersTotalFields + numTotalFields;
signatureData.push({
signer: signer.toLowerCase(),
signed: signed.length,
notSigned: fieldSigned.length-signed.length,
fieldSigned: fieldSigned
})
signers.push({
address: signer.toLowerCase(),
avatar: null,
alias: null,
fullySigned: numSignedFields == numTotalFields
})
})
if ( numAllSignersTotalSigned == numAllSignersTotalFields ){
voteStatus = 3;
}
let withPassword = await isFileWithPassword(docHash);
const enrolledNumOfSigners = await instance.getNumberOfSignersForDocument(documentKey); // Total number of signers enrolled (needs to match totalNumOfSigners to proceed at all)
if (enrolledNumOfSigners != numOfSigners) {
voteStatus = 5
}
// TODO: voteStatus for need more signers state
// with the assumption that all files (doc, meta, comments) are stored at the same storageprovider
const storageProvider = safeToAscii(docStorageProvider)
return ({
documentKey: documentKey,
initiator: initiator,
name: name,
creation: { block: birth, date: created_at.timestamp },
expiration: { block: expiration_block, date: expire_at ? expire_at : null },
status: voteStatus,
ipfsHash: docHash,
metaHash: metaHash,
storageProvider: storageProvider,
commentData: commentData,
withPassword: withPassword,
signers: signers,
signatureData: signatureData,
});
}
export const getDocument = async (documentKey, contract, provider, formatMessage) => {
const instance = await contract.connect(provider.getSigner());
let document = {}
try {
const documentBasicInfo = await instance.getDocumentBasicInfo(documentKey);
document.birth = documentBasicInfo.birth.toNumber();
document.expiration = documentBasicInfo.expiration.toNumber();
document.name = safeToAscii(documentBasicInfo.name).replace(/\0.*$/g, '');
document.numOfSigners = documentBasicInfo.numOfSigners.toNumber();
document.initiator = documentBasicInfo.initiator?.toLowerCase();
} catch (err) {
console.log(err)
storeNotif(formatMessage({id: "ERROR_FETCHING_DATA"}), formatMessage({id: "DATA_NOT_FETCHED_PLEASE_RELOAD"}), 'danger')
}
return document;
}
export const getData = async (filter, contract, provider) => {
const instance = await contract.connect(provider.getSigner()); // This gives a JsonRpcSigner, aka read & write
// Commented code below is for testing
// const docName = fromAscii('Name_PLACEHOLDER2.pdf');
// const docPW = fromAscii('Password PLACEHOLDER');
// const expiration = 0; // PLACEHOLDER
// const numOfSigners = 1; // PLACEHOLDER
// const docKey = await instance.hashDocumentKey(docName, docPW);
// await handleNewBasicDocument(instance, docKey, docName, expiration, numOfSigners);
// await handleAddSigners(instance, docKey, ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266']);
let documents = [];
if (filter == 'original') {
const numOfDocumentsCreatedByMe = (await instance.getNumOfDocumentsCreatedByMe()).toNumber();
// console.log("numOfDocumentsCreatedByMe,", numOfDocumentsCreatedByMe);
for (let i = 0; i < numOfDocumentsCreatedByMe; ++i) {
let document = {};
const documentKey = await instance.getDocumentCreatedByMeAtIndex(i);
const documentBasicInfo = await instance.getDocumentBasicInfo(documentKey);
// console.log(documentBasicInfo);
document.birth = documentBasicInfo.birth.toNumber();
document.expiration = documentBasicInfo.expiration.toNumber();
document.name = safeToAscii(documentBasicInfo.name).replace(/\0.*$/g, '');
document.numOfSigners = documentBasicInfo.numOfSigners.toNumber();
document.initiator = documentBasicInfo.initiator.toLowerCase();
// console.log(i);
document = await getDocumentDetails(documentKey, document, contract, provider)
document.type = 'CreatedByMe';
if (document.status != 5){
documents.push(document);
}
// console.log("findSignersForDocument():", await findSignersForDocument(contract, documentKey));
// await loadHistory(contract, provider, documentBasicInfo, documentKey);
}
} else if (filter == 'shared') {
const numOfDocumentsSharedWithMe = (await instance.getNumOfDocumentsSharedWithMe()).toNumber();
// console.log("numOfDocumentsSharedWithMe,", numOfDocumentsSharedWithMe);
for (let i = 0; i < numOfDocumentsSharedWithMe; ++i) {
let document = {};
const documentKey = await instance.getDocumentSharedWithMeAtIndex(i);
const documentBasicInfo = await instance.getDocumentBasicInfo(documentKey);
document.birth = documentBasicInfo.birth.toNumber();
document.expiration = documentBasicInfo.expiration.toNumber();
document.name = safeToAscii(documentBasicInfo.name).replace(/\0.*$/g, '');
document.numOfSigners = documentBasicInfo.numOfSigners.toNumber();
document.initiator = documentBasicInfo.initiator.toLowerCase();
document = await getDocumentDetails(documentKey, document, contract, provider)
document.type = 'SharedWithMe';
if (document.status != 5){
documents.push(document);
}
// console.log("getDocumentDetails():", await getDocumentDetails(documentKey, documentBasicInfo, contract, provider));
// console.log("findSignersForDocument():", await findSignersForDocument(contract, documentKey));
}
} else if(filter=='archived') {
const numOfDocumentsArchived = (await instance.getNumOfDocumentsArchived()).toNumber();
// console.log("numOfDocumentsCreatedByMe,", numOfDocumentsCreatedByMe);
for (let i = 0; i < numOfDocumentsArchived; ++i) {
let document = {};
const documentKey = await instance.getDocumentArchivedAtIndex(i);
const documentBasicInfo = await instance.getDocumentBasicInfo(documentKey);
// console.log(documentBasicInfo);
document.birth = documentBasicInfo.birth.toNumber();
document.expiration = documentBasicInfo.expiration.toNumber();
document.name = safeToAscii(documentBasicInfo.name).replace(/\0.*$/g, '');
document.numOfSigners = documentBasicInfo.numOfSigners.toNumber();
document.initiator = documentBasicInfo.initiator.toLowerCase();
// console.log(i);
document = await getDocumentDetails(documentKey, document, contract, provider);
document.type = 'Archived';
if (document.status != 5){
documents.push(document);
}
// console.log("findSignersForDocument():", await findSignersForDocument(contract, documentKey));
// await loadHistory(contract, provider, documentBasicInfo, documentKey);
}
}
// let table_data = [];
// for (const event of events) {
// // Get basic document info
// const documentKey = event.args.documentKey;
// const document = await getDocumentDetails(documentKey, contract, ethAccount, provider);
// if (document !== 0) {
// table_data.unshift(document);
// }
// }
return documents;
}
export const archiveDocuments = async (provider, contract, documentKeys, handleArchivedWaiting, formatMessage) => {
try {
const signer = await provider.getSigner(); // signer == current logged in user
const instance = await contract.connect(signer);
let tx = await instance.archiveDocuments(documentKeys, { gasLimit: 250000 });
handleArchivedWaiting(true);
const networkId = (await provider.getNetwork()).chainId;
await tx.wait(networkId == 1287 ? 2 : 1).then((receipt) => {
// console.log(receipt)
})
return true;
} catch(err) {
storeNotif(formatMessage({id: "TRANSACTION_ERROR"}), formatMessage({id: "ERROR_ARCHIVING_DOCUMENT"}), 'danger');
console.log(err);
return false;
}
}
export const getCurrentBlockNumber = async (provider) => {
const currentBlock = await provider.getBlockNumber();
return currentBlock;
}
export const findCreator = async (provider, contract, datasource) => {
const LogNewDocumentFilter = contract.filters.LogNewDocument(null, datasource.documentKey);
const newDocEvent = await getPastEvents(provider, contract, LogNewDocumentFilter);
return newDocEvent[0].args.sender;
}
// This replaces findTrustedParties
export const findSignersForDocument = async (contract, documentKey) => {
let signers = [];
const numOfSigners = (await contract.getNumberOfSignersForDocument(documentKey)).toNumber();
for (let i = 0; i < numOfSigners; ++i) {
const signer = await contract.getDocumentSignerAtIndex(documentKey, i);
signers.push(signer.toLowerCase());
}
return signers;
}
export const findTrustedParties = async (contract, datasource, creator) => {
let trustedParties = [];
const LogClearedProposalFilter = contract.filters.LogClearedProposal(null, datasource.documentKey, null, null, 1);
const addedTrustedPartyEvents = await getPastEvents(provider, contract, LogClearedProposalFilter);
for (const event of addedTrustedPartyEvents) {
const returnValues = event.args;
if (
returnValues.proposedAuthorizedParty !==
'0x0000000000000000000000000000000000000000'
) {
if (returnValues.passed) {
// this is an add party event
trustedParties.push(returnValues.proposedAuthorizedParty);
} else {
// this is a remove party event
// Don't think this is possible
trustedParties = trustedParties.filter(
(item) => item !== returnValues.proposedAuthorizedParty
);
}
}
}
// adds creator to trustedParties if there are other trustedparties
if (trustedParties.length > 0 && creator) {
trustedParties.push(creator);
}
return trustedParties;
}
export const validateExpiration = (documentExpiration, currentBlock) => {
if (documentExpiration <= currentBlock && documentExpiration != 0) {
store.addNotification({
title: 'Error',
message: `The expiration block (${documentExpiration}) must be larger than the current block (${currentBlock}).`,
type: 'danger',
insert: 'top',
container: 'bottom-right',
animationIn: ['animated', 'fadeIn'],
animationOut: ['animated', 'fadeOut'],
dismiss: {
duration: 10000,
onScreen: true,
},
});
return false;
} else {
return true;
}
}
export const getNewDocumentKey = async (contract) => {
let documentKey;
let boolDocumentExists = true;
while (boolDocumentExists==true) {
try {
documentKey = await contract.hashDocumentKey(v4());
document = await contract.getDocumentBasicInfo(documentKey);
} catch (error) {
boolDocumentExists = false;
}
}
return documentKey;
}
export const safeToAscii = (value) => {
let parsed;
try {
parsed = toAscii(value);
} catch (err) {
parsed = "";
}
return parsed;
}
export const loadHistory = async (contract, provider, doc, documentKey) => {
const selfAddress = await provider.getSigner().getAddress();
const birth = doc.creation.block;
const LogNewDocumentFilter = contract.filters.LogNewDocument(null, documentKey);
const newDocumentEvent = await getPastEvents(provider, contract, LogNewDocumentFilter, birth);
const LogChangedStorageFilter = contract.filters.LogChangedDocumentStorage(documentKey);
const changedStorageEvents = await getPastEvents(provider, contract, LogChangedStorageFilter, birth);
const LogChangedMetadataFilter = contract.filters.LogChangedMetadataStorage(documentKey);
const changedMetadataEvents = await getPastEvents(provider, contract, LogChangedMetadataFilter, birth);
const LogAddedNewSignerForDocumentFilter = contract.filters.LogAddedNewSignerForDocument(null, documentKey);
const newSignerEvents = await getPastEvents(provider, contract, LogAddedNewSignerForDocumentFilter, birth);
const LogSetNumberOfSignatureFieldsFilter = contract.filters.LogSetNumberOfSignatureFields(documentKey);
const setNumberOfSignatureFieldsEvents = await getPastEvents(provider, contract, LogSetNumberOfSignatureFieldsFilter, birth);
const LogLeftNewCommentOnDocumentFilter = contract.filters.LogLeftNewCommentOnDocument(null, documentKey);
const leftNewCommentOnDocumentEvents = await getPastEvents(provider, contract, LogLeftNewCommentOnDocumentFilter, birth);
const LogEditedCommentOnDocumentFilter = contract.filters.LogEditedCommentOnDocument(null, documentKey);
const editedCommentOnDocumentEvents = await getPastEvents(provider, contract, LogEditedCommentOnDocumentFilter, birth);
let combined = [].concat.apply(
[],
[
newDocumentEvent,
changedStorageEvents,
changedMetadataEvents,
newSignerEvents,
setNumberOfSignatureFieldsEvents,
leftNewCommentOnDocumentEvents,
editedCommentOnDocumentEvents,
]
);
combined.sort((a, b) =>
a.blockNumber > b.blockNumber
? 1
: a.blockNumber === b.blockNumber
? a.event === 'LogNewDocument'
? 1
: a.event !== 'LogNewDocument'
? a.event === 'LogAddedNewSignerForDocument'
? 1
: -1
: -1
: -1
);
const toAscii = ethers.utils.parseBytes32String;
let combinedViewModel = [];
// TODO: Change history table columns to:
// Event type, comment (not the comment in 2.0, but any extra information), raw event name (e.g. LogChangedDocumentStorage)
for (const event of combined) {
let eventType = '-';
let comment = '';
const storage_provider = safeToAscii(event.args.provider)
const id0 = safeToAscii(event.args.storage_id0);
const id1 = safeToAscii(event.args.storage_id1);
switch (event.event) {
case 'LogNewDocument':
eventType = 'Document created';
comment = "Initiator: " + event.args.sender;
break;
case 'LogChangedDocumentStorage':
eventType = 'Document updated';
comment = storage_provider + ": " + id0 + id1 // Maybe need to convert to IPFS hash if provider is IPFS or Fleek?
break;
case 'LogAddedNewSignerForDocument':
eventType = 'New signer added';
comment = "New signer: " + event.args.party;
break;
case 'LogChangedMetadataStorage':
eventType = 'Document annotations updated';
comment = storage_provider + ": " + id0 + id1
break;
case 'LogSetNumberOfSignatureFields':
eventType = 'Number of signature fields set';
comment = event.args.number + " signature fields for " + event.args.signer;
break;
case 'LogLeftNewCommentOnDocument':
eventType = 'New comment';
comment = event.args.author + " left a new comment";
break;
case 'LogEditedCommentOnDocument':
eventType = 'Edited comment';
comment = event.args.author + " edited a comment";
break;
default:
eventType = event.event;
}
// This would be nice to have still, might need to run a check in every case (or pre-process it?)
// if (sender === selfAddress) sender += ' (Me)';
// if (newParty === selfAddress) newParty += ' (Me)';
// if (newHash !== '-') newHash = getIpfsHashFromBytes32(newHash);
const block = await provider.getBlock(event.blockNumber);
// combinedViewModel.push({
// block: event.blockNumber,
// created_at: block.timestamp,
// eventType: eventType,
// sender: sender,
// newHash: newHash,
// newParty: newParty,
// comment: comment,
// });
}
return combinedViewModel;
}
export const exportHistory = (doc, history) => {
const unit = "pt";
const size = "A4"; // Use A1, A2, A3 or A4
const orientation = "portrait"; // portrait or landscape
const marginLeft = 40;
const pdf = new jsPDF(orientation, unit, size);
// Total page size is 595.28 x 841.89
pdf.setFontSize(15);
const title = `Contract History of ${doc.name}`;
const headers = [["Created At", "Event Type", "Comment", "Sender", "New Hash", "New Party"]];
var img = new Image()
img.src = logo;
pdf.addImage(img, 'png', 40, 40, 114, 57, undefined, 'FAST');
const data = history.map(record => [
`Block #${record.block} - ${moment.unix(record.created_at).format('lll')}`,
record.eventType,
record.comment,
record.sender,
record.newHash,
record.newParty
]);
let content = {
startY: 120,
head: headers,
body: data,
columnStyles: {
0: { cellWidth: 60 },
1: { cellWidth: 60 },
2: { cellWidth: 60 },
3: { cellWidth: 111.76 },
4: { cellWidth: 111.76 },
5: { cellWidth: 111.76 },
}
};
pdf.text(title, marginLeft, 110);
pdf.autoTable(content);
pdf.save(`history_${doc.name}.pdf`)
}
export const manipulateFileName = (file_name, handleFileName) => {
const fileExt = file_name.substring(file_name.lastIndexOf('.'));
handleFileName({
name: file_name,
ext: fileExt
});
}
export const handleShowLabel = (value, handleLabel) => {
if (value != '') {
handleLabel(true)
} else {
handleLabel(false)
}
}
export const isEmptyFile = (ipfsHash, handleEmptyFile) => {
const url = `https://ipfs.infura.io:5001/api/v0/block/stat?arg=${ipfsHash}`
request({ url: url }, (error, response, body) => {
body = JSON.parse(body);
const size = body.Size
if (size !== 72) {
handleEmptyFile(false);
}
})
}
export const getDocumentFormattedStatus = (status, formatMessage) => {
/*
* Statuses:
* -2: 'Search Results'
* -1: 'All Status'
* 0: 'PDF Not Uploaded'
* 1: 'More Signers Needed'
* 2: 'Pending Signatures'
* 3: 'All Signed'
* 4: 'Waiting For Others'
*/
switch(status) {
case -2:
return formatMessage({id: 'SEARCH_RESULTS'});
case -1:
return formatMessage({id: 'ALL_STATUS'});
case 0:
return formatMessage({id: 'PDF_NOT_UPLOADED'});
case 1:
return formatMessage({id: 'MORE_SIGNERS_NEEDED'});
case 2:
return formatMessage({id: 'PENDING_SIGNATURES'});
case 3:
return formatMessage({id: 'ALL_SIGNED'});
case 4:
return formatMessage({id: 'WAITING_FOR_OTHERS'});
default:
return '';
}
}
export const getDocumentComment = async (contract, provider, documentKey) => {
const signer = provider.getSigner();
const instance = await contract.connect(signer);
const ethAccount = await signer.getAddress();
const comment = await instance.getDocumentCommentsForSigner(ethAccount, documentKey);
// See smart contract for return values
return comment;
}
export const storeNotif = (subject, message, type) => {
store.addNotification({
title: subject,
message: message? message:" ",
type: type.toString(),
insert: 'top',
container: 'bottom-right',
animationIn: ['animated', 'fadeIn'],
animationOut: ['animated', 'fadeOut'],
dismiss: {
duration: 10000,
onScreen: true,
showIcon: true,
click: false,
touch: false
},
});
}
export const truncate = (fullStr, frontChars, backChars, separator) => {
frontChars = frontChars || 5;
backChars = backChars || 3;
separator = separator || '...';
if (fullStr.length <= frontChars+backChars ) return fullStr;
return fullStr.substr(0, frontChars) +
separator +
fullStr.substr(fullStr.length - backChars);
};
export default { getDocumentDetails, getDocument, getWeb3Credentials, getData, getCurrentBlockNumber, findCreator, findTrustedParties, validateExpiration, getNewDocumentKey, manipulateFileName, handleShowLabel, loadHistory, exportHistory, isEmptyFile, storeNotif, truncate }