Merge pull request #6 from sairajzero/master

This commit is contained in:
Sai Raj 2020-05-06 19:03:08 +05:30 committed by GitHub
commit 1e6d2462af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -3,7 +3,6 @@
<head>
<title>FLO Standard Operators</title>
<script id="floGlobals">
/* Constants for FLO blockchain operations !!Make sure to add this at begining!! */
const floGlobals = {
@ -13,10 +12,12 @@
//Required for blockchain API operators
apiURL: {
FLO: ['https://explorer.mediciland.com/', 'https://livenet.flocha.in/', 'https://flosight.duckdns.org/', 'http://livenet-explorer.floexperiments.com/'],
FLO: ['https://explorer.mediciland.com/', 'https://livenet.flocha.in/', 'https://flosight.duckdns.org/',
'http://livenet-explorer.floexperiments.com/'
],
FLO_TEST: ['https://testnet-flosight.duckdns.org/', 'https://testnet.flocha.in/']
},
adminID: "FMeiptdJNtYQEtzyYAVNP8fjsDJ1i4EPfE",
adminID: "FKAEdnPfjXLHSYwrXQu377ugN4tXU7VGdf",
sendAmt: 0.001,
fee: 0.0005,
@ -7091,7 +7092,8 @@ Bitcoin.Util = {
deriveSharedKeyReceiver: function (senderPublicKeyString, receiverPrivateKey) {
try {
return ellipticCurveEncryption.receiverSharedKeyDerivation(senderPublicKeyString.XValuePublicString,
return ellipticCurveEncryption.receiverSharedKeyDerivation(senderPublicKeyString
.XValuePublicString,
senderPublicKeyString.YValuePublicString, receiverPrivateKey);
} catch (error) {
@ -7128,7 +7130,8 @@ Bitcoin.Util = {
if (alphaNumeric)
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
else
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():';
var characters =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():';
for (var i = 0; i < length; i++)
result += characters.charAt(Math.floor(Math.random() * characters.length));
return result;
@ -7137,7 +7140,8 @@ Bitcoin.Util = {
//Encrypt Data using public-key
encryptData: function (data, receiverCompressedPublicKey) {
var senderECKeyData = this.util.getSenderPublicKeyString();
var senderDerivedKey = this.util.deriveSharedKeySender(receiverCompressedPublicKey, senderECKeyData.privateKey);
var senderDerivedKey = this.util.deriveSharedKeySender(receiverCompressedPublicKey, senderECKeyData
.privateKey);
let senderKey = senderDerivedKey.XValue + senderDerivedKey.YValue;
let secret = Crypto.AES.encrypt(data, senderKey);
return {
@ -7156,7 +7160,8 @@ Bitcoin.Util = {
"Failed to detremine your private key.");
receiverECKeyData.privateKey = privateKey.privateKeyDecimal;
var receiverDerivedKey = this.util.deriveReceiverSharedKey(data.senderPublicKeyString, receiverECKeyData
var receiverDerivedKey = this.util.deriveReceiverSharedKey(data.senderPublicKeyString,
receiverECKeyData
.privateKey);
let receiverKey = receiverDerivedKey.XValue + receiverDerivedKey.YValue;
@ -7212,11 +7217,11 @@ Bitcoin.Util = {
//Returns public-key from private-key
getPubKeyHex: function (privateKeyHex) {
if(!privateKeyHex)
return null;
var key = new Bitcoin.ECKey(privateKeyHex);
if (key.priv == null) {
alert("Invalid Private key");
return;
}
if (key.priv == null)
return null;
key.setCompressed(true);
var pubkeyHex = key.getPubKeyHex();
return pubkeyHex;
@ -7224,9 +7229,13 @@ Bitcoin.Util = {
//Returns flo-ID from public-key
getFloIDfromPubkeyHex: function (pubkeyHex) {
try {
var key = new Bitcoin.ECKey().setPub(pubkeyHex);
var floID = key.getBitcoinAddress();
return floID;
} catch (e) {
console.error(e);
}
},
//Verify the private-key for the given public-key or flo-ID
@ -7286,7 +7295,7 @@ Bitcoin.Util = {
}
return false;
} catch {
return false
return false;
}
}
}
@ -7350,22 +7359,24 @@ Bitcoin.Util = {
},
//Write Data into blockchain
writeData: function (senderAddr, Data, PrivKey, receiverAddr = floGlobals.adminID) {
writeData: function (senderAddr, data, privKey, receiverAddr = floGlobals.adminID) {
return new Promise((resolve, reject) => {
this.sendTx(senderAddr, receiverAddr, floGlobals.sendAmt, PrivKey, Data)
if (typeof data != "string")
data = JSON.stringify(data);
this.sendTx(senderAddr, receiverAddr, floGlobals.sendAmt, privKey, data)
.then(txid => resolve(txid))
.catch(error => reject(error))
});
},
//Send Tx to blockchain
sendTx: function (senderAddr, receiverAddr, sendAmt, PrivKey, floData = '') {
sendTx: function (senderAddr, receiverAddr, sendAmt, privKey, floData = '') {
return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(senderAddr))
reject(`Invalid address : ${senderAddr}`);
else if (!floCrypto.validateAddr(receiverAddr))
reject(`Invalid address : ${receiverAddr}`);
if (PrivKey.length < 1 || !floCrypto.verifyPrivKey(PrivKey, senderAddr))
if (privKey.length < 1 || !floCrypto.verifyPrivKey(privKey, senderAddr))
reject("Invalid Private key!");
else if (typeof sendAmt !== 'number' || sendAmt <= 0)
reject(`Invalid sendAmt : ${sendAmt}`);
@ -7377,7 +7388,8 @@ Bitcoin.Util = {
for (var i = utxos.length - 1;
(i >= 0) && (utxoAmt < sendAmt + fee); i--) {
if (utxos[i].confirmations) {
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i].scriptPubKey)
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i]
.scriptPubKey)
utxoAmt += utxos[i].amount;
} else break;
}
@ -7389,7 +7401,7 @@ Bitcoin.Util = {
if (change > 0)
trx.addoutput(senderAddr, change);
trx.addflodata(floData);
var signedTxHash = trx.sign(PrivKey, 1);
var signedTxHash = trx.sign(privKey, 1);
this.broadcastTx(signedTxHash)
.then(txid => resolve(txid))
.catch(error => reject(error))
@ -7399,11 +7411,229 @@ Bitcoin.Util = {
});
},
//merge all UTXOs of a given floID into a single UTXO
mergeUTXOs: function (floID, privKey, floData = '') {
return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(floID))
return reject(`Invalid floID`);
if (!floCrypto.verifyPrivKey(privKey, floID))
return reject("Invalid Private Key")
var trx = bitjs.transaction();
var utxoAmt = 0.0;
var fee = floGlobals.fee;
this.promisedAPI(`api/addr/${floID}/utxo`).then(utxos => {
for (var i = utxos.length - 1; i >= 0; i--) {
if (utxos[i].confirmations) {
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i]
.scriptPubKey)
utxoAmt += utxos[i].amount;
}
}
trx.addoutput(floID, utxoAmt - fee);
trx.addflodata(floData);
var signedTxHash = trx.sign(privKey, 1);
this.broadcastTx(signedTxHash)
.then(txid => resolve(txid))
.catch(error => reject(error))
}).catch(error => reject(error))
})
},
/**Write data into blockchain from (and/or) to multiple floID
* @param {Array} senderPrivKeys List of sender private-keys
* @param {string} data FLO data of the txn
* @param {Array} receivers List of receivers
* @param {float} sendAmt (optional) amount to be sent to receivers (default value: floGlobals.sendAmt)
* @return {Promise}
*/
writeDataMultiple: function (senderPrivKeys, data, receivers = [floGlobals.adminID], preserveRatio = true){
return new Promise((resolve, reject) => {
if (!Array.isArray(senderPrivKeys))
return reject("Invalid senderPrivKeys: SenderPrivKeys must be Array")
if(!preserveRatio){
let tmp = {};
let amount = (floGlobals.sendAmt * receivers.length) / senderPrivKeys.length;
senderPrivKeys.forEach(key => tmp[key] = amount);
senderPrivKeys = tmp
}
if (!Array.isArray(receivers))
return reject("Invalid receivers: Receivers must be Array")
else {
let tmp = {};
let amount = floGlobals.sendAmt;
receivers.forEach(floID => tmp[floID] = amount);
receivers = tmp
}
if (typeof data != "string")
data = JSON.stringify(data);
this.sendTxMultiple(senderPrivKeys, receivers, data)
.then(txid => resolve(txid))
.catch(error => reject(error))
})
},
/**Send Tx from (and/or) to multiple floID
* @param {Array or Object} senderPrivKeys List of sender private-key (optional: with coins to be sent)
* @param {Object} receivers List of receivers with respective amount to be sent
* @param {string} floData FLO data of the txn
* @return {Promise}
*/
sendTxMultiple: function (senderPrivKeys, receivers, floData = '') {
return new Promise((resolve, reject) => {
let senders = {}, preserveRatio;
//check for argument validations
try{
let invalids = {
InvalidSenderPrivKeys: [],
InvalidSenderAmountFor: [],
InvalidReceiverIDs: [],
InvalidReceiveAmountFor: []
}
let inputVal = 0, outputVal = 0;
//Validate sender privatekeys (and send amount if passed)
//conversion when only privateKeys are passed (preserveRatio mode)
if(Array.isArray(senderPrivKeys)){
senderPrivKeys.forEach(key => {
try{
if(!key)
invalids.InvalidSenderPrivKeys.push(key);
else{
let floID = floCrypto.getFloIDfromPubkeyHex(floCrypto.getPubKeyHex(key));
senders[floID] = {
wif: key
}
}
}catch(error){
invalids.InvalidSenderPrivKeys.push(key)
}
})
preserveRatio = true;
}
//conversion when privatekeys are passed with send amount
else{
for(let key in senderPrivKeys){
try{
if(!key)
invalids.InvalidSenderPrivKeys.push(key);
else{
if(typeof senderPrivKeys[key] !== 'number' || senderPrivKeys[key] <= 0)
invalids.InvalidSenderAmountFor.push(key)
else
inputVal += senderPrivKeys[key];
let floID = floCrypto.getFloIDfromPubkeyHex(floCrypto.getPubKeyHex(key));
senders[floID] = {
wif: key,
coins: senderPrivKeys[key]
}
}
}catch(error){
invalids.InvalidSenderPrivKeys.push(key)
}
}
preserveRatio = false;
}
//Validate the receiver IDs and receive amount
for (let floID in receivers) {
if (!floCrypto.validateAddr(floID))
invalids.InvalidReceiverIDs.push(floID)
if (typeof receivers[floID] !== 'number' || receivers[floID] <= 0)
invalids.InvalidReceiveAmountFor.push(floID)
else
outputVal += receivers[floID];
}
//Reject if any invalids are found
for (let i in invalids)
if (!invalids[i].length)
delete invalids[i];
if (Object.keys(invalids).length)
return reject(invalids);
//Reject if given inputVal and outputVal are not equal
if(!preserveRatio && inputVal != outputVal)
return reject(`Input Amount (${inputVal}) not equal to Output Amount (${outputVal})`)
}catch(error){
return reject(error)
}
//Get balance of senders
let promises = []
for (let floID in senders)
promises.push(this.getBalance(floID))
Promise.all(promises).then(results => {
let totalBalance = 0,
totalFee = floGlobals.fee,
balance = {};
//Divide fee among sender if not for preserveRatio
if(!preserveRatio)
var dividedFee = totalFee / Object.keys(senders).length;
//Check if balance of each sender is sufficient enough
let insufficient = [];
for (let floID in senders) {
balance[floID] = parseFloat(results.shift());
if (isNaN(balance[floID]) || (preserveRatio && balance[floID] <= totalFee) || (!preserveRatio && balance[floID] < senders[floID].coins + dividedFee))
insufficient.push(floID)
totalBalance += balance[floID];
}
if (insufficient.length)
return reject({InsufficientBalance: insufficient})
//Calculate totalSentAmount and check if totalBalance is sufficient
let totalSendAmt = totalFee;
for (floID in receivers)
totalSendAmt += receivers[floID];
if (totalBalance < totalSendAmt)
return reject("Insufficient total Balance")
//Get the UTXOs of the senders
let promises = []
for (floID in senders)
promises.push(this.promisedAPI(`api/addr/${floID}/utxo`))
Promise.all(promises).then(results => {
let wifSeq = [];
var trx = bitjs.transaction();
for (floID in senders) {
let utxos = results.shift();
let sendAmt;
if(preserveRatio){
let ratio = (balance[floID] / totalBalance);
sendAmt = totalSendAmt * ratio;
} else
sendAmt = senders[floID].coins + dividedFee;
let wif = senders[floID].wif;
let utxoAmt = 0.0;
for (let i = utxos.length - 1;
(i >= 0) && (utxoAmt < sendAmt); i--) {
if (utxos[i].confirmations) {
trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i]
.scriptPubKey)
wifSeq.push(wif);
utxoAmt += utxos[i].amount;
}
}
if (utxoAmt < sendAmt)
return reject("Insufficient balance:" + floID);
let change = (utxoAmt - sendAmt);
if (change > 0)
trx.addoutput(floID, change);
}
for (floID in receivers)
trx.addoutput(floID, receivers[floID]);
trx.addflodata(floData);
for (let i = 0; i < wifSeq.length; i++)
trx.signinput(i, wifSeq[i], 1);
var signedTxHash = trx.serialize();
this.broadcastTx(signedTxHash)
.then(txid => resolve(txid))
.catch(error => reject(error))
}).catch(error => reject(error))
}).catch(error => reject(error))
})
},
//Broadcast signed Tx in blockchain using API
broadcastTx: function (signedTxHash) {
return new Promise((resolve, reject) => {
var request = new XMLHttpRequest();
var url = this.util.serverList[this.util.curPos] + 'api/tx/send';
console.log(url)
if (signedTxHash.length < 1)
reject("Empty Signature");
else {
@ -7458,22 +7688,32 @@ Bitcoin.Util = {
return new Promise((resolve, reject) => {
this.promisedAPI(`api/addrs/${addr}/txs?from=0&to=1`).then(response => {
var newItems = response.totalItems - options.ignoreOld;
this.promisedAPI(`api/addrs/${addr}/txs?from=0&to=${newItems*2}`).then(response => {
this.promisedAPI(`api/addrs/${addr}/txs?from=0&to=${newItems*2}`).then(
response => {
if (options.limit <= 0)
options.limit = response.items.length;
var filteredData = [];
for (i = 0; i < (response.totalItems - options.ignoreOld) && filteredData.length < options.limit; i++){
if(options.sentOnly && response.items[i].vin[0].addr !== addr)
for (i = 0; i < (response.totalItems - options.ignoreOld) &&
filteredData.length < options.limit; i++) {
if (options.sentOnly && response.items[i].vin[0].addr !==
addr)
continue;
if(options.pattern && !response.items[i].floData.startsWith(options.pattern, 0) && !response.items[i].floData.startsWith(options.pattern, 2))
if (options.pattern && !response.items[i].floData
.startsWith(options.pattern, 0) && !response.items[i]
.floData.startsWith(options.pattern, 2))
continue;
if(options.contains && !response.items[i].floData.includes(options.contains))
if (options.contains && !response.items[i].floData.includes(
options.contains))
continue;
if(options.filter && !options.filter(response.items[i].floData))
if (options.filter && !options.filter(response.items[i]
.floData))
continue;
filteredData.push(response.items[i].floData);
}
resolve({totalTxs:response.totalItems , data:filteredData});
resolve({
totalTxs: response.totalItems,
data: filteredData
});
}).catch(error => {
reject(error);
});
@ -7504,7 +7744,8 @@ Bitcoin.Util = {
const nodeIdNewInt8Array = new Uint8Array(nodeIdBytes);
return nodeIdNewInt8Array;
},
launch: function (superNodeList = Object.keys(floGlobals.supernodes), master_floID = floGlobals.adminID) {
launch: function (superNodeList = Object.keys(floGlobals.supernodes), master_floID = floGlobals
.adminID) {
return new Promise((resolve, reject) => {
try {
const SuKBucketId = this.floIdToKbucketId(master_floID);
@ -8119,7 +8360,6 @@ Bitcoin.Util = {
}
}
</script>
<script id="compactIDB">
/* Compact IndexedDB operations */
@ -8147,19 +8387,26 @@ Bitcoin.Util = {
idb.onupgradeneeded = (event) => {
var db = event.target.result;
for (obs in objectStores) {
var objectStore = db.createObjectStore(obs, objectStores[obs].options || {});
if (objectStores[obs].indexes && typeof objectStores[obs].indexes === 'object')
var objectStore = db.createObjectStore(obs, objectStores[obs].options ||
{});
if (objectStores[obs].indexes && typeof objectStores[obs].indexes ===
'object')
for (i in objectStores[obs].indexes)
objectStore.createIndex(i, i, objectStores[obs].indexes[i] || {});
}
}
idb.onsuccess = (event) => {
var db = event.target.result;
if (JSON.stringify(Object.values(db.objectStoreNames).sort()) === JSON.stringify(Object.keys(
if (JSON.stringify(Object.values(db.objectStoreNames).sort()) === JSON
.stringify(Object.keys(
objectStores).sort()))
resolve("Initiated IndexedDB");
else
reject("IndexedDB already exist with different ObjectStores!");
else {
Object.values(db.objectStoreNames).forEach(obs => delete objectStores[obs])
this.initDB(dbName, objectStores, db.version + 1)
.then(result => resolve(result))
.catch(error => reject(error))
}
db.close();
}
});
@ -8188,7 +8435,8 @@ Bitcoin.Util = {
let writeReq = (key ? obs.put(data, key) : obs.put(data));
writeReq.onsuccess = (evt) => resolve(`Write data Successful`);
writeReq.onerror = (evt) => reject(
`Write data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`);
`Write data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
);
db.close();
}).catch(error => reject(error));
});
@ -8201,7 +8449,8 @@ Bitcoin.Util = {
let addReq = (key ? obs.add(data, key) : obs.add(data));
addReq.onsuccess = (evt) => resolve(`Add data successful`);
addReq.onerror = (evt) => reject(
`Add data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`);
`Add data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
);
db.close();
}).catch(error => reject(error));
});
@ -8214,7 +8463,20 @@ Bitcoin.Util = {
let delReq = obs.delete(key);
delReq.onsuccess = (evt) => resolve(`Removed Data ${key}`);
delReq.onerror = (evt) => reject(
`Remove data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`);
`Remove data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
);
db.close();
}).catch(error => reject(error));
});
},
clearData: function (obsName, dbName = this.dbName) {
return new Promise((resolve, reject) => {
this.openDB(dbName).then(db => {
var obs = db.transaction(obsName, "readwrite").objectStore(obsName);
let clearReq = obs.clear();
clearReq.onsuccess = (evt) => resolve(`Clear data Successful`);
clearReq.onerror = (evt) => reject(`Clear data Unsuccessful`);
db.close();
}).catch(error => reject(error));
});
@ -8227,7 +8489,8 @@ Bitcoin.Util = {
let getReq = obs.get(key);
getReq.onsuccess = (evt) => resolve(evt.target.result);
getReq.onerror = (evt) => reject(
`Read data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`);
`Read data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
);
db.close();
}).catch(error => reject(error));
});
@ -8248,7 +8511,8 @@ Bitcoin.Util = {
resolve(tmpResult);
}
curReq.onerror = (evt) => reject(
`Read-All data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`);
`Read-All data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
);
db.close();
}).catch(error => reject(error));
});
@ -8270,7 +8534,8 @@ Bitcoin.Util = {
resolve(filteredResult);
}
curReq.onerror = (evt) => reject(
`Search unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`);
`Search unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`
);
db.close();
}).catch(error => reject(error));
});
@ -8282,6 +8547,9 @@ Bitcoin.Util = {
const floCloudAPI = {
util: {
lastCommit: {},
resetData: function (dataSet) {
try {
dataSet = JSON.parse(dataSet);
@ -8291,7 +8559,8 @@ Bitcoin.Util = {
if (message.reset) {
floGlobals.appObjects[message.object] = message.reset
floGlobals.vectorClock[message.object] = vc
compactIDB.writeData("appObjects", floGlobals.appObjects[message.object], message.object)
compactIDB.writeData("appObjects", floGlobals.appObjects[message.object], message
.object)
compactIDB.writeData("vectorClock", vc, message.object)
}
}
@ -8307,8 +8576,10 @@ Bitcoin.Util = {
for (vc in dataSet) {
var message = dataSet[vc].message;
if (message.diff) {
floGlobals.appObjects[message.object] = mergeDifference(floGlobals.appObjects[message.object], message.diff)
compactIDB.writeData("appObjects",floGlobals.appObjects[message.object], message.object)
floGlobals.appObjects[message.object] = mergeDifference(floGlobals.appObjects[
message.object], message.diff)
compactIDB.writeData("appObjects", floGlobals.appObjects[message.object], message
.object)
}
floGlobals.vectorClock[message.object] = vc
compactIDB.writeData("vectorClock", vc, message.object)
@ -8325,7 +8596,11 @@ Bitcoin.Util = {
if (!Array.isArray(floGlobals.generalData[filterStr]))
floGlobals.generalData[filterStr] = []
for (vc in dataSet) {
floGlobals.generalData[filterStr].push({sender: dataSet[vc].senderID, vectorClock: vc, message: dataSet[vc].message})
floGlobals.generalData[filterStr].push({
sender: dataSet[vc].senderID,
vectorClock: vc,
message: dataSet[vc].message
})
compactIDB.writeData("generalData", floGlobals.generalData[filterStr], filterStr)
floGlobals.generalVC[filterStr] = vc
compactIDB.writeData("generalVC", vc, filterStr)
@ -8387,9 +8662,14 @@ Bitcoin.Util = {
//request General Data
requestGeneralData: function (type, options = {}) {
return new Promise((resolve, reject) => {
var filterStr = JSON.stringify({application: options.application || floGlobals.application, type: type, comment: options.comment})
var filterStr = JSON.stringify({
application: options.application || floGlobals.application,
type: type,
comment: options.comment
})
options.type = type
options.lowerVectorClock = options.lowerVectorClock || floGlobals.generalVC[filterStr] + 1
options.lowerVectorClock = options.lowerVectorClock || floGlobals.generalVC[filterStr] +
1
this.requestApplicationData(options).then(dataSet => {
this.util.storeGeneralData(filterStr, dataSet)
resolve('General Data Updated')
@ -8402,7 +8682,8 @@ Bitcoin.Util = {
return new Promise((resolve, reject) => {
var request = {
receiverID: options.receiverID || floGlobals.adminID,
senderIDs: (options.senderIDs === false) ? false: options.senderIDs || floGlobals.subAdmins,
senderIDs: (options.senderIDs === false) ? false : options.senderIDs ||
floGlobals.subAdmins,
application: options.application || floGlobals.application,
comment: options.comment,
type: `${objectName}@Reset`,
@ -8414,8 +8695,11 @@ Bitcoin.Util = {
request.type = `${objectName}@Update`
request.lowerVectorClock = floGlobals.vectorClock[objectName] + 1
request.mostRecent = false
floSupernode.requestData(JSON.stringify(request), request.receiverID).then(dataSet => {
floSupernode.requestData(JSON.stringify(request), request.receiverID).then(
dataSet => {
this.util.updateData(dataSet)
this.util.lastCommit[objectName] = JSON.stringify(floGlobals
.appObjects[objectName])
resolve('Object Data Updated')
}).catch(error => reject(error))
}).catch(error => reject(error))
@ -8423,32 +8707,37 @@ Bitcoin.Util = {
},
//reset or initialize an object and send it to cloud
resetObjectData: function(newObject, objectName, options = {}){
resetObjectData: function (objectName, options = {}) {
return new Promise((resolve, reject) => {
var message = {
division: options.division || floGlobals.division,
object: objectName,
vectorClock: floGlobals.vectorClock[objectName],
reset: newObject
reset: floGlobals.appObjects[objectName]
}
this.sendApplicationData(message, `${objectName}@Reset`, options)
.then(result => resolve(result))
.catch(error => reject(error))
this.sendApplicationData(message, `${objectName}@Reset`, options).then(result => {
this.util.lastCommit[objectName] = JSON.stringify(floGlobals.appObjects[
objectName])
resolve(result)
}).catch(error => reject(error))
})
},
//update the diff and send it to cloud
updateObjectData: function(oldObject, newObject, objectName, options = {}){
updateObjectData: function (objectName, options = {}) {
return new Promise((resolve, reject) => {
var message = {
division: options.division || floGlobals.division,
object: objectName,
vectorClock: floGlobals.vectorClock[objectName],
diff: findDifference(oldObject, newObject)
diff: findDifference(JSON.parse(this.util.lastCommit[objectName]), floGlobals
.appObjects[objectName])
}
this.sendApplicationData(message, `${objectName}@Update`, options)
.then(result => resolve(result))
.catch(error => reject(error))
this.sendApplicationData(message, `${objectName}@Update`, options).then(result => {
this.util.lastCommit[objectName] = JSON.stringify(floGlobals.appObjects[
objectName])
resolve(result)
}).catch(error => reject(error))
})
}
}
@ -8468,7 +8757,10 @@ Bitcoin.Util = {
lastTx: {},
//supernode (cloud list)
supernodes: {
indexes:{ uri:null, pubKey:null }
indexes: {
uri: null,
pubKey: null
}
},
//login credentials
credentials: {},
@ -8489,30 +8781,36 @@ Bitcoin.Util = {
})
},
privKeyInput: function(){
var privKey = prompt("Enter Private Key: ")
return privKey
},
startUpFunctions: {
readSupernodeListFromAPI: function () {
return new Promise((resolve, reject) => {
compactIDB.readData("lastTx", floGlobals.SNStorageID).then(lastTx => {
floBlockchainAPI.readData(floGlobals.SNStorageID,{ignoreOld:lastTx,sentOnly:true,pattern:"SuperNodeStorage"}).then(result => {
floBlockchainAPI.readData(floGlobals.SNStorageID, {
ignoreOld: lastTx,
sentOnly: true,
pattern: "SuperNodeStorage"
}).then(result => {
for (var i = result.data.length - 1; i >= 0; i--) {
var content = JSON.parse(result.data[i]).SuperNodeStorage;
var content = JSON.parse(result.data[i])
.SuperNodeStorage;
for (sn in content.removeNodes)
compactIDB.removeData("supernodes", sn);
for (sn in content.addNodes)
compactIDB.writeData("supernodes",content.addNodes[sn],sn);
compactIDB.writeData("supernodes", content
.addNodes[sn], sn);
}
compactIDB.writeData("lastTx",result.totalTxs,floGlobals.SNStorageID);
compactIDB.writeData("lastTx", result.totalTxs,
floGlobals.SNStorageID);
compactIDB.readAllData("supernodes").then(result => {
floGlobals.supernodes = result;
floSupernode.kBucket.launch(Object.keys(floGlobals.supernodes),floGlobals.SNStorageID)
.then(result => resolve("Loaded Supernode list\n"+result))
floSupernode.kBucket.launch(Object.keys(
floGlobals.supernodes),
floGlobals.SNStorageID)
.then(result => resolve(
"Loaded Supernode list\n" +
result))
})
})
}).catch(error => reject(error))
@ -8522,17 +8820,27 @@ Bitcoin.Util = {
readSubAdminListFromAPI: function () {
return new Promise((resolve, reject) => {
compactIDB.readData("lastTx", floGlobals.adminID).then(lastTx => {
floBlockchainAPI.readData(floGlobals.adminID,{ignoreOld:lastTx,sentOnly:true,pattern:floGlobals.application}).then(result => {
floBlockchainAPI.readData(floGlobals.adminID, {
ignoreOld: lastTx,
sentOnly: true,
pattern: floGlobals.application
}).then(result => {
for (var i = result.data.length - 1; i >= 0; i--) {
var content = JSON.parse(result.data[i])[floGlobals.application];
var content = JSON.parse(result.data[i])[floGlobals
.application];
if (Array.isArray(content.removeSubAdmin))
for(var j = 0; j < content.removeSubAdmin.length; j++)
compactIDB.removeData("subAdmins",content.removeSubAdmin[j]);
for (var j = 0; j < content.removeSubAdmin
.length; j++)
compactIDB.removeData("subAdmins", content
.removeSubAdmin[j]);
if (Array.isArray(content.addSubAdmin))
for(var k = 0; k < content.addSubAdmin.length; k++)
compactIDB.writeData("subAdmins",true,content.addSubAdmin[k]);
for (var k = 0; k < content.addSubAdmin
.length; k++)
compactIDB.writeData("subAdmins", true,
content.addSubAdmin[k]);
}
compactIDB.writeData("lastTx",result.totalTxs,floGlobals.adminID);
compactIDB.writeData("lastTx", result.totalTxs,
floGlobals.adminID);
compactIDB.readAllData("subAdmins").then(result => {
floGlobals.subAdmins = Object.keys(result);
resolve("Read subAdmins from blockchain");
@ -8558,7 +8866,19 @@ Bitcoin.Util = {
getCredentials: function () {
var readSharesFromIDB = function(indexArr){
const defaultInput = function (type) {
return new Promise((resolve, reject) => {
let inputVal = prompt(`Enter ${type}: `)
if (inputVal === null)
reject(null)
else
resolve(inputVal)
})
}
const inputFn = this.getCredentials.privKeyInput || defaultInput;
const readSharesFromIDB = function (indexArr) {
return new Promise((resolve, reject) => {
var promises = []
for (var i = 0; i < indexArr.length; i++)
@ -8573,7 +8893,7 @@ Bitcoin.Util = {
})
}
var writeSharesToIDB = function(shares, i = 0, resultIndexes = []){
const writeSharesToIDB = function (shares, i = 0, resultIndexes = []) {
return new Promise((resolve, reject) => {
if (i >= shares.length)
return resolve(resultIndexes)
@ -8589,7 +8909,7 @@ Bitcoin.Util = {
})
}
var getPrivateKeyCredentials = function(){
const getPrivateKeyCredentials = function () {
return new Promise((resolve, reject) => {
var indexArr = localStorage.getItem(`${floGlobals.application}#privKey`)
if (indexArr) {
@ -8597,59 +8917,105 @@ Bitcoin.Util = {
.then(result => resolve(result))
.catch(error => reject(error))
} else {
var privKey;
inputFn("PRIVATE_KEY").then(result => {
try {
var privKey = floDapps.util.privKeyInput();
if(!privKey)
if (!result)
return reject("Empty Private Key")
var floID = floCrypto.getFloIDfromPubkeyHex(floCrypto.getPubKeyHex(privKey))
console.log(floID)
var floID = floCrypto.getFloIDfromPubkeyHex(
floCrypto.getPubKeyHex(result))
privKey = result
} catch (error) {
console.error(error)
return reject("Invalid Private Key")
}
}).catch(error => {
console.log(error, "Generating Random Keys")
privKey = floCrypto.generateNewID().privKey
}).finally(_ => {
var threshold = floCrypto.randInt(10, 20)
writeSharesToIDB(floCrypto.createShamirsSecretShares(privKey, threshold, threshold)).then(resultIndexes =>{
writeSharesToIDB(floCrypto.createShamirsSecretShares(
privKey, threshold, threshold)).then(
resultIndexes => {
//store index keys in localStorage
localStorage.setItem(`${floGlobals.application}#privKey`, JSON.stringify(resultIndexes))
localStorage.setItem(
`${floGlobals.application}#privKey`,
JSON.stringify(resultIndexes))
//also add a dummy privatekey to the IDB
var randomPrivKey = floCrypto.generateNewID().privKey
var randomThreshold = floCrypto.randInt(10,20)
writeSharesToIDB(floCrypto.createShamirsSecretShares(randomPrivKey, randomThreshold, randomThreshold))
var randomPrivKey = floCrypto
.generateNewID().privKey
var randomThreshold = floCrypto.randInt(10,
20)
writeSharesToIDB(floCrypto
.createShamirsSecretShares(
randomPrivKey, randomThreshold,
randomThreshold))
//resolve private Key
resolve(privKey)
}).catch(error => reject(error))
})
}
})
}
const checkIfPinRequired = function(key){
return new Promise((resolve, reject) => {
if(key.length == 52)
resolve(key)
else {
inputFn("PIN/Password").then(pwd => {
try{
let privKey = Crypto.AES.decrypt(key, pwd);
resolve(privKey)
}catch(error){
reject("Access Denied: Incorrect PIN/Password")
}
}).catch(error => reject("Access Denied: PIN/Password required"))
}
})
}
return new Promise((resolve, reject) => {
getPrivateKeyCredentials().then(privKey => {
getPrivateKeyCredentials().then(key => {
checkIfPinRequired(key).then(privKey => {
try{
myPrivKey = privKey
myPubKey = floCrypto.getPubKeyHex(myPrivKey)
myFloID = floCrypto.getFloIDfromPubkeyHex(myPubKey)
resolve('Login Credentials loaded successful')
}catch(error){
reject("Corrupted Private Key")
}
}).catch(error => reject(error))
}).catch(error => reject(error))
})
}
},
callStartUpFunction: function (fname) {
return new Promise((resolve, reject) => {
this.startUpFunctions[fname]().then(result => {
this.callStartUpFunction.completed += 1
reactor.dispatchEvent("startUpSuccessLog",`${result}\nCompleted ${this.callStartUpFunction.completed}/${this.callStartUpFunction.total} Startup functions`)
reactor.dispatchEvent("startUpSuccessLog",
`${result}\nCompleted ${this.callStartUpFunction.completed}/${this.callStartUpFunction.total} Startup functions`
)
resolve(true)
}).catch(error => {
this.callStartUpFunction.failed += 1
reactor.dispatchEvent("startUpErrorLog",`${error}\nFailed ${this.callStartUpFunction.failed}/${this.callStartUpFunction.total} Startup functions`)
reactor.dispatchEvent("startUpErrorLog",
`${error}\nFailed ${this.callStartUpFunction.failed}/${this.callStartUpFunction.total} Startup functions`
)
reject(false)
})
})
},
getFilterString: function (type, options = {}) {
var filterStr = JSON.stringify({application: options.application || floGlobals.application, type: type, comment: options.comment})
var filterStr = JSON.stringify({
application: options.application || floGlobals.application,
type: type,
comment: options.comment
})
return filterStr
}
},
@ -8658,7 +9024,8 @@ Bitcoin.Util = {
return new Promise((resolve, reject) => {
this.util.initIndexedDB().then(log => {
console.log(log)
this.util.callStartUpFunction.total = Object.keys(this.util.startUpFunctions).length
this.util.callStartUpFunction.total = Object.keys(this.util
.startUpFunctions).length
this.util.callStartUpFunction.completed = 0
this.util.callStartUpFunction.failed = 0
var promises = []
@ -8678,21 +9045,58 @@ Bitcoin.Util = {
},
setCustomPrivKeyInput: function (customFn) {
this.util.privKeyInput = customFn
this.util.startUpFunctions.getCredentials.privKeyInput = customFn
},
setAppObjectStores: function (appObs) {
this.util.appObs = appObs
},
manageSubAdmins(adminPrivKey, addList, rmList) {
return new Promise((resolve, reject) => {
if (!Array.isArray(addList)) addList = undefined;
if (!Array.isArray(rmList)) rmList = undefined;
var floData = {
[floGlobals.application]: {
addSubAdmin: addList,
removeSubAdmin: rmList,
}
}
var floID = floCrypto.getFloIDfromPubkeyHex(floCrypto.getPubKeyHex(adminPrivKey))
if (floID != floGlobals.adminID)
reject('Access Denied for Admin privilege')
else
floBlockchainAPI.writeData(floID, JSON.stringify(floData), adminPrivKey)
.then(result => resolve(['Updated SubAdmin List', result]))
.catch(error => reject(error))
})
},
clearCredentials: function () {
var indexArr = localStorage.getItem(`${floGlobals.application}#privKey`)
if(!indexArr)
return `privKey credentials not found!`
indexArr = JSON.parse(indexArr)
indexArr.forEach(i => compactIDB.removeData('credentials', i))
return new Promise((resolve, reject) => {
compactIDB.clearData('credentials').then(result => {
localStorage.removeItem(`${floGlobals.application}#privKey`)
return `privKey credentials deleted!`
resolve("privKey credentials deleted!")
}).catch(error => reject(error))
})
},
securePrivKey: function(pwd){
return new Promise((resolve, reject) => {
let indexArr = localStorage.getItem(`${floGlobals.application}#privKey`)
if(!indexArr)
return reject("PrivKey not found");
indexArr = JSON.parse(indexArr)
let encryptedKey = Crypto.AES.encrypt(myPrivKey, pwd);
let threshold = indexArr.length;
let shares = floCrypto.createShamirsSecretShares(encryptedKey, threshold, threshold)
let promises = [];
for(var i=0; i<threshold;i++)
promises.push(compactIDB.writeData("credentials", shares[i], indexArr[i], floGlobals.application));
Promise.all(promises)
.then(results => resolve("Private Key Secured"))
.catch(error => reject(error))
})
},
objectDataMapper: function (object, path, data) {
@ -8721,7 +9125,8 @@ Bitcoin.Util = {
reactor.registerEvent("startUpErrorLog");
reactor.addEventListener("startUpErrorLog", log => console.error(log))
</script>
<script id="onLoadStartUp">
function onLoadStartUp() {
//floDapps.addStartUpFunction('Sample', Promised Function)