Merge pull request #9 from sairajzero/master

This commit is contained in:
Sai Raj 2020-08-20 17:53:05 +05:30 committed by GitHub
commit 49d4377900
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 168 additions and 71 deletions

View File

@ -282,16 +282,15 @@ Note: If passed as Array, then ratio of the balance of the senders are preserved
`readData` reads FLO data from transactions of specified address `readData` reads FLO data from transactions of specified address
1. addr - FLO address for which the transactions data has to be read. 1. addr - FLO address for which the transactions data has to be read.
2. options - Contains options for filter data from transactions. 2. options - Contains options for filter data from transactions.
- limit : maximum number of filtered data (default = 1000, negative = no limit) - limit : maximum number of filtered data (default = no limit)
- ignoreOld : ignore old transactions (default = 0) - ignoreOld : ignore old transactions (default = 0)
- sentOnly : filters only sent data - sentOnly : filters only sent data
- pattern : filters data that starts with a pattern - pattern : filters data that contains pattern as an object key in the JSON string
- contains : filters data that contains a string
- filter : custom filter funtion for floData (eg . filter: d => {return d[0] == '$'}) - filter : custom filter funtion for floData (eg . filter: d => {return d[0] == '$'})
* Resolves: Object {totalTxs, floData (Array)} * Resolves: Object {totalTxs, floData (Array)}
## Compact IndexedDB operations ## Compact IndexedDB operations
`compactIDB` operations can be used to perform basic IndexedDB operations such as add, read/write, modify and remove.Contains following operations. `compactIDB` operations can be used to perform basic IndexedDB operations such as add, read/write, modify and remove. These functions are asynchronous and return a promise. Contains the following operations.
#### Important: Compact IndexedDB operations have all been promisified. All output needs to be handled using .then These operations do not return function return values. Once again, they resolve: they do not return. #### Important: Compact IndexedDB operations have all been promisified. All output needs to be handled using .then These operations do not return function return values. Once again, they resolve: they do not return.
@ -299,22 +298,26 @@ Note: If passed as Array, then ratio of the balance of the senders are preserved
compactIDB.setDefaultDB(dbName) compactIDB.setDefaultDB(dbName)
`setDefaultDB` sets the database on which further operations will be performed. `setDefaultDB` sets the database on which further operations will be performed.
1. dbName - This is the name of default database to be used. 1. dbName - This is the name of default database to be used.
* Note: this operation is neither promisified nor returns a value. It just sets the default DB
#### initDB #### initDB
compactIDB.initDB(dbName, objectStores = {}) compactIDB.initDB(dbName, objectStores = {})
`initDB` initializes new IndexedDB. `initDB` initializes new IndexedDB.
1. dbName - Specifies database to be initialized. 1. dbName - Specifies database to be initialized.
2. objectStores - This is an object containing various objectStores to be initiazed when creating an IDB. 2. objectStores - This is an object containing various objectStores to be initiazed when creating an IDB.
* Resolves: Status (string) | Rejects: error
#### openDB #### openDB
compactIDB.openDB(dbName = this.defaultDB) compactIDB.openDB(dbName = this.defaultDB)
`openDB` returns a promise that resolves to a default database object. `openDB` returns a promise that resolves to a default database object.
1. dbName - Name of the database (optional, uses defaultDB if not specified) 1. dbName - Name of the database (optional, uses defaultDB if not specified)
* Resolves: database (IDB) | Rejects: error
#### deleteDB #### deleteDB
compactIDB.deleteDB(dbName = this.defaultDB) compactIDB.deleteDB(dbName = this.defaultDB)
`deleteDB` deletes the specified database. `deleteDB` deletes the specified database.
1. dbName - Name of the database (optional, uses defaultDB if not specified) 1. dbName - Name of the database (optional, uses defaultDB if not specified)
* Resolves: Status (string) | Rejects: error
#### writeData #### writeData
compactIDB.writeData(obsName, data, key = false, dbName = this.defaultDB) compactIDB.writeData(obsName, data, key = false, dbName = this.defaultDB)
@ -323,6 +326,7 @@ Note: If passed as Array, then ratio of the balance of the senders are preserved
2. data - data that has to be written in specified object store. 2. data - data that has to be written in specified object store.
3. key - Primary key of the data (optional, false indicates key is autoincremented or passed in data) 3. key - Primary key of the data (optional, false indicates key is autoincremented or passed in data)
4. dbName - Name of the database (optional, uses defaultDB if not specified) 4. dbName - Name of the database (optional, uses defaultDB if not specified)
* Resolves: Status (string) | Rejects: error
#### addData #### addData
compactIDB.addData(obsName, data, key = false, dbName = this.defaultDB) compactIDB.addData(obsName, data, key = false, dbName = this.defaultDB)
@ -331,6 +335,7 @@ Note: If passed as Array, then ratio of the balance of the senders are preserved
2. data - The data which has to be added to obeject store. 2. data - The data which has to be added to obeject store.
3. key - Primary key of the data (optional, false indicates key is autoincremented or passed in data) 3. key - Primary key of the data (optional, false indicates key is autoincremented or passed in data)
4. dbName - Name of the database (optional, uses defaultDB if not specified) 4. dbName - Name of the database (optional, uses defaultDB if not specified)
* Resolves: Status (string) | Rejects: error
#### removeData #### removeData
compactDB.removeData(obsName, key, dbName = this.defaultDB) compactDB.removeData(obsName, key, dbName = this.defaultDB)
@ -338,12 +343,14 @@ Note: If passed as Array, then ratio of the balance of the senders are preserved
1. obsName - Name of object store from which the data has to be removed. 1. obsName - Name of object store from which the data has to be removed.
2. key - Primary key of the data. 2. key - Primary key of the data.
3. dbName - Name of the database (optional, uses defaultDB if not specified) 3. dbName - Name of the database (optional, uses defaultDB if not specified)
* Resolves: Status (string) | Rejects: error
#### clearData #### clearData
compactDB.clearData(obsName, dbName = this.defaultDB) compactDB.clearData(obsName, dbName = this.defaultDB)
`clearData` clears all data in the objectStore. `clearData` clears all data in the objectStore.
1. obsName - Name of object store from which the data has to be removed. 1. obsName - Name of object store from which the data has to be removed.
2. dbName - Name of the database (optional, uses defaultDB if not specified) 2. dbName - Name of the database (optional, uses defaultDB if not specified)
* Resolves: Status (string) | Rejects: error
#### readData #### readData
compactDB.readData(obsName, key, dbName = this.defaultDB) compactDB.readData(obsName, key, dbName = this.defaultDB)
@ -351,20 +358,34 @@ Note: If passed as Array, then ratio of the balance of the senders are preserved
1. obsName - Name of object store from which the data has to be retrieved. 1. obsName - Name of object store from which the data has to be retrieved.
2. key - Primary key of the data to read. 2. key - Primary key of the data to read.
3. dbName - Name of the database (optional, uses defaultDB if not specified) 3. dbName - Name of the database (optional, uses defaultDB if not specified)
* Resolves: data (Object) | Rejects: error
#### readAllData #### readAllData
compactDB.readAllData(obsName, dbName = this.defaultDB) compactDB.readAllData(obsName, dbName = this.defaultDB)
`readAllData` reads all the data from specified object store using IndexedDB openCursor method. `readAllData` reads all the data from specified object store using IndexedDB openCursor method.
1. obsName - Name of object store from which the data has to be retrieved. 1. obsName - Name of object store from which the data has to be retrieved.
2. dbName - Name of the database (optional, uses defaultDB if not specified) 2. dbName - Name of the database (optional, uses defaultDB if not specified)
* Resolves: data (Object) | Rejects: error
## FLO Supernode module ## FLO Supernode module
This module contains functions that interact with the supernode to send and retrive data in the backend. Use floClouldAPI operations to send and receive data for application. This module contains functions that interact with the supernode to send and retrive data in the backend. Use floClouldAPI operations to send and receive data for application.
## FLO Cloud API operations ## FLO Cloud API operations
`floCloudAPI` operations can interact with floSupernode cloud to send and retrieve data for applications. floCloudAPI uses floSupernode module for backend interactions. `floCloudAPI` operations can interact with floSupernode cloud to send and retrieve data for applications. floCloudAPI uses floSupernode module for backend interactions. FLO Cloud API functions are promisified and resolves the data or status.
FLO Cloud API operations have all been promisified. All output needs to be handled using .then These operations do not return function return values. Once again, they resolve: they do not return. #### sendApplicationData
floCloudAPI.sendApplicationData(message, type, options = {})
`sendApplicationData` sends application data to the cloud.
1. message - data to be sent
2. type - type of the data
3. options - (optional, options detailed at end of module)
* Resolves: Sent-Status (string) | Rejects: error
#### requestApplicationData
floCloudAPI.requestApplicationData(options = {})
`requestApplicationData` requests application data from the cloud.
1. options - (optional, options detailed at end of module)
* Resolves: data (Object) | Rejects: error
#### sendGeneralData #### sendGeneralData
floCloudAPI.sendGeneralData(message, type, options = {}) floCloudAPI.sendGeneralData(message, type, options = {})
@ -372,6 +393,7 @@ FLO Cloud API operations have all been promisified. All output needs to be handl
1. message - data to be sent 1. message - data to be sent
2. type - type of the data 2. type - type of the data
3. options - (optional, options detailed at end of module) 3. options - (optional, options detailed at end of module)
* Resolves: Sent-Status (string) | Rejects: error
###### Minimal Example: ###### Minimal Example:
floCloudAPI.sendGeneralData("Hello World", "type1") floCloudAPI.sendGeneralData("Hello World", "type1")
@ -382,6 +404,7 @@ Sends "Hello World" message to the cloud as General Data with type1 as `type` wi
`requestGeneralData` requests application data from the cloud. `requestGeneralData` requests application data from the cloud.
1. type - type of the data 1. type - type of the data
2. options - (optional, options detailed at end of module) 2. options - (optional, options detailed at end of module)
* Resolves: Status (string) | Rejects: error
###### Minimal Example: ###### Minimal Example:
floCloudAPI.requestGeneralData("type1") floCloudAPI.requestGeneralData("type1")
@ -392,9 +415,9 @@ Requests all messages of General Data nature from the cloud with type1 as `type`
`resetObjectData` resets the objectData to cloud. `resetObjectData` resets the objectData to cloud.
1. "objectName" - Name of the objectData to be reset. Quotes are must 1. "objectName" - Name of the objectData to be reset. Quotes are must
2. options - (optional, options detailed at end of module) 2. options - (optional, options detailed at end of module)
* Resolves: Sent-Status (string) | Rejects: error
Note: value of objectData is taken from floGlobals.appObjects["objectName"] Note: value of objectData is taken from floGlobals.appObjects["objectName"]
The object data corresponding with Object Name must be defined in floGlobals.appObjects["objectName"] before a reset can be done The object data corresponding with Object Name must be defined in floGlobals.appObjects["objectName"] before a reset can be done
###### Minimal Example: ###### Minimal Example:
@ -407,9 +430,9 @@ Initiates "myFirstObject" with {a:1,b:2}, and sends to cloud with `myFloID` as d
`updateObjectData` updates the objectData to cloud. `updateObjectData` updates the objectData to cloud.
1. "objectName" - Name of the objectData to be updated. Quotes are must. 1. "objectName" - Name of the objectData to be updated. Quotes are must.
2. options - (optional, options detailed at end of module) 2. options - (optional, options detailed at end of module)
* Resolves: Sent-Status (string) | Rejects: error
Note: value of objectData is taken from floGlobals.appObjects["objectName"] Note: value of objectData is taken from floGlobals.appObjects["objectName"]
The object data corresponding with Object Name must be defined in floGlobals.appObjects["objectName"] before an update can be done The object data corresponding with Object Name must be defined in floGlobals.appObjects["objectName"] before an update can be done
###### Minimal Example: ###### Minimal Example:
@ -422,6 +445,7 @@ Updates "myFirstObject" with {a:1,c:3,d:4}, and sends to cloud with `myFloID` as
`requestObjectData` requests application data from the cloud. `requestObjectData` requests application data from the cloud.
1. "objectName" - Name of the objectData to be requested. Quotes are must. 1. "objectName" - Name of the objectData to be requested. Quotes are must.
2. options - (optional, options detailed at end of module) 2. options - (optional, options detailed at end of module)
* Resolves: Status (string) | Rejects: error
Note: The output is available at floGlobals.appObjects["objectName"] after the promise is resolved Note: The output is available at floGlobals.appObjects["objectName"] after the promise is resolved

