diff --git a/floCloudAPI.js b/floCloudAPI.js index ca31378..e06ba60 100644 --- a/floCloudAPI.js +++ b/floCloudAPI.js @@ -1,4 +1,4 @@ -(function(EXPORTS) { //floCloudAPI v2.3.0 +(function(EXPORTS) { //floCloudAPI v2.4.0 /* FLO Cloud operations to send/request application data*/ 'use strict'; const floCloudAPI = EXPORTS; @@ -6,9 +6,32 @@ const DEFAULT = { SNStorageID: floGlobals.SNStorageID || "FNaN9McoBAEFUjkRmNQRYLmBF8SpS7Tgfk", adminID: floGlobals.adminID, - application: floGlobals.application + application: floGlobals.application, + callback: (d, e) => console.debug(d, e) }; + var user_id, user_public, user_private; + const user = { + get id() { + if (!user_id) + throw "User not set"; + return user_id; + }, + get public() { + if (!user_public) + throw "User not set"; + return user_public; + }, + sign(msg) { + if (!user_private) + throw "User not set"; + return floCrypto.signData(msg, user_private); + }, + clear() { + user_id = user_public = user_private = undefined; + } + } + Object.defineProperties(floCloudAPI, { SNStorageID: { get: () => DEFAULT.SNStorageID @@ -18,6 +41,21 @@ }, application: { get: () => DEFAULT.application + }, + user: { + set: priv => { + if (!priv) + user_id = user_public = user_private = undefined; + else { + user_public = floCrypto.getPubKeyHex(priv); + user_id = floCrypto.getFloID(user_public); + if (!user_public || !user_id || !floCrypto.verifyPrivKey(priv, user_id)) + user_id = user_public = user_private = undefined; + else + user_private = priv; + } + }, + get: () => user } }); @@ -392,19 +430,19 @@ })); } - //set status as online for myFloID + //set status as online for user_id floCloudAPI.setStatus = function(options = {}) { return new Promise((resolve, reject) => { - let callback = options.callback instanceof Function ? options.callback : (d, e) => console.debug(d, e); + let callback = options.callback instanceof Function ? options.callback : DEFAULT.callback; var request = { - floID: myFloID, + floID: user.id, application: options.application || DEFAULT.application, time: Date.now(), status: true, - pubKey: myPubKey + pubKey: user.public } let hashcontent = ["time", "application", "floID"].map(d => request[d]).join("|"); - request.sign = floCrypto.signData(hashcontent, myPrivKey); + request.sign = user.sign(hashcontent); liveRequest(options.refID || DEFAULT.adminID, request, callback) .then(result => resolve(result)) .catch(error => reject(error)) @@ -416,7 +454,7 @@ return new Promise((resolve, reject) => { if (!Array.isArray(trackList)) trackList = [trackList]; - let callback = options.callback instanceof Function ? options.callback : (d, e) => console.debug(d, e); + let callback = options.callback instanceof Function ? options.callback : DEFAULT.callback; let request = { status: false, application: options.application || DEFAULT.application, @@ -432,9 +470,9 @@ const sendApplicationData = floCloudAPI.sendApplicationData = function(message, type, options = {}) { return new Promise((resolve, reject) => { var data = { - senderID: myFloID, + senderID: user.id, receiverID: options.receiverID || DEFAULT.adminID, - pubKey: myPubKey, + pubKey: user.public, message: encodeMessage(message), time: Date.now(), application: options.application || DEFAULT.application, @@ -443,7 +481,7 @@ } let hashcontent = ["receiverID", "time", "application", "type", "message", "comment"] .map(d => data[d]).join("|") - data.sign = floCrypto.signData(hashcontent, myPrivKey); + data.sign = user.sign(hashcontent); singleRequest(data.receiverID, data) .then(result => resolve(result)) .catch(error => reject(error)) @@ -482,19 +520,20 @@ }) } - //(NEEDS UPDATE) delete data from supernode cloud (received only) + /*(NEEDS UPDATE) + //delete data from supernode cloud (received only) floCloudAPI.deleteApplicationData = function(vectorClocks, options = {}) { return new Promise((resolve, reject) => { var delreq = { - requestorID: myFloID, - pubKey: myPubKey, + requestorID: user.id, + pubKey: user.public, time: Date.now(), delete: (Array.isArray(vectorClocks) ? vectorClocks : [vectorClocks]), application: options.application || DEFAULT.application } let hashcontent = ["time", "application", "delete"] .map(d => delreq[d]).join("|") - delreq.sign = floCrypto.signData(hashcontent, myPrivKey) + delreq.sign = user.sign(hashcontent) singleRequest(delreq.requestorID, delreq).then(result => { let success = [], failed = []; @@ -507,8 +546,9 @@ }).catch(error => reject(error)) }) } - - //(NEEDS UPDATE) edit comment of data in supernode cloud (mutable comments only) + */ + /*(NEEDS UPDATE) + //edit comment of data in supernode cloud (mutable comments only) floCloudAPI.editApplicationData = function(vectorClock, newComment, oldData, options = {}) { return new Promise((resolve, reject) => { let p0 @@ -523,12 +563,12 @@ } }) p0.then(d => { - if (d.senderID != myFloID) + if (d.senderID != user.id) return reject("Invalid requestorID") else if (!d.comment.startsWith("EDIT:")) return reject("Data immutable") let data = { - requestorID: myFloID, + requestorID: user.id, receiverID: d.receiverID, time: Date.now(), application: d.application, @@ -542,29 +582,30 @@ "comment" ] .map(x => d[x]).join("|") - data.edit.sign = floCrypto.signData(hashcontent, myPrivKey) + data.edit.sign = user.sign(hashcontent) singleRequest(data.receiverID, data) .then(result => resolve("Data comment updated")) .catch(error => reject(error)) }) }) } + */ //tag data in supernode cloud (subAdmin access only) floCloudAPI.tagApplicationData = function(vectorClock, tag, options = {}) { return new Promise((resolve, reject) => { - if (!floGlobals.subAdmins.includes(myFloID)) + if (!floGlobals.subAdmins.includes(user.id)) return reject("Only subAdmins can tag data") var request = { receiverID: options.receiverID || DEFAULT.adminID, - requestorID: myFloID, - pubKey: myPubKey, + requestorID: user.id, + pubKey: user.public, time: Date.now(), vectorClock: vectorClock, tag: tag, } let hashcontent = ["time", "vectorClock", 'tag'].map(d => request[d]).join("|"); - request.sign = floCrypto.signData(hashcontent, myPrivKey); + request.sign = user.sign(hashcontent); singleRequest(request.receiverID, request) .then(result => resolve(result)) .catch(error => reject(error)) @@ -576,14 +617,14 @@ return new Promise((resolve, reject) => { var request = { receiverID: options.receiverID || DEFAULT.adminID, - requestorID: myFloID, - pubKey: myPubKey, + requestorID: user.id, + pubKey: user.public, time: Date.now(), vectorClock: vectorClock, note: note, } let hashcontent = ["time", "vectorClock", 'note'].map(d => request[d]).join("|"); - request.sign = floCrypto.signData(hashcontent, myPrivKey); + request.sign = user.sign(hashcontent); singleRequest(request.receiverID, request) .then(result => resolve(result)) .catch(error => reject(error)) diff --git a/floDapps.js b/floDapps.js index 0e92708..08e3dd4 100644 --- a/floDapps.js +++ b/floDapps.js @@ -1,8 +1,88 @@ -(function(EXPORTS) { //floDapps v2.2.1 +(function(EXPORTS) { //floDapps v2.3.0 /* General functions for FLO Dapps*/ - //'use strict'; + 'use strict'; const floDapps = EXPORTS; + const DEFAULT = { + get root() { + return "floDapps" + }, + application: floGlobals.application, + adminID: floGlobals.adminID + }; + + var raw_user_private; //private variable inside capsule + const raw_user = { + get private() { + if (!raw_user_private) + throw "User not logged in"; + return raw_user_private; + } + } + + var user_id, user_public, user_private; + const user = floDapps.user = { + get id() { + if (!user_id) + throw "User not logged in"; + return user_id; + }, + get public() { + if (!user_public) + throw "User not logged in"; + return user_public; + }, + get private() { + if (!user_private) + throw "User not logged in"; + else if (user_private instanceof Function) + return user_private(); + else + return user_private; + }, + get db_name() { + return "floDapps#" + user.id; + }, + clear() { + user_id = user_public = user_private = undefined; + raw_user_private = undefined; + delete user.contacts; + delete user.pubKeys; + delete user.messages; + } + }; + + Object.defineProperties(window, { + myFloID: { + get: () => user.id + }, + myPubKey: { + get: () => user.public + }, + myPrivKey: { + get: () => user.private + } + }); + + var subAdmins, settings + Object.defineProperties(floGlobals, { + subAdmins: { + get: () => subAdmins + }, + settings: { + get: () => settings + }, + contacts: { + get: () => user.contacts + }, + pubKeys: { + get: () => user.pubKeys + }, + messages: { + get: () => user.messages + } + }) + function initIndexedDB() { return new Promise((resolve, reject) => { var obs_g = { @@ -32,37 +112,37 @@ if (!(o in obs_a)) obs_a[o] = initIndexedDB.appObs[o] Promise.all([ - compactIDB.initDB(floGlobals.application, obs_a), - compactIDB.initDB("floDapps", obs_g) + compactIDB.initDB(DEFAULT.application, obs_a), + compactIDB.initDB(DEFAULT.root, obs_g) ]).then(result => { - compactIDB.setDefaultDB(floGlobals.application) + compactIDB.setDefaultDB(DEFAULT.application) resolve("IndexedDB App Storage Initated Successfully") }).catch(error => reject(error)); }) } - function initUserDB(floID) { + function initUserDB() { return new Promise((resolve, reject) => { var obs = { contacts: {}, pubKeys: {}, messages: {} } - compactIDB.initDB(`floDapps#${floID}`, obs).then(result => { + compactIDB.initDB(user.db_name, obs).then(result => { resolve("UserDB Initated Successfully") }).catch(error => reject('Init userDB failed')); }) } - function loadUserDB(floID) { + function loadUserDB() { return new Promise((resolve, reject) => { var loadData = ["contacts", "pubKeys", "messages"] var promises = [] for (var i = 0; i < loadData.length; i++) - promises[i] = compactIDB.readAllData(loadData[i], `floDapps#${floID}`) + promises[i] = compactIDB.readAllData(loadData[i], user.db_name) Promise.all(promises).then(results => { for (var i = 0; i < loadData.length; i++) - floGlobals[loadData[i]] = results[i] + user[loadData[i]] = results[i] resolve("Loaded Data from userDB") }).catch(error => reject('Load userDB failed')) }) @@ -72,7 +152,7 @@ startUpFunctions.push(function readSupernodeListFromAPI() { return new Promise((resolve, reject) => { - compactIDB.readData("lastTx", floCloudAPI.SNStorageID, "floDapps").then(lastTx => { + compactIDB.readData("lastTx", floCloudAPI.SNStorageID, DEFAULT.root).then(lastTx => { floBlockchainAPI.readData(floCloudAPI.SNStorageID, { ignoreOld: lastTx, sentOnly: true, @@ -81,12 +161,12 @@ for (var i = result.data.length - 1; i >= 0; i--) { var content = JSON.parse(result.data[i]).SuperNodeStorage; for (sn in content.removeNodes) - compactIDB.removeData("supernodes", sn, "floDapps"); + compactIDB.removeData("supernodes", sn, DEFAULT.root); for (sn in content.newNodes) - compactIDB.writeData("supernodes", content.newNodes[sn], sn, "floDapps"); + compactIDB.writeData("supernodes", content.newNodes[sn], sn, DEFAULT.root); } - compactIDB.writeData("lastTx", result.totalTxs, floCloudAPI.SNStorageID, "floDapps"); - compactIDB.readAllData("supernodes", "floDapps").then(result => { + compactIDB.writeData("lastTx", result.totalTxs, floCloudAPI.SNStorageID, DEFAULT.root); + compactIDB.readAllData("supernodes", DEFAULT.root).then(result => { floCloudAPI.init(result) .then(result => resolve("Loaded Supernode list\n" + result)) .catch(error => reject(error)) @@ -98,14 +178,14 @@ startUpFunctions.push(function readAppConfigFromAPI() { return new Promise((resolve, reject) => { - compactIDB.readData("lastTx", `${floGlobals.application}|${floGlobals.adminID}`, "floDapps").then(lastTx => { - floBlockchainAPI.readData(floGlobals.adminID, { + compactIDB.readData("lastTx", `${DEFAULT.application}|${DEFAULT.adminID}`, DEFAULT.root).then(lastTx => { + floBlockchainAPI.readData(DEFAULT.adminID, { ignoreOld: lastTx, sentOnly: true, - pattern: floGlobals.application + pattern: DEFAULT.application }).then(result => { for (var i = result.data.length - 1; i >= 0; i--) { - var content = JSON.parse(result.data[i])[floGlobals.application]; + var content = JSON.parse(result.data[i])[DEFAULT.application]; if (!content || typeof content !== "object") continue; if (Array.isArray(content.removeSubAdmin)) @@ -118,11 +198,11 @@ for (let l in content.settings) compactIDB.writeData("settings", content.settings[l], l) } - compactIDB.writeData("lastTx", result.totalTxs, `${floGlobals.application}|${floGlobals.adminID}`, "floDapps"); + compactIDB.writeData("lastTx", result.totalTxs, `${DEFAULT.application}|${DEFAULT.adminID}`, DEFAULT.root); compactIDB.readAllData("subAdmins").then(result => { - floGlobals.subAdmins = Object.keys(result); + subAdmins = Object.keys(result); compactIDB.readAllData("settings").then(result => { - floGlobals.settings = result; + settings = result; resolve("Read app configuration from blockchain"); }) }) @@ -153,7 +233,7 @@ resolve(inputVal) }); - function getCredentials() { + function getCredentials(invisible_key) { const readSharesFromIDB = indexArr => new Promise((resolve, reject) => { var promises = [] @@ -186,7 +266,7 @@ }); const getPrivateKeyCredentials = () => new Promise((resolve, reject) => { - var indexArr = localStorage.getItem(`${floGlobals.application}#privKey`) + var indexArr = localStorage.getItem(`${DEFAULT.application}#privKey`) if (indexArr) { readSharesFromIDB(JSON.parse(indexArr)) .then(result => resolve(result)) @@ -210,7 +290,7 @@ var shares = floCrypto.createShamirsSecretShares(privKey, threshold, threshold) writeSharesToIDB(shares).then(resultIndexes => { //store index keys in localStorage - localStorage.setItem(`${floGlobals.application}#privKey`, JSON.stringify(resultIndexes)) + localStorage.setItem(`${DEFAULT.application}#privKey`, JSON.stringify(resultIndexes)) //also add a dummy privatekey to the IDB var randomPrivKey = floCrypto.generateNewID().privKey var randomThreshold = floCrypto.randInt(10, 20) @@ -242,9 +322,13 @@ getPrivateKeyCredentials().then(key => { checkIfPinRequired(key).then(privKey => { try { - myPrivKey = privKey - myPubKey = floCrypto.getPubKeyHex(myPrivKey) - myFloID = floCrypto.getFloID(myPubKey) + user_public = floCrypto.getPubKeyHex(privKey); + user_id = floCrypto.getFloID(privKey); + floCloudAPI.user = privKey; //Set user for floCloudAPI + if (!invisible_key) + user_private = privKey; + else + user_private = () => checkIfPinRequired(key); resolve('Login Credentials loaded successful') } catch (error) { console.log(error) @@ -289,7 +373,7 @@ }) }); - floDapps.launchStartUp = function() { + floDapps.launchStartUp = function(options = {}) { return new Promise((resolve, reject) => { initIndexedDB().then(log => { console.log(log) @@ -304,9 +388,9 @@ }) }); let p2 = new Promise((res, rej) => { - callAndLog(getCredentials()).then(r => { - callAndLog(initUserDB(myFloID)).then(r => { - callAndLog(loadUserDB(myFloID)) + callAndLog(getCredentials(options.invisible_key)).then(r => { + callAndLog(initUserDB()).then(r => { + callAndLog(loadUserDB()) .then(r => res(true)) .catch(e => rej(false)) }).catch(e => rej(false)) @@ -333,8 +417,8 @@ return new Promise((resolve, reject) => { if (!floCrypto.validateAddr(floID)) return reject("Invalid floID!") - compactIDB.writeData("contacts", name, floID, `floDapps#${myFloID}`).then(result => { - floGlobals.contacts[floID] = name; + compactIDB.writeData("contacts", name, floID, user.db_name).then(result => { + user.contacts[floID] = name; resolve("Contact stored") }).catch(error => reject(error)) }); @@ -342,14 +426,14 @@ floDapps.storePubKey = function(floID, pubKey) { return new Promise((resolve, reject) => { - if (floID in floGlobals.pubKeys) + if (floID in user.pubKeys) return resolve("pubKey already stored") if (!floCrypto.validateAddr(floID)) return reject("Invalid floID!") if (floCrypto.getFloID(pubKey) != floID) return reject("Incorrect pubKey") - compactIDB.writeData("pubKeys", pubKey, floID, `floDapps#${myFloID}`).then(result => { - floGlobals.pubKeys[floID] = pubKey; + compactIDB.writeData("pubKeys", pubKey, floID, user.db_name).then(result => { + user.pubKeys[floID] = pubKey; resolve("pubKey stored") }).catch(error => reject(error)) }); @@ -359,11 +443,11 @@ return new Promise((resolve, reject) => { let options = { receiverID: floID, - application: "floDapps", - comment: floGlobals.application + application: DEFAULT.root, + comment: DEFAULT.application } - if (floID in floGlobals.pubKeys) - message = floCrypto.encryptData(JSON.stringify(message), floGlobals.pubKeys[floID]) + if (floID in user.pubKeys) + message = floCrypto.encryptData(JSON.stringify(message), user.pubKeys[floID]) floCloudAPI.sendApplicationData(message, "Message", options) .then(result => resolve(result)) .catch(error => reject(error)) @@ -372,20 +456,21 @@ floDapps.requestInbox = function(callback) { return new Promise((resolve, reject) => { - let lastVC = Object.keys(floGlobals.messages).sort().pop() + let lastVC = Object.keys(user.messages).sort().pop() let options = { - receiverID: myFloID, - application: "floDapps", + receiverID: user.id, + application: DEFAULT.root, lowerVectorClock: lastVC + 1 } + let privKey = raw_user.private; options.callback = (d, e) => { for (let v in d) { try { if (d[v].message instanceof Object && "secret" in d[v].message) - d[v].message = floCrypto.decryptData(d[v].message, myPrivKey) + d[v].message = floCrypto.decryptData(d[v].message, privKey) } catch (error) {} - compactIDB.writeData("messages", d[v], v, `floDapps#${myFloID}`) - floGlobals.messages[v] = d[v] + compactIDB.writeData("messages", d[v], v, user.db_name) + user.messages[v] = d[v] } if (callback instanceof Function) callback(d, e) @@ -404,14 +489,14 @@ if (!addList && !rmList && !settings) return reject("No configuration change") var floData = { - [floGlobals.application]: { + [DEFAULT.application]: { addSubAdmin: addList, removeSubAdmin: rmList, settings: settings } } var floID = floCrypto.getFloID(adminPrivKey) - if (floID != floGlobals.adminID) + if (floID != DEFAULT.adminID) reject('Access Denied for Admin privilege') else floBlockchainAPI.writeData(floID, JSON.stringify(floData), adminPrivKey) @@ -422,9 +507,9 @@ const clearCredentials = floDapps.clearCredentials = function() { return new Promise((resolve, reject) => { - compactIDB.clearData('credentials', floGlobals.application).then(result => { - localStorage.removeItem(`${floGlobals.application}#privKey`) - myPrivKey = myPubKey = myFloID = undefined; + compactIDB.clearData('credentials', DEFAULT.application).then(result => { + localStorage.removeItem(`${DEFAULT.application}#privKey`); + user.clear(); resolve("privKey credentials deleted!") }).catch(error => reject(error)) }) @@ -433,7 +518,7 @@ floDapps.deleteUserData = function(credentials = false) { return new Promise((resolve, reject) => { let p = [] - p.push(compactIDB.deleteDB(`floDapps#${myFloID}`)) + p.push(compactIDB.deleteDB(user.db_name)) if (credentials) p.push(clearCredentials()) Promise.all(p) @@ -444,10 +529,10 @@ floDapps.deleteAppData = function() { return new Promise((resolve, reject) => { - compactIDB.deleteDB(floGlobals.application).then(result => { - localStorage.removeItem(`${floGlobals.application}#privKey`) - myPrivKey = myPubKey = myFloID = undefined; - compactIDB.removeData('lastTx', `${floGlobals.application}|${floGlobals.adminID}`, 'floDapps') + compactIDB.deleteDB(DEFAULT.application).then(result => { + localStorage.removeItem(`${DEFAULT.application}#privKey`) + user.clear(); + compactIDB.removeData('lastTx', `${DEFAULT.application}|${DEFAULT.adminID}`, DEFAULT.root) .then(result => resolve("App database(local) deleted")) .catch(error => reject(error)) }).catch(error => reject(error)) @@ -455,17 +540,17 @@ } floDapps.securePrivKey = function(pwd) { - return new Promise((resolve, reject) => { - let indexArr = localStorage.getItem(`${floGlobals.application}#privKey`) + return new Promise(async (resolve, reject) => { + let indexArr = localStorage.getItem(`${DEFAULT.application}#privKey`) if (!indexArr) return reject("PrivKey not found"); indexArr = JSON.parse(indexArr) - let encryptedKey = Crypto.AES.encrypt(myPrivKey, pwd); + let encryptedKey = Crypto.AES.encrypt(await user.private, pwd); let threshold = indexArr.length; let shares = floCrypto.createShamirsSecretShares(encryptedKey, threshold, threshold) let promises = []; let overwriteFn = (share, index) => - compactIDB.writeData("credentials", share, index, floGlobals.application); + compactIDB.writeData("credentials", share, index, DEFAULT.application); for (var i = 0; i < threshold; i++) promises.push(overwriteFn(shares[i], indexArr[i])); Promise.all(promises) @@ -494,7 +579,7 @@ }) } return new Promise((resolve, reject) => { - var indexArr = localStorage.getItem(`${floGlobals.application}#privKey`) + var indexArr = localStorage.getItem(`${DEFAULT.application}#privKey`) console.info(indexArr) if (!indexArr) reject('No login credentials found') @@ -535,7 +620,7 @@ filteredResult[d] = JSON.parse(JSON.stringify(floGlobals.generalData[fk][d])) } if (options.decrypt) { - let decryptionKey = (options.decrypt === true) ? myPrivKey : options.decrypt; + let decryptionKey = (options.decrypt === true) ? raw_user.private : options.decrypt; if (!Array.isArray(decryptionKey)) decryptionKey = [decryptionKey]; for (let f in filteredResult) { @@ -561,14 +646,14 @@ syncData.oldDevice = () => new Promise((resolve, reject) => { let sync = { - contacts: floGlobals.contacts, - pubKeys: floGlobals.pubKeys, - messages: floGlobals.messages + contacts: user.contacts, + pubKeys: user.pubKeys, + messages: user.messages } - let message = Crypto.AES.encrypt(JSON.stringify(sync), myPrivKey) + let message = Crypto.AES.encrypt(JSON.stringify(sync), raw_user.private) let options = { - receiverID: myFloID, - application: "floDapps" + receiverID: user.id, + application: DEFAULT.root } floCloudAPI.sendApplicationData(message, "syncData", options) .then(result => resolve(result)) @@ -577,20 +662,20 @@ syncData.newDevice = () => new Promise((resolve, reject) => { var options = { - receiverID: myFloID, - senderID: myFloID, - application: "floDapps", + receiverID: user.id, + senderID: user.id, + application: DEFAULT.root, mostRecent: true, } floCloudAPI.requestApplicationData("syncData", options).then(response => { let vc = Object.keys(response).sort().pop() - let sync = JSON.parse(Crypto.AES.decrypt(response[vc].message, myPrivKey)) + let sync = JSON.parse(Crypto.AES.decrypt(response[vc].message, raw_user.private)) let promises = [] - let store = (key, val, obs) => promises.push(compactIDB.writeData(obs, val, key, `floDapps#${floID}`)); + let store = (key, val, obs) => promises.push(compactIDB.writeData(obs, val, key, user.db_name)); ["contacts", "pubKeys", "messages"].forEach(c => { for (let i in sync[c]) { store(i, sync[c][i], c) - floGlobals[c][i] = sync[c][i] + user[c][i] = sync[c][i] } }) Promise.all(promises) diff --git a/index.html b/index.html index 03ee1ba..c1999d7 100644 --- a/index.html +++ b/index.html @@ -24,8 +24,7 @@ //floDapps.addStartUpFunction('Sample', Promised Function) //floDapps.setAppObjectStores({sampleObs1:{}, sampleObs2:{options{autoIncrement:true, keyPath:'SampleKey'}, Indexes:{sampleIndex:{}}}}) //floDapps.setCustomPrivKeyInput( () => { FUNCTION BODY *must resolve private key* } ) - - floDapps.launchStartUp().then(result => { + floDapps.launchStartUp( /*{invisible_key: true}*/ ).then(result => { console.log(result) alert(`Welcome FLO_ID: ${myFloID}`) //App functions....