Merge pull request #6 from sairajzero/master
This commit is contained in:
commit
1e6d2462af
@ -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)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user