View File

@ -7400,7 +7400,7 @@ Bitcoin.Util = {
var change = utxoAmt - sendAmt - fee; var change = utxoAmt - sendAmt - fee;
if (change > 0) if (change > 0)
trx.addoutput(senderAddr, change); trx.addoutput(senderAddr, change);
trx.addflodata(floData.replace(/\n/g,' ')); trx.addflodata(floData.replace(/\n/g, ' '));
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))
@ -7431,7 +7431,7 @@ Bitcoin.Util = {
} }
} }
trx.addoutput(floID, utxoAmt - fee); trx.addoutput(floID, utxoAmt - fee);
trx.addflodata(floData.replace(/\n/g,' ')); trx.addflodata(floData.replace(/\n/g, ' '));
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))
@ -7447,11 +7447,11 @@ Bitcoin.Util = {
* @param {boolean} preserveRatio (optional) preserve ratio or equal contribution * @param {boolean} preserveRatio (optional) preserve ratio or equal contribution
* @return {Promise} * @return {Promise}
*/ */
writeDataMultiple: function (senderPrivKeys, data, receivers = [floGlobals.adminID], preserveRatio = true){ writeDataMultiple: function (senderPrivKeys, data, receivers = [floGlobals.adminID], preserveRatio = true) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!Array.isArray(senderPrivKeys)) if (!Array.isArray(senderPrivKeys))
return reject("Invalid senderPrivKeys: SenderPrivKeys must be Array") return reject("Invalid senderPrivKeys: SenderPrivKeys must be Array")
if(!preserveRatio){ if (!preserveRatio) {
let tmp = {}; let tmp = {};
let amount = (floGlobals.sendAmt * receivers.length) / senderPrivKeys.length; let amount = (floGlobals.sendAmt * receivers.length) / senderPrivKeys.length;
senderPrivKeys.forEach(key => tmp[key] = amount); senderPrivKeys.forEach(key => tmp[key] = amount);
@ -7481,54 +7481,59 @@ Bitcoin.Util = {
*/ */
sendTxMultiple: function (senderPrivKeys, receivers, floData = '') { sendTxMultiple: function (senderPrivKeys, receivers, floData = '') {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let senders = {}, preserveRatio; let senders = {},
preserveRatio;
//check for argument validations //check for argument validations
try{ try {
let invalids = { let invalids = {
InvalidSenderPrivKeys: [], InvalidSenderPrivKeys: [],
InvalidSenderAmountFor: [], InvalidSenderAmountFor: [],
InvalidReceiverIDs: [], InvalidReceiverIDs: [],
InvalidReceiveAmountFor: [] InvalidReceiveAmountFor: []
} }
let inputVal = 0, outputVal = 0; let inputVal = 0,
outputVal = 0;
//Validate sender privatekeys (and send amount if passed) //Validate sender privatekeys (and send amount if passed)
//conversion when only privateKeys are passed (preserveRatio mode) //conversion when only privateKeys are passed (preserveRatio mode)
if(Array.isArray(senderPrivKeys)){ if (Array.isArray(senderPrivKeys)) {
senderPrivKeys.forEach(key => { senderPrivKeys.forEach(key => {
try{ try {
if(!key) if (!key)
invalids.InvalidSenderPrivKeys.push(key); invalids.InvalidSenderPrivKeys.push(key);
else{ else {
let floID = floCrypto.getFloIDfromPubkeyHex(floCrypto.getPubKeyHex(key)); let floID = floCrypto.getFloIDfromPubkeyHex(floCrypto
.getPubKeyHex(key));
senders[floID] = { senders[floID] = {
wif: key wif: key
} }
} }
}catch(error){ } catch (error) {
invalids.InvalidSenderPrivKeys.push(key) invalids.InvalidSenderPrivKeys.push(key)
} }
}) })
preserveRatio = true; preserveRatio = true;
} }
//conversion when privatekeys are passed with send amount //conversion when privatekeys are passed with send amount
else{ else {
for(let key in senderPrivKeys){ for (let key in senderPrivKeys) {
try{ try {
if(!key) if (!key)
invalids.InvalidSenderPrivKeys.push(key); invalids.InvalidSenderPrivKeys.push(key);
else{ else {
if(typeof senderPrivKeys[key] !== 'number' || senderPrivKeys[key] <= 0) if (typeof senderPrivKeys[key] !== 'number' || senderPrivKeys[
key] <= 0)
invalids.InvalidSenderAmountFor.push(key) invalids.InvalidSenderAmountFor.push(key)
else else
inputVal += senderPrivKeys[key]; inputVal += senderPrivKeys[key];
let floID = floCrypto.getFloIDfromPubkeyHex(floCrypto.getPubKeyHex(key)); let floID = floCrypto.getFloIDfromPubkeyHex(floCrypto.getPubKeyHex(
key));
senders[floID] = { senders[floID] = {
wif: key, wif: key,
coins: senderPrivKeys[key] coins: senderPrivKeys[key]
} }
} }
}catch(error){ } catch (error) {
invalids.InvalidSenderPrivKeys.push(key) invalids.InvalidSenderPrivKeys.push(key)
} }
} }
@ -7550,9 +7555,10 @@ Bitcoin.Util = {
if (Object.keys(invalids).length) if (Object.keys(invalids).length)
return reject(invalids); return reject(invalids);
//Reject if given inputVal and outputVal are not equal //Reject if given inputVal and outputVal are not equal
if(!preserveRatio && inputVal != outputVal) if (!preserveRatio && inputVal != outputVal)
return reject(`Input Amount (${inputVal}) not equal to Output Amount (${outputVal})`) return reject(
}catch(error){ `Input Amount (${inputVal}) not equal to Output Amount (${outputVal})`)
} catch (error) {
return reject(error) return reject(error)
} }
//Get balance of senders //Get balance of senders
@ -7564,18 +7570,22 @@ Bitcoin.Util = {
totalFee = floGlobals.fee, totalFee = floGlobals.fee,
balance = {}; balance = {};
//Divide fee among sender if not for preserveRatio //Divide fee among sender if not for preserveRatio
if(!preserveRatio) if (!preserveRatio)
var dividedFee = totalFee / Object.keys(senders).length; var dividedFee = totalFee / Object.keys(senders).length;
//Check if balance of each sender is sufficient enough //Check if balance of each sender is sufficient enough
let insufficient = []; let insufficient = [];
for (let floID in senders) { for (let floID in senders) {
balance[floID] = parseFloat(results.shift()); balance[floID] = parseFloat(results.shift());
if (isNaN(balance[floID]) || (preserveRatio && balance[floID] <= totalFee) || (!preserveRatio && balance[floID] < senders[floID].coins + dividedFee)) if (isNaN(balance[floID]) || (preserveRatio && balance[floID] <=
totalFee) || (!preserveRatio && balance[floID] < senders[floID]
.coins + dividedFee))
insufficient.push(floID) insufficient.push(floID)
totalBalance += balance[floID]; totalBalance += balance[floID];
} }
if (insufficient.length) if (insufficient.length)
return reject({InsufficientBalance: insufficient}) return reject({
InsufficientBalance: insufficient
})
//Calculate totalSentAmount and check if totalBalance is sufficient //Calculate totalSentAmount and check if totalBalance is sufficient
let totalSendAmt = totalFee; let totalSendAmt = totalFee;
for (floID in receivers) for (floID in receivers)
@ -7592,10 +7602,10 @@ Bitcoin.Util = {
for (floID in senders) { for (floID in senders) {
let utxos = results.shift(); let utxos = results.shift();
let sendAmt; let sendAmt;
if(preserveRatio){ if (preserveRatio) {
let ratio = (balance[floID] / totalBalance); let ratio = (balance[floID] / totalBalance);
sendAmt = totalSendAmt * ratio; sendAmt = totalSendAmt * ratio;
} else } else
sendAmt = senders[floID].coins + dividedFee; sendAmt = senders[floID].coins + dividedFee;
let wif = senders[floID].wif; let wif = senders[floID].wif;
let utxoAmt = 0.0; let utxoAmt = 0.0;
@ -7616,7 +7626,7 @@ Bitcoin.Util = {
} }
for (floID in receivers) for (floID in receivers)
trx.addoutput(floID, receivers[floID]); trx.addoutput(floID, receivers[floID]);
trx.addflodata(floData.replace(/\n/g,' ')); trx.addflodata(floData.replace(/\n/g, ' '));
for (let i = 0; i < wifSeq.length; i++) for (let i = 0; i < wifSeq.length; i++)
trx.signinput(i, wifSeq[i], 1); trx.signinput(i, wifSeq[i], 1);
var signedTxHash = trx.serialize(); var signedTxHash = trx.serialize();
@ -7683,7 +7693,7 @@ Bitcoin.Util = {
filter : custom filter funtion for floData (eg . filter: d => {return d[0] == '$'}) filter : custom filter funtion for floData (eg . filter: d => {return d[0] == '$'})
*/ */
readData: function (addr, options = {}) { readData: function (addr, options = {}) {
options.limit = options.limit | 1000 options.limit = options.limit | 0
options.ignoreOld = options.ignoreOld | 0 options.ignoreOld = options.ignoreOld | 0
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 => {
@ -7698,13 +7708,17 @@ Bitcoin.Util = {
if (options.sentOnly && response.items[i].vin[0].addr !== if (options.sentOnly && response.items[i].vin[0].addr !==
addr) addr)
continue; continue;
if (options.pattern && !response.items[i].floData if (options.pattern) {
.startsWith(options.pattern, 0) && !response.items[i] try {
.floData.startsWith(options.pattern, 2)) let jsonContent = JSON.parse(response.items[i]
continue; .floData)
if (options.contains && !response.items[i].floData.includes( if (!Object.keys(jsonContent).includes(options
options.contains)) .pattern))
continue; continue;
} catch (error) {
continue;
}
}
if (options.filter && !options.filter(response.items[i] if (options.filter && !options.filter(response.items[i]
.floData)) .floData))
continue; continue;
@ -8606,7 +8620,9 @@ Bitcoin.Util = {
floGlobals.generalData[filterStr].push({ floGlobals.generalData[filterStr].push({
sender: dataSet[vc].senderID, sender: dataSet[vc].senderID,
vectorClock: vc, vectorClock: vc,
message: dataSet[vc].message message: dataSet[vc].message,
sign: dataSet[vc].sign,
pubKey: dataSet[vc].pubKey
}) })
compactIDB.writeData("generalData", floGlobals.generalData[filterStr], filterStr) compactIDB.writeData("generalData", floGlobals.generalData[filterStr], filterStr)
floGlobals.generalVC[filterStr] = vc floGlobals.generalVC[filterStr] = vc
@ -8660,6 +8676,10 @@ Bitcoin.Util = {
//send General Data //send General Data
sendGeneralData: function (message, type, options = {}) { sendGeneralData: function (message, type, options = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if(options.encrypt){
let encryptionKey = (options.encrypt === true) ? floGlobals.settings.encryptionKey : options.encrypt
message = floCrypto.encryptData(JSON.stringify(message), encryptionKey)
}
this.sendApplicationData(message, type, options) this.sendApplicationData(message, type, options)
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error)) .catch(error => reject(error))
@ -8772,6 +8792,7 @@ Bitcoin.Util = {
credentials: {}, credentials: {},
//for Dapps //for Dapps
subAdmins: {}, subAdmins: {},
settings: {},
appObjects: {}, appObjects: {},
vectorClock: {}, vectorClock: {},
generalData: {}, generalData: {},
@ -8823,7 +8844,7 @@ Bitcoin.Util = {
}) })
}, },
readSubAdminListFromAPI: function () { readAppConfigFromAPI: 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, { floBlockchainAPI.readData(floGlobals.adminID, {
@ -8834,6 +8855,8 @@ Bitcoin.Util = {
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 var content = JSON.parse(result.data[i])[floGlobals
.application]; .application];
if (!content || typeof content !== "object")
continue;
if (Array.isArray(content.removeSubAdmin)) if (Array.isArray(content.removeSubAdmin))
for (var j = 0; j < content.removeSubAdmin for (var j = 0; j < content.removeSubAdmin
.length; j++) .length; j++)
@ -8844,12 +8867,21 @@ Bitcoin.Util = {
.length; k++) .length; k++)
compactIDB.writeData("subAdmins", true, compactIDB.writeData("subAdmins", true,
content.addSubAdmin[k]); content.addSubAdmin[k]);
if (content.settings)
for (let l in content.settings)
compactIDB.writeData("settings", content
.settings[l], l)
} }
compactIDB.writeData("lastTx", result.totalTxs, compactIDB.writeData("lastTx", result.totalTxs,
floGlobals.adminID); 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"); compactIDB.readAllData("settings").then(
result => {
floGlobals.settings = result;
resolve(
"Read app configuration from blockchain");
})
}) })
}) })
}).catch(error => reject(error)) }).catch(error => reject(error))
@ -8949,7 +8981,7 @@ Bitcoin.Util = {
JSON.stringify(resultIndexes)) JSON.stringify(resultIndexes))
//also add a dummy privatekey to the IDB //also add a dummy privatekey to the IDB
var randomPrivKey = floCrypto var randomPrivKey = floCrypto
.generateNewID().privKey .generateNewID().privKey
var randomThreshold = floCrypto.randInt(10, var randomThreshold = floCrypto.randInt(10,
20) 20)
writeSharesToIDB(floCrypto writeSharesToIDB(floCrypto
@ -8964,32 +8996,33 @@ Bitcoin.Util = {
}) })
} }
const checkIfPinRequired = function(key){ const checkIfPinRequired = function (key) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if(key.length == 52) if (key.length == 52)
resolve(key) resolve(key)
else { else {
inputFn("PIN/Password").then(pwd => { inputFn("PIN/Password").then(pwd => {
try{ try {
let privKey = Crypto.AES.decrypt(key, pwd); let privKey = Crypto.AES.decrypt(key, pwd);
resolve(privKey) resolve(privKey)
}catch(error){ } catch (error) {
reject("Access Denied: Incorrect PIN/Password") reject("Access Denied: Incorrect PIN/Password")
} }
}).catch(error => reject("Access Denied: PIN/Password required")) }).catch(error => reject(
} "Access Denied: PIN/Password required"))
}
}) })
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getPrivateKeyCredentials().then(key => { getPrivateKeyCredentials().then(key => {
checkIfPinRequired(key).then(privKey => { checkIfPinRequired(key).then(privKey => {
try{ 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){ } catch (error) {
reject("Corrupted Private Key") reject("Corrupted Private Key")
} }
}).catch(error => reject(error)) }).catch(error => reject(error))
@ -9004,13 +9037,13 @@ Bitcoin.Util = {
this.callStartUpFunction.completed += 1 this.callStartUpFunction.completed += 1
reactor.dispatchEvent("startUpSuccessLog", reactor.dispatchEvent("startUpSuccessLog",
`${result}\nCompleted ${this.callStartUpFunction.completed}/${this.callStartUpFunction.total} Startup functions` `${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", reactor.dispatchEvent("startUpErrorLog",
`${error}\nFailed ${this.callStartUpFunction.failed}/${this.callStartUpFunction.total} Startup functions` `${error}\nFailed ${this.callStartUpFunction.failed}/${this.callStartUpFunction.total} Startup functions`
) )
reject(false) reject(false)
}) })
}) })
@ -9060,8 +9093,10 @@ Bitcoin.Util = {
manageSubAdmins(adminPrivKey, addList, rmList) { manageSubAdmins(adminPrivKey, addList, rmList) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!Array.isArray(addList)) addList = undefined; if (!Array.isArray(addList) || !addList.length) addList = undefined;
if (!Array.isArray(rmList)) rmList = undefined; if (!Array.isArray(rmList) || !rmList.length) rmList = undefined;
if (!addList && !rmList)
return reject("subAdmin manage list is empty")
var floData = { var floData = {
[floGlobals.application]: { [floGlobals.application]: {
addSubAdmin: addList, addSubAdmin: addList,
@ -9078,6 +9113,25 @@ Bitcoin.Util = {
}) })
}, },
setApplicationSettings(adminPrivKey, settings = {}) {
return new Promise((resolve, reject) => {
if (!settings || typeof settings !== "object")
return reject("Settings must be object")
var floData = {
[floGlobals.application]: {
settings: settings
}
}
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 app settings', result]))
.catch(error => reject(error))
})
},
clearCredentials: function () { clearCredentials: function () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compactIDB.clearData('credentials').then(result => { compactIDB.clearData('credentials').then(result => {
@ -9088,18 +9142,19 @@ Bitcoin.Util = {
}) })
}, },
securePrivKey: function(pwd){ securePrivKey: function (pwd) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let indexArr = localStorage.getItem(`${floGlobals.application}#privKey`) let indexArr = localStorage.getItem(`${floGlobals.application}#privKey`)
if(!indexArr) if (!indexArr)
return reject("PrivKey not found"); return reject("PrivKey not found");
indexArr = JSON.parse(indexArr) indexArr = JSON.parse(indexArr)
let encryptedKey = Crypto.AES.encrypt(myPrivKey, pwd); let encryptedKey = Crypto.AES.encrypt(myPrivKey, pwd);
let threshold = indexArr.length; let threshold = indexArr.length;
let shares = floCrypto.createShamirsSecretShares(encryptedKey, threshold, threshold) let shares = floCrypto.createShamirsSecretShares(encryptedKey, threshold, threshold)
let promises = []; let promises = [];
for(var i=0; i<threshold;i++) for (var i = 0; i < threshold; i++)
promises.push(compactIDB.writeData("credentials", shares[i], indexArr[i], floGlobals.application)); promises.push(compactIDB.writeData("credentials", shares[i], indexArr[i], floGlobals
.application));
Promise.all(promises) Promise.all(promises)
.then(results => resolve("Private Key Secured")) .then(results => resolve("Private Key Secured"))
.catch(error => reject(error)) .catch(error => reject(error))
@ -9122,7 +9177,25 @@ Bitcoin.Util = {
var filteredResult = [] var filteredResult = []
for (var i = 0; i < floGlobals.generalData[filter].length; i++) for (var i = 0; i < floGlobals.generalData[filter].length; i++)
if (floGlobals.generalData[filter][i].vectorClock > vectorClock) if (floGlobals.generalData[filter][i].vectorClock > vectorClock)
filteredResult.push(floGlobals.generalData[filter][i]) filteredResult.push(JSON.parse(JSON.stringify(floGlobals.generalData[filter][i])))
if (options.decrypt) {
let decryptionKey = (options.decrypt === true) ? myPrivKey : options.decrypt;
if (!Array.isArray(decryptionKey))
decryptionKey = [decryptionKey];
filteredResult.forEach(data => {
try {
if ("secret" in data.message && "senderPublicKeyString" in data.message) {
for (let key of decryptionKey) {
try {
let tmp = floCrypto.decryptData(data.message, key)
data.message = JSON.parse(tmp)
break;
} catch (error) {}
}
}
} catch (error) {}
})
}
return filteredResult return filteredResult
} }
} }