From ad1aa27ba00d3ba9aa93750b68ea917a3b2c7844 Mon Sep 17 00:00:00 2001 From: sairajzero Date: Thu, 6 Jul 2023 19:43:10 +0530 Subject: [PATCH] relocate script files - moved required script files to scripts/ - Updated LICENCE - Fixes for blockbook API --- LICENCE | 2 +- compactIDB.js | 257 ---- floCloudAPI.js | 1055 ----------------- floDapps.js | 845 ------------- floTokenAPI.js | 166 --- index.html | 15 +- btcOperator.js => scripts/btcOperator.js | 0 .../floBlockchainAPI.js | 0 floCrypto.js => scripts/floCrypto.js | 0 lib.js => scripts/lib.js | 0 10 files changed, 10 insertions(+), 2330 deletions(-) delete mode 100644 compactIDB.js delete mode 100644 floCloudAPI.js delete mode 100644 floDapps.js delete mode 100644 floTokenAPI.js rename btcOperator.js => scripts/btcOperator.js (100%) rename floBlockchainAPI.js => scripts/floBlockchainAPI.js (100%) rename floCrypto.js => scripts/floCrypto.js (100%) rename lib.js => scripts/lib.js (100%) diff --git a/LICENCE b/LICENCE index d3f4c4c..5d14a81 100644 --- a/LICENCE +++ b/LICENCE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Sai Raj +Copyright (c) 2023 RanchiMall Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/compactIDB.js b/compactIDB.js deleted file mode 100644 index ba843ec..0000000 --- a/compactIDB.js +++ /dev/null @@ -1,257 +0,0 @@ -(function (EXPORTS) { //compactIDB v2.1.2 - /* Compact IndexedDB operations */ - 'use strict'; - const compactIDB = EXPORTS; - - var defaultDB; - - const indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; - const IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; - const IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange; - - if (!indexedDB) { - console.error("Your browser doesn't support a stable version of IndexedDB."); - return; - } - - compactIDB.setDefaultDB = dbName => defaultDB = dbName; - - Object.defineProperty(compactIDB, 'default', { - get: () => defaultDB, - set: dbName => defaultDB = dbName - }); - - function getDBversion(dbName = defaultDB) { - return new Promise((resolve, reject) => { - openDB(dbName).then(db => { - resolve(db.version) - db.close() - }).catch(error => reject(error)) - }) - } - - function upgradeDB(dbName, createList = null, deleteList = null) { - return new Promise((resolve, reject) => { - getDBversion(dbName).then(version => { - var idb = indexedDB.open(dbName, version + 1); - idb.onerror = (event) => reject("Error in opening IndexedDB"); - idb.onupgradeneeded = (event) => { - let db = event.target.result; - if (createList instanceof Object) { - if (Array.isArray(createList)) { - let tmp = {} - createList.forEach(o => tmp[o] = {}) - createList = tmp - } - for (let o in createList) { - let obs = db.createObjectStore(o, createList[o].options || {}); - if (createList[o].indexes instanceof Object) - for (let i in createList[o].indexes) - obs.createIndex(i, i, createList[o].indexes || {}); - } - } - if (Array.isArray(deleteList)) - deleteList.forEach(o => db.deleteObjectStore(o)); - resolve('Database upgraded') - } - idb.onsuccess = (event) => event.target.result.close(); - }).catch(error => reject(error)) - }) - } - - compactIDB.initDB = function (dbName, objectStores = {}) { - return new Promise((resolve, reject) => { - if (!(objectStores instanceof Object)) - return reject('ObjectStores must be an object or array') - defaultDB = defaultDB || dbName; - var idb = indexedDB.open(dbName); - idb.onerror = (event) => reject("Error in opening IndexedDB"); - idb.onsuccess = (event) => { - var db = event.target.result; - let cList = Object.values(db.objectStoreNames); - var obs = {}, - a_obs = {}, - d_obs = []; - if (!Array.isArray(objectStores)) - var obs = objectStores - else - objectStores.forEach(o => obs[o] = {}) - let nList = Object.keys(obs) - for (let o of nList) - if (!cList.includes(o)) - a_obs[o] = obs[o] - for (let o of cList) - if (!nList.includes(o)) - d_obs.push(o) - if (!Object.keys(a_obs).length && !d_obs.length) - resolve("Initiated IndexedDB"); - else - upgradeDB(dbName, a_obs, d_obs) - .then(result => resolve(result)) - .catch(error => reject(error)) - db.close(); - } - }); - } - - const openDB = compactIDB.openDB = function (dbName = defaultDB) { - return new Promise((resolve, reject) => { - var idb = indexedDB.open(dbName); - idb.onerror = (event) => reject("Error in opening IndexedDB"); - idb.onupgradeneeded = (event) => { - event.target.result.close(); - deleteDB(dbName).then(_ => null).catch(_ => null).finally(_ => reject("Datebase not found")) - } - idb.onsuccess = (event) => resolve(event.target.result); - }); - } - - const deleteDB = compactIDB.deleteDB = function (dbName = defaultDB) { - return new Promise((resolve, reject) => { - var deleteReq = indexedDB.deleteDatabase(dbName);; - deleteReq.onerror = (event) => reject("Error deleting database!"); - deleteReq.onsuccess = (event) => resolve("Database deleted successfully"); - }); - } - - compactIDB.writeData = function (obsName, data, key = false, dbName = defaultDB) { - return new Promise((resolve, reject) => { - openDB(dbName).then(db => { - var obs = db.transaction(obsName, "readwrite").objectStore(obsName); - let writeReq = (key ? obs.put(data, key) : obs.put(data)); - writeReq.onsuccess = (evt) => resolve(`Write data Successful`); - writeReq.onerror = (evt) => reject( - `Write data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}` - ); - db.close(); - }).catch(error => reject(error)); - }); - } - - compactIDB.addData = function (obsName, data, key = false, dbName = defaultDB) { - return new Promise((resolve, reject) => { - openDB(dbName).then(db => { - var obs = db.transaction(obsName, "readwrite").objectStore(obsName); - let addReq = (key ? obs.add(data, key) : obs.add(data)); - addReq.onsuccess = (evt) => resolve(`Add data successful`); - addReq.onerror = (evt) => reject( - `Add data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}` - ); - db.close(); - }).catch(error => reject(error)); - }); - } - - compactIDB.removeData = function (obsName, key, dbName = defaultDB) { - return new Promise((resolve, reject) => { - openDB(dbName).then(db => { - var obs = db.transaction(obsName, "readwrite").objectStore(obsName); - let delReq = obs.delete(key); - delReq.onsuccess = (evt) => resolve(`Removed Data ${key}`); - delReq.onerror = (evt) => reject( - `Remove data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}` - ); - db.close(); - }).catch(error => reject(error)); - }); - } - - compactIDB.clearData = function (obsName, dbName = defaultDB) { - return new Promise((resolve, reject) => { - openDB(dbName).then(db => { - var obs = db.transaction(obsName, "readwrite").objectStore(obsName); - let clearReq = obs.clear(); - clearReq.onsuccess = (evt) => resolve(`Clear data Successful`); - clearReq.onerror = (evt) => reject(`Clear data Unsuccessful`); - db.close(); - }).catch(error => reject(error)); - }); - } - - compactIDB.readData = function (obsName, key, dbName = defaultDB) { - return new Promise((resolve, reject) => { - openDB(dbName).then(db => { - var obs = db.transaction(obsName, "readonly").objectStore(obsName); - let getReq = obs.get(key); - getReq.onsuccess = (evt) => resolve(evt.target.result); - getReq.onerror = (evt) => reject( - `Read data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}` - ); - db.close(); - }).catch(error => reject(error)); - }); - } - - compactIDB.readAllData = function (obsName, dbName = defaultDB) { - return new Promise((resolve, reject) => { - openDB(dbName).then(db => { - var obs = db.transaction(obsName, "readonly").objectStore(obsName); - var tmpResult = {} - let curReq = obs.openCursor(); - curReq.onsuccess = (evt) => { - var cursor = evt.target.result; - if (cursor) { - tmpResult[cursor.primaryKey] = cursor.value; - cursor.continue(); - } else - resolve(tmpResult); - } - curReq.onerror = (evt) => reject( - `Read-All data unsuccessful [${evt.target.error.name}] ${evt.target.error.message}` - ); - db.close(); - }).catch(error => reject(error)); - }); - } - - /* compactIDB.searchData = function (obsName, options = {}, dbName = defaultDB) { - - return new Promise((resolve, reject) => { - openDB(dbName).then(db => { - var obs = db.transaction(obsName, "readonly").objectStore(obsName); - var filteredResult = {} - let keyRange; - if(options.lowerKey!==null && options.upperKey!==null) - keyRange = IDBKeyRange.bound(options.lowerKey, options.upperKey); - else if(options.lowerKey!==null) - keyRange = IDBKeyRange.lowerBound(options.lowerKey); - else if (options.upperKey!==null) - keyRange = IDBKeyRange.upperBound(options.upperBound); - else if (options.atKey) - let curReq = obs.openCursor(keyRange, ) - }).catch(error => reject(error)) - }) - }*/ - - compactIDB.searchData = function (obsName, options = {}, dbName = defaultDB) { - options.lowerKey = options.atKey || options.lowerKey || 0 - options.upperKey = options.atKey || options.upperKey || false - options.patternEval = options.patternEval || ((k, v) => true); - options.limit = options.limit || false; - options.reverse = options.reverse || false; - options.lastOnly = options.lastOnly || false - return new Promise((resolve, reject) => { - openDB(dbName).then(db => { - var obs = db.transaction(obsName, "readonly").objectStore(obsName); - var filteredResult = {} - let curReq = obs.openCursor( - options.upperKey ? IDBKeyRange.bound(options.lowerKey, options.upperKey) : IDBKeyRange.lowerBound(options.lowerKey), - options.lastOnly || options.reverse ? "prev" : "next"); - curReq.onsuccess = (evt) => { - var cursor = evt.target.result; - if (!cursor || (options.limit && options.limit <= Object.keys(filteredResult).length)) - return resolve(filteredResult); //reached end of key list or limit reached - else if (options.patternEval(cursor.primaryKey, cursor.value)) { - filteredResult[cursor.primaryKey] = cursor.value; - options.lastOnly ? resolve(filteredResult) : cursor.continue(); - } else - cursor.continue(); - } - curReq.onerror = (evt) => reject(`Search unsuccessful [${evt.target.error.name}] ${evt.target.error.message}`); - db.close(); - }).catch(error => reject(error)); - }); - } - - -})(window.compactIDB = {}); \ No newline at end of file diff --git a/floCloudAPI.js b/floCloudAPI.js deleted file mode 100644 index c2d2c3f..0000000 --- a/floCloudAPI.js +++ /dev/null @@ -1,1055 +0,0 @@ -(function (EXPORTS) { //floCloudAPI v2.4.3a - /* FLO Cloud operations to send/request application data*/ - 'use strict'; - const floCloudAPI = EXPORTS; - - const DEFAULT = { - blockchainPrefix: 0x23, //Prefix version for FLO blockchain - SNStorageID: floGlobals.SNStorageID || "FNaN9McoBAEFUjkRmNQRYLmBF8SpS7Tgfk", - adminID: floGlobals.adminID, - application: floGlobals.application, - SNStorageName: "SuperNodeStorage", - callback: (d, e) => console.debug(d, e) - }; - - var user_id, user_public, user_private, aes_key; - - function user(id, priv) { - if (!priv || !id) - return user.clear(); - let pub = floCrypto.getPubKeyHex(priv); - if (!pub || !floCrypto.verifyPubKey(pub, id)) - return user.clear(); - let n = floCrypto.randInt(12, 20); - aes_key = floCrypto.randString(n); - user_private = Crypto.AES.encrypt(priv, aes_key); - user_public = pub; - user_id = id; - return user_id; - } - - Object.defineProperties(user, { - id: { - get: () => { - if (!user_id) - throw "User not set"; - return user_id; - } - }, - public: { - get: () => { - if (!user_public) - throw "User not set"; - return user_public; - } - }, - sign: { - value: msg => { - if (!user_private) - throw "User not set"; - return floCrypto.signData(msg, Crypto.AES.decrypt(user_private, aes_key)); - } - }, - clear: { - value: () => user_id = user_public = user_private = aes_key = undefined - } - }) - - Object.defineProperties(floCloudAPI, { - SNStorageID: { - get: () => DEFAULT.SNStorageID - }, - SNStorageName: { - get: () => DEFAULT.SNStorageName - }, - adminID: { - get: () => DEFAULT.adminID - }, - application: { - get: () => DEFAULT.application - }, - user: { - get: () => user - } - }); - - var appObjects, generalData, lastVC; - Object.defineProperties(floGlobals, { - appObjects: { - get: () => appObjects, - set: obj => appObjects = obj - }, - generalData: { - get: () => generalData, - set: data => generalData = data - }, - generalDataset: { - value: (type, options = {}) => generalData[filterKey(type, options)] - }, - lastVC: { - get: () => lastVC, - set: vc => lastVC = vc - } - }); - - var supernodes = {}; //each supnernode must be stored as floID : {uri:,pubKey:} - Object.defineProperty(floCloudAPI, 'nodes', { - get: () => JSON.parse(JSON.stringify(supernodes)) - }); - - var kBucket; - const K_Bucket = floCloudAPI.K_Bucket = function (masterID, nodeList) { - - const decodeID = floID => { - let k = bitjs.Base58.decode(floID); - k.shift(); - k.splice(-4, 4); - let decodedId = Crypto.util.bytesToHex(k); - let nodeIdBigInt = new BigInteger(decodedId, 16); - let nodeIdBytes = nodeIdBigInt.toByteArrayUnsigned(); - let nodeIdNewInt8Array = new Uint8Array(nodeIdBytes); - return nodeIdNewInt8Array; - }; - - const _KB = new BuildKBucket({ - localNodeId: decodeID(masterID) - }); - nodeList.forEach(id => _KB.add({ - id: decodeID(id), - floID: id - })); - - const _CO = nodeList.map(id => [_KB.distance(_KB.localNodeId, decodeID(id)), id]) - .sort((a, b) => a[0] - b[0]) - .map(a => a[1]); - - const self = this; - Object.defineProperty(self, 'tree', { - get: () => _KB - }); - Object.defineProperty(self, 'list', { - get: () => Array.from(_CO) - }); - - self.isNode = floID => _CO.includes(floID); - self.innerNodes = function (id1, id2) { - if (!_CO.includes(id1) || !_CO.includes(id2)) - throw Error('Given nodes are not supernode'); - let iNodes = [] - for (let i = _CO.indexOf(id1) + 1; _CO[i] != id2; i++) { - if (i < _CO.length) - iNodes.push(_CO[i]) - else i = -1 - } - return iNodes - } - self.outterNodes = function (id1, id2) { - if (!_CO.includes(id1) || !_CO.includes(id2)) - throw Error('Given nodes are not supernode'); - let oNodes = [] - for (let i = _CO.indexOf(id2) + 1; _CO[i] != id1; i++) { - if (i < _CO.length) - oNodes.push(_CO[i]) - else i = -1 - } - return oNodes - } - self.prevNode = function (id, N = 1) { - let n = N || _CO.length; - if (!_CO.includes(id)) - throw Error('Given node is not supernode'); - let pNodes = [] - for (let i = 0, j = _CO.indexOf(id) - 1; i < n; j--) { - if (j == _CO.indexOf(id)) - break; - else if (j > -1) - pNodes[i++] = _CO[j] - else j = _CO.length - } - return (N == 1 ? pNodes[0] : pNodes) - } - self.nextNode = function (id, N = 1) { - let n = N || _CO.length; - if (!_CO.includes(id)) - throw Error('Given node is not supernode'); - if (!n) n = _CO.length; - let nNodes = [] - for (let i = 0, j = _CO.indexOf(id) + 1; i < n; j++) { - if (j == _CO.indexOf(id)) - break; - else if (j < _CO.length) - nNodes[i++] = _CO[j] - else j = -1 - } - return (N == 1 ? nNodes[0] : nNodes) - } - self.closestNode = function (id, N = 1) { - let decodedId = decodeID(id); - let n = N || _CO.length; - let cNodes = _KB.closest(decodedId, n) - .map(k => k.floID) - return (N == 1 ? cNodes[0] : cNodes) - } - } - - floCloudAPI.init = function startCloudProcess(nodes) { - return new Promise((resolve, reject) => { - try { - supernodes = nodes; - kBucket = new K_Bucket(DEFAULT.SNStorageID, Object.keys(supernodes)); - resolve('Cloud init successful'); - } catch (error) { - reject(error); - } - }) - } - - Object.defineProperty(floCloudAPI, 'kBucket', { - get: () => kBucket - }); - - const _inactive = new Set(); - - function ws_connect(snID) { - return new Promise((resolve, reject) => { - if (!(snID in supernodes)) - return reject(`${snID} is not a supernode`) - if (_inactive.has(snID)) - return reject(`${snID} is not active`) - var wsConn = new WebSocket("wss://" + supernodes[snID].uri + "/"); - wsConn.onopen = evt => resolve(wsConn); - wsConn.onerror = evt => { - _inactive.add(snID) - reject(`${snID} is unavailable`) - } - }) - } - - function ws_activeConnect(snID, reverse = false) { - return new Promise((resolve, reject) => { - if (_inactive.size === kBucket.list.length) - return reject('Cloud offline'); - if (!(snID in supernodes)) - snID = kBucket.closestNode(proxyID(snID)); - ws_connect(snID) - .then(node => resolve(node)) - .catch(error => { - if (reverse) - var nxtNode = kBucket.prevNode(snID); - else - var nxtNode = kBucket.nextNode(snID); - ws_activeConnect(nxtNode, reverse) - .then(node => resolve(node)) - .catch(error => reject(error)) - }) - }) - } - - function fetch_API(snID, data) { - return new Promise((resolve, reject) => { - if (_inactive.has(snID)) - return reject(`${snID} is not active`); - let fetcher, sn_url = "https://" + supernodes[snID].uri; - if (typeof data === "string") - fetcher = fetch(sn_url + "?" + data); - else if (typeof data === "object" && data.method === "POST") - fetcher = fetch(sn_url, data); - fetcher.then(response => { - if (response.ok || response.status === 400 || response.status === 500) - resolve(response); - else - reject(response); - }).catch(error => reject(error)) - }) - } - - function fetch_ActiveAPI(snID, data, reverse = false) { - return new Promise((resolve, reject) => { - if (_inactive.size === kBucket.list.length) - return reject('Cloud offline'); - if (!(snID in supernodes)) - snID = kBucket.closestNode(proxyID(snID)); - fetch_API(snID, data) - .then(result => resolve(result)) - .catch(error => { - _inactive.add(snID) - if (reverse) - var nxtNode = kBucket.prevNode(snID); - else - var nxtNode = kBucket.nextNode(snID); - fetch_ActiveAPI(nxtNode, data, reverse) - .then(result => resolve(result)) - .catch(error => reject(error)); - }) - }) - } - - function singleRequest(floID, data_obj, method = "POST") { - return new Promise((resolve, reject) => { - let data; - if (method === "POST") - data = { - method: "POST", - body: JSON.stringify(data_obj) - }; - else - data = new URLSearchParams(JSON.parse(JSON.stringify(data_obj))).toString(); - fetch_ActiveAPI(floID, data).then(response => { - if (response.ok) - response.json() - .then(result => resolve(result)) - .catch(error => reject(error)) - else response.text() - .then(result => reject(response.status + ": " + result)) //Error Message from Node - .catch(error => reject(error)) - }).catch(error => reject(error)) - }) - } - - const _liveRequest = {}; - - function liveRequest(floID, request, callback) { - const filterData = typeof request.status !== 'undefined' ? - data => { - if (request.status) - return data; - else { - let filtered = {}; - for (let i in data) - if (request.trackList.includes(i)) - filtered[i] = data[i]; - return filtered; - } - } : - data => { - data = objectifier(data); - let filtered = {}, - proxy = proxyID(request.receiverID), - r = request; - for (let v in data) { - let d = data[v]; - if ((!r.atVectorClock || r.atVectorClock == v) && - (r.atVectorClock || !r.lowerVectorClock || r.lowerVectorClock <= v) && - (r.atVectorClock || !r.upperVectorClock || r.upperVectorClock >= v) && - (!r.afterTime || r.afterTime < d.log_time) && - r.application == d.application && - (proxy == d.receiverID || proxy == d.proxyID) && - (!r.comment || r.comment == d.comment) && - (!r.type || r.type == d.type) && - (!r.senderID || r.senderID.includes(d.senderID))) - filtered[v] = data[v]; - } - return filtered; - }; - - return new Promise((resolve, reject) => { - ws_activeConnect(floID).then(node => { - let randID = floCrypto.randString(5); - node.send(JSON.stringify(request)); - node.onmessage = (evt) => { - let d = null, - e = null; - try { - d = filterData(JSON.parse(evt.data)); - } catch (error) { - e = evt.data - } finally { - callback(d, e) - } - } - _liveRequest[randID] = node; - _liveRequest[randID].request = request; - resolve(randID); - }).catch(error => reject(error)); - }); - } - - Object.defineProperty(floCloudAPI, 'liveRequest', { - get: () => _liveRequest - }); - - Object.defineProperty(floCloudAPI, 'inactive', { - get: () => _inactive - }); - - const util = floCloudAPI.util = {}; - - const encodeMessage = util.encodeMessage = function (message) { - return btoa(unescape(encodeURIComponent(JSON.stringify(message)))) - } - - const decodeMessage = util.decodeMessage = function (message) { - return JSON.parse(decodeURIComponent(escape(atob(message)))) - } - - const filterKey = util.filterKey = function (type, options = {}) { - return type + (options.comment ? ':' + options.comment : '') + - '|' + (options.group || options.receiverID || DEFAULT.adminID) + - '|' + (options.application || DEFAULT.application); - } - - const proxyID = util.proxyID = function (address) { - if (!address) - return; - var bytes; - if (address.length == 33 || address.length == 34) { //legacy encoding - let decode = bitjs.Base58.decode(address); - bytes = decode.slice(0, decode.length - 4); - let checksum = decode.slice(decode.length - 4), - hash = Crypto.SHA256(Crypto.SHA256(bytes, { - asBytes: true - }), { - asBytes: true - }); - hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3] ? - bytes = undefined : bytes.shift(); - } else if (address.length == 42 || address.length == 62) { //bech encoding - if (typeof coinjs !== 'function') - throw "library missing (lib_btc.js)"; - let decode = coinjs.bech32_decode(address); - if (decode) { - bytes = decode.data; - bytes.shift(); - bytes = coinjs.bech32_convert(bytes, 5, 8, false); - if (address.length == 62) //for long bech, aggregate once more to get 160 bit - bytes = coinjs.bech32_convert(bytes, 5, 8, false); - } - } else if (address.length == 66) { //public key hex - bytes = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(address), { - asBytes: true - })); - } - if (!bytes) - throw "Invalid address: " + address; - else { - bytes.unshift(DEFAULT.blockchainPrefix); - let hash = Crypto.SHA256(Crypto.SHA256(bytes, { - asBytes: true - }), { - asBytes: true - }); - return bitjs.Base58.encode(bytes.concat(hash.slice(0, 4))); - } - } - - const lastCommit = {}; - Object.defineProperty(lastCommit, 'get', { - value: objName => JSON.parse(lastCommit[objName]) - }); - Object.defineProperty(lastCommit, 'set', { - value: objName => lastCommit[objName] = JSON.stringify(appObjects[objName]) - }); - - function updateObject(objectName, dataSet) { - try { - console.log(dataSet) - let vcList = Object.keys(dataSet).sort(); - for (let vc of vcList) { - if (vc < lastVC[objectName] || dataSet[vc].type !== objectName) - continue; - switch (dataSet[vc].comment) { - case "RESET": - if (dataSet[vc].message.reset) - appObjects[objectName] = dataSet[vc].message.reset; - break; - case "UPDATE": - if (dataSet[vc].message.diff) - appObjects[objectName] = diff.merge(appObjects[objectName], dataSet[vc].message.diff); - } - lastVC[objectName] = vc; - } - lastCommit.set(objectName); - compactIDB.writeData("appObjects", appObjects[objectName], objectName); - compactIDB.writeData("lastVC", lastVC[objectName], objectName); - } catch (error) { - console.error(error) - } - } - - function storeGeneral(fk, dataSet) { - try { - console.log(dataSet) - if (typeof generalData[fk] !== "object") - generalData[fk] = {} - for (let vc in dataSet) { - generalData[fk][vc] = dataSet[vc]; - if (dataSet[vc].log_time > lastVC[fk]) - lastVC[fk] = dataSet[vc].log_time; - } - compactIDB.writeData("lastVC", lastVC[fk], fk) - compactIDB.writeData("generalData", generalData[fk], fk) - } catch (error) { - console.error(error) - } - } - - function objectifier(data) { - if (!Array.isArray(data)) - data = [data]; - return Object.fromEntries(data.map(d => { - d.message = decodeMessage(d.message); - return [d.vectorClock, d]; - })); - } - - //set status as online for user_id - floCloudAPI.setStatus = function (options = {}) { - return new Promise((resolve, reject) => { - let callback = options.callback instanceof Function ? options.callback : DEFAULT.callback; - var request = { - floID: user.id, - application: options.application || DEFAULT.application, - time: Date.now(), - status: true, - pubKey: user.public - } - let hashcontent = ["time", "application", "floID"].map(d => request[d]).join("|"); - request.sign = user.sign(hashcontent); - liveRequest(options.refID || DEFAULT.adminID, request, callback) - .then(result => resolve(result)) - .catch(error => reject(error)) - }) - } - - //request status of floID(s) in trackList - floCloudAPI.requestStatus = function (trackList, options = {}) { - return new Promise((resolve, reject) => { - if (!Array.isArray(trackList)) - trackList = [trackList]; - let callback = options.callback instanceof Function ? options.callback : DEFAULT.callback; - let request = { - status: false, - application: options.application || DEFAULT.application, - trackList: trackList - } - liveRequest(options.refID || DEFAULT.adminID, request, callback) - .then(result => resolve(result)) - .catch(error => reject(error)) - }) - } - - //send any message to supernode cloud storage - const sendApplicationData = floCloudAPI.sendApplicationData = function (message, type, options = {}) { - return new Promise((resolve, reject) => { - var data = { - senderID: user.id, - receiverID: options.receiverID || DEFAULT.adminID, - pubKey: user.public, - message: encodeMessage(message), - time: Date.now(), - application: options.application || DEFAULT.application, - type: type, - comment: options.comment || "" - } - let hashcontent = ["receiverID", "time", "application", "type", "message", "comment"] - .map(d => data[d]).join("|") - data.sign = user.sign(hashcontent); - singleRequest(data.receiverID, data) - .then(result => resolve(result)) - .catch(error => reject(error)) - }) - } - - //request any data from supernode cloud - const requestApplicationData = floCloudAPI.requestApplicationData = function (type, options = {}) { - return new Promise((resolve, reject) => { - var request = { - receiverID: options.receiverID || DEFAULT.adminID, - senderID: options.senderID || undefined, - application: options.application || DEFAULT.application, - type: type, - comment: options.comment || undefined, - lowerVectorClock: options.lowerVectorClock || undefined, - upperVectorClock: options.upperVectorClock || undefined, - atVectorClock: options.atVectorClock || undefined, - afterTime: options.afterTime || undefined, - mostRecent: options.mostRecent || undefined, - } - - if (options.callback instanceof Function) { - liveRequest(request.receiverID, request, options.callback) - .then(result => resolve(result)) - .catch(error => reject(error)) - } else { - if (options.method === "POST") - request = { - time: Date.now(), - request - }; - singleRequest(request.receiverID, request, options.method || "GET") - .then(data => resolve(data)).catch(error => reject(error)) - } - }) - } - - /*(NEEDS UPDATE) - //delete data from supernode cloud (received only) - floCloudAPI.deleteApplicationData = function(vectorClocks, options = {}) { - return new Promise((resolve, reject) => { - var delreq = { - 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 = user.sign(hashcontent) - singleRequest(delreq.requestorID, delreq).then(result => { - let success = [], - failed = []; - result.forEach(r => r.status === 'fulfilled' ? - success.push(r.value) : failed.push(r.reason)); - resolve({ - success, - failed - }) - }).catch(error => reject(error)) - }) - } - */ - /*(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 - if (!oldData) { - options.atVectorClock = vectorClock; - options.callback = false; - p0 = requestApplicationData(false, options) - } else - p0 = Promise.resolve({ - vectorClock: { - ...oldData - } - }) - p0.then(d => { - if (d.senderID != user.id) - return reject("Invalid requestorID") - else if (!d.comment.startsWith("EDIT:")) - return reject("Data immutable") - let data = { - requestorID: user.id, - receiverID: d.receiverID, - time: Date.now(), - application: d.application, - edit: { - vectorClock: vectorClock, - comment: newComment - } - } - d.comment = data.edit.comment; - let hashcontent = ["receiverID", "time", "application", "type", "message", - "comment" - ] - .map(x => d[x]).join("|") - 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(user.id)) - return reject("Only subAdmins can tag data") - var request = { - receiverID: options.receiverID || DEFAULT.adminID, - 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 = user.sign(hashcontent); - singleRequest(request.receiverID, request) - .then(result => resolve(result)) - .catch(error => reject(error)) - }) - } - - //note data in supernode cloud (receiver only or subAdmin allowed if receiver is adminID) - floCloudAPI.noteApplicationData = function (vectorClock, note, options = {}) { - return new Promise((resolve, reject) => { - var request = { - receiverID: options.receiverID || DEFAULT.adminID, - 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 = user.sign(hashcontent); - singleRequest(request.receiverID, request) - .then(result => resolve(result)) - .catch(error => reject(error)) - }) - } - - //send general data - floCloudAPI.sendGeneralData = function (message, type, options = {}) { - 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) - } - sendApplicationData(message, type, options) - .then(result => resolve(result)) - .catch(error => reject(error)) - }) - } - - //request general data - floCloudAPI.requestGeneralData = function (type, options = {}) { - return new Promise((resolve, reject) => { - var fk = filterKey(type, options) - lastVC[fk] = parseInt(lastVC[fk]) || 0; - options.afterTime = options.afterTime || lastVC[fk]; - if (options.callback instanceof Function) { - let new_options = Object.create(options) - new_options.callback = (d, e) => { - storeGeneral(fk, d); - options.callback(d, e) - } - requestApplicationData(type, new_options) - .then(result => resolve(result)) - .catch(error => reject(error)) - } else { - requestApplicationData(type, options).then(dataSet => { - storeGeneral(fk, objectifier(dataSet)) - resolve(dataSet) - }).catch(error => reject(error)) - } - }) - } - - //request an object data from supernode cloud - floCloudAPI.requestObjectData = function (objectName, options = {}) { - return new Promise((resolve, reject) => { - options.lowerVectorClock = options.lowerVectorClock || lastVC[objectName] + 1; - options.senderID = [false, null].includes(options.senderID) ? null : - options.senderID || floGlobals.subAdmins; - options.mostRecent = true; - options.comment = 'RESET'; - let callback = null; - if (options.callback instanceof Function) { - let old_callback = options.callback; - callback = (d, e) => { - updateObject(objectName, d); - old_callback(d, e); - } - delete options.callback; - } - requestApplicationData(objectName, options).then(dataSet => { - updateObject(objectName, objectifier(dataSet)); - delete options.comment; - options.lowerVectorClock = lastVC[objectName] + 1; - delete options.mostRecent; - if (callback) { - let new_options = Object.create(options); - new_options.callback = callback; - requestApplicationData(objectName, new_options) - .then(result => resolve(result)) - .catch(error => reject(error)) - } else { - requestApplicationData(objectName, options).then(dataSet => { - updateObject(objectName, objectifier(dataSet)) - resolve(appObjects[objectName]) - }).catch(error => reject(error)) - } - }).catch(error => reject(error)) - }) - } - - floCloudAPI.closeRequest = function (requestID) { - return new Promise((resolve, reject) => { - let conn = _liveRequest[requestID] - if (!conn) - return reject('Request not found') - conn.onclose = evt => { - delete _liveRequest[requestID]; - resolve('Request connection closed') - } - conn.close() - }) - } - - //reset or initialize an object and send it to cloud - floCloudAPI.resetObjectData = function (objectName, options = {}) { - return new Promise((resolve, reject) => { - let message = { - reset: appObjects[objectName] - } - options.comment = 'RESET'; - sendApplicationData(message, objectName, options).then(result => { - lastCommit.set(objectName); - resolve(result) - }).catch(error => reject(error)) - }) - } - - //update the diff and send it to cloud - floCloudAPI.updateObjectData = function (objectName, options = {}) { - return new Promise((resolve, reject) => { - let message = { - diff: diff.find(lastCommit.get(objectName), appObjects[ - objectName]) - } - options.comment = 'UPDATE'; - sendApplicationData(message, objectName, options).then(result => { - lastCommit.set(objectName); - resolve(result) - }).catch(error => reject(error)) - }) - } - - /* - Functions: - findDiff(original, updatedObj) returns an object with the added, deleted and updated differences - mergeDiff(original, allDiff) returns a new object from original object merged with all differences (allDiff is returned object of findDiff) - */ - var diff = (function () { - const isDate = d => d instanceof Date; - const isEmpty = o => Object.keys(o).length === 0; - const isObject = o => o != null && typeof o === 'object'; - const properObject = o => isObject(o) && !o.hasOwnProperty ? { - ...o - } : o; - const getLargerArray = (l, r) => l.length > r.length ? l : r; - - const preserve = (diff, left, right) => { - if (!isObject(diff)) return diff; - return Object.keys(diff).reduce((acc, key) => { - const leftArray = left[key]; - const rightArray = right[key]; - if (Array.isArray(leftArray) && Array.isArray(rightArray)) { - const array = [...getLargerArray(leftArray, rightArray)]; - return { - ...acc, - [key]: array.reduce((acc2, item, index) => { - if (diff[key].hasOwnProperty(index)) { - acc2[index] = preserve(diff[key][index], leftArray[index], rightArray[index]); // diff recurse and check for nested arrays - return acc2; - } - delete acc2[index]; // no diff aka empty - return acc2; - }, array) - }; - } - return { - ...acc, - [key]: diff[key] - }; - }, {}); - }; - - const updatedDiff = (lhs, rhs) => { - if (lhs === rhs) return {}; - if (!isObject(lhs) || !isObject(rhs)) return rhs; - const l = properObject(lhs); - const r = properObject(rhs); - if (isDate(l) || isDate(r)) { - if (l.valueOf() == r.valueOf()) return {}; - return r; - } - return Object.keys(r).reduce((acc, key) => { - if (l.hasOwnProperty(key)) { - const difference = updatedDiff(l[key], r[key]); - if (isObject(difference) && isEmpty(difference) && !isDate(difference)) return acc; - return { - ...acc, - [key]: difference - }; - } - return acc; - }, {}); - }; - - - const diff = (lhs, rhs) => { - if (lhs === rhs) return {}; // equal return no diff - if (!isObject(lhs) || !isObject(rhs)) return rhs; // return updated rhs - const l = properObject(lhs); - const r = properObject(rhs); - const deletedValues = Object.keys(l).reduce((acc, key) => { - return r.hasOwnProperty(key) ? acc : { - ...acc, - [key]: null - }; - }, {}); - if (isDate(l) || isDate(r)) { - if (l.valueOf() == r.valueOf()) return {}; - return r; - } - return Object.keys(r).reduce((acc, key) => { - if (!l.hasOwnProperty(key)) return { - ...acc, - [key]: r[key] - }; // return added r key - const difference = diff(l[key], r[key]); - if (isObject(difference) && isEmpty(difference) && !isDate(difference)) return acc; // return no diff - return { - ...acc, - [key]: difference - }; // return updated key - }, deletedValues); - }; - - const addedDiff = (lhs, rhs) => { - if (lhs === rhs || !isObject(lhs) || !isObject(rhs)) return {}; - const l = properObject(lhs); - const r = properObject(rhs); - return Object.keys(r).reduce((acc, key) => { - if (l.hasOwnProperty(key)) { - const difference = addedDiff(l[key], r[key]); - if (isObject(difference) && isEmpty(difference)) return acc; - return { - ...acc, - [key]: difference - }; - } - return { - ...acc, - [key]: r[key] - }; - }, {}); - }; - - const arrayDiff = (lhs, rhs) => { - if (lhs === rhs) return {}; // equal return no diff - if (!isObject(lhs) || !isObject(rhs)) return rhs; // return updated rhs - const l = properObject(lhs); - const r = properObject(rhs); - const deletedValues = Object.keys(l).reduce((acc, key) => { - return r.hasOwnProperty(key) ? acc : { - ...acc, - [key]: null - }; - }, {}); - if (isDate(l) || isDate(r)) { - if (l.valueOf() == r.valueOf()) return {}; - return r; - } - if (Array.isArray(r) && Array.isArray(l)) { - const deletedValues = l.reduce((acc, item, index) => { - return r.hasOwnProperty(index) ? acc.concat(item) : acc.concat(null); - }, []); - return r.reduce((acc, rightItem, index) => { - if (!deletedValues.hasOwnProperty(index)) { - return acc.concat(rightItem); - } - const leftItem = l[index]; - const difference = diff(rightItem, leftItem); - if (isObject(difference) && isEmpty(difference) && !isDate(difference)) { - delete acc[index]; - return acc; // return no diff - } - return acc.slice(0, index).concat(rightItem).concat(acc.slice(index + 1)); // return updated key - }, deletedValues); - } - - return Object.keys(r).reduce((acc, key) => { - if (!l.hasOwnProperty(key)) return { - ...acc, - [key]: r[key] - }; // return added r key - const difference = diff(l[key], r[key]); - if (isObject(difference) && isEmpty(difference) && !isDate(difference)) return acc; // return no diff - return { - ...acc, - [key]: difference - }; // return updated key - }, deletedValues); - }; - - const deletedDiff = (lhs, rhs) => { - if (lhs === rhs || !isObject(lhs) || !isObject(rhs)) return {}; - const l = properObject(lhs); - const r = properObject(rhs); - return Object.keys(l).reduce((acc, key) => { - if (r.hasOwnProperty(key)) { - const difference = deletedDiff(l[key], r[key]); - if (isObject(difference) && isEmpty(difference)) return acc; - return { - ...acc, - [key]: difference - }; - } - return { - ...acc, - [key]: null - }; - }, {}); - }; - - const mergeRecursive = (obj1, obj2, deleteMode = false) => { - for (var p in obj2) { - try { - if (obj2[p].constructor == Object) - obj1[p] = mergeRecursive(obj1[p], obj2[p], deleteMode); - // Property in destination object set; update its value. - else if (Array.isArray(obj2[p])) { - // obj1[p] = []; - if (obj2[p].length < 1) - obj1[p] = obj2[p]; - else - obj1[p] = mergeRecursive(obj1[p], obj2[p], deleteMode); - } else - obj1[p] = deleteMode && obj2[p] === null ? undefined : obj2[p]; - } catch (e) { - // Property in destination object not set; create it and set its value. - obj1[p] = deleteMode && obj2[p] === null ? undefined : obj2[p]; - } - } - return obj1; - } - - const cleanse = (obj) => { - Object.keys(obj).forEach(key => { - var value = obj[key]; - if (typeof value === "object" && value !== null) - obj[key] = cleanse(value); - else if (typeof value === 'undefined') - delete obj[key]; // undefined, remove it - }); - if (Array.isArray(obj)) - obj = obj.filter(v => typeof v !== 'undefined'); - return obj; - } - - - const findDiff = (lhs, rhs) => ({ - added: addedDiff(lhs, rhs), - deleted: deletedDiff(lhs, rhs), - updated: updatedDiff(lhs, rhs), - }); - - /*obj is original object or array, diff is the output of findDiff */ - const mergeDiff = (obj, diff) => { - if (Object.keys(diff.updated).length !== 0) - obj = mergeRecursive(obj, diff.updated) - if (Object.keys(diff.deleted).length !== 0) { - obj = mergeRecursive(obj, diff.deleted, true) - obj = cleanse(obj) - } - if (Object.keys(diff.added).length !== 0) - obj = mergeRecursive(obj, diff.added) - return obj - } - - return { - find: findDiff, - merge: mergeDiff - } - })(); - - -})('object' === typeof module ? module.exports : window.floCloudAPI = {}); \ No newline at end of file diff --git a/floDapps.js b/floDapps.js deleted file mode 100644 index 4d525a2..0000000 --- a/floDapps.js +++ /dev/null @@ -1,845 +0,0 @@ -(function (EXPORTS) { //floDapps v2.4.0 - /* General functions for FLO Dapps*/ - 'use strict'; - const floDapps = EXPORTS; - - const DEFAULT = { - root: "floDapps", - application: floGlobals.application, - adminID: floGlobals.adminID - }; - - Object.defineProperties(floDapps, { - application: { - get: () => DEFAULT.application - }, - adminID: { - get: () => DEFAULT.adminID - }, - root: { - get: () => DEFAULT.root - } - }); - - var user_priv_raw, aes_key, user_priv_wrap; //private variable inside capsule - const raw_user = { - get private() { - if (!user_priv_raw) - throw "User not logged in"; - return Crypto.AES.decrypt(user_priv_raw, aes_key); - } - } - - 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 Crypto.AES.decrypt(user_private, aes_key); - }, - sign(message) { - return floCrypto.signData(message, raw_user.private); - }, - decrypt(data) { - return floCrypto.decryptData(data, raw_user.private); - }, - encipher(message) { - return Crypto.AES.encrypt(message, raw_user.private); - }, - decipher(data) { - return Crypto.AES.decrypt(data, raw_user.private); - }, - get db_name() { - return "floDapps#" + floCrypto.toFloID(user.id); - }, - lock() { - user_private = user_priv_wrap; - }, - async unlock() { - if (await user.private === raw_user.private) - user_private = user_priv_raw; - }, - get_contact(id) { - if (!user.contacts) - throw "Contacts not available"; - else if (user.contacts[id]) - return user.contacts[id]; - else { - let id_raw = floCrypto.decodeAddr(id).hex; - for (let i in user.contacts) - if (floCrypto.decodeAddr(i).hex == id_raw) - return user.contacts[i]; - } - }, - get_pubKey(id) { - if (!user.pubKeys) - throw "Contacts not available"; - else if (user.pubKeys[id]) - return user.pubKeys[id]; - else { - let id_raw = floCrypto.decodeAddr(id).hex; - for (let i in user.pubKeys) - if (floCrypto.decodeAddr(i).hex == id_raw) - return user.pubKeys[i]; - } - }, - clear() { - user_id = user_public = user_private = undefined; - user_priv_raw = aes_key = undefined; - delete user.contacts; - delete user.pubKeys; - delete user.messages; - } - }; - - Object.defineProperties(window, { - myFloID: { - get: () => { - try { - return user.id; - } catch { - return; - } - } - }, - myUserID: { - get: () => { - try { - return user.id; - } catch { - return; - } - } - }, - myPubKey: { - get: () => { - try { - return user.public; - } catch { - return; - } - } - }, - myPrivKey: { - get: () => { - try { - return user.private; - } catch { - return; - } - } - } - }); - - var subAdmins, trustedIDs, settings; - Object.defineProperties(floGlobals, { - subAdmins: { - get: () => subAdmins - }, - trustedIDs: { - get: () => trustedIDs - }, - 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 = { - //general - lastTx: {}, - //supernode (cloud list) - supernodes: { - indexes: { - uri: null, - pubKey: null - } - } - } - var obs_a = { - //login credentials - credentials: {}, - //for Dapps - subAdmins: {}, - trustedIDs: {}, - settings: {}, - appObjects: {}, - generalData: {}, - lastVC: {} - } - //add other given objectStores - initIndexedDB.appObs = initIndexedDB.appObs || {} - for (let o in initIndexedDB.appObs) - if (!(o in obs_a)) - obs_a[o] = initIndexedDB.appObs[o] - Promise.all([ - compactIDB.initDB(DEFAULT.application, obs_a), - compactIDB.initDB(DEFAULT.root, obs_g) - ]).then(result => { - compactIDB.setDefaultDB(DEFAULT.application) - resolve("IndexedDB App Storage Initated Successfully") - }).catch(error => reject(error)); - }) - } - - function initUserDB() { - return new Promise((resolve, reject) => { - var obs = { - contacts: {}, - pubKeys: {}, - messages: {} - } - compactIDB.initDB(user.db_name, obs).then(result => { - resolve("UserDB Initated Successfully") - }).catch(error => reject('Init userDB failed')); - }) - } - - 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], user.db_name) - Promise.all(promises).then(results => { - for (var i = 0; i < loadData.length; i++) - user[loadData[i]] = results[i] - resolve("Loaded Data from userDB") - }).catch(error => reject('Load userDB failed')) - }) - } - - const startUpOptions = { - cloud: true, - app_config: true, - } - - floDapps.startUpOptions = { - set app_config(val) { - if (val === true || val === false) - startUpOptions.app_config = val; - }, - get app_config() { return startUpOptions.app_config }, - - set cloud(val) { - if (val === true || val === false) - startUpOptions.cloud = val; - }, - get cloud() { return startUpOptions.cloud }, - } - - const startUpFunctions = []; - - startUpFunctions.push(function readSupernodeListFromAPI() { - return new Promise((resolve, reject) => { - if (!startUpOptions.cloud) - return resolve("No cloud for this app"); - compactIDB.readData("lastTx", floCloudAPI.SNStorageID, DEFAULT.root).then(lastTx => { - var query_options = { sentOnly: true, pattern: floCloudAPI.SNStorageName }; - if (typeof lastTx == 'number') //lastTx is tx count (*backward support) - query_options.ignoreOld = lastTx; - else if (typeof lastTx == 'string') //lastTx is txid of last tx - query_options.after = lastTx; - //fetch data from flosight - floBlockchainAPI.readData(floCloudAPI.SNStorageID, query_options).then(result => { - for (var i = result.data.length - 1; i >= 0; i--) { - var content = JSON.parse(result.data[i])[floCloudAPI.SNStorageName]; - for (let sn in content.removeNodes) - compactIDB.removeData("supernodes", sn, DEFAULT.root); - for (let sn in content.newNodes) - compactIDB.writeData("supernodes", content.newNodes[sn], sn, DEFAULT.root); - for (let sn in content.updateNodes) - compactIDB.readData("supernodes", sn, DEFAULT.root).then(r => { - r = r || {} - r.uri = content.updateNodes[sn]; - compactIDB.writeData("supernodes", r, sn, DEFAULT.root); - }); - } - compactIDB.writeData("lastTx", result.lastItem, floCloudAPI.SNStorageID, DEFAULT.root); - compactIDB.readAllData("supernodes", DEFAULT.root).then(nodes => { - floCloudAPI.init(nodes) - .then(result => resolve("Loaded Supernode list\n" + result)) - .catch(error => reject(error)) - }) - }) - }).catch(error => reject(error)) - }) - }); - - startUpFunctions.push(function readAppConfigFromAPI() { - return new Promise((resolve, reject) => { - if (!startUpOptions.app_config) - return resolve("No configs for this app"); - compactIDB.readData("lastTx", `${DEFAULT.application}|${DEFAULT.adminID}`, DEFAULT.root).then(lastTx => { - var query_options = { sentOnly: true, pattern: DEFAULT.application }; - if (typeof lastTx == 'number') //lastTx is tx count (*backward support) - query_options.ignoreOld = lastTx; - else if (typeof lastTx == 'string') //lastTx is txid of last tx - query_options.after = lastTx; - //fetch data from flosight - floBlockchainAPI.readData(DEFAULT.adminID, query_options).then(result => { - for (var i = result.data.length - 1; i >= 0; i--) { - var content = JSON.parse(result.data[i])[DEFAULT.application]; - if (!content || typeof content !== "object") - continue; - if (Array.isArray(content.removeSubAdmin)) - for (var j = 0; j < content.removeSubAdmin.length; j++) - compactIDB.removeData("subAdmins", content.removeSubAdmin[j]); - if (Array.isArray(content.addSubAdmin)) - for (var k = 0; k < content.addSubAdmin.length; k++) - compactIDB.writeData("subAdmins", true, content.addSubAdmin[k]); - if (Array.isArray(content.removeTrustedID)) - for (var j = 0; j < content.removeTrustedID.length; j++) - compactIDB.removeData("trustedIDs", content.removeTrustedID[j]); - if (Array.isArray(content.addTrustedID)) - for (var k = 0; k < content.addTrustedID.length; k++) - compactIDB.writeData("trustedIDs", true, content.addTrustedID[k]); - if (content.settings) - for (let l in content.settings) - compactIDB.writeData("settings", content.settings[l], l) - } - compactIDB.writeData("lastTx", result.lastItem, `${DEFAULT.application}|${DEFAULT.adminID}`, DEFAULT.root); - compactIDB.readAllData("subAdmins").then(result => { - subAdmins = Object.keys(result); - compactIDB.readAllData("trustedIDs").then(result => { - trustedIDs = Object.keys(result); - compactIDB.readAllData("settings").then(result => { - settings = result; - resolve("Read app configuration from blockchain"); - }) - }) - }) - }) - }).catch(error => reject(error)) - }) - }); - - startUpFunctions.push(function loadDataFromAppIDB() { - return new Promise((resolve, reject) => { - if (!startUpOptions.cloud) - return resolve("No cloud for this app"); - var loadData = ["appObjects", "generalData", "lastVC"] - var promises = [] - for (var i = 0; i < loadData.length; i++) - promises[i] = compactIDB.readAllData(loadData[i]) - Promise.all(promises).then(results => { - for (var i = 0; i < loadData.length; i++) - floGlobals[loadData[i]] = results[i] - resolve("Loaded Data from app IDB") - }).catch(error => reject(error)) - }) - }); - - var keyInput = type => new Promise((resolve, reject) => { - let inputVal = prompt(`Enter ${type}: `) - if (inputVal === null) - reject(null) - else - resolve(inputVal) - }); - - function getCredentials() { - - const readSharesFromIDB = indexArr => new Promise((resolve, reject) => { - var promises = [] - for (var i = 0; i < indexArr.length; i++) - promises.push(compactIDB.readData('credentials', indexArr[i])) - Promise.all(promises).then(shares => { - var secret = floCrypto.retrieveShamirSecret(shares) - if (secret) - resolve(secret) - else - reject("Shares are insufficient or incorrect") - }).catch(error => { - clearCredentials(); - location.reload(); - }) - }); - - const writeSharesToIDB = (shares, i = 0, resultIndexes = []) => new Promise(resolve => { - if (i >= shares.length) - return resolve(resultIndexes) - var n = floCrypto.randInt(0, 100000) - compactIDB.addData("credentials", shares[i], n).then(res => { - resultIndexes.push(n) - writeSharesToIDB(shares, i + 1, resultIndexes) - .then(result => resolve(result)) - }).catch(error => { - writeSharesToIDB(shares, i, resultIndexes) - .then(result => resolve(result)) - }) - }); - - const getPrivateKeyCredentials = () => new Promise((resolve, reject) => { - var indexArr = localStorage.getItem(`${DEFAULT.application}#privKey`) - if (indexArr) { - readSharesFromIDB(JSON.parse(indexArr)) - .then(result => resolve(result)) - .catch(error => reject(error)) - } else { - var privKey; - keyInput("PRIVATE_KEY").then(result => { - if (!result) - return reject("Empty Private Key") - var floID = floCrypto.getFloID(result) - if (!floID || !floCrypto.validateFloID(floID)) - return reject("Invalid Private Key") - privKey = result; - }).catch(error => { - console.log(error, "Generating Random Keys") - privKey = floCrypto.generateNewID().privKey - }).finally(_ => { - if (!privKey) - return; - var threshold = floCrypto.randInt(10, 20) - var shares = floCrypto.createShamirsSecretShares(privKey, threshold, threshold) - writeSharesToIDB(shares).then(resultIndexes => { - //store index keys in localStorage - 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) - var randomShares = floCrypto.createShamirsSecretShares(randomPrivKey, randomThreshold, randomThreshold) - writeSharesToIDB(randomShares) - //resolve private Key - resolve(privKey) - }) - }) - } - }); - - const checkIfPinRequired = key => new Promise((resolve, reject) => { - if (key.length == 52) - resolve(key) - else { - keyInput("PIN/Password").then(pwd => { - try { - let privKey = Crypto.AES.decrypt(key, pwd); - resolve(privKey) - } catch (error) { - reject("Access Denied: Incorrect PIN/Password") - } - }).catch(error => reject("Access Denied: PIN/Password required")) - } - }); - - return new Promise((resolve, reject) => { - getPrivateKeyCredentials().then(key => { - checkIfPinRequired(key).then(privKey => { - try { - user_public = floCrypto.getPubKeyHex(privKey); - user_id = floCrypto.getAddress(privKey); - if (startUpOptions.cloud) - floCloudAPI.user(user_id, privKey); //Set user for floCloudAPI - user_priv_wrap = () => checkIfPinRequired(key); - let n = floCrypto.randInt(12, 20); - aes_key = floCrypto.randString(n); - user_priv_raw = Crypto.AES.encrypt(privKey, aes_key); - user_private = user_priv_wrap; - resolve('Login Credentials loaded successful') - } catch (error) { - console.log(error) - reject("Corrupted Private Key") - } - }).catch(error => reject(error)) - }).catch(error => reject(error)) - }) - } - - var startUpLog = (status, log) => status ? console.log(log) : console.error(log); - - const callStartUpFunction = i => new Promise((resolve, reject) => { - startUpFunctions[i]().then(result => { - callStartUpFunction.completed += 1; - startUpLog(true, `${result}\nCompleted ${callStartUpFunction.completed}/${callStartUpFunction.total} Startup functions`) - resolve(true) - }).catch(error => { - callStartUpFunction.failed += 1; - startUpLog(false, `${error}\nFailed ${callStartUpFunction.failed}/${callStartUpFunction.total} Startup functions`) - reject(false) - }) - }); - - var _midFunction; - const midStartUp = () => new Promise((res, rej) => { - if (_midFunction instanceof Function) { - _midFunction() - .then(r => res("Mid startup function completed")) - .catch(e => rej("Mid startup function failed")) - } else - res("No mid startup function") - }); - - const callAndLog = p => new Promise((res, rej) => { - p.then(r => { - startUpLog(true, r) - res(r) - }).catch(e => { - startUpLog(false, e) - rej(e) - }) - }); - - floDapps.launchStartUp = function () { - return new Promise((resolve, reject) => { - initIndexedDB().then(log => { - console.log(log) - callStartUpFunction.total = startUpFunctions.length; - callStartUpFunction.completed = 0; - callStartUpFunction.failed = 0; - let p1 = new Promise((res, rej) => { - Promise.all(startUpFunctions.map((f, i) => callStartUpFunction(i))).then(r => { - callAndLog(midStartUp()) - .then(r => res(true)) - .catch(e => rej(false)) - }) - }); - let p2 = new Promise((res, rej) => { - callAndLog(getCredentials()).then(r => { - callAndLog(initUserDB()).then(r => { - callAndLog(loadUserDB()) - .then(r => res(true)) - .catch(e => rej(false)) - }).catch(e => rej(false)) - }).catch(e => rej(false)) - }) - Promise.all([p1, p2]) - .then(r => resolve('App Startup finished successful')) - .catch(e => reject('App Startup failed')) - }).catch(error => { - startUpLog(false, error); - reject("App database initiation failed") - }) - }) - } - - floDapps.addStartUpFunction = fn => fn instanceof Function && !startUpFunctions.includes(fn) ? startUpFunctions.push(fn) : false; - - floDapps.setMidStartup = fn => fn instanceof Function ? _midFunction = fn : false; - - floDapps.setCustomStartupLogger = fn => fn instanceof Function ? startUpLog = fn : false; - - floDapps.setCustomPrivKeyInput = fn => fn instanceof Function ? keyInput = fn : false; - - floDapps.setAppObjectStores = appObs => initIndexedDB.appObs = appObs; - - floDapps.storeContact = function (floID, name) { - return new Promise((resolve, reject) => { - if (!floCrypto.validateAddr(floID)) - return reject("Invalid floID!") - compactIDB.writeData("contacts", name, floID, user.db_name).then(result => { - user.contacts[floID] = name; - resolve("Contact stored") - }).catch(error => reject(error)) - }); - } - - floDapps.storePubKey = function (floID, pubKey) { - return new Promise((resolve, reject) => { - if (floID in user.pubKeys) - return resolve("pubKey already stored") - if (!floCrypto.validateAddr(floID)) - return reject("Invalid floID!") - if (!floCrypto.verifyPubKey(pubKey, floID)) - return reject("Incorrect pubKey") - compactIDB.writeData("pubKeys", pubKey, floID, user.db_name).then(result => { - user.pubKeys[floID] = pubKey; - resolve("pubKey stored") - }).catch(error => reject(error)) - }); - } - - floDapps.sendMessage = function (floID, message) { - return new Promise((resolve, reject) => { - let options = { - receiverID: floID, - application: DEFAULT.root, - comment: DEFAULT.application - } - 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)) - }) - } - - floDapps.requestInbox = function (callback) { - return new Promise((resolve, reject) => { - let lastVC = Object.keys(user.messages).sort().pop() - let options = { - 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, privKey) - } catch (error) { } - compactIDB.writeData("messages", d[v], v, user.db_name) - user.messages[v] = d[v] - } - if (callback instanceof Function) - callback(d, e) - } - floCloudAPI.requestApplicationData("Message", options) - .then(result => resolve(result)) - .catch(error => reject(error)) - }) - } - - floDapps.manageAppConfig = function (adminPrivKey, addList, rmList, settings) { - return new Promise((resolve, reject) => { - if (!startUpOptions.app_config) - return reject("No configs for this app"); - if (!Array.isArray(addList) || !addList.length) addList = undefined; - if (!Array.isArray(rmList) || !rmList.length) rmList = undefined; - if (!settings || typeof settings !== "object" || !Object.keys(settings).length) settings = undefined; - if (!addList && !rmList && !settings) - return reject("No configuration change") - var floData = { - [DEFAULT.application]: { - addSubAdmin: addList, - removeSubAdmin: rmList, - settings: settings - } - } - var floID = floCrypto.getFloID(adminPrivKey) - if (floID != DEFAULT.adminID) - reject('Access Denied for Admin privilege') - else - floBlockchainAPI.writeData(floID, JSON.stringify(floData), adminPrivKey) - .then(result => resolve(['Updated App Configuration', result])) - .catch(error => reject(error)) - }) - } - - floDapps.manageAppTrustedIDs = function (adminPrivKey, addList, rmList) { - return new Promise((resolve, reject) => { - if (!startUpOptions.app_config) - return reject("No configs for this app"); - if (!Array.isArray(addList) || !addList.length) addList = undefined; - if (!Array.isArray(rmList) || !rmList.length) rmList = undefined; - if (!addList && !rmList) - return reject("No change in list") - var floData = { - [DEFAULT.application]: { - addTrustedID: addList, - removeTrustedID: rmList - } - } - var floID = floCrypto.getFloID(adminPrivKey) - if (floID != DEFAULT.adminID) - reject('Access Denied for Admin privilege') - else - floBlockchainAPI.writeData(floID, JSON.stringify(floData), adminPrivKey) - .then(result => resolve(['Updated App Configuration', result])) - .catch(error => reject(error)) - }) - } - - const clearCredentials = floDapps.clearCredentials = function () { - return new Promise((resolve, reject) => { - compactIDB.clearData('credentials', DEFAULT.application).then(result => { - localStorage.removeItem(`${DEFAULT.application}#privKey`); - user.clear(); - resolve("privKey credentials deleted!") - }).catch(error => reject(error)) - }) - } - - floDapps.deleteUserData = function (credentials = false) { - return new Promise((resolve, reject) => { - let p = [] - p.push(compactIDB.deleteDB(user.db_name)) - if (credentials) - p.push(clearCredentials()) - Promise.all(p) - .then(result => resolve('User database(local) deleted')) - .catch(error => reject(error)) - }) - } - - floDapps.deleteAppData = function () { - return new Promise((resolve, reject) => { - 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)) - }) - } - - floDapps.securePrivKey = function (pwd) { - 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(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, DEFAULT.application); - for (var i = 0; i < threshold; i++) - promises.push(overwriteFn(shares[i], indexArr[i])); - Promise.all(promises) - .then(results => resolve("Private Key Secured")) - .catch(error => reject(error)) - }) - } - - floDapps.verifyPin = function (pin = null) { - const readSharesFromIDB = function (indexArr) { - return new Promise((resolve, reject) => { - var promises = [] - for (var i = 0; i < indexArr.length; i++) - promises.push(compactIDB.readData('credentials', indexArr[i])) - Promise.all(promises).then(shares => { - var secret = floCrypto.retrieveShamirSecret(shares) - console.info(shares, secret) - if (secret) - resolve(secret) - else - reject("Shares are insufficient or incorrect") - }).catch(error => { - clearCredentials(); - location.reload(); - }) - }) - } - return new Promise((resolve, reject) => { - var indexArr = localStorage.getItem(`${DEFAULT.application}#privKey`) - console.info(indexArr) - if (!indexArr) - reject('No login credentials found') - readSharesFromIDB(JSON.parse(indexArr)).then(key => { - if (key.length == 52) { - if (pin === null) - resolve("Private key not secured") - else - reject("Private key not secured") - } else { - if (pin === null) - return reject("PIN/Password required") - try { - let privKey = Crypto.AES.decrypt(key, pin); - resolve("PIN/Password verified") - } catch (error) { - reject("Incorrect PIN/Password") - } - } - }).catch(error => reject(error)) - }) - } - - const getNextGeneralData = floDapps.getNextGeneralData = function (type, vectorClock = null, options = {}) { - var fk = floCloudAPI.util.filterKey(type, options) - vectorClock = vectorClock || getNextGeneralData[fk] || '0'; - var filteredResult = {} - if (floGlobals.generalData[fk]) { - for (let d in floGlobals.generalData[fk]) - if (d > vectorClock) - filteredResult[d] = JSON.parse(JSON.stringify(floGlobals.generalData[fk][d])) - } else if (options.comment) { - let comment = options.comment; - delete options.comment; - let fk = floCloudAPI.util.filterKey(type, options); - for (let d in floGlobals.generalData[fk]) - if (d > vectorClock && floGlobals.generalData[fk][d].comment == comment) - filteredResult[d] = JSON.parse(JSON.stringify(floGlobals.generalData[fk][d])) - } - if (options.decrypt) { - let decryptionKey = (options.decrypt === true) ? raw_user.private : options.decrypt; - if (!Array.isArray(decryptionKey)) - decryptionKey = [decryptionKey]; - for (let f in filteredResult) { - let data = filteredResult[f] - try { - if (data.message instanceof Object && "secret" 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) { } - } - } - getNextGeneralData[fk] = Object.keys(filteredResult).sort().pop(); - return filteredResult; - } - - const syncData = floDapps.syncData = {}; - - syncData.oldDevice = () => new Promise((resolve, reject) => { - let sync = { - contacts: user.contacts, - pubKeys: user.pubKeys, - messages: user.messages - } - let message = Crypto.AES.encrypt(JSON.stringify(sync), raw_user.private) - let options = { - receiverID: user.id, - application: DEFAULT.root - } - floCloudAPI.sendApplicationData(message, "syncData", options) - .then(result => resolve(result)) - .catch(error => reject(error)) - }); - - syncData.newDevice = () => new Promise((resolve, reject) => { - var options = { - 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, raw_user.private)) - let promises = [] - 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) - user[c][i] = sync[c][i] - } - }) - Promise.all(promises) - .then(results => resolve("Sync data successful")) - .catch(error => reject(error)) - }).catch(error => reject(error)) - }); -})('object' === typeof module ? module.exports : window.floDapps = {}); \ No newline at end of file diff --git a/floTokenAPI.js b/floTokenAPI.js deleted file mode 100644 index 2456b88..0000000 --- a/floTokenAPI.js +++ /dev/null @@ -1,166 +0,0 @@ -(function (EXPORTS) { //floTokenAPI v1.0.4a - /* Token Operator to send/receive tokens via blockchain using API calls*/ - 'use strict'; - const tokenAPI = EXPORTS; - - const DEFAULT = { - apiURL: floGlobals.tokenURL || "https://ranchimallflo.duckdns.org/", - currency: floGlobals.currency || "rupee" - } - - Object.defineProperties(tokenAPI, { - URL: { - get: () => DEFAULT.apiURL - }, - currency: { - get: () => DEFAULT.currency, - set: currency => DEFAULT.currency = currency - } - }); - - if (floGlobals.currency) tokenAPI.currency = floGlobals.currency; - - Object.defineProperties(floGlobals, { - currency: { - get: () => DEFAULT.currency, - set: currency => DEFAULT.currency = currency - } - }); - - const fetch_api = tokenAPI.fetch = function (apicall) { - return new Promise((resolve, reject) => { - console.debug(DEFAULT.apiURL + apicall); - fetch(DEFAULT.apiURL + apicall).then(response => { - if (response.ok) - response.json().then(data => resolve(data)); - else - reject(response) - }).catch(error => reject(error)) - }) - } - - const getBalance = tokenAPI.getBalance = function (floID, token = DEFAULT.currency) { - return new Promise((resolve, reject) => { - fetch_api(`api/v1.0/getFloAddressBalance?token=${token}&floAddress=${floID}`) - .then(result => resolve(result.balance || 0)) - .catch(error => reject(error)) - }) - } - - tokenAPI.getTx = function (txID) { - return new Promise((resolve, reject) => { - fetch_api(`api/v1.0/getTransactionDetails/${txID}`).then(res => { - if (res.result === "error") - reject(res.description); - else if (!res.parsedFloData) - reject("Data piece (parsedFloData) missing"); - else if (!res.transactionDetails) - reject("Data piece (transactionDetails) missing"); - else - resolve(res); - }).catch(error => reject(error)) - }) - } - - tokenAPI.sendToken = function (privKey, amount, receiverID, message = "", token = DEFAULT.currency, options = {}) { - return new Promise((resolve, reject) => { - let senderID = floCrypto.getFloID(privKey); - if (typeof amount !== "number" || isNaN(amount) || amount <= 0) - return reject("Invalid amount"); - getBalance(senderID, token).then(bal => { - if (amount > bal) - return reject(`Insufficient ${token}# balance`); - floBlockchainAPI.writeData(senderID, `send ${amount} ${token}# ${message}`, privKey, receiverID, options) - .then(txid => resolve(txid)) - .catch(error => reject(error)) - }).catch(error => reject(error)) - }); - } - - function sendTokens_raw(privKey, receiverID, token, amount, utxo, vout, scriptPubKey) { - return new Promise((resolve, reject) => { - var trx = bitjs.transaction(); - trx.addinput(utxo, vout, scriptPubKey) - trx.addoutput(receiverID, floBlockchainAPI.sendAmt); - trx.addflodata(`send ${amount} ${token}#`); - var signedTxHash = trx.sign(privKey, 1); - floBlockchainAPI.broadcastTx(signedTxHash) - .then(txid => resolve([receiverID, txid])) - .catch(error => reject([receiverID, error])) - }) - } - - //bulk transfer tokens - tokenAPI.bulkTransferTokens = function (sender, privKey, token, receivers) { - return new Promise((resolve, reject) => { - if (typeof receivers !== 'object') - return reject("receivers must be object in format {receiver1: amount1, receiver2:amount2...}") - - let receiver_list = Object.keys(receivers), amount_list = Object.values(receivers); - let invalidReceivers = receiver_list.filter(id => !floCrypto.validateFloID(id)); - let invalidAmount = amount_list.filter(val => typeof val !== 'number' || val <= 0); - if (invalidReceivers.length) - return reject(`Invalid receivers: ${invalidReceivers}`); - else if (invalidAmount.length) - return reject(`Invalid amounts: ${invalidAmount}`); - - if (receiver_list.length == 0) - return reject("Receivers cannot be empty"); - - if (receiver_list.length == 1) { - let receiver = receiver_list[0], amount = amount_list[0]; - floTokenAPI.sendToken(privKey, amount, receiver, "", token) - .then(txid => resolve({ success: { [receiver]: txid } })) - .catch(error => reject(error)) - } else { - //check for token balance - floTokenAPI.getBalance(sender, token).then(token_balance => { - let total_token_amout = amount_list.reduce((a, e) => a + e, 0); - if (total_token_amout > token_balance) - return reject(`Insufficient ${token}# balance`); - - //split utxos - floBlockchainAPI.splitUTXOs(sender, privKey, receiver_list.length).then(split_txid => { - //wait for the split utxo to get confirmation - floBlockchainAPI.waitForConfirmation(split_txid).then(split_tx => { - //send tokens using the split-utxo - var scriptPubKey = split_tx.vout[0].scriptPubKey.hex; - let promises = []; - for (let i in receiver_list) - promises.push(sendTokens_raw(privKey, receiver_list[i], token, amount_list[i], split_txid, i, scriptPubKey)); - Promise.allSettled(promises).then(results => { - let success = Object.fromEntries(results.filter(r => r.status == 'fulfilled').map(r => r.value)); - let failed = Object.fromEntries(results.filter(r => r.status == 'rejected').map(r => r.reason)); - resolve({ success, failed }); - }) - }).catch(error => reject(error)) - }).catch(error => reject(error)) - }).catch(error => reject(error)) - } - - }) - } - - tokenAPI.getAllTxs = function (floID, token = DEFAULT.currency) { - return new Promise((resolve, reject) => { - fetch_api(`api/v1.0/getFloAddressTransactions?token=${token}&floAddress=${floID}`) - .then(result => resolve(result)) - .catch(error => reject(error)) - }) - } - - const util = tokenAPI.util = {}; - - util.parseTxData = function (txData) { - let parsedData = {}; - for (let p in txData.parsedFloData) - parsedData[p] = txData.parsedFloData[p]; - parsedData.sender = txData.transactionDetails.vin[0].addr; - for (let vout of txData.transactionDetails.vout) - if (vout.scriptPubKey.addresses[0] !== parsedData.sender) - parsedData.receiver = vout.scriptPubKey.addresses[0]; - parsedData.time = txData.transactionDetails.time; - return parsedData; - } - -})('object' === typeof module ? module.exports : window.floTokenAPI = {}); \ No newline at end of file diff --git a/index.html b/index.html index 4b775c5..e037c09 100644 --- a/index.html +++ b/index.html @@ -378,12 +378,15 @@ floGlobals.validCerts = new Map() function readTx() { return new Promise((resolve, reject) => { - floBlockchainAPI.readAllTxs('FFCpiaZi31TpbYw5q5VNk8qJMeDiTLgsrE').then(res => { - for (tx of res) { - const { vin, vout, time, floData, txid } = tx - if (!vin.some(i => i.addr === floGlobals.RM_CertificateIssuer_id)) continue; - if (!vout.some(o => [floGlobals.RMincorporationID, floGlobals.RIBC_id].includes(o.scriptPubKey.addresses[0]))) continue; - if (!floData.startsWith('CERTIFICATE OF')) continue; + floBlockchainAPI.readData(floGlobals.RM_CertificateIssuer_id, { + sentOnly: true, + tx: true, + receivers: [floGlobals.RMincorporationID, floGlobals.RIBC_id], + filter: d => d.startsWith('CERTIFICATE OF') + }).then(res => { + for (tx of res.items) { + const { time, txid } = tx; + const floData = tx.data; let name, floId, certType, certPara = '' let isNewer = true // check if certificates are of newer format diff --git a/btcOperator.js b/scripts/btcOperator.js similarity index 100% rename from btcOperator.js rename to scripts/btcOperator.js diff --git a/floBlockchainAPI.js b/scripts/floBlockchainAPI.js similarity index 100% rename from floBlockchainAPI.js rename to scripts/floBlockchainAPI.js diff --git a/floCrypto.js b/scripts/floCrypto.js similarity index 100% rename from floCrypto.js rename to scripts/floCrypto.js diff --git a/lib.js b/scripts/lib.js similarity index 100% rename from lib.js rename to scripts/lib.js