diff --git a/bin/lamassu-update b/bin/lamassu-update index fda7b99b..2dabc953 100755 --- a/bin/lamassu-update +++ b/bin/lamassu-update @@ -49,7 +49,7 @@ fi decho "updating node" npm install n -g >> ${LOG_FILE} 2>&1 -n lts >> ${LOG_FILE} 2>&1 +n 8 >> ${LOG_FILE} 2>&1 decho "version installed $(node -v)" export NPM_BIN=$(npm -g bin) diff --git a/dev/recreate-seeds.js b/dev/recreate-seeds.js new file mode 100644 index 00000000..7ed801c6 --- /dev/null +++ b/dev/recreate-seeds.js @@ -0,0 +1,26 @@ +#!/usr/bin/env node + +'use strict' + +const fs = require('fs') +const path = require('path') +const os = require('os') +const bip39 = require('bip39') +const options = require('../lib/options-loader')() + +if (options.opts.mnemonicPath && !options.opts.seedPath) { + const mnemonic = fs.readFileSync(options.opts.mnemonicPath, 'utf8') + const seed = bip39.mnemonicToEntropy(mnemonic.split('\n').join(' ').trim()).toString('hex') + + options.opts.seedPath = path.resolve(os.homedir(), '.lamassu', 'seeds', 'seed.txt') + + if (!fs.existsSync(path.dirname(options.opts.seedPath))) { + fs.mkdirSync(path.dirname(options.opts.seedPath)) + } + + if (!fs.existsSync(options.opts.seedPath)) { + fs.writeFileSync(options.opts.seedPath, seed, 'utf8') + } + + fs.writeFileSync(options.path, JSON.stringify(options.opts, null, '\t'), 'utf8') +} diff --git a/lib/admin/config.js b/lib/admin/config.js index 825f08a0..ad4f2531 100644 --- a/lib/admin/config.js +++ b/lib/admin/config.js @@ -181,7 +181,7 @@ function fetchData () { {code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH']}, {code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC']}, {code: 'quadrigacx', display: 'QuadrigaCX', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH']}, - {code: 'mock-ticker', display: 'Mock ticker', class: 'ticker', cryptos: ALL_CRYPTOS}, + {code: 'mock-ticker', display: 'Mock (Caution!)', class: 'ticker', cryptos: ALL_CRYPTOS}, {code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC']}, {code: 'no-layer2', display: 'No Layer 2', class: 'layer2', cryptos: ALL_CRYPTOS}, {code: 'infura', display: 'Infura', class: 'wallet', cryptos: ['ETH']}, diff --git a/lib/blockchain/common.js b/lib/blockchain/common.js index bde996f6..fce05ef7 100644 --- a/lib/blockchain/common.js +++ b/lib/blockchain/common.js @@ -25,12 +25,12 @@ const BINARIES = { dir: 'bitcoin-0.16.3/bin' }, ETH: { - url: 'https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.8.15-89451f7c.tar.gz', - dir: 'geth-linux-amd64-1.8.15-89451f7c' + url: 'https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.8.19-dae82f09.tar.gz', + dir: 'geth-linux-amd64-1.8.19-dae82f09' }, ZEC: { - url: 'https://z.cash/downloads/zcash-2.0.0-linux64.tar.gz', - dir: 'zcash-2.0.0/bin' + url: 'https://z.cash/downloads/zcash-2.0.2-linux64.tar.gz', + dir: 'zcash-2.0.2/bin' }, DASH: { url: 'https://github.com/dashpay/dash/releases/download/v0.12.3.3/dashcore-0.12.3.3-x86_64-linux-gnu.tar.gz', @@ -41,8 +41,8 @@ const BINARIES = { dir: 'litecoin-0.16.3/bin' }, BCH: { - url: 'https://download.bitcoinabc.org/0.18.2/linux/bitcoin-abc-0.18.2-x86_64-linux-gnu.tar.gz', - dir: 'bitcoin-abc-0.18.2/bin', + url: 'https://download.bitcoinabc.org/0.18.5/linux/bitcoin-abc-0.18.5-x86_64-linux-gnu.tar.gz', + dir: 'bitcoin-abc-0.18.5/bin', files: [['bitcoind', 'bitcoincashd'], ['bitcoin-cli', 'bitcoincash-cli']] } } diff --git a/lib/coinatmradar/coinatmradar.js b/lib/coinatmradar/coinatmradar.js index 4330e86d..d7d713fb 100644 --- a/lib/coinatmradar/coinatmradar.js +++ b/lib/coinatmradar/coinatmradar.js @@ -156,5 +156,5 @@ function update (info) { } function computeOperatorId (masterSeed) { - return hkdf(masterSeed, 32, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex') + return hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex') } diff --git a/lib/migrate-options.js b/lib/migrate-options.js index 82374cea..994be05b 100644 --- a/lib/migrate-options.js +++ b/lib/migrate-options.js @@ -1,10 +1,19 @@ const _ = require('lodash/fp') const fs = require('fs') const makeDir = require('make-dir') +const path = require('path') const load = require('./options-loader') -module.exports = {run, mapKeyValuesDeep} +// current path of lamassu-server project +const currentBasePath = path.dirname(__dirname) +// get path as array of path components +const paths = _.wrap(_.split, path.sep) +// find the index of the lamassu-server directory +// /usr/lib/node_modules/lamassu-server/certs/Lamassu_OP.pem => 3 +const indexOfLs = _.flow(paths, _.wrap(_.indexOf, 'lamassu-server')) + +module.exports = {run, mapKeyValuesDeep, updateOptionBasepath} function mapKeyValuesDeep (cb, obj, key) { if (_.isArray(obj)) { @@ -16,6 +25,32 @@ function mapKeyValuesDeep (cb, obj, key) { } } +function updateOptionBasepath (result, optionName) { + const currentPath = _.get(optionName, result) + + // process only keys that contains + // lamassu-server dir in its path + const i = indexOfLs(currentPath) + if (i === -1) { + return + } + + // workout the relative path + // /usr/lib/node_modules/lamassu-server/certs/Lamassu_OP.pem => certs/Lamassu_OP.pem + const rPath = _.drop(i + 1, paths(currentPath)) + + // prepend the current lamassu-server path + // certs/Lamassu_OP.pem => /usr/local/lib/node_modules/lamassu-server/certs/Lamassu_OP.pem + const newPath = _.join(path.sep, _.concat([currentBasePath], rPath)) + + // update this option + // if the value has changed + if (!_.isEqual(currentPath, newPath)) { + console.log(`Migrating option ${optionName} to new path ${newPath}`) + result[optionName] = newPath + } +} + async function run () { // load defaults const defaultOpts = require('../lamassu-default') @@ -26,6 +61,19 @@ async function run () { // check if there are new options to add let result = _.mergeAll([defaultOpts, currentOpts]) + + // get all the options + // that ends with "Path" suffix + console.log(`Detected lamassu-server basepath: ${currentBasePath}`) + _.each(_.wrap(updateOptionBasepath, result), + [ + 'seedPath', + 'caPath', + 'certPath', + 'keyPath', + 'lamassuCaPath' + ]) + const shouldMigrate = !_.isEqual(result, currentOpts) || _.has('lamassuServerPath', result) // write the resulting lamassu.json @@ -33,8 +81,18 @@ async function run () { // remove old lamassuServerPath config result = _.omit('lamassuServerPath', result) - const newOpts = _.pick(_.difference(_.keys(result), _.keys(currentOpts)), result) - console.log('Adding options', newOpts) + // find keys for which values + // have been changed + const differentValue = _.wrap(_.filter, key => !_.isEqual(result[key], currentOpts[key])) + + // output affected options + const newOpts = _.pick(_.union( + // find change keys + differentValue(_.keys(result)), + // find new opts + _.difference(_.keys(result), _.keys(currentOpts)) + ), result) + console.log('Updating options', newOpts) // store new lamassu.json file fs.writeFileSync(options.path, JSON.stringify(result, null, ' ')) diff --git a/lib/pairing.js b/lib/pairing.js index bc2d4ccc..6fc8599d 100644 --- a/lib/pairing.js +++ b/lib/pairing.js @@ -74,14 +74,7 @@ function isPaired (deviceId) { const sql = 'select device_id, name from devices where device_id=$1 and paired=TRUE' return db.oneOrNone(sql, [deviceId]) - .then(row => { - const deviceName = row.name - const isDevicePaired = row && row.device_id === deviceId - return { - deviceName: deviceName, - isDevicePaired: isDevicePaired - } - }) + .then(row => row && row.device_id === deviceId ? row.name : false) } module.exports = {pair, unpair, authorizeCaDownload, isPaired} diff --git a/lib/routes.js b/lib/routes.js index 3f8e81dd..4bbd9dd2 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -311,10 +311,10 @@ function authorize (req, res, next) { const deviceId = req.deviceId return pairing.isPaired(deviceId) - .then(r => { - if (r.isDevicePaired) { + .then(deviceName => { + if (deviceName) { req.deviceId = deviceId - req.deviceName = r.deviceName + req.deviceName = deviceName return next() } diff --git a/lib/wallet.js b/lib/wallet.js index 24982462..0e069f8c 100644 --- a/lib/wallet.js +++ b/lib/wallet.js @@ -25,7 +25,7 @@ function httpError (msg, code) { } function computeSeed (masterSeed) { - return hkdf(masterSeed, 32, { salt: 'lamassu-server-salt', info: 'wallet-seed' }).toString('hex') + return hkdf(masterSeed, 32, {salt: 'lamassu-server-salt', info: 'wallet-seed'}) } function fetchWallet (settings, cryptoCode) { diff --git a/public/styles.css b/public/styles.css index 290cc50e..376ae9d2 100644 --- a/public/styles.css +++ b/public/styles.css @@ -21,6 +21,7 @@ p { .lamassuAdminMain { display: flex; + height: 100%; margin-bottom: 40px; } diff --git a/test/unit/migrate-options.js b/test/unit/migrate-options.js index 396da464..10ae126e 100644 --- a/test/unit/migrate-options.js +++ b/test/unit/migrate-options.js @@ -1,7 +1,10 @@ import test from 'ava' import _ from 'lodash/fp' +import path from 'path' -import {mapKeyValuesDeep} from '../../lib/migrate-options' +import {mapKeyValuesDeep, updateOptionBasepath} from '../../lib/migrate-options' + +const currentBasePath = path.dirname(path.dirname(__dirname)) test('mapKeyValuesDeep', t => { const test = { @@ -33,3 +36,29 @@ test('mapKeyValuesDeep', t => { t.deepEqual(result, expected) }) + +test('updateOptionBasepath', t => { + const test = { + someBooleanOption: true, + someStringOption: 'my-custom-option', + customExternalPath: '/usr/lib/node_modules/ava', + seedPath: '/etc/lamassu/seeds/seed.txt', + caPath: '/usr/lib/node_modules/lamassu-server/certs/Lamassu_OP_Root_CA.pem' + } + const expected = { + someBooleanOption: true, + someStringOption: 'my-custom-option', + customExternalPath: '/usr/lib/node_modules/ava', + seedPath: '/etc/lamassu/seeds/seed.txt', + caPath: path.join(currentBasePath, 'certs/Lamassu_OP_Root_CA.pem') + } + + let result = _.clone(test) + + _.each( + _.wrap(updateOptionBasepath, result), + _.keys(test) + ) + + t.deepEqual(result, expected) +})