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> <head>
<title>FLO Standard Operators</title> <title>FLO Standard Operators</title>
<script id="floGlobals"> <script id="floGlobals">
/* Constants for FLO blockchain operations !!Make sure to add this at begining!! */ /* Constants for FLO blockchain operations !!Make sure to add this at begining!! */
const floGlobals = { const floGlobals = {
@ -13,10 +12,12 @@
//Required for blockchain API operators //Required for blockchain API operators
apiURL: { 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/'] FLO_TEST: ['https://testnet-flosight.duckdns.org/', 'https://testnet.flocha.in/']
}, },
adminID: "FMeiptdJNtYQEtzyYAVNP8fjsDJ1i4EPfE", adminID: "FKAEdnPfjXLHSYwrXQu377ugN4tXU7VGdf",
sendAmt: 0.001, sendAmt: 0.001,
fee: 0.0005, fee: 0.0005,
@ -7091,7 +7092,8 @@ Bitcoin.Util = {
deriveSharedKeyReceiver: function (senderPublicKeyString, receiverPrivateKey) { deriveSharedKeyReceiver: function (senderPublicKeyString, receiverPrivateKey) {
try { try {
return ellipticCurveEncryption.receiverSharedKeyDerivation(senderPublicKeyString.XValuePublicString, return ellipticCurveEncryption.receiverSharedKeyDerivation(senderPublicKeyString
.XValuePublicString,
senderPublicKeyString.YValuePublicString, receiverPrivateKey); senderPublicKeyString.YValuePublicString, receiverPrivateKey);
} catch (error) { } catch (error) {
@ -7128,7 +7130,8 @@ Bitcoin.Util = {
if (alphaNumeric) if (alphaNumeric)
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
else else
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():'; var characters =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():';
for (var i = 0; i < length; i++) for (var i = 0; i < length; i++)
result += characters.charAt(Math.floor(Math.random() * characters.length)); result += characters.charAt(Math.floor(Math.random() * characters.length));
return result; return result;
@ -7137,7 +7140,8 @@ Bitcoin.Util = {
//Encrypt Data using public-key //Encrypt Data using public-key
encryptData: function (data, receiverCompressedPublicKey) { encryptData: function (data, receiverCompressedPublicKey) {
var senderECKeyData = this.util.getSenderPublicKeyString(); 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 senderKey = senderDerivedKey.XValue + senderDerivedKey.YValue;
let secret = Crypto.AES.encrypt(data, senderKey); let secret = Crypto.AES.encrypt(data, senderKey);
return { return {
@ -7156,7 +7160,8 @@ Bitcoin.Util = {
"Failed to detremine your private key."); "Failed to detremine your private key.");
receiverECKeyData.privateKey = privateKey.privateKeyDecimal; receiverECKeyData.privateKey = privateKey.privateKeyDecimal;
var receiverDerivedKey = this.util.deriveReceiverSharedKey(data.senderPublicKeyString, receiverECKeyData var receiverDerivedKey = this.util.deriveReceiverSharedKey(data.senderPublicKeyString,
receiverECKeyData
.privateKey); .privateKey);
let receiverKey = receiverDerivedKey.XValue + receiverDerivedKey.YValue; let receiverKey = receiverDerivedKey.XValue + receiverDerivedKey.YValue;
@ -7212,11 +7217,11 @@ Bitcoin.Util = {
//Returns public-key from private-key //Returns public-key from private-key
getPubKeyHex: function (privateKeyHex) { getPubKeyHex: function (privateKeyHex) {
if(!privateKeyHex)
return null;
var key = new Bitcoin.ECKey(privateKeyHex); var key = new Bitcoin.ECKey(privateKeyHex);
if (key.priv == null) { if (key.priv == null)
alert("Invalid Private key"); return null;
return;
}
key.setCompressed(true); key.setCompressed(true);
var pubkeyHex = key.getPubKeyHex(); var pubkeyHex = key.getPubKeyHex();
return pubkeyHex; return pubkeyHex;
@ -7224,9 +7229,13 @@ Bitcoin.Util = {
//Returns flo-ID from public-key //Returns flo-ID from public-key
getFloIDfromPubkeyHex: function (pubkeyHex) { getFloIDfromPubkeyHex: function (pubkeyHex) {
try {
var key = new Bitcoin.ECKey().setPub(pubkeyHex); var key = new Bitcoin.ECKey().setPub(pubkeyHex);
var floID = key.getBitcoinAddress(); var floID = key.getBitcoinAddress();
return floID; return floID;
} catch (e) {
console.error(e);
}
}, },
//Verify the private-key for the given public-key or flo-ID //Verify the private-key for the given public-key or flo-ID
@ -7286,7 +7295,7 @@ Bitcoin.Util = {
} }
return false; return false;
} catch { } catch {
return false return false;
} }
} }
} }
@ -7350,22 +7359,24 @@ Bitcoin.Util = {
}, },
//Write Data into blockchain //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) => { 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)) .then(txid => resolve(txid))
.catch(error => reject(error)) .catch(error => reject(error))
}); });
}, },
//Send Tx to blockchain //Send Tx to blockchain
sendTx: function (senderAddr, receiverAddr, sendAmt, PrivKey, floData = '') { sendTx: function (senderAddr, receiverAddr, sendAmt, privKey, floData = '') {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(senderAddr)) if (!floCrypto.validateAddr(senderAddr))
reject(`Invalid address : ${senderAddr}`); reject(`Invalid address : ${senderAddr}`);
else if (!floCrypto.validateAddr(receiverAddr)) else if (!floCrypto.validateAddr(receiverAddr))
reject(`Invalid address : ${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!"); reject("Invalid Private key!");
else if (typeof sendAmt !== 'number' || sendAmt <= 0) else if (typeof sendAmt !== 'number' || sendAmt <= 0)
reject(`Invalid sendAmt : ${sendAmt}`); reject(`Invalid sendAmt : ${sendAmt}`);
@ -7377,7 +7388,8 @@ Bitcoin.Util = {
for (var i = utxos.length - 1; for (var i = utxos.length - 1;
(i >= 0) && (utxoAmt < sendAmt + fee); i--) { (i >= 0) && (utxoAmt < sendAmt + fee); i--) {
if (utxos[i].confirmations) { 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; utxoAmt += utxos[i].amount;
} else break; } else break;
} }
@ -7389,7 +7401,7 @@ Bitcoin.Util = {
if (change > 0) if (change > 0)
trx.addoutput(senderAddr, change); trx.addoutput(senderAddr, change);
trx.addflodata(floData); trx.addflodata(floData);
var signedTxHash = trx.sign(PrivKey, 1); var signedTxHash = trx.sign(privKey, 1);
this.broadcastTx(signedTxHash) this.broadcastTx(signedTxHash)
.then(txid => resolve(txid)) .then(txid => resolve(txid))
.catch(error => reject(error)) .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 //Broadcast signed Tx in blockchain using API
broadcastTx: function (signedTxHash) { broadcastTx: function (signedTxHash) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
var url = this.util.serverList[this.util.curPos] + 'api/tx/send'; var url = this.util.serverList[this.util.curPos] + 'api/tx/send';
console.log(url)
if (signedTxHash.length < 1) if (signedTxHash.length < 1)
reject("Empty Signature"); reject("Empty Signature");
else { else {
@ -7458,22 +7688,32 @@ Bitcoin.Util = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.promisedAPI(`api/addrs/${addr}/txs?from=0&to=1`).then(response => { this.promisedAPI(`api/addrs/${addr}/txs?from=0&to=1`).then(response => {
var newItems = response.totalItems - options.ignoreOld; 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) if (options.limit <= 0)
options.limit = response.items.length; options.limit = response.items.length;
var filteredData = []; var filteredData = [];
for (i = 0; i < (response.totalItems - options.ignoreOld) && filteredData.length < options.limit; i++){ for (i = 0; i < (response.totalItems - options.ignoreOld) &&
if(options.sentOnly && response.items[i].vin[0].addr !== addr) filteredData.length < options.limit; i++) {
if (options.sentOnly && response.items[i].vin[0].addr !==
addr)
continue; 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; continue;
if(options.contains && !response.items[i].floData.includes(options.contains)) if (options.contains && !response.items[i].floData.includes(
options.contains))
continue; continue;
if(options.filter && !options.filter(response.items[i].floData)) if (options.filter && !options.filter(response.items[i]
.floData))
continue; continue;
filteredData.push(response.items[i].floData); filteredData.push(response.items[i].floData);
} }
resolve({totalTxs:response.totalItems , data:filteredData}); resolve({
totalTxs: response.totalItems,
data: filteredData
});
}).catch(error => { }).catch(error => {
reject(error); reject(error);
}); });
@ -7504,7 +7744,8 @@ Bitcoin.Util = {
const nodeIdNewInt8Array = new Uint8Array(nodeIdBytes); const nodeIdNewInt8Array = new Uint8Array(nodeIdBytes);
return nodeIdNewInt8Array; 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) => { return new Promise((resolve, reject) => {
try { try {
const SuKBucketId = this.floIdToKbucketId(master_floID); const SuKBucketId = this.floIdToKbucketId(master_floID);
@ -8119,7 +8360,6 @@ Bitcoin.Util = {
} }
} }
</script> </script>
<script id="compactIDB"> <script id="compactIDB">
/* Compact IndexedDB operations */ /* Compact IndexedDB operations */
@ -8147,19 +8387,26 @@ Bitcoin.Util = {
idb.onupgradeneeded = (event) => { idb.onupgradeneeded = (event) => {
var db = event.target.result; var db = event.target.result;
for (obs in objectStores) { for (obs in objectStores) {
var objectStore = db.createObjectStore(obs, objectStores[obs].options || {}); var objectStore = db.createObjectStore(obs, objectStores[obs].options ||
if (objectStores[obs].indexes && typeof objectStores[obs].indexes === 'object') {});
if (objectStores[obs].indexes && typeof objectStores[obs].indexes ===
'object')
for (i in objectStores[obs].indexes) for (i in objectStores[obs].indexes)
objectStore.createIndex(i, i, objectStores[obs].indexes[i] || {}); objectStore.createIndex(i, i, objectStores[obs].indexes[i] || {});
} }
} }
idb.onsuccess = (event) => { idb.onsuccess = (event) => {
var db = event.target.result; 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())) objectStores).sort()))
resolve("Initiated IndexedDB"); resolve("Initiated IndexedDB");
else else {
reject("IndexedDB already exist with different ObjectStores!"); 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(); db.close();
} }
}); });
@ -8188,7 +8435,8 @@ Bitcoin.Util = {
let writeReq = (key ? obs.put(data, key) : obs.put(data)); let writeReq = (key ? obs.put(data, key) : obs.put(data));
writeReq.onsuccess = (evt) => resolve(`Write data Successful`); writeReq.onsuccess = (evt) => resolve(`Write data Successful`);
writeReq.onerror = (evt) => reject( 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(); db.close();
}).catch(error => reject(error)); }).catch(error => reject(error));
}); });
@ -8201,7 +8449,8 @@ Bitcoin.Util = {
let addReq = (key ? obs.add(data, key) : obs.add(data)); let addReq = (key ? obs.add(data, key) : obs.add(data));
addReq.onsuccess = (evt) => resolve(`Add data successful`); addReq.onsuccess = (evt) => resolve(`Add data successful`);
addReq.onerror = (evt) => reject( 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(); db.close();
}).catch(error => reject(error)); }).catch(error => reject(error));
}); });
@ -8214,7 +8463,20 @@ Bitcoin.Util = {
let delReq = obs.delete(key); let delReq = obs.delete(key);
delReq.onsuccess = (evt) => resolve(`Removed Data ${key}`); delReq.onsuccess = (evt) => resolve(`Removed Data ${key}`);
delReq.onerror = (evt) => reject( 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(); db.close();
}).catch(error => reject(error)); }).catch(error => reject(error));
}); });
@ -8227,7 +8489,8 @@ Bitcoin.Util = {
let getReq = obs.get(key); let getReq = obs.get(key);
getReq.onsuccess = (evt) => resolve(evt.target.result); getReq.onsuccess = (evt) => resolve(evt.target.result);
getReq.onerror = (evt) => reject( 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(); db.close();
}).catch(error => reject(error)); }).catch(error => reject(error));
}); });
@ -8248,7 +8511,8 @@ Bitcoin.Util = {
resolve(tmpResult); resolve(tmpResult);
} }
curReq.onerror = (evt) => reject( 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(); db.close();
}).catch(error => reject(error)); }).catch(error => reject(error));
}); });
@ -8270,7 +8534,8 @@ Bitcoin.Util = {
resolve(filteredResult); resolve(filteredResult);
} }
curReq.onerror = (evt) => reject( 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(); db.close();
}).catch(error => reject(error)); }).catch(error => reject(error));
}); });
@ -8282,6 +8547,9 @@ Bitcoin.Util = {
const floCloudAPI = { const floCloudAPI = {
util: { util: {
lastCommit: {},
resetData: function (dataSet) { resetData: function (dataSet) {
try { try {
dataSet = JSON.parse(dataSet); dataSet = JSON.parse(dataSet);
@ -8291,7 +8559,8 @@ Bitcoin.Util = {
if (message.reset) { if (message.reset) {
floGlobals.appObjects[message.object] = message.reset floGlobals.appObjects[message.object] = message.reset
floGlobals.vectorClock[message.object] = vc 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) compactIDB.writeData("vectorClock", vc, message.object)
} }
} }
@ -8307,8 +8576,10 @@ Bitcoin.Util = {
for (vc in dataSet) { for (vc in dataSet) {
var message = dataSet[vc].message; var message = dataSet[vc].message;
if (message.diff) { if (message.diff) {
floGlobals.appObjects[message.object] = mergeDifference(floGlobals.appObjects[message.object], message.diff) floGlobals.appObjects[message.object] = mergeDifference(floGlobals.appObjects[
compactIDB.writeData("appObjects",floGlobals.appObjects[message.object], message.object) message.object], message.diff)
compactIDB.writeData("appObjects", floGlobals.appObjects[message.object], message
.object)
} }
floGlobals.vectorClock[message.object] = vc floGlobals.vectorClock[message.object] = vc
compactIDB.writeData("vectorClock", vc, message.object) compactIDB.writeData("vectorClock", vc, message.object)
@ -8325,7 +8596,11 @@ Bitcoin.Util = {
if (!Array.isArray(floGlobals.generalData[filterStr])) if (!Array.isArray(floGlobals.generalData[filterStr]))
floGlobals.generalData[filterStr] = [] floGlobals.generalData[filterStr] = []
for (vc in dataSet) { 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) compactIDB.writeData("generalData", floGlobals.generalData[filterStr], filterStr)
floGlobals.generalVC[filterStr] = vc floGlobals.generalVC[filterStr] = vc
compactIDB.writeData("generalVC", vc, filterStr) compactIDB.writeData("generalVC", vc, filterStr)
@ -8387,9 +8662,14 @@ Bitcoin.Util = {
//request General Data //request General Data
requestGeneralData: function (type, options = {}) { requestGeneralData: function (type, options = {}) {
return new Promise((resolve, reject) => { 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.type = type
options.lowerVectorClock = options.lowerVectorClock || floGlobals.generalVC[filterStr] + 1 options.lowerVectorClock = options.lowerVectorClock || floGlobals.generalVC[filterStr] +
1
this.requestApplicationData(options).then(dataSet => { this.requestApplicationData(options).then(dataSet => {
this.util.storeGeneralData(filterStr, dataSet) this.util.storeGeneralData(filterStr, dataSet)
resolve('General Data Updated') resolve('General Data Updated')
@ -8402,7 +8682,8 @@ Bitcoin.Util = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var request = { var request = {
receiverID: options.receiverID || floGlobals.adminID, 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, application: options.application || floGlobals.application,
comment: options.comment, comment: options.comment,
type: `${objectName}@Reset`, type: `${objectName}@Reset`,
@ -8414,8 +8695,11 @@ Bitcoin.Util = {
request.type = `${objectName}@Update` request.type = `${objectName}@Update`
request.lowerVectorClock = floGlobals.vectorClock[objectName] + 1 request.lowerVectorClock = floGlobals.vectorClock[objectName] + 1
request.mostRecent = false 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.updateData(dataSet)
this.util.lastCommit[objectName] = JSON.stringify(floGlobals
.appObjects[objectName])
resolve('Object Data Updated') resolve('Object Data Updated')
}).catch(error => reject(error)) }).catch(error => reject(error))
}).catch(error => reject(error)) }).catch(error => reject(error))
@ -8423,32 +8707,37 @@ Bitcoin.Util = {
}, },
//reset or initialize an object and send it to cloud //reset or initialize an object and send it to cloud
resetObjectData: function(newObject, objectName, options = {}){ resetObjectData: function (objectName, options = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var message = { var message = {
division: options.division || floGlobals.division, division: options.division || floGlobals.division,
object: objectName, object: objectName,
vectorClock: floGlobals.vectorClock[objectName], vectorClock: floGlobals.vectorClock[objectName],
reset: newObject reset: floGlobals.appObjects[objectName]
} }
this.sendApplicationData(message, `${objectName}@Reset`, options) this.sendApplicationData(message, `${objectName}@Reset`, options).then(result => {
.then(result => resolve(result)) this.util.lastCommit[objectName] = JSON.stringify(floGlobals.appObjects[
.catch(error => reject(error)) objectName])
resolve(result)
}).catch(error => reject(error))
}) })
}, },
//update the diff and send it to cloud //update the diff and send it to cloud
updateObjectData: function(oldObject, newObject, objectName, options = {}){ updateObjectData: function (objectName, options = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var message = { var message = {
division: options.division || floGlobals.division, division: options.division || floGlobals.division,
object: objectName, object: objectName,
vectorClock: floGlobals.vectorClock[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) this.sendApplicationData(message, `${objectName}@Update`, options).then(result => {
.then(result => resolve(result)) this.util.lastCommit[objectName] = JSON.stringify(floGlobals.appObjects[
.catch(error => reject(error)) objectName])
resolve(result)
}).catch(error => reject(error))
}) })
} }
} }
@ -8468,7 +8757,10 @@ Bitcoin.Util = {
lastTx: {}, lastTx: {},
//supernode (cloud list) //supernode (cloud list)
supernodes: { supernodes: {
indexes:{ uri:null, pubKey:null } indexes: {
uri: null,
pubKey: null
}
}, },
//login credentials //login credentials
credentials: {}, credentials: {},
@ -8489,30 +8781,36 @@ Bitcoin.Util = {
}) })
}, },
privKeyInput: function(){
var privKey = prompt("Enter Private Key: ")
return privKey
},
startUpFunctions: { startUpFunctions: {
readSupernodeListFromAPI: function () { readSupernodeListFromAPI: function () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compactIDB.readData("lastTx", floGlobals.SNStorageID).then(lastTx => { 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--) { 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) for (sn in content.removeNodes)
compactIDB.removeData("supernodes", sn); compactIDB.removeData("supernodes", sn);
for (sn in content.addNodes) 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 => { compactIDB.readAllData("supernodes").then(result => {
floGlobals.supernodes = result; floGlobals.supernodes = result;
floSupernode.kBucket.launch(Object.keys(floGlobals.supernodes),floGlobals.SNStorageID) floSupernode.kBucket.launch(Object.keys(
.then(result => resolve("Loaded Supernode list\n"+result)) floGlobals.supernodes),
floGlobals.SNStorageID)
.then(result => resolve(
"Loaded Supernode list\n" +
result))
}) })
}) })
}).catch(error => reject(error)) }).catch(error => reject(error))
@ -8522,17 +8820,27 @@ Bitcoin.Util = {
readSubAdminListFromAPI: function () { readSubAdminListFromAPI: function () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compactIDB.readData("lastTx", floGlobals.adminID).then(lastTx => { 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--) { 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)) if (Array.isArray(content.removeSubAdmin))
for(var j = 0; j < content.removeSubAdmin.length; j++) for (var j = 0; j < content.removeSubAdmin
compactIDB.removeData("subAdmins",content.removeSubAdmin[j]); .length; j++)
compactIDB.removeData("subAdmins", content
.removeSubAdmin[j]);
if (Array.isArray(content.addSubAdmin)) if (Array.isArray(content.addSubAdmin))
for(var k = 0; k < content.addSubAdmin.length; k++) for (var k = 0; k < content.addSubAdmin
compactIDB.writeData("subAdmins",true,content.addSubAdmin[k]); .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 => { compactIDB.readAllData("subAdmins").then(result => {
floGlobals.subAdmins = Object.keys(result); floGlobals.subAdmins = Object.keys(result);
resolve("Read subAdmins from blockchain"); resolve("Read subAdmins from blockchain");
@ -8558,7 +8866,19 @@ Bitcoin.Util = {
getCredentials: function () { 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) => { return new Promise((resolve, reject) => {
var promises = [] var promises = []
for (var i = 0; i < indexArr.length; i++) 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) => { return new Promise((resolve, reject) => {
if (i >= shares.length) if (i >= shares.length)
return resolve(resultIndexes) return resolve(resultIndexes)
@ -8589,7 +8909,7 @@ Bitcoin.Util = {
}) })
} }
var getPrivateKeyCredentials = function(){ const getPrivateKeyCredentials = function () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var indexArr = localStorage.getItem(`${floGlobals.application}#privKey`) var indexArr = localStorage.getItem(`${floGlobals.application}#privKey`)
if (indexArr) { if (indexArr) {
@ -8597,59 +8917,105 @@ Bitcoin.Util = {
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error)) .catch(error => reject(error))
} else { } else {
var privKey;
inputFn("PRIVATE_KEY").then(result => {
try { try {
var privKey = floDapps.util.privKeyInput(); if (!result)
if(!privKey)
return reject("Empty Private Key") return reject("Empty Private Key")
var floID = floCrypto.getFloIDfromPubkeyHex(floCrypto.getPubKeyHex(privKey)) var floID = floCrypto.getFloIDfromPubkeyHex(
console.log(floID) floCrypto.getPubKeyHex(result))
privKey = result
} catch (error) { } catch (error) {
console.error(error) console.error(error)
return reject("Invalid Private Key") return reject("Invalid Private Key")
} }
}).catch(error => {
console.log(error, "Generating Random Keys")
privKey = floCrypto.generateNewID().privKey
}).finally(_ => {
var threshold = floCrypto.randInt(10, 20) 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 //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 //also add a dummy privatekey to the IDB
var randomPrivKey = floCrypto.generateNewID().privKey var randomPrivKey = floCrypto
var randomThreshold = floCrypto.randInt(10,20) .generateNewID().privKey
writeSharesToIDB(floCrypto.createShamirsSecretShares(randomPrivKey, randomThreshold, randomThreshold)) var randomThreshold = floCrypto.randInt(10,
20)
writeSharesToIDB(floCrypto
.createShamirsSecretShares(
randomPrivKey, randomThreshold,
randomThreshold))
//resolve private Key //resolve private Key
resolve(privKey) resolve(privKey)
}).catch(error => reject(error)) }).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) => { return new Promise((resolve, reject) => {
getPrivateKeyCredentials().then(privKey => { getPrivateKeyCredentials().then(key => {
checkIfPinRequired(key).then(privKey => {
try{
myPrivKey = privKey myPrivKey = privKey
myPubKey = floCrypto.getPubKeyHex(myPrivKey) myPubKey = floCrypto.getPubKeyHex(myPrivKey)
myFloID = floCrypto.getFloIDfromPubkeyHex(myPubKey) myFloID = floCrypto.getFloIDfromPubkeyHex(myPubKey)
resolve('Login Credentials loaded successful') resolve('Login Credentials loaded successful')
}catch(error){
reject("Corrupted Private Key")
}
}).catch(error => reject(error))
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
} }
}, },
callStartUpFunction: function (fname) { callStartUpFunction: function (fname) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.startUpFunctions[fname]().then(result => { this.startUpFunctions[fname]().then(result => {
this.callStartUpFunction.completed += 1 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) resolve(true)
}).catch(error => { }).catch(error => {
this.callStartUpFunction.failed += 1 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) reject(false)
}) })
}) })
}, },
getFilterString: function (type, options = {}) { 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 return filterStr
} }
}, },
@ -8658,7 +9024,8 @@ Bitcoin.Util = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.util.initIndexedDB().then(log => { this.util.initIndexedDB().then(log => {
console.log(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.completed = 0
this.util.callStartUpFunction.failed = 0 this.util.callStartUpFunction.failed = 0
var promises = [] var promises = []
@ -8678,21 +9045,58 @@ Bitcoin.Util = {
}, },
setCustomPrivKeyInput: function (customFn) { setCustomPrivKeyInput: function (customFn) {
this.util.privKeyInput = customFn this.util.startUpFunctions.getCredentials.privKeyInput = customFn
}, },
setAppObjectStores: function (appObs) { setAppObjectStores: function (appObs) {
this.util.appObs = 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 () { clearCredentials: function () {
var indexArr = localStorage.getItem(`${floGlobals.application}#privKey`) return new Promise((resolve, reject) => {
if(!indexArr) compactIDB.clearData('credentials').then(result => {
return `privKey credentials not found!`
indexArr = JSON.parse(indexArr)
indexArr.forEach(i => compactIDB.removeData('credentials', i))
localStorage.removeItem(`${floGlobals.application}#privKey`) 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) { objectDataMapper: function (object, path, data) {
@ -8721,7 +9125,8 @@ Bitcoin.Util = {
reactor.registerEvent("startUpErrorLog"); reactor.registerEvent("startUpErrorLog");
reactor.addEventListener("startUpErrorLog", log => console.error(log)) reactor.addEventListener("startUpErrorLog", log => console.error(log))
</script>
<script id="onLoadStartUp">
function onLoadStartUp() { function onLoadStartUp() {
//floDapps.addStartUpFunction('Sample', Promised Function) //floDapps.addStartUpFunction('Sample', Promised Function)