diff --git a/gui/EasyDEX-GUI b/gui/EasyDEX-GUI index b9b1283..88a8bcf 160000 --- a/gui/EasyDEX-GUI +++ b/gui/EasyDEX-GUI @@ -1 +1 @@ -Subproject commit b9b1283f55561064794a7ba58bc8ae4371b106fc +Subproject commit 88a8bcf78b2c8d5e400f8a58512195383dd4db8f diff --git a/main.js b/main.js index 7646286..e541cc6 100644 --- a/main.js +++ b/main.js @@ -20,11 +20,14 @@ const fsnode = require('fs'); const fs = require('fs-extra'); const Promise = require('bluebird'); const arch = require('arch'); +const bip39 = require('bip39'); if (osPlatform === 'linux') { process.env.ELECTRON_RUN_AS_NODE = true; } +process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true; + // GUI APP settings and starting gui on address http://120.0.0.1:17777 let shepherd = require('./routes/shepherd'); let guiapp = express(); @@ -124,8 +127,7 @@ process.once('loaded', () => { }); // silent errors -if (!appConfig.debug || - !appConfig.dev) { +if (!appConfig.dev) { process.on('uncaughtException', (err) => { shepherd.log(`${(new Date).toUTCString()} uncaughtException: ${err.message}`); shepherd.log(err.stack); @@ -185,7 +187,7 @@ function createAppCloseWindow() { appCloseWindow.setResizable(false); - appCloseWindow.loadURL(`http://${appConfig.host}:${appConfig.agamaPort}/gui/startup/app-closing.html`); + appCloseWindow.loadURL(appConfig.dev ? `http://${appConfig.host}:${appConfig.agamaPort}/gui/startup/app-closing.html` : `file://${__dirname}/gui/startup/app-closing.html`); appCloseWindow.webContents.on('did-finish-load', () => { setTimeout(() => { @@ -232,7 +234,7 @@ function createWindow(status, hideLoadingWindow) { shepherd.log(`guiapp and sockets.io are listening on port ${appConfig.agamaPort}`); shepherd.writeLog(`guiapp and sockets.io are listening on port ${appConfig.agamaPort}`); // start sockets.io - io.set('origins', appConfig.dev ? 'http://127.0.0.1:3000' : `http://127.0.0.1:${appConfig.agamaPort}`); // set origin + io.set('origins', appConfig.dev ? 'http://127.0.0.1:3000' : null); // set origin }); // initialise window @@ -246,15 +248,15 @@ function createWindow(status, hideLoadingWindow) { if (appConfig.dev) { mainWindow.loadURL('http://127.0.0.1:3000'); } else { - mainWindow.loadURL(`http://${appConfig.host}:${appConfig.agamaPort}/gui/EasyDEX-GUI/react/build`); + mainWindow.loadURL(`file://${__dirname}/gui/EasyDEX-GUI/react/build/index.html`); } shepherd.setIO(io); // pass sockets object to shepherd router shepherd.setVar('appBasicInfo', appBasicInfo); shepherd.setVar('appSessionHash', appSessionHash); - // load our index.html (i.e. easyDEX GUI) - shepherd.writeLog('show edex gui'); + // load our index.html (i.e. Agama GUI) + shepherd.writeLog('show agama gui'); mainWindow.appConfig = appConfig; mainWindow.appConfigSchema = shepherd.appConfigSchema; mainWindow.arch = arch(); @@ -288,15 +290,19 @@ function createWindow(status, hideLoadingWindow) { firstLoginPH: null, secondaryLoginPH: null, }; - mainWindow.nnVoteChain = 'VOTE2018'; mainWindow.checkStringEntropy = shepherd.checkStringEntropy; + mainWindow.pinAccess = false; + mainWindow.bip39 = bip39; + mainWindow.isWatchOnly = shepherd.isWatchOnly; + mainWindow.setPubkey = shepherd.setPubkey; + mainWindow.getPubkeys = shepherd.getPubkeys; - /*for (let i = 0; i < process.argv.length; i++) { + for (let i = 0; i < process.argv.length; i++) { if (process.argv[i].indexOf('nvote') > -1) { - console.log(`notary node elections chain ${process.argv[i].replace('nvote=', '')}`); - mainWindow.nnVoteChain = process.argv[i].replace('nvote=', ''); + console.log(`enable notary node elections ui`); + mainWindow.nnVoteChain = 'VOTE2018'; } - }*/ + } } else { mainWindow = new BrowserWindow({ width: 500, @@ -314,7 +320,7 @@ function createWindow(status, hideLoadingWindow) { shepherd.log(`guiapp and sockets.io are listening on port ${appConfig.agamaPort + 1}`); shepherd.writeLog(`guiapp and sockets.io are listening on port ${appConfig.agamaPort + 1}`); }); - mainWindow.loadURL(`http://${appConfig.host}:${appConfig.agamaPort + 1}/gui/startup/agama-instance-error.html`); + mainWindow.loadURL(appConfig.dev ? `http://${appConfig.host}:${appConfig.agamaPort + 1}/gui/startup/agama-instance-error.html` : `file://${__dirname}/gui/startup/agama-instance-error.html`); shepherd.log('another agama app is already running'); } @@ -485,4 +491,4 @@ function formatBytes(bytes, decimals) { const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`; -} +} \ No newline at end of file diff --git a/package.json b/package.json index eadb790..23bbbd0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "agama-app", "productName": "Agama", - "version": "0.2.32", + "version": "0.2.35", "description": "Agama Wallet Desktop App", "main": "main.js", "scripts": { @@ -31,11 +31,12 @@ "arch": "^2.1.0", "async": "^2.6.0", "bigi": "^1.4.2", - "bip39": "^2.4.0", + "bip39": "^2.5.0", "bitcoinforksjs-lib": "git://github.com/SuperNETorg/bitcoinjs-lib#opt-in-bitcoincash-sighash", "bitcoinjs-lib": "git://github.com/SuperNETorg/bitcoinjs-lib", - "bitcoinjs-lib-zcash": "git://github.com/pbca26/bitcoinjs-lib#zcash", "bitcoinjs-lib-pos": "git://github.com/KomodoPlatform/bitcoinjs-lib-pos", + "bitcoinjs-lib-zcash": "git://github.com/pbca26/bitcoinjs-lib#zcash", + "tx-decoder": "git://github.com/pbca26/tx-decoder", "bluebird": "^3.4.7", "body-parser": "^1.15.2", "buffer-reverse": "^1.0.1", @@ -46,9 +47,10 @@ "fs-extra": "^4.0.2", "graceful-fs": "^4.1.11", "js-sha256": "^0.7.1", + "lz-string": "^1.4.4", "marketmaker": "git://github.com/pbca26/marketmaker", "nodejs-aes256": "^1.0.1", - "passwd-strength": "https://github.com/pbca26/passwd-strength", + "passwd-strength": "git+https://github.com/pbca26/passwd-strength.git", "portscanner": "^2.1.1", "ps-node": "^0.1.5", "remote-file-size": "^3.0.3", diff --git a/routes/electrumjs/electrumServers.js b/routes/electrumjs/electrumServers.js index ab6ebec..c8b11e9 100644 --- a/routes/electrumjs/electrumServers.js +++ b/routes/electrumjs/electrumServers.js @@ -1,4 +1,15 @@ let electrumServers = { + kv: { // !estimatefee + address: 'electrum1.cipig.net', + port: 10016, + proto: 'tcp', + txfee: 10000, + abbr: 'KV', + serverList: [ + 'electrum1.cipig.net:10016', + 'electrum2.cipig.net:10016' + ], + }, bntn: { // !estimatefee address: 'electrum1.cipig.net', port: 10026, @@ -280,113 +291,113 @@ let electrumServers = { ], }, dogecoin: { // !estimatefee - address: '173.212.225.176', - port: 50015, + address: 'electrum1.cipig.net', + port: 10060, proto: 'tcp', txfee: 100000000, abbr: 'DOGE', serverList: [ - '173.212.225.176:50015', - '136.243.45.140:50015' + 'electrum1.cipig.net:10060', + 'electrum2.cipig.net:10060' ], }, viacoin: { // !estimatefee - address: '173.212.225.176', - port: 50033, + address: 'electrum1.cipig.net', + port: 10067, proto: 'tcp', txfee: 100000, abbr: 'VIA', serverList: [ - '173.212.225.176:50033', - '136.243.45.140:50033' + 'electrum1.cipig.net:10067', + 'electrum2.cipig.net:10067' ], }, vertcoin: { - address: '173.212.225.176', - port: 50088, + address: 'electrum1.cipig.net', + port: 10071, proto: 'tcp', txfee: 100000, abbr: 'VTC', serverList: [ - '173.212.225.176:50088', - '136.243.45.140:50088' + 'electrum1.cipig.net:10071', + 'electrum2.cipig.net:10071' ], }, namecoin: { - address: '173.212.225.176', - port: 50036, + address: 'electrum1.cipig.net', + port: 10066, proto: 'tcp', txfee: 100000, abbr: 'NMC', serverList: [ - '173.212.225.176:50036', - '136.243.45.140:50036' + 'electrum1.cipig.net:10066', + 'electrum2.cipig.net:10066' ], }, monacoin: { // !estimatefee - address: '173.212.225.176', - port: 50002, + address: 'electrum1.cipig.net', + port: 10070, proto: 'tcp', txfee: 100000, abbr: 'MONA', serverList: [ - '173.212.225.176:50002', - '136.243.45.140:50002' + 'electrum1.cipig.net:10070', + 'electrum2.cipig.net:10070' ], }, litecoin: { - address: '173.212.225.176', - port: 50012, + address: 'electrum1.cipig.net', + port: 10065, proto: 'tcp', txfee: 100000, abbr: 'LTC', serverList: [ - '173.212.225.176:50012', - '136.243.45.140:50012' + 'electrum1.cipig.net:10065', + 'electrum2.cipig.net:10065' ], }, faircoin: { - address: '173.212.225.176', - port: 50005, + address: 'electrum1.cipig.net', + port: 10063, proto: 'tcp', txfee: 1000000, abbr: 'FAIR', serverList: [ - '173.212.225.176:50005', - '136.243.45.140:50005' + 'electrum1.cipig.net:10063', + 'electrum2.cipig.net:10063' ], }, dgb: { - address: '173.212.225.176', - port: 50022, + address: 'electrum1.cipig.net', + port: 10059, proto: 'tcp', txfee: 100000, abbr: 'DGB', serverList: [ - '173.212.225.176:50022', - '136.243.45.140:50022' + 'electrum1.cipig.net:10059', + 'electrum2.cipig.net:10059' ], }, dash: { - address: '173.212.225.176', - port: 50098, + address: 'electrum1.cipig.net', + port: 10061, proto: 'tcp', txfee: 10000, abbr: 'DASH', serverList: [ - '173.212.225.176:50098', - '136.243.45.140:50098' + 'electrum1.cipig.net:10061', + 'electrum2.cipig.net:10061' ], }, crown: { - address: '173.212.225.176', - port: 50041, + address: 'electrum1.cipig.net', + port: 10069, proto: 'tcp', txfee: 10000, abbr: 'CRW', serverList: [ - '173.212.225.176:50041', - '136.243.45.140:50041' + 'electrum1.cipig.net:10069', + 'electrum2.cipig.net:10069' ], }, btc: { @@ -395,6 +406,8 @@ let electrumServers = { proto: 'tcp', abbr: 'BTC', serverList: [ + 'electrum1.cipig.net:10000', + 'electrum2.cipig.net:10000', 'mooo.not.fyi:50011', 'e-x.not.fyi:50001', 'vps.hsmiths.com:50001', @@ -450,14 +463,14 @@ let electrumServers = { ], }, argentum: { // !estimatefee - address: '173.212.225.176', - port: 50081, + address: 'electrum1.cipig.net', + port: 10069, proto: 'tcp', txfee: 50000, abbr: 'ARG', serverList: [ - '173.212.225.176:50081', - '136.243.45.140:50081' + 'electrum1.cipig.net:10069', + 'electrum2.cipig.net:10069' ], }, chips: { // !estimatefee @@ -472,25 +485,25 @@ let electrumServers = { ], }, zec: { - address: '173.212.225.176', - port: 50032, + address: 'electrum1.cipig.net', + port: 10058, proto: 'tcp', txfee: 10000, abbr: 'ZEC', serverList: [ - '173.212.225.176:50032', - '136.243.45.140:50032' + 'electrum1.cipig.net:10058', + 'electrum2.cipig.net:10058' ], }, hush: { - address: '173.212.225.176', - port: 50013, + address: 'electrum1.cipig.net', + port: 10064, proto: 'tcp', txfee: 10000, abbr: 'HUSH', serverList: [ - '173.212.225.176:50013', - '136.243.45.140:50013' + 'electrum1.cipig.net:10064', + 'electrum2.cipig.net:10064' ], }, sng: { // ssl 50002 @@ -581,6 +594,188 @@ let electrumServers = { 's2.qtum.info:50001' ], }, + // TODO: figure out fees + btcp: { // multisig? + address: 'electrum.btcprivate.org', + port: 5222, + proto: 'tcp', + txfee: 10000, + abbr: 'BTCP', + serverList: [ + 'electrum.btcprivate.org:5222', + 'electrum2.btcprivate.org:5222' + ], + }, + emc2: { + address: 'electrum1.cipig.net', + port: 10062, + proto: 'tcp', + txfee: 100000, + abbr: 'EMC2', + serverList: [ + 'electrum1.cipig.net:10062', + 'electrum2.cipig.net:10062' + ], + }, + bcbc: { + address: 'bsmn0.cleanblockchain.io', + port: 50001, + proto: 'tcp', + txfee: 10000, + abbr: 'BCBC', + serverList: [ + 'bsmn0.cleanblockchain.io:50001', + 'bsmn1.cleanblockchain.io:50001' + ], + }, + zen: { + txfee: 10000, + abbr: 'ZEN', + }, + xzc: { + txfee: 10000, + abbr: 'XZC', + }, + game: { + txfee: 100000, + abbr: 'GAME', + }, + iop: { + txfee: 10000, + abbr: 'IOP', + }, + sys: { + txfee: 10000, + abbr: 'SYS', + }, + bta: { + txfee: 100000, + abbr: 'BTA', + }, + erc: { + txfee: 10000, + abbr: 'ERC', + }, + lbc: { + txfee: 1000, + abbr: 'LBC', + }, + bsd: { + txfee: 10000, + abbr: 'BSD', + }, + gbx: { + txfee: 10000, + abbr: 'GBX', + }, + efl: { + txfee: 100000, + abbr: 'EFL', + }, + xwc: { + txfee: 10000, + abbr: 'XWC', + }, + vivo: { + txfee: 10000, + abbr: 'VIVO', + }, + xvg: { + txfee: 10000, + abbr: 'XVG', + }, + xvc: { + txfee: 10000, + abbr: 'XVC', + }, + uno: { + txfee: 10000, + abbr: 'UNO', + }, + smart: { + txfee: 10000, + abbr: 'SMART', + }, + rdd: { + txfee: 10000, + abbr: 'RDD', + }, + pivx: { + txfee: 10000, + abbr: 'PIVX', + }, + omni: { + txfee: 10000, + abbr: 'OMNI', + }, + ok: { + txfee: 10000, + abbr: 'OK', + }, + neos: { + txfee: 10000, + abbr: 'NEOS', + }, + nav: { + txfee: 10000, + abbr: 'NAV', + }, + mnx: { + txfee: 10000, + abbr: 'MNX', + }, + lcc: { + txfee: 10000, + abbr: 'LCC', + }, + nlg: { + txfee: 10000, + abbr: 'NLG', + }, + fjc: { + txfee: 10000, + abbr: 'FJC', + }, + flash: { + txfee: 10000, + abbr: 'FLASH', + }, + ftc: { + proto: 'tcp', + txfee: 10000, + }, + excl: { + txfee: 10000, + abbr: 'EXCL', + }, + dmd: { + proto: 'tcp', + txfee: 10000, + }, + crave: { + txfee: 10000, + abbr: 'CRAVE', + }, + club: { + txfee: 10000, + abbr: 'CLUB', + }, + clam: { + txfee: 10000, + abbr: 'CLAM', + }, + bca: { + txfee: 10000, + abbr: 'BCA', + }, + aur: { + txfee: 10000, + abbr: 'AUR', + }, + acc: { + txfee: 10000, + abbr: 'ACC', + }, // insight aby: { address: 'http://explorer.artbyte.me/api/', @@ -620,7 +815,7 @@ electrumServers.crw = electrumServers.crown; electrumServers.fair = electrumServers.faircoin; electrumServers.arg = electrumServers.argentum; electrumServers.ltc = electrumServers.litecoin; -electrumServers.mona = electrumServers.litecoin; +electrumServers.mona = electrumServers.monacoin; electrumServers.nmc = electrumServers.namecoin; electrumServers.vtc = electrumServers.vertcoin; electrumServers.via = electrumServers.viacoin; diff --git a/routes/electrumjs/electrumjs.networks.js b/routes/electrumjs/electrumjs.networks.js index fb63fd0..b1ad7d6 100644 --- a/routes/electrumjs/electrumjs.networks.js +++ b/routes/electrumjs/electrumjs.networks.js @@ -92,6 +92,7 @@ networks.xzc = { scriptHash: 0x07, wif: 0x52 + 128, dustThreshold: 1000, // https://github.com/zcoinofficial/zcoin/blob/f755f95a036eedfef7c96bcfb6769cb79278939f/src/main.h#L59 + isZcash: true, }; // https://raw.githubusercontent.com/jl777/komodo/beta/src/chainparams.cpp @@ -105,6 +106,7 @@ networks.komodo = { scriptHash: 0x55, wif: 0xbc, dustThreshold: 1000, + isZcash: true, }; networks.viacoin = { @@ -262,6 +264,7 @@ networks.zcash = { scriptHash: 0x1cbd, wif: 0x80, dustThreshold: 1000, + isZcash: true, }; networks.hush = { @@ -274,6 +277,7 @@ networks.hush = { scriptHash: 0x1cbd, wif: 0x80, dustThreshold: 1000, + isZcash: true, }; networks.zcl = { @@ -286,6 +290,7 @@ networks.zcl = { scriptHash: 0x1cbd, wif: 0x80, dustThreshold: 1000, + isZcash: true, }; networks.sng = { @@ -298,6 +303,7 @@ networks.sng = { scriptHash: 0x1c2D, wif: 0x80, dustThreshold: 1000, + isZcash: true, }; networks.xmy = { @@ -358,6 +364,7 @@ networks.btcz = { scriptHash: 0x1cbd, wif: 0x80, dustThreshold: 1000, + isZcash: true, }; networks.grs = { // fails to gen a proper addr @@ -406,6 +413,7 @@ networks.vot = { scriptHash: 0x1cbd, wif: 0x80, dustThreshold: 1000, + isZcash: true, }; networks.iop = { @@ -455,6 +463,7 @@ networks.zen = { // new address type scriptHash: 0x2086, wif: 0x80, dustThreshold: 1000, + isZcash: true, }; networks.sys = { // zec based @@ -467,6 +476,7 @@ networks.sys = { // zec based scriptHash: 0x5, wif: 0x80, dustThreshold: 1000, + isZcash: true, }; networks.emc2 = { @@ -632,6 +642,7 @@ networks.smart = { // wrong address generated scriptHash: 0x12, wif: 0xBF, dustThreshold: 1000, + isZcash: true, }; // https://github.com/reddcoin-project/reddcoin/blob/master/src/chainparams.cpp#L79 @@ -891,6 +902,18 @@ networks.acc = { dustThreshold: 1000, }; +networks.bcbc = { + messagePrefix: '\x19Bitcoin CBC Signed Message:\n', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4, + }, + pubKeyHash: 0x0, + scriptHash: 0x5, + wif: 0x80, + dustThreshold: 1000, +}; + networks.btc = networks.bitcoin; networks.crw = networks.crown; networks.dgb = networks.digibyte; diff --git a/routes/electrumjs/electrumjs.txdecoder-2bytes.js b/routes/electrumjs/electrumjs.txdecoder-2bytes.js index f96199a..f59d8d1 100644 --- a/routes/electrumjs/electrumjs.txdecoder-2bytes.js +++ b/routes/electrumjs/electrumjs.txdecoder-2bytes.js @@ -1,7 +1,8 @@ /* MIT License -Copyright (c) 2017 Yuki Akiyama, SuperNET +Copyright (c) 2017 Yuki Akiyama +Copyright (c) 2017 - 2018 SuperNET Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -23,6 +24,26 @@ SOFTWARE. */ var bitcoin = require('bitcoinjs-lib-zcash'); +// zcash fallback +const Buffer = require('safe-buffer').Buffer; +const { + readSlice, + readInt32, + readUInt32, +} = require('tx-decoder/src/buffer-utils'); +const { + compose, + addProp, +} = require('tx-decoder/src/compose'); +const { + readInputs, + readInput, + readOutput, +} = require('tx-decoder/src/tx-decoder'); +const crypto = require('crypto'); +const _sha256 = (data) => { + return crypto.createHash('sha256').update(data).digest(); +}; var decodeFormat = function(tx) { var result = { @@ -39,7 +60,7 @@ var decodeInput = function(tx) { tx.ins.forEach(function(input, n) { var vin = { - txid: input.hash.reverse().toString('hex'), + txid: !input.hash.reverse ? input.hash : input.hash.reverse().toString('hex'), n: input.index, script: bitcoin.script.toASM(input.script), sequence: input.sequence, @@ -102,7 +123,41 @@ var TxDecoder = module.exports = function(rawtx, network) { outputs: decodeOutput(_tx, network), }; } catch (e) { - return false; + if (network.isZcash) { + console.log('z tx decode fallback'); + + const buffer = Buffer.from(rawtx, 'hex'); + + const decodeTx = buffer => ( + compose([ + addProp('version', readInt32), // 4 bytes + addProp('ins', readInputs(readInput)), // 1-9 bytes (VarInt), Input counter; Variable, Inputs + addProp('outs', readInputs(readOutput)), // 1-9 bytes (VarInt), Output counter; Variable, Outputs + addProp('locktime', readUInt32) // 4 bytes + ])({}, buffer) + ); + + const readHash = buffer => { + const [res, bufferLeft] = readSlice(32)(_sha256(_sha256(buffer))); + const hash = Buffer.from(res, 'hex').reverse().toString('hex'); + return [hash, bufferLeft]; + }; + + let decodedtx = decodeTx(buffer); + decodedtx[0].getId = () => { + return readHash(buffer)[0]; + }; + + return { + tx: decodedtx[0], + network: network, + format: decodeFormat(decodedtx[0]), + inputs: !decodedtx[0].ins.length ? [{ txid: '0000000000000000000000000000000000000000000000000000000000000000' }] : decodeInput(decodedtx[0]), + outputs: decodeOutput(decodedtx[0], network), + }; + } else { + return false; + } } } diff --git a/routes/electrumjs/electrumjs.txdecoder.js b/routes/electrumjs/electrumjs.txdecoder.js index f956249..14204d5 100644 --- a/routes/electrumjs/electrumjs.txdecoder.js +++ b/routes/electrumjs/electrumjs.txdecoder.js @@ -1,7 +1,8 @@ /* MIT License -Copyright (c) 2017 Yuki Akiyama, SuperNET +Copyright (c) 2017 Yuki Akiyama +Copyright (c) 2017 - 2018 SuperNET Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -23,6 +24,26 @@ SOFTWARE. */ var bitcoin = require('bitcoinjs-lib'); +// zcash fallback +const Buffer = require('safe-buffer').Buffer; +const { + readSlice, + readInt32, + readUInt32, +} = require('tx-decoder/src/buffer-utils'); +const { + compose, + addProp, +} = require('tx-decoder/src/compose'); +const { + readInputs, + readInput, + readOutput, +} = require('tx-decoder/src/tx-decoder'); +const crypto = require('crypto'); +const _sha256 = (data) => { + return crypto.createHash('sha256').update(data).digest(); +}; var decodeFormat = function(tx) { var result = { @@ -39,7 +60,7 @@ var decodeInput = function(tx) { tx.ins.forEach(function(input, n) { var vin = { - txid: input.hash.reverse().toString('hex'), + txid: !input.hash.reverse ? input.hash : input.hash.reverse().toString('hex'), n: input.index, script: bitcoin.script.toASM(input.script), sequence: input.sequence, @@ -102,7 +123,41 @@ var TxDecoder = module.exports = function(rawtx, network) { outputs: decodeOutput(_tx, network), }; } catch (e) { - return false; + if (network.isZcash) { + console.log('z tx decode fallback'); + + const buffer = Buffer.from(rawtx, 'hex'); + + const decodeTx = buffer => ( + compose([ + addProp('version', readInt32), // 4 bytes + addProp('ins', readInputs(readInput)), // 1-9 bytes (VarInt), Input counter; Variable, Inputs + addProp('outs', readInputs(readOutput)), // 1-9 bytes (VarInt), Output counter; Variable, Outputs + addProp('locktime', readUInt32) // 4 bytes + ])({}, buffer) + ); + + const readHash = buffer => { + const [res, bufferLeft] = readSlice(32)(_sha256(_sha256(buffer))) + const hash = Buffer.from(res, 'hex').reverse().toString('hex') + return [hash, bufferLeft] + }; + + let decodedtx = decodeTx(buffer); + decodedtx[0].getId = () => { + return readHash(buffer)[0]; + }; + + return { + tx: decodedtx[0], + network: network, + format: decodeFormat(decodedtx[0]), + inputs: !decodedtx[0].ins.length ? [{ txid: '0000000000000000000000000000000000000000000000000000000000000000' }] : decodeInput(decodedtx[0]), + outputs: decodeOutput(decodedtx[0], network), + }; + } else { + return false; + } } } diff --git a/routes/shepherd.js b/routes/shepherd.js index f6ec72d..c3e8b07 100644 --- a/routes/shepherd.js +++ b/routes/shepherd.js @@ -37,6 +37,9 @@ shepherd.rpcConf = {}; shepherd.appRuntimeLog = []; shepherd.appRuntimeSPVLog = []; shepherd.lockDownAddCoin = false; +shepherd.isWatchOnly = false; + +shepherd.staking = {}; // dex cache shepherd.mmupass = null; @@ -60,7 +63,6 @@ shepherd.electrumCoins = { auth: false, }; shepherd.electrumKeys = {}; - shepherd.electrumCache = {}; shepherd.electrumJSCore = require('./electrumjs/electrumjs.core.js'); diff --git a/routes/shepherd/addCoinShortcuts.js b/routes/shepherd/addCoinShortcuts.js index 79d2249..a2a7906 100644 --- a/routes/shepherd/addCoinShortcuts.js +++ b/routes/shepherd/addCoinShortcuts.js @@ -21,19 +21,30 @@ module.exports = (shepherd) => { } shepherd.startKMDNative = (selection, isManual) => { - if (isManual) { - shepherd.kmdMainPassiveMode = true; - } - - if (selection === 'KMD') { - const herdData = { - 'ac_name': 'komodod', - 'ac_options': [ - '-daemon=0', - '-addnode=78.47.196.146', - ], - }; - + let herdData; + const acHerdData = { + REVS: { + name: 'REVS', + seedNode: '78.47.196.146', + supply: 1300000, + }, + JUMBLR: { + name: 'JUMBLR', + seedNode: '78.47.196.146', + supply: 999999, + }, + MNZ: { + name: 'MNZ', + seedNode: '78.47.196.146', + supply: 257142858, + }, + BTCH: { + name: 'BTCH', + seedNode: '78.47.196.146', + supply: 20998641, + }, + }; + const httpRequest = () => { const options = { url: `http://127.0.0.1:${shepherd.appConfig.agamaPort}/shepherd/herd`, method: 'POST', @@ -48,157 +59,49 @@ module.exports = (shepherd) => { }; request(options, (error, response, body) => { - if (response && - response.statusCode && - response.statusCode === 200) { - //resolve(body); - } else { - //resolve(body); - } + // resolve(body); }); - } else if (selection === 'REVS') { - const herdData = { - 'ac_name': 'REVS', - 'ac_options': [ - '-daemon=0', - '-server', - `-ac_name=REVS`, - '-addnode=78.47.196.146', - '-ac_supply=1300000' - ] - }; + }; - const options = { - url: `http://127.0.0.1:${shepherd.appConfig.agamaPort}/shepherd/herd`, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - herd: 'komodod', - options: herdData, - token: shepherd.appSessionHash, - }), - }; - - request(options, (error, response, body) => { - if (response && - response.statusCode && - response.statusCode === 200) { - //resolve(body); - } else { - //resolve(body); - } - }); - } else if (selection === 'JUMRLR') { - const herdData = { - 'ac_name': 'JUMRLR', - 'ac_options': [ - '-daemon=0', - '-server', - `-ac_name=JUMRLR`, - '-addnode=78.47.196.146', - '-ac_supply=999999' - ] - }; - - const options = { - url: `http://127.0.0.1:${shepherd.appConfig.agamaPort}/shepherd/herd`, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - herd: 'komodod', - options: herdData, - token: shepherd.appSessionHash, - }), - }; + if (isManual) { + shepherd.kmdMainPassiveMode = true; + } - request(options, (error, response, body) => { - if (response && - response.statusCode && - response.statusCode === 200) { - //resolve(body); - } else { - //resolve(body); - } - }); - } else if (selection === 'MNZ') { - const herdData = { - 'ac_name': 'MNZ', + if (selection === 'KMD') { + herdData = { + 'ac_name': 'komodod', 'ac_options': [ '-daemon=0', - '-server', - `-ac_name=MNZ`, '-addnode=78.47.196.146', - '-ac_supply=257142858' - ] - }; - - const options = { - url: `http://127.0.0.1:${shepherd.appConfig.agamaPort}/shepherd/herd`, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - herd: 'komodod', - options: herdData, - token: shepherd.appSessionHash, - }), + ], }; - request(options, (error, response, body) => { - if (response && - response.statusCode && - response.statusCode === 200) { - //resolve(body); - } else { - //resolve(body); - } - }); - } else if (selection === 'BTCH') { - const herdData = { - 'ac_name': 'BTCH', + httpRequest(); + } else if ( + selection === 'REVS' || + selection === 'JUMRLR' || + selection === 'MNZ' || + selection === 'BTCH' + ) { + herdData = { + 'ac_name': acHerdData[selection].name, 'ac_options': [ '-daemon=0', '-server', - `-ac_name=BTCH`, - '-addnode=78.47.196.146', - '-ac_supply=20998641' - ] - }; - - const options = { - url: `http://127.0.0.1:${shepherd.appConfig.agamaPort}/shepherd/herd`, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - herd: 'komodod', - options: herdData, - token: shepherd.appSessionHash, - }), + `-ac_name=${acHerdData[selection].name}`, + `-addnode=${acHerdData[selection].seedNode}`, + `-ac_supply=${acHerdData[selection].supply}`, + ], }; - request(options, (error, response, body) => { - if (response && - response.statusCode && - response.statusCode === 200) { - //resolve(body); - } else { - //resolve(body); - } - }); + httpRequest(); } else { const herdData = [{ 'ac_name': 'komodod', 'ac_options': [ '-daemon=0', '-addnode=78.47.196.146', - ] + ], }, { 'ac_name': 'REVS', 'ac_options': [ @@ -206,8 +109,8 @@ module.exports = (shepherd) => { '-server', `-ac_name=REVS`, '-addnode=78.47.196.146', - '-ac_supply=1300000' - ] + '-ac_supply=1300000', + ], }, { 'ac_name': 'JUMBLR', 'ac_options': [ @@ -215,8 +118,8 @@ module.exports = (shepherd) => { '-server', `-ac_name=JUMBLR`, '-addnode=78.47.196.146', - '-ac_supply=999999' - ] + '-ac_supply=999999', + ], }]; for (let i = 0; i < herdData.length; i++) { @@ -235,13 +138,7 @@ module.exports = (shepherd) => { }; request(options, (error, response, body) => { - if (response && - response.statusCode && - response.statusCode === 200) { - //resolve(body); - } else { - //resolve(body); - } + // resolve(body); }); }, 100); } diff --git a/routes/shepherd/auth.js b/routes/shepherd/auth.js index 9c1ff73..fa7a907 100644 --- a/routes/shepherd/auth.js +++ b/routes/shepherd/auth.js @@ -14,12 +14,21 @@ module.exports = (shepherd) => { if (Object.keys(shepherd.electrumCoins).length > 1 && shepherd.electrumCoins.auth) { _status = true; - } else if (Object.keys(shepherd.electrumCoins).length === 1 && !shepherd.electrumCoins.auth) { + } else if ( + Object.keys(shepherd.electrumCoins).length === 1 && + !shepherd.electrumCoins.auth + ) { _status = true; } - } else if (Object.keys(shepherd.electrumCoins).length > 1 && shepherd.electrumCoins.auth) { + } else if ( + Object.keys(shepherd.electrumCoins).length > 1 && + shepherd.electrumCoins.auth + ) { _status = true; - } else if (Object.keys(shepherd.electrumCoins).length === 1 && !Object.keys(shepherd.coindInstanceRegistry).length) { + } else if ( + Object.keys(shepherd.electrumCoins).length === 1 && + !Object.keys(shepherd.coindInstanceRegistry).length + ) { _status = true; } @@ -50,5 +59,32 @@ module.exports = (shepherd) => { return passwdStrength(str) < 29 ? false : true; }; + shepherd.isWatchOnly = () => { + return shepherd.isWatchOnly; + }; + + shepherd.setPubkey = (seed, coin) => { + const { + pub, + pubHex, + } = shepherd.seedToWif(seed, 'komodo', true); + + shepherd.staking[coin] = { + pub, + pubHex, + }; + + shepherd.log(`pub key for ${coin} is set`); + shepherd.log(shepherd.staking[coin]); + }; + + shepherd.getPubkeys = () => { + return shepherd.staking; + }; + + shepherd.removePubkey = (coin) => { + delete shepherd.staking[coin]; + }; + return shepherd; }; \ No newline at end of file diff --git a/routes/shepherd/coindWalletKeys.js b/routes/shepherd/coindWalletKeys.js index b3c7b98..3fc4a57 100644 --- a/routes/shepherd/coindWalletKeys.js +++ b/routes/shepherd/coindWalletKeys.js @@ -13,7 +13,7 @@ module.exports = (shepherd) => { const chain = req.query.chain; // ref: https://gist.github.com/kendricktan/1e62495150ad236b38616d733aac4eb9 - let _walletDatLocation = chain === 'komodo' || chain === 'null' ? `${shepherd.komodoDir}/wallet.dat` : `${shepherd.komodoDir}/${chain}/wallet.dat`; + let _walletDatLocation = chain === 'komodo' || chain === 'KMD' || chain === 'null' ? `${shepherd.komodoDir}/wallet.dat` : `${shepherd.komodoDir}/${chain}/wallet.dat`; _walletDatLocation = chain === 'CHIPS' ? `${shepherd.chipsDir}/wallet.dat` : _walletDatLocation; try { diff --git a/routes/shepherd/daemonControl.js b/routes/shepherd/daemonControl.js index bf9d719..0a205fd 100644 --- a/routes/shepherd/daemonControl.js +++ b/routes/shepherd/daemonControl.js @@ -187,12 +187,14 @@ module.exports = (shepherd) => { change: '-pubkey=', datadir: '-datadir=', rescan: '-rescan', + gen: '-gen', }; let _customParam = ''; if (data.ac_custom_param === 'silent' || data.ac_custom_param === 'reindex' || - data.ac_custom_param === 'rescan') { + data.ac_custom_param === 'rescan' || + data.ac_custom_param === 'gen') { _customParam = ` ${_customParamDict[data.ac_custom_param]}`; } else if (data.ac_custom_param === 'change' && data.ac_custom_param_value) { _customParam = ` ${_customParamDict[data.ac_custom_param]}${data.ac_custom_param_value}`; @@ -359,14 +361,14 @@ module.exports = (shepherd) => { shepherd.log(`daemon param ${data.ac_custom_param}`); - shepherd.coindInstanceRegistry['CHIPS'] = true; + shepherd.coindInstanceRegistry.CHIPS = true; let _arg = `${_customParam}`; _arg = _arg.trim().split(' '); if (_arg && _arg.length > 1) { execFile(`${shepherd.chipsBin}`, _arg, { - maxBuffer: 1024 * 1000000 // 1000 mb + maxBuffer: 1024 * 1000000, // 1000 mb }, (error, stdout, stderr) => { shepherd.writeLog(`stdout: ${stdout}`); shepherd.writeLog(`stderr: ${stderr}`); @@ -464,7 +466,7 @@ module.exports = (shepherd) => { let _arg = `${data.ac_options.join(' ')}`; _arg = _arg.trim().split(' '); execFile(`${coindBin}`, _arg, { - maxBuffer: 1024 * 1000000 // 1000 mb + maxBuffer: 1024 * 1000000, // 1000 mb }, (error, stdout, stderr) => { shepherd.writeLog(`stdout: ${stdout}`); shepherd.writeLog(`stderr: ${stderr}`); @@ -651,7 +653,6 @@ module.exports = (shepherd) => { shepherd.writeLog(`append daemon conf err: ${err}`); shepherd.log(`append daemon conf err: ${err}`); } - // throw err; shepherd.log('rpcpassword: ADDED'); shepherd.writeLog('rpcpassword: ADDED'); }); @@ -678,7 +679,6 @@ module.exports = (shepherd) => { shepherd.writeLog(`append daemon conf err: ${err}`); shepherd.log(`append daemon conf err: ${err}`); } - // throw err; shepherd.log('rpcport: ADDED'); shepherd.writeLog('rpcport: ADDED'); }); @@ -754,7 +754,6 @@ module.exports = (shepherd) => { shepherd.writeLog(`append daemon conf err: ${err}`); shepherd.log(`append daemon conf err: ${err}`); } - // throw err; shepherd.log('addnode: ADDED'); shepherd.writeLog('addnode: ADDED'); }); diff --git a/routes/shepherd/dashboardUpdate.js b/routes/shepherd/dashboardUpdate.js index 1557db2..117a622 100644 --- a/routes/shepherd/dashboardUpdate.js +++ b/routes/shepherd/dashboardUpdate.js @@ -277,13 +277,7 @@ module.exports = (shepherd) => { }; request(options, (error, response, body) => { - if (response && - response.statusCode && - response.statusCode === 200) { - resolve(body); - } else { - resolve(body); - } + resolve(body); }); }); } diff --git a/routes/shepherd/debugLog.js b/routes/shepherd/debugLog.js index 9658f81..f2deab3 100644 --- a/routes/shepherd/debugLog.js +++ b/routes/shepherd/debugLog.js @@ -1,6 +1,7 @@ const path = require('path'); const _fs = require('graceful-fs'); const Promise = require('bluebird'); +const os = require('os'); module.exports = (shepherd) => { /* @@ -13,18 +14,19 @@ module.exports = (shepherd) => { let _ac = req.body.ac; let _lastNLines = req.body.lastLines; let _location; - - if (shepherd.os.platform() === 'darwin') { - shepherd.komodoDir = shepherd.appConfig.dataDir.length ? shepherd.appConfig.dataDir : `${process.env.HOME}/Library/Application Support/Komodo`; - } - - if (shepherd.os.platform() === 'linux') { - shepherd.komodoDir = shepherd.appConfig.dataDir.length ? shepherd.appConfig.dataDir : `${process.env.HOME}/.komodo`; - } - - if (shepherd.os.platform() === 'win32') { - shepherd.komodoDir = shepherd.appConfig.dataDir.length ? shepherd.appConfig.dataDir : `${process.env.APPDATA}/Komodo`; - shepherd.komodoDir = path.normalize(shepherd.komodoDir); + const _platform = os.platform(); + + switch (_platform) { + case 'darwin': + shepherd.komodoDir = shepherd.appConfig.dataDir.length ? shepherd.appConfig.dataDir : `${process.env.HOME}/Library/Application Support/Komodo`; + break; + case 'linux': + shepherd.komodoDir = shepherd.appConfig.dataDir.length ? shepherd.appConfig.dataDir : `${process.env.HOME}/.komodo`; + break; + case 'win32': + shepherd.komodoDir = shepherd.appConfig.dataDir.length ? shepherd.appConfig.dataDir : `${process.env.APPDATA}/Komodo`; + shepherd.komodoDir = path.normalize(shepherd.komodoDir); + break; } if (_herd === 'komodo') { @@ -97,44 +99,42 @@ module.exports = (shepherd) => { }); shepherd.readDebugLog = (fileLocation, lastNLines) => { - return new Promise( - (resolve, reject) => { - if (lastNLines) { - try { - _fs.access(fileLocation, shepherd.fs.constants.R_OK, (err) => { - if (err) { - shepherd.log(`error reading ${fileLocation}`); - shepherd.writeLog(`error reading ${fileLocation}`); - reject(`readDebugLog error: ${err}`); - } else { - shepherd.log(`reading ${fileLocation}`); - _fs.readFile(fileLocation, 'utf-8', (err, data) => { - if (err) { - shepherd.writeLog(`readDebugLog err: ${err}`); - shepherd.log(`readDebugLog err: ${err}`); - } - - const lines = data.trim().split('\n'); - let lastLine; - - if (lastNLines === 'all') { - lastLine = data.trim(); - } else { - lastLine = lines.slice(lines.length - lastNLines, lines.length).join('\n'); - } - - resolve(lastLine); - }); - } - }); - } catch (e) { - reject(`readDebugLog error: ${e}`); - } - } else { - reject('readDebugLog error: lastNLines param is not provided!'); + return new Promise((resolve, reject) => { + if (lastNLines) { + try { + _fs.access(fileLocation, shepherd.fs.constants.R_OK, (err) => { + if (err) { + shepherd.log(`error reading ${fileLocation}`); + shepherd.writeLog(`error reading ${fileLocation}`); + reject(`readDebugLog error: ${err}`); + } else { + shepherd.log(`reading ${fileLocation}`); + _fs.readFile(fileLocation, 'utf-8', (err, data) => { + if (err) { + shepherd.writeLog(`readDebugLog err: ${err}`); + shepherd.log(`readDebugLog err: ${err}`); + } + + const lines = data.trim().split('\n'); + let lastLine; + + if (lastNLines === 'all') { + lastLine = data.trim(); + } else { + lastLine = lines.slice(lines.length - lastNLines, lines.length).join('\n'); + } + + resolve(lastLine); + }); + } + }); + } catch (e) { + reject(`readDebugLog error: ${e}`); } + } else { + reject('readDebugLog error: lastNLines param is not provided!'); } - ); + }); }; return shepherd; diff --git a/routes/shepherd/elections.js b/routes/shepherd/elections.js index ac27e1c..192aabb 100644 --- a/routes/shepherd/elections.js +++ b/routes/shepherd/elections.js @@ -5,12 +5,12 @@ const Promise = require('bluebird'); module.exports = (shepherd) => { shepherd.elections = {}; - shepherd.hex2str = (hexx) => { - const hex = hexx.toString(); // force conversion + shepherd.hex2str = (hex) => { + const _hex = hex.toString(); // force conversion let str = ''; - for (let i = 0; i < hex.length; i += 2) { - str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + for (let i = 0; i < _hex.length; i += 2) { + str += String.fromCharCode(parseInt(_hex.substr(i, 2), 16)); } return str; @@ -167,7 +167,11 @@ module.exports = (shepherd) => { shepherd.get('/elections/listtransactions', (req, res, next) => { if (shepherd.checkToken(req.query.token)) { const network = req.query.network || shepherd.findNetworkObj(req.query.coin); - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[network].port, + shepherd.electrumServers[network].address, + shepherd.electrumServers[network].proto + ); // tcp or tls const type = req.query.type; const _address = req.query.address; @@ -299,7 +303,10 @@ module.exports = (shepherd) => { .then((res) => { if (decodedTx.outputs[i].scriptPubKey.addresses[0] === _address) { _candidate.amount = decodedTx.outputs[i].value; - } else if (decodedTx.outputs[i].scriptPubKey.addresses[0] !== _address && decodedTx.outputs[i].scriptPubKey.asm.indexOf('OP_RETURN') === -1) { + } else if ( + decodedTx.outputs[i].scriptPubKey.addresses[0] !== _address && + decodedTx.outputs[i].scriptPubKey.asm.indexOf('OP_RETURN') === -1 + ) { _candidate.address = decodedTx.outputs[i].scriptPubKey.addresses[0]; _candidate.region = _region; _candidate.timestamp = blockInfo.timestamp; diff --git a/routes/shepherd/electrum/auth.js b/routes/shepherd/electrum/auth.js index 182a52b..9091838 100644 --- a/routes/shepherd/electrum/auth.js +++ b/routes/shepherd/electrum/auth.js @@ -14,14 +14,17 @@ module.exports = (shepherd) => { let keys; let isWif = false; - if (req.body.seed.match('^[a-zA-Z0-9]{34}$') && + if (_seed.match('^[a-zA-Z0-9]{34}$') && shepherd.appConfig.experimentalFeatures) { shepherd.log('watchonly pub addr'); shepherd.electrumKeys[_abbr] = { - priv: req.body.seed, - pub: req.body.seed, + priv: _seed, + pub: _seed, }; + shepherd.isWatchOnly = true; } else { + shepherd.isWatchOnly = false; + try { bs58check.decode(_seed); isWif = true; @@ -39,7 +42,11 @@ module.exports = (shepherd) => { break; } } else { - keys = shepherd.seedToWif(_seed, shepherd.findNetworkObj(_abbr), req.body.iguana); + keys = shepherd.seedToWif( + _seed, + shepherd.findNetworkObj(_abbr), + req.body.iguana, + ); } shepherd.electrumKeys[_abbr] = { diff --git a/routes/shepherd/electrum/balance.js b/routes/shepherd/electrum/balance.js index b580c5a..415e400 100644 --- a/routes/shepherd/electrum/balance.js +++ b/routes/shepherd/electrum/balance.js @@ -47,7 +47,12 @@ module.exports = (shepherd) => { // decode tx const _network = shepherd.getNetworkData(network); - const decodedTx = shepherd.electrumJSTxDecoder(_rawtxJSON, network, _network, shepherd.electrumServers[network].proto === 'insight'); + const decodedTx = shepherd.electrumJSTxDecoder( + _rawtxJSON, + network, + _network, + shepherd.electrumServers[network].proto === 'insight' + ); if (decodedTx && decodedTx.format && diff --git a/routes/shepherd/electrum/block.js b/routes/shepherd/electrum/block.js index 5ac9a3c..979bb7a 100644 --- a/routes/shepherd/electrum/block.js +++ b/routes/shepherd/electrum/block.js @@ -24,7 +24,11 @@ module.exports = (shepherd) => { shepherd.electrumGetBlockInfo = (height, network) => { return new Promise((resolve, reject) => { - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[network].port, + shepherd.electrumServers[network].address, + shepherd.electrumServers[network].proto + ); // tcp or tls ecl.connect(); ecl.blockchainBlockGetHeader(height) @@ -61,7 +65,11 @@ module.exports = (shepherd) => { shepherd.electrumGetCurrentBlock = (network) => { return new Promise((resolve, reject) => { - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[network].port, + shepherd.electrumServers[network].address, + shepherd.electrumServers[network].proto + ); // tcp or tls ecl.connect(); ecl.blockchainNumblocksSubscribe() diff --git a/routes/shepherd/electrum/btcFees.js b/routes/shepherd/electrum/btcFees.js index 25f25be..b42293c 100644 --- a/routes/shepherd/electrum/btcFees.js +++ b/routes/shepherd/electrum/btcFees.js @@ -35,7 +35,11 @@ module.exports = (shepherd) => { if (shepherd.checkToken(req.query.token)) { if (checkTimestamp(btcFees.lastUpdated) > BTC_FEES_MIN_ELAPSED_TIME) { const _randomServer = shepherd.electrumServers.btc.serverList[getRandomIntInclusive(0, shepherd.electrumServers.btc.serverList.length - 1)].split(':'); - const ecl = new shepherd.electrumJSCore(_randomServer[1], _randomServer[0], 'tcp'); + const ecl = new shepherd.electrumJSCore( + _randomServer[1], + _randomServer[0], + 'tcp' + ); let _btcFeeEstimates = []; console.log(`btc fees server ${_randomServer.join(':')}`); @@ -56,12 +60,7 @@ module.exports = (shepherd) => { .then(result => { ecl.close(); - if (result && - result.length) { - btcFees.electrum = _btcFeeEstimates; - } else { - btcFees.electrum = 'error'; - } + btcFees.electrum = result && result.length ? _btcFeeEstimates : 'error'; let options = { url: `https://bitcoinfees.earn.com/api/v1/fees/recommended`, diff --git a/routes/shepherd/electrum/coins.js b/routes/shepherd/electrum/coins.js index 295fadb..6dca0dd 100644 --- a/routes/shepherd/electrum/coins.js +++ b/routes/shepherd/electrum/coins.js @@ -15,7 +15,7 @@ module.exports = (shepherd) => { max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; // the maximum is inclusive and the minimum is inclusive - } + }; let randomServer; // pick a random server to communicate with @@ -43,7 +43,7 @@ module.exports = (shepherd) => { port: randomServer ? randomServer.port : shepherd.electrumServers[key].port, }, serverList: shepherd.electrumServers[key].serverList ? shepherd.electrumServers[key].serverList : 'none', - txfee: 'calculated' /*shepherd.electrumServers[key].txfee*/, + txfee: key === 'btc' ? 'calculated' : shepherd.electrumServers[key].txfee, }; shepherd.log(`default ${coin} electrum server ${shepherd.electrumServers[key].address + ':' + shepherd.electrumServers[key].port}`, true); diff --git a/routes/shepherd/electrum/createtx-multi.js b/routes/shepherd/electrum/createtx-multi.js index 92b91ad..8224e1f 100644 --- a/routes/shepherd/electrum/createtx-multi.js +++ b/routes/shepherd/electrum/createtx-multi.js @@ -15,16 +15,20 @@ module.exports = (shepherd) => { // TODO: 1) unconf output(s) error message // 2) check targets integrity const network = req.body.network || shepherd.findNetworkObj(req.body.coin); - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[network].port, + shepherd.electrumServers[network].address, + shepherd.electrumServers[network].proto + ); // tcp or tls const initTargets = JSON.parse(JSON.stringify(req.body.targets)); - let targets = req.body.targets; const changeAddress = req.body.change; const push = req.body.push; const opreturn = req.body.opreturn; const btcFee = req.body.btcfee ? Number(req.body.btcfee) : null; let fee = shepherd.electrumServers[network].txfee; let wif = req.body.wif; - + let targets = req.body.targets; + if (req.body.gui) { wif = shepherd.electrumKeys[req.body.coin].priv; } @@ -40,7 +44,13 @@ module.exports = (shepherd) => { shepherd.log('electrum createrawtx =>', true); ecl.connect(); - shepherd.listunspent(ecl, changeAddress, network, true, req.body.verify === 'true' ? true : null) + shepherd.listunspent( + ecl, + changeAddress, + network, + true, + req.body.verify === 'true' ? true : null + ) .then((utxoList) => { ecl.close(); @@ -96,7 +106,11 @@ module.exports = (shepherd) => { // default coin selection algo blackjack with fallback to accumulative // make a first run, calc approx tx fee // if ins and outs are empty reduce max spend by txfee - const firstRun = coinSelect(utxoListFormatted, targets, btcFee ? btcFee : 0); + const firstRun = coinSelect( + utxoListFormatted, + targets, + btcFee ? btcFee : 0 + ); let inputs = firstRun.inputs; let outputs = firstRun.outputs; @@ -119,7 +133,11 @@ module.exports = (shepherd) => { shepherd.log('coinselect adjusted targets =>', true); shepherd.log(targets, true); - const secondRun = coinSelect(utxoListFormatted, targets, 0); + const secondRun = coinSelect( + utxoListFormatted, + targets, + 0 + ); inputs = secondRun.inputs; outputs = secondRun.outputs; fee = fee ? fee : secondRun.fee; @@ -333,7 +351,11 @@ module.exports = (shepherd) => { res.end(JSON.stringify(successObj)); } else { - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[network].port, + shepherd.electrumServers[network].address, + shepherd.electrumServers[network].proto + ); // tcp or tls ecl.connect(); ecl.blockchainTransactionBroadcast(_rawtx) @@ -451,7 +473,11 @@ module.exports = (shepherd) => { for (let i = 0; i < sendTo.length; i++) { if (shepherd.isPos(network)) { - tx.addOutput(sendTo[i].address, Number(sendTo[i].value), shepherd.getNetworkData(network)); + tx.addOutput( + sendTo[i].address, + Number(sendTo[i].value), + shepherd.getNetworkData(network) + ); } else { tx.addOutput(sendTo[i].address, Number(sendTo[i].value)); } @@ -459,7 +485,11 @@ module.exports = (shepherd) => { if (changeValue > 0) { if (shepherd.isPos(network)) { - tx.addOutput(changeAddress, Number(changeValue), shepherd.getNetworkData(network)); + tx.addOutput( + changeAddress, + Number(changeValue), + shepherd.getNetworkData(network) + ); } else { tx.addOutput(changeAddress, Number(changeValue)); } @@ -492,7 +522,11 @@ module.exports = (shepherd) => { for (let i = 0; i < utxo.length; i++) { if (shepherd.isPos(network)) { - tx.sign(shepherd.getNetworkData(network), i, key); + tx.sign( + shepherd.getNetworkData(network), + i, + key + ); } else { tx.sign(i, key); } diff --git a/routes/shepherd/electrum/createtx-split.js b/routes/shepherd/electrum/createtx-split.js index bce7cac..58698d6 100644 --- a/routes/shepherd/electrum/createtx-split.js +++ b/routes/shepherd/electrum/createtx-split.js @@ -35,7 +35,11 @@ module.exports = (shepherd) => { for (let i = 0; i < targets.length; i++) { if (shepherd.isPos(network)) { - tx.addOutput(outputAddress, Number(targets[i]), shepherd.getNetworkData(network)); + tx.addOutput( + outputAddress, + Number(targets[i]), + shepherd.getNetworkData(network) + ); } else { tx.addOutput(outputAddress, Number(targets[i])); } @@ -43,7 +47,11 @@ module.exports = (shepherd) => { if (Number(change) > 0) { if (shepherd.isPos(network)) { - tx.addOutput(changeAddress, Number(change), shepherd.getNetworkData(network)); + tx.addOutput( + changeAddress, + Number(change), + shepherd.getNetworkData(network) + ); } else { shepherd.log(`change ${change}`, true); tx.addOutput(changeAddress, Number(change)); @@ -59,7 +67,11 @@ module.exports = (shepherd) => { for (let i = 0; i < utxo.length; i++) { if (shepherd.isPos(network)) { - tx.sign(shepherd.getNetworkData(network), i, key); + tx.sign( + shepherd.getNetworkData(network), + i, + key + ); } else { tx.sign(i, key); } diff --git a/routes/shepherd/electrum/createtx.js b/routes/shepherd/electrum/createtx.js index e824d0f..9705f6b 100644 --- a/routes/shepherd/electrum/createtx.js +++ b/routes/shepherd/electrum/createtx.js @@ -78,14 +78,22 @@ module.exports = (shepherd) => { } if (shepherd.isPos(network)) { - tx.addOutput(sendTo, Number(spendValue), shepherd.getNetworkData(network)); + tx.addOutput( + sendTo, + Number(spendValue), + shepherd.getNetworkData(network) + ); } else { tx.addOutput(sendTo, Number(spendValue)); } if (changeValue > 0) { if (shepherd.isPos(network)) { - tx.addOutput(changeAddress, Number(changeValue), shepherd.getNetworkData(network)); + tx.addOutput( + changeAddress, + Number(changeValue), + shepherd.getNetworkData(network) + ); } else { tx.addOutput(changeAddress, Number(changeValue)); } @@ -114,7 +122,11 @@ module.exports = (shepherd) => { for (let i = 0; i < utxo.length; i++) { if (shepherd.isPos(network)) { - tx.sign(shepherd.getNetworkData(network), i, key); + tx.sign( + shepherd.getNetworkData(network), + i, + key + ); } else { tx.sign(i, key); } @@ -144,7 +156,12 @@ module.exports = (shepherd) => { shepherd.log(`buildSignedTx${network.toUpperCase()}`, true); for (let i = 0; i < utxo.length; i++) { - tx.addInput(utxo[i].txid, utxo[i].vout, bitcoinJSForks.Transaction.DEFAULT_SEQUENCE, spk); + tx.addInput( + utxo[i].txid, + utxo[i].vout, + bitcoinJSForks.Transaction.DEFAULT_SEQUENCE, + spk + ); } tx.addOutput(sendTo, Number(spendValue)); @@ -171,7 +188,13 @@ module.exports = (shepherd) => { const hashType = bitcoinJSForks.Transaction.SIGHASH_ALL | bitcoinJSForks.Transaction.SIGHASH_BITCOINCASHBIP143; for (let i = 0; i < utxo.length; i++) { - tx.sign(i, keyPair, null, hashType, utxo[i].value); + tx.sign( + i, + keyPair, + null, + hashType, + utxo[i].value + ); } const rawtx = tx.build().toHex(); @@ -200,7 +223,11 @@ module.exports = (shepherd) => { if (shepherd.checkToken(req.query.token)) { // TODO: unconf output(s) error message const network = req.query.network || shepherd.findNetworkObj(req.query.coin); - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[network].port, + shepherd.electrumServers[network].address, + shepherd.electrumServers[network].proto + ); // tcp or tls const outputAddress = req.query.address; const changeAddress = req.query.change; const push = req.query.push; @@ -225,7 +252,13 @@ module.exports = (shepherd) => { shepherd.log('electrum createrawtx =>', true); ecl.connect(); - shepherd.listunspent(ecl, changeAddress, network, true, req.query.verify === 'true' ? true : null) + shepherd.listunspent( + ecl, + changeAddress, + network, + true, + req.query.verify === 'true' ? true : null + ) .then((utxoList) => { ecl.close(); @@ -281,7 +314,11 @@ module.exports = (shepherd) => { // default coin selection algo blackjack with fallback to accumulative // make a first run, calc approx tx fee // if ins and outs are empty reduce max spend by txfee - const firstRun = coinSelect(utxoListFormatted, targets, btcFee ? btcFee : 0); + const firstRun = coinSelect( + utxoListFormatted, + targets, + btcFee ? btcFee : 0 + ); let inputs = firstRun.inputs; let outputs = firstRun.outputs; @@ -304,7 +341,11 @@ module.exports = (shepherd) => { shepherd.log('coinselect adjusted targets =>', true); shepherd.log(targets, true); - const secondRun = coinSelect(utxoListFormatted, targets, 0); + const secondRun = coinSelect( + utxoListFormatted, + targets, + 0 + ); inputs = secondRun.inputs; outputs = secondRun.outputs; fee = fee ? fee : secondRun.fee; @@ -493,7 +534,11 @@ module.exports = (shepherd) => { res.end(JSON.stringify(successObj)); } else { - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[network].port, + shepherd.electrumServers[network].address, + shepherd.electrumServers[network].proto + ); // tcp or tls ecl.connect(); ecl.blockchainTransactionBroadcast(_rawtx) @@ -591,7 +636,11 @@ module.exports = (shepherd) => { if (shepherd.checkToken(req.body.token)) { const rawtx = req.body.rawtx; const _network = req.body.network; - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[_network].port, shepherd.electrumServers[_network].address, shepherd.electrumServers[_network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[_network].port, + shepherd.electrumServers[_network].address, + shepherd.electrumServers[_network].proto + ); // tcp or tls ecl.connect(); ecl.blockchainTransactionBroadcast(rawtx) diff --git a/routes/shepherd/electrum/estimate.js b/routes/shepherd/electrum/estimate.js index f065414..4f080b3 100644 --- a/routes/shepherd/electrum/estimate.js +++ b/routes/shepherd/electrum/estimate.js @@ -1,7 +1,11 @@ module.exports = (shepherd) => { shepherd.get('/electrum/estimatefee', (req, res, next) => { if (shepherd.checkToken(req.query.token)) { - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[req.query.network].port, shepherd.electrumServers[req.query.network].address, shepherd.electrumServers[req.query.network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[req.query.network].port, + shepherd.electrumServers[req.query.network].address, + shepherd.electrumServers[req.query.network].proto + ); // tcp or tls ecl.connect(); ecl.blockchainEstimatefee(req.query.blocks) diff --git a/routes/shepherd/electrum/keys.js b/routes/shepherd/electrum/keys.js index 229056c..39844eb 100644 --- a/routes/shepherd/electrum/keys.js +++ b/routes/shepherd/electrum/keys.js @@ -40,6 +40,7 @@ module.exports = (shepherd) => { const keys = { pub: keyPair.getAddress(), priv: keyPair.toWIF(), + pubHex: keyPair.getPublicKeyBuffer().toString('hex'), }; /*shepherd.log(`seed: ${seed}`, true); @@ -98,28 +99,6 @@ module.exports = (shepherd) => { } }); - shepherd.post('/electrum/seedtowif', (req, res, next) => { - if (shepherd.checkToken(req.body.token)) { - let keys = shepherd.seedToWif(req.body.seed, req.body.network.toLowerCase(), req.body.iguana); - - const successObj = { - msg: 'success', - result: { - keys, - }, - }; - - res.end(JSON.stringify(successObj)); - } else { - const errorObj = { - msg: 'error', - result: 'unauthorized access', - }; - - res.end(JSON.stringify(errorObj)); - } - }); - shepherd.getCoinByPub = (address) => { const _skipNetworks = ['btc', 'crw', 'dgb', 'arg', 'zec', 'nmc', 'ltc', 'vtc', 'via', 'fair', 'doge', 'kmd', 'mona']; diff --git a/routes/shepherd/electrum/network.js b/routes/shepherd/electrum/network.js index 0ec8869..37b6e00 100644 --- a/routes/shepherd/electrum/network.js +++ b/routes/shepherd/electrum/network.js @@ -58,9 +58,14 @@ module.exports = (shepherd) => { }; shepherd.getNetworkData = (network) => { - const coin = shepherd.findNetworkObj(network) || shepherd.findNetworkObj(network.toUpperCase()) || shepherd.findNetworkObj(network.toLowerCase()); + let coin = shepherd.findNetworkObj(network) || shepherd.findNetworkObj(network.toUpperCase()) || shepherd.findNetworkObj(network.toLowerCase()); const coinUC = coin ? coin.toUpperCase() : null; + if (!coin && + !coinUC) { + coin = network.toUpperCase(); + } + if (coin === 'SUPERNET' || coin === 'REVS' || coin === 'SUPERNET' || @@ -70,10 +75,10 @@ module.exports = (shepherd) => { coin === 'BET' || coin === 'CRYPTO' || coin === 'COQUI' || - coin === 'GLXT' || + coin === 'GLXT' || coin === 'OOT' || coin === 'HODL' || - coin === 'EQL' || + coin === 'EQL' || coin === 'SHARK' || coin === 'MSHARK' || coin === 'BOTS' || @@ -101,9 +106,9 @@ module.exports = (shepherd) => { coinUC === 'BET' || coinUC === 'CRYPTO' || coinUC === 'COQUI' || - coinUC === 'GLXT' || + coinUC === 'GLXT' || coinUC === 'OOT' || - coinUC === 'EQL' || + coinUC === 'EQL' || coinUC === 'HODL' || coinUC === 'SHARK' || coinUC === 'MSHARK' || @@ -182,7 +187,7 @@ module.exports = (shepherd) => { }; for (let key in shepherd.electrumServers) { - if (shepherd.electrumServers[key].abbr === req.query.coin) { // a bit risky + if (shepherd.electrumServers[key].abbr === req.query.coin) { shepherd.electrumServers[key].address = req.query.address; shepherd.electrumServers[key].port = req.query.port; break; diff --git a/routes/shepherd/electrum/transactions.js b/routes/shepherd/electrum/transactions.js index 40f81ad..dc1c353 100644 --- a/routes/shepherd/electrum/transactions.js +++ b/routes/shepherd/electrum/transactions.js @@ -1,7 +1,9 @@ const async = require('async'); const Promise = require('bluebird'); -const MAX_VOUT_LENGTH = 10; +const MAX_VIN_LENGTH = 150; // parse up to MAX_VIN_LENGTH vins + +// TODO: add z -> pub, pub -> z flag for zcash forks module.exports = (shepherd) => { shepherd.sortTransactions = (transactions, sortBy) => { @@ -131,6 +133,8 @@ module.exports = (shepherd) => { const decodedTx = shepherd.electrumJSTxDecoder(_rawtxJSON, network, _network); let txInputs = []; + let opreturn = false; + shepherd.log(`decodedtx network ${network}`, true); shepherd.log('decodedtx =>', true); @@ -138,6 +142,16 @@ module.exports = (shepherd) => { let index2 = 0; + if (decodedTx && + decodedTx.outputs && + decodedTx.outputs.length) { + for (let i = 0; i < decodedTx.outputs.length; i++) { + if (decodedTx.outputs[i].scriptPubKey.type === 'nulldata') { + opreturn = shepherd.hex2str(decodedTx.outputs[i].scriptPubKey.hex); + } + } + } + if (decodedTx && decodedTx.inputs && decodedTx.inputs.length) { @@ -145,7 +159,8 @@ module.exports = (shepherd) => { const checkLoop = () => { index2++; - if (index2 === decodedTx.inputs.length || index2 === MAX_VOUT_LENGTH) { + if (index2 === decodedTx.inputs.length || + index2 === MAX_VIN_LENGTH) { shepherd.log(`tx history decode inputs ${decodedTx.inputs.length} | ${index2} => main callback`, true); const _parsedTx = { network: decodedTx.network, @@ -153,36 +168,45 @@ module.exports = (shepherd) => { inputs: txInputs, outputs: decodedTx.outputs, height: transaction.height, - timestamp: Number(transaction.height) === 0 ? Math.floor(Date.now() / 1000) : blockInfo.timestamp, - confirmations: Number(transaction.height) === 0 ? 0 : currentHeight - transaction.height, + timestamp: Number(transaction.height) === 0 || Number(transaction.height) === -1 ? Math.floor(Date.now() / 1000) : blockInfo.timestamp, + confirmations: Number(transaction.height) === 0 || Number(transaction.height) === -1 ? 0 : currentHeight - transaction.height, }; const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, _address, network); if (formattedTx.type) { formattedTx.height = transaction.height; - formattedTx.blocktime = blockInfo.timestamp; - formattedTx.timereceived = blockInfo.timereceived; + formattedTx.blocktime = Number(transaction.height) === 0 || Number(transaction.height) === -1 ? Math.floor(Date.now() / 1000) : blockInfo.timestamp; + formattedTx.timereceived = Number(transaction.height) === 0 || Number(transaction.height) === -1 ? Math.floor(Date.now() / 1000) : blockInfo.timereceived; formattedTx.hex = _rawtxJSON; formattedTx.inputs = decodedTx.inputs; formattedTx.outputs = decodedTx.outputs; formattedTx.locktime = decodedTx.format.locktime; + formattedTx.vinLen = decodedTx.inputs.length; + formattedTx.vinMaxLen = MAX_VIN_LENGTH; + formattedTx.opreturn = opreturn; _rawtx.push(formattedTx); } else { formattedTx[0].height = transaction.height; - formattedTx[0].blocktime = blockInfo.timestamp; - formattedTx[0].timereceived = blockInfo.timereceived; + formattedTx[0].blocktime = Number(transaction.height) === 0 || Number(transaction.height) === -1 ? Math.floor(Date.now() / 1000) : blockInfo.timestamp; + formattedTx[0].timereceived = Number(transaction.height) === 0 || Number(transaction.height) === -1 ? Math.floor(Date.now() / 1000) : blockInfo.timereceived; formattedTx[0].hex = _rawtxJSON; formattedTx[0].inputs = decodedTx.inputs; formattedTx[0].outputs = decodedTx.outputs; formattedTx[0].locktime = decodedTx.format.locktime; + formattedTx[0].vinLen = decodedTx.inputs.length; + formattedTx[0].vinMaxLen = MAX_VIN_LENGTH; + formattedTx[0].opreturn = opreturn[0]; formattedTx[1].height = transaction.height; - formattedTx[1].blocktime = blockInfo.timestamp; - formattedTx[1].timereceived = blockInfo.timereceived; + formattedTx[1].blocktime = Number(transaction.height) === 0 || Number(transaction.height) === -1 ? Math.floor(Date.now() / 1000) : blockInfo.timestamp; + formattedTx[1].timereceived = Number(transaction.height) === 0 || Number(transaction.height) === -1 ? Math.floor(Date.now() / 1000) : blockInfo.timereceived; formattedTx[1].hex = _rawtxJSON; formattedTx[1].inputs = decodedTx.inputs; formattedTx[1].outputs = decodedTx.outputs; formattedTx[1].locktime = decodedTx.format.locktime; + formattedTx[1].vinLen = decodedTx.inputs.length; + formattedTx[1].vinMaxLen = MAX_VIN_LENGTH; + formattedTx[1].opreturn = opreturn[1]; _rawtx.push(formattedTx[0]); _rawtx.push(formattedTx[1]); } @@ -230,6 +254,7 @@ module.exports = (shepherd) => { height: transaction.height, timestamp: Number(transaction.height) === 0 ? Math.floor(Date.now() / 1000) : blockInfo.timestamp, confirmations: Number(transaction.height) === 0 ? 0 : currentHeight - transaction.height, + opreturn, }; const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, _address, network); @@ -313,7 +338,11 @@ module.exports = (shepherd) => { shepherd.get('/electrum/gettransaction', (req, res, next) => { if (shepherd.checkToken(req.query.token)) { const network = req.query.network || shepherd.findNetworkObj(req.query.coin); - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[network].port, shepherd.electrumServers[network].address, shepherd.electrumServers[network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[network].port, + shepherd.electrumServers[network].address, + shepherd.electrumServers[network].proto + ); // tcp or tls shepherd.log('electrum gettransaction =>', true); @@ -551,7 +580,11 @@ module.exports = (shepherd) => { res.end(JSON.stringify(successObj)); } else { - const ecl = new shepherd.electrumJSCore(shepherd.electrumServers[req.query.network].port, shepherd.electrumServers[req.query.network].address, shepherd.electrumServers[req.query.network].proto); // tcp or tls + const ecl = new shepherd.electrumJSCore( + shepherd.electrumServers[req.query.network].port, + shepherd.electrumServers[req.query.network].address, + shepherd.electrumServers[req.query.network].proto + ); // tcp or tls shepherd.log(decodedTx.inputs[0]); shepherd.log(decodedTx.inputs[0].txid); diff --git a/routes/shepherd/log.js b/routes/shepherd/log.js index 3a09445..30d55ce 100644 --- a/routes/shepherd/log.js +++ b/routes/shepherd/log.js @@ -8,17 +8,10 @@ module.exports = (shepherd) => { console.log(msg); } - if (!isSpvOut) { - shepherd.appRuntimeLog.push({ - time: Date.now(), - msg: msg, - }); - } else { - shepherd.appRuntimeSPVLog.push({ - time: Date.now(), - msg: msg, - }); - } + shepherd[!isSpvOut ? 'appRuntimeLog' : 'appRuntimeSPVLog'].push({ + time: Date.now(), + msg: msg, + }); } shepherd.writeLog = (data) => { @@ -73,16 +66,17 @@ module.exports = (shepherd) => { shepherd.post('/guilog', (req, res, next) => { if (shepherd.checkToken(req.body.token)) { const logLocation = `${shepherd.agamaDir}/shepherd`; + const timestamp = req.body.timestamp; if (!shepherd.guiLog[shepherd.appSessionHash]) { shepherd.guiLog[shepherd.appSessionHash] = {}; } - if (shepherd.guiLog[shepherd.appSessionHash][req.body.timestamp]) { - shepherd.guiLog[shepherd.appSessionHash][req.body.timestamp].status = req.body.status; - shepherd.guiLog[shepherd.appSessionHash][req.body.timestamp].response = req.body.response; + if (shepherd.guiLog[shepherd.appSessionHash][timestamp]) { + shepherd.guiLog[shepherd.appSessionHash][timestamp].status = req.body.status; + shepherd.guiLog[shepherd.appSessionHash][timestamp].response = req.body.response; } else { - shepherd.guiLog[shepherd.appSessionHash][req.body.timestamp] = { + shepherd.guiLog[shepherd.appSessionHash][timestamp] = { function: req.body.function, type: req.body.type, url: req.body.url, diff --git a/routes/shepherd/pin.js b/routes/shepherd/pin.js index 3d9229f..824bb32 100644 --- a/routes/shepherd/pin.js +++ b/routes/shepherd/pin.js @@ -1,5 +1,9 @@ const fs = require('fs-extra'); const aes256 = require('nodejs-aes256'); +const passwdStrength = require('passwd-strength'); +const bitcoin = require('bitcoinjs-lib'); +const sha256 = require('js-sha256'); +const bigi = require('bigi'); module.exports = (shepherd) => { /* @@ -9,36 +13,69 @@ module.exports = (shepherd) => { shepherd.post('/encryptkey', (req, res, next) => { if (shepherd.checkToken(req.body.token)) { if (req.body.key && - req.body.string && - req.body.pubkey) { - const encryptedString = aes256.encrypt(req.body.key, req.body.string); - - // test pin security - // - at least 1 char in upper case - // - at least 1 digit - // - at least one special character - // - min length 8 - + req.body.string) { const _pin = req.body.key; - const _pinTest = _pin.match('^(?=.*[A-Z])(?=.*[^<>{}\"/|;:.,~!?@#$%^=&*\\]\\\\()\\[_+]*$)(?=.*[0-9])(?=.*[a-z]).{8}$'); + const hash = sha256.create().update(req.body.string); + let bytes = hash.array(); + bytes[0] &= 248; + bytes[31] &= 127; + bytes[31] |= 64; - fs.writeFile(`${shepherd.agamaDir}/shepherd/pin/${req.body.pubkey}.pin`, encryptedString, (err) => { - if (err) { - shepherd.log('error writing pin file'); - } + const d = bigi.fromBuffer(bytes); + const keyPair = new bitcoin.ECPair(d, null, { network: shepherd.getNetworkData('btc') }); + const keys = { + pub: keyPair.getAddress(), + priv: keyPair.toWIF(), + }; + let pubkey = req.body.pubkey ? req.body.pubkey : keyPair.getAddress(); + + if (passwdStrength(_pin) < 29) { + shepherd.log('seed storage weak pin!'); const returnObj = { - msg: 'success', - result: encryptedString, + msg: 'error', + result: false, }; res.end(JSON.stringify(returnObj)); - }); + } else { + const _customPinFilenameTest = /^[0-9a-zA-Z-_]+$/g; + + if (_customPinFilenameTest.test(pubkey)) { + const encryptedString = aes256.encrypt(req.body.key, req.body.string); + + fs.writeFile(`${shepherd.agamaDir}/shepherd/pin/${pubkey}.pin`, encryptedString, (err) => { + if (err) { + shepherd.log('error writing pin file'); + + const returnObj = { + msg: 'error', + result: 'error writing pin file', + }; + + res.end(JSON.stringify(returnObj)); + } else { + const returnObj = { + msg: 'success', + result: pubkey, + }; + + res.end(JSON.stringify(returnObj)); + } + }); + } else { + const returnObj = { + msg: 'error', + result: 'pin file name can only contain alphanumeric characters, dash "-" and underscore "_"', + }; + + res.end(JSON.stringify(returnObj)); + } + } } else { const _paramsList = [ 'key', - 'string', - 'pubkey' + 'string' ]; let errorObj = { msg: 'error', @@ -127,7 +164,7 @@ module.exports = (shepherd) => { }); shepherd.get('/getpinlist', (req, res, next) => { - if (shepherd.checkToken(req.body.token)) { + if (shepherd.checkToken(req.query.token)) { if (fs.existsSync(`${shepherd.agamaDir}/shepherd/pin`)) { fs.readdir(`${shepherd.agamaDir}/shepherd/pin`, (err, items) => { let _pins = []; @@ -172,5 +209,101 @@ module.exports = (shepherd) => { } }); + shepherd.post('/modifypin', (req, res, next) => { + if (shepherd.checkToken(req.body.token)) { + const pubkey = req.body.pubkey; + + if (pubkey) { + if (fs.existsSync(`${shepherd.agamaDir}/shepherd/pin/${pubkey}.pin`)) { + fs.readFile(`${shepherd.agamaDir}/shepherd/pin/${pubkey}.pin`, 'utf8', (err, data) => { + if (err) { + const errorObj = { + msg: 'error', + result: err, + }; + + res.end(JSON.stringify(errorObj)); + } else { + if (req.body.delete) { + fs.unlinkSync(`${shepherd.agamaDir}/shepherd/pin/${pubkey}.pin`); + + const returnObj = { + msg: 'success', + result: `${pubkey}.pin is removed`, + }; + + res.end(JSON.stringify(returnObj)); + } else { + const pubkeynew = req.body.pubkeynew; + const _customPinFilenameTest = /^[0-9a-zA-Z-_]+$/g; + + if (pubkeynew) { + if (_customPinFilenameTest.test(pubkeynew)) { + fs.writeFile(`${shepherd.agamaDir}/shepherd/pin/${pubkeynew}.pin`, data, (err) => { + if (err) { + shepherd.log('error writing pin file'); + + const returnObj = { + msg: 'error', + result: 'error writing pin file', + }; + + res.end(JSON.stringify(returnObj)); + } else { + fs.unlinkSync(`${shepherd.agamaDir}/shepherd/pin/${pubkey}.pin`); + + const returnObj = { + msg: 'success', + result: pubkeynew, + }; + + res.end(JSON.stringify(returnObj)); + } + }); + } else { + const returnObj = { + msg: 'error', + result: 'pin file name can only contain alphanumeric characters, dash "-" and underscore "_"', + }; + + res.end(JSON.stringify(returnObj)); + } + } else { + const returnObj = { + msg: 'error', + result: 'missing param pubkeynew', + }; + + res.end(JSON.stringify(returnObj)); + } + } + } + }); + } else { + const errorObj = { + msg: 'error', + result: `file ${pubkey}.pin doesnt exist`, + }; + + res.end(JSON.stringify(errorObj)); + } + } else { + const errorObj = { + msg: 'error', + result: 'missing pubkey param', + }; + + res.end(JSON.stringify(errorObj)); + } + } else { + const errorObj = { + msg: 'error', + result: 'unauthorized access', + }; + + res.end(JSON.stringify(errorObj)); + } + }); + return shepherd; }; \ No newline at end of file diff --git a/routes/shepherd/quitDaemon.js b/routes/shepherd/quitDaemon.js index 45fa7b8..5749659 100644 --- a/routes/shepherd/quitDaemon.js +++ b/routes/shepherd/quitDaemon.js @@ -25,13 +25,19 @@ module.exports = (shepherd) => { let _arg = []; if (chain && - !shepherd.nativeCoindList[key.toLowerCase()] && key !== 'CHIPS') { + !shepherd.nativeCoindList[key.toLowerCase()] && + key !== 'CHIPS') { + shepherd.removePubkey(chain.toLowerCase()); + _arg.push(`-ac_name=${chain}`); if (shepherd.appConfig.dataDir.length) { _arg.push(`-datadir=${shepherd.appConfig.dataDir + (key !== 'komodod' ? '/' + key : '')}`); } - } else if (key === 'komodod' && shepherd.appConfig.dataDir.length) { + } else if ( + key === 'komodod' && + shepherd.appConfig.dataDir.length + ) { _arg.push(`-datadir=${shepherd.appConfig.dataDir}`); } @@ -43,7 +49,7 @@ module.exports = (shepherd) => { if (stdout.indexOf('EOF reached') > -1 || stderr.indexOf('EOF reached') > -1 || - (error && error.toString().indexOf('Command failed') > -1 && !stderr) || // win "special snowflake" case + (error && error.toString().indexOf('Command failed') > -1 && !stderr) || // windows stdout.indexOf('connect to server: unknown (code -1)') > -1 || stderr.indexOf('connect to server: unknown (code -1)') > -1) { delete shepherd.coindInstanceRegistry[key]; @@ -88,7 +94,10 @@ module.exports = (shepherd) => { let _coindQuitCmd = shepherd.komodocliBin; let _arg = []; + if (_chain) { + shepherd.removePubkey(_chain.toLowerCase()); + _arg.push(`-ac_name=${_chain}`); if (shepherd.appConfig.dataDir.length) { @@ -154,6 +163,10 @@ module.exports = (shepherd) => { if (req.body.mode === 'native') { delete shepherd.coindInstanceRegistry[_chain ? _chain : 'komodod']; + if (_chain) { + shepherd.removePubkey(_chain.toLowerCase()); + } + const obj = { msg: 'success', result: 'result', diff --git a/version b/version index fa76357..10b4176 100644 --- a/version +++ b/version @@ -1,3 +1,3 @@ -version=0.2.32 +version=0.2.36 type=beta -minversion=0.2.32 \ No newline at end of file +minversion=0.2.36 \ No newline at end of file diff --git a/version_build b/version_build index 38a87a9..de83d4b 100644 --- a/version_build +++ b/version_build @@ -1 +1 @@ -0.2.32-beta \ No newline at end of file +0.2.36-beta \ No newline at end of file