From f4d6b5e454fd4788aacbfdfb5401f2ab4845c7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Tue, 29 Mar 2022 15:00:52 +0100 Subject: [PATCH] feat: decouple l-s entrypoint --- .env | 1 - .sample.env | 59 +++++++++++++++++++ bin/convert-txs.js | 10 +++- bin/lamassu-configure-frontcamera | 10 ++-- bin/lamassu-eth-recovery | 8 ++- bin/lamassu-migrate | 12 +++- bin/lamassu-mnemonic | 6 +- bin/lamassu-ofac-update-sources | 22 ++----- bin/lamassu-operator | 8 ++- bin/lamassu-register | 7 ++- bin/lamassu-update-to-mnemonic | 23 ++++---- bin/migrate-config.js | 8 ++- bin/old-lamassu-register | 8 ++- dev/notify.js | 4 +- dev/recreate-seeds.js | 20 +++---- lib/admin/admin-server.js | 41 ++++++------- lib/admin/admin-support.js | 10 ++-- lib/admin/pairing.js | 7 +-- lib/app.js | 15 +++-- lib/blockchain/do-volume.js | 6 +- lib/blockchain/install.js | 9 +-- lib/coinatmradar/coinatmradar.js | 8 +-- lib/constants.js | 11 +++- lib/customers.js | 16 ++--- lib/db.js | 4 +- lib/logger.js | 8 ++- lib/new-admin/admin-server.js | 31 +++++----- lib/new-admin/graphql-dev-insecure.js | 3 + lib/new-admin/middlewares/session.js | 3 - lib/new-admin/services/pairing.js | 9 +-- lib/ofac/index.js | 9 +-- lib/ofac/update.js | 23 +++++--- lib/options-loader.js | 3 +- lib/pairing.js | 8 +-- lib/plugins/common/json-rpc.js | 6 +- lib/plugins/layer2/strike/strike.js | 4 +- lib/plugins/wallet/lnd/lnd.js | 5 +- lib/plugins/wallet/monerod/monerod.js | 7 +-- .../wallet/pazuz-wallet/pazuz-wallet.js | 13 ++-- lib/routes.js | 3 +- lib/wallet.js | 5 +- .../1623413776161-create-operator-ids.js | 3 +- new-lamassu-admin/.env | 2 +- .../src/pages/Accounting/Accounting.js | 36 ++++++----- tools/build-dev-env.js | 32 ++++++++++ tools/build-prod-env.js | 45 ++++++++++++++ tools/cert-gen.sh | 28 +-------- tools/set-env-var.js | 24 ++++++++ 48 files changed, 411 insertions(+), 232 deletions(-) delete mode 100644 .env create mode 100644 .sample.env create mode 100644 tools/build-dev-env.js create mode 100644 tools/build-prod-env.js create mode 100644 tools/set-env-var.js diff --git a/.env b/.env deleted file mode 100644 index db93e716..00000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -LAMASSU_DB=DEV \ No newline at end of file diff --git a/.sample.env b/.sample.env new file mode 100644 index 00000000..ae44d16f --- /dev/null +++ b/.sample.env @@ -0,0 +1,59 @@ +## Database variables + +# Used to describe which database to use. Possible values include: DEV, RELEASE, STRESS_TEST +LAMASSU_DB= + +# Postgres related environment variables +POSTGRES_USER= +POSTGRES_PASSWORD= +POSTGRES_HOST= +POSTGRES_PORT= +POSTGRES_DB= + +## File paths + +# Certificate-related variables +LAMASSU_CA_PATH= +CA_PATH= +CERT_PATH= +KEY_PATH= + +# Full path to where the wallet's mnemonic is stored +MNEMONIC_PATH= + +MIGRATE_STATE_PATH= + +## Directories + +BLOCKCHAIN_DIR= +OFAC_DATA_DIR= +ID_PHOTO_CARD_DIR= +FRONT_CAMERA_DIR= +OPERATOR_DATA_DIR= + +## URLs + +STRIKE_BASE_URL= +COIN_ATM_RADAR_URL= + +## OFAC Sources variables + +# These variables map to each other, similar to a zip HOF. Entries are separated by commas +# Example: +# OFAC_SOURCES_NAMES=name1,name2 +# OFAC_SOURCES_URLS=url1,url2 +OFAC_SOURCES_NAMES= +OFAC_SOURCES_URLS= + +## Misc + +HOSTNAME= +LOG_LEVEL= +LIGHTNING_NETWORK_DAEMON= + +## Deprecated or in deprecation + +HTTP= +DEV_MODE= + +## Uncategorized variables diff --git a/bin/convert-txs.js b/bin/convert-txs.js index 2e724f98..71c81f95 100755 --- a/bin/convert-txs.js +++ b/bin/convert-txs.js @@ -1,9 +1,13 @@ #!/usr/bin/env node -var pgp = require('pg-promise')() -var psqlUrl = require('../lib/options').postgresql +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) -var db = pgp(psqlUrl) +var pgp = require('pg-promise')() + +const { PSQL_URL } = require('../lib/constants') + +var db = pgp(PSQL_URL) db.manyOrNone(`select * from transactions where incoming=false and stage='final_request' and authority='machine'`) diff --git a/bin/lamassu-configure-frontcamera b/bin/lamassu-configure-frontcamera index 5a6d4d06..31780f3e 100755 --- a/bin/lamassu-configure-frontcamera +++ b/bin/lamassu-configure-frontcamera @@ -2,11 +2,11 @@ 'use strict' -const fs = require('fs') -const options = require('../lib/options-loader')() +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) -if (!options.opts.frontCameraDir) { - options.opts.frontCameraDir = '/opt/lamassu-server/frontcamera' +const setEnvVariable = require('../tools/set-env-var') - fs.writeFileSync(options.path, JSON.stringify(options.opts, null, '\t'), 'utf8') +if (!process.env.FRONT_CAMERA_DIR) { + setEnvVariable('FRONT_CAMERA_DIR', '/opt/lamassu-server/frontcamera') } diff --git a/bin/lamassu-eth-recovery b/bin/lamassu-eth-recovery index e8e2991a..1d9c71cd 100644 --- a/bin/lamassu-eth-recovery +++ b/bin/lamassu-eth-recovery @@ -1,5 +1,7 @@ #!/usr/bin/env node +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) const hdkey = require('ethereumjs-wallet/hdkey') const hkdf = require('futoin-hkdf') const db = require('../lib/db') @@ -9,14 +11,14 @@ const mnemonicHelpers = require('../lib/mnemonic-helpers') const pify = require('pify') const fs = pify(require('fs')) -const options = require('../lib/options') +const MNEMONIC_PATH = process.env.MNEMONIC_PATH const defaultPrefixPath = "m/44'/60'/1'/0'" const paymentPrefixPath = "m/44'/60'/0'/0'" const address = process.argv[2] -if (!options || !options.mnemonicPath) { +if (!MNEMONIC_PATH) { console.error(`Unable to fetch mnemonic from your account!`) process.exit(1) } @@ -47,7 +49,7 @@ function searchForHdIndex (address) { } function fetchMnemonic () { - return fs.readFile(options.mnemonicPath, 'utf8') + return fs.readFile(MNEMONIC_PATH, 'utf8') .then(mnemonic => computeSeed(mnemonic)) } diff --git a/bin/lamassu-migrate b/bin/lamassu-migrate index 3138efc8..e09c1fdf 100755 --- a/bin/lamassu-migrate +++ b/bin/lamassu-migrate @@ -1,10 +1,16 @@ #!/usr/bin/env node const FileStore = require('migrate/lib/file-store') +const _ = require('lodash/fp') +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) + const db = require('../lib/db') const migrate = require('../lib/migrate') -const options = require('../lib/options') const { asyncLocalStorage, defaultStore } = require('../lib/async-storage') + +const MIGRATE_STATE_PATH = process.env.MIGRATE_STATE_PATH + const createMigration = `CREATE TABLE IF NOT EXISTS migrations ( id serial PRIMARY KEY, data json NOT NULL @@ -14,7 +20,7 @@ const select = 'select * from migrations limit 1' const getMigrateFile = () => { return new Promise((resolve, reject) => { - new FileStore(options.migrateStatePath).load((err, store) => { + new FileStore(MIGRATE_STATE_PATH).load((err, store) => { if (err) return reject(err) return resolve(store) }) @@ -26,7 +32,7 @@ asyncLocalStorage.run(store, () => { db.none(createMigration) .then(() => Promise.all([db.oneOrNone(select), getMigrateFile()])) .then(([qResult, migrateFile]) => { - process.env.SKIP_SERVER_LOGS = !(qResult && qResult.data.migrations.find(({ title }) => title === '1572524820075-server-support-logs.js')) + process.env.SKIP_SERVER_LOGS = !(qResult && _.find(({ title }) => title === '1572524820075-server-support-logs.js', qResult.data.migrations ?? [])) if (!qResult && migrateFile) { return db.none('insert into migrations (id, data) values (1, $1)', [migrateFile]) } diff --git a/bin/lamassu-mnemonic b/bin/lamassu-mnemonic index 500d07bb..fa841b08 100755 --- a/bin/lamassu-mnemonic +++ b/bin/lamassu-mnemonic @@ -1,8 +1,10 @@ #!/usr/bin/env node const fs = require('fs') +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) -const options = require('../lib/options') +const MNEMONIC_PATH = process.env.MNEMONIC_PATH -const mnemonic = fs.readFileSync(options.mnemonicPath, 'utf8').trim() +const mnemonic = fs.readFileSync(MNEMONIC_PATH, 'utf8').trim() console.log(mnemonic) diff --git a/bin/lamassu-ofac-update-sources b/bin/lamassu-ofac-update-sources index 83f6c011..0a7f9528 100755 --- a/bin/lamassu-ofac-update-sources +++ b/bin/lamassu-ofac-update-sources @@ -2,22 +2,12 @@ 'use strict' -const fs = require('fs') +const setEnvVariable = require('../tools/set-env-var') -const ofacSources = [ - { - name: 'sdn_advanced', - url: 'https://www.treasury.gov/ofac/downloads/sanctions/1.0/sdn_advanced.xml' - }, - { - name: 'cons_advanced', - url: 'https://www.treasury.gov/ofac/downloads/sanctions/1.0/cons_advanced.xml' - } -] +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) -const options = require('../lib/options-loader')() - -if (!options.opts.ofacSources) { - options.opts.ofacSources = ofacSources - fs.writeFileSync(options.path, JSON.stringify(options.opts, null, ' '), 'utf8') +if (!process.env.OFAC_SOURCES_NAMES && !process.env.OFAC_SOURCES_URLS) { + setEnvVariable('OFAC_SOURCES_NAMES', 'sdn_advanced,cons_advanced') + setEnvVariable('OFAC_SOURCES_URLS', 'https://www.treasury.gov/ofac/downloads/sanctions/1.0/sdn_advanced.xml,https://www.treasury.gov/ofac/downloads/sanctions/1.0/cons_advanced.xml') } diff --git a/bin/lamassu-operator b/bin/lamassu-operator index 104a1c5e..8249ee64 100644 --- a/bin/lamassu-operator +++ b/bin/lamassu-operator @@ -3,10 +3,14 @@ const fs = require('fs') const hkdf = require('futoin-hkdf') -const options = require('../lib/options') +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) + const mnemonicHelpers = require('../lib/mnemonic-helpers') -const mnemonic = fs.readFileSync(options.mnemonicPath, 'utf8').trim() +const MNEMONIC_PATH = process.env.MNEMONIC_PATH + +const mnemonic = fs.readFileSync(MNEMONIC_PATH, 'utf8').trim() const masterSeed = mnemonicHelpers.toEntropyBuffer(mnemonic) console.log(hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex')) diff --git a/bin/lamassu-register b/bin/lamassu-register index 7d5284bc..66af20ef 100755 --- a/bin/lamassu-register +++ b/bin/lamassu-register @@ -1,16 +1,17 @@ #!/usr/bin/env node +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) const { asyncLocalStorage, defaultStore } = require('../lib/async-storage') const userManagement = require('../lib/new-admin/graphql/modules/userManagement') const authErrors = require('../lib/new-admin/graphql/errors/authentication') -const options = require('../lib/options') const name = process.argv[2] const role = process.argv[3] -const domain = options.hostname +const domain = process.env.HOSTNAME if (!domain) { - console.error('No hostname configured in lamassu.json') + console.error('No hostname configured in the environment') process.exit(1) } diff --git a/bin/lamassu-update-to-mnemonic b/bin/lamassu-update-to-mnemonic index d4f30ed1..ed14222e 100755 --- a/bin/lamassu-update-to-mnemonic +++ b/bin/lamassu-update-to-mnemonic @@ -6,25 +6,26 @@ const fs = require('fs') const path = require('path') const os = require('os') const mnemonicHelpers = require('../lib/mnemonic-helpers') -const options = require('../lib/options-loader')() +const setEnvVariable = require('../tools/set-env-var') -if (!options.opts.mnemonicPath && options.opts.seedPath) { - const seed = fs.readFileSync(options.opts.seedPath, 'utf8').trim() +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) + +if (!process.env.MNEMONIC_PATH && process.env.SEED_PATH) { + const seed = fs.readFileSync(process.env.SEED_PATH, 'utf8').trim() const mnemonic = mnemonicHelpers.fromSeed(seed) if (process.argv[2] === '--prod') { - options.opts.mnemonicPath = path.resolve('/etc', 'lamassu', 'mnemonics', 'mnemonic.txt') + setEnvVariable('MNEMONIC_PATH', path.resolve('/etc', 'lamassu', 'mnemonics', 'mnemonic.txt')) } else { - options.opts.mnemonicPath = path.resolve(os.homedir(), '.lamassu', 'mnemonics', 'mnemonic.txt') + setEnvVariable('MNEMONIC_PATH', path.resolve(os.homedir(), '.lamassu', 'mnemonics', 'mnemonic.txt')) } - if (!fs.existsSync(path.dirname(options.opts.mnemonicPath))) { - fs.mkdirSync(path.dirname(options.opts.mnemonicPath)) + if (!fs.existsSync(path.dirname(process.env.MNEMONIC_PATH))) { + fs.mkdirSync(path.dirname(process.env.MNEMONIC_PATH)) } - if (!fs.existsSync(options.opts.mnemonicPath)) { - fs.writeFileSync(options.opts.mnemonicPath, mnemonic, 'utf8') + if (!fs.existsSync(process.env.MNEMONIC_PATH)) { + fs.writeFileSync(process.env.MNEMONIC_PATH, mnemonic, 'utf8') } - - fs.writeFileSync(options.path, JSON.stringify(options.opts, null, '\t'), 'utf8') } diff --git a/bin/migrate-config.js b/bin/migrate-config.js index 32e89ae2..759e5e31 100644 --- a/bin/migrate-config.js +++ b/bin/migrate-config.js @@ -3,9 +3,13 @@ 'use strict' const pgp = require('pg-promise')() -const psqlUrl = require('../lib/options').postgresql -const db = pgp(psqlUrl) +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) + +const { PSQL_URL } = require('../lib/constants') + +const db = pgp(PSQL_URL) db.many('select data from user_config', 'exchanges') .then(rows => { diff --git a/bin/old-lamassu-register b/bin/old-lamassu-register index 119632f3..e6e2313a 100755 --- a/bin/old-lamassu-register +++ b/bin/old-lamassu-register @@ -1,13 +1,15 @@ #!/usr/bin/env node +const path = require('path') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) + const login = require('../lib/admin/login') -const options = require('../lib/options') const name = process.argv[2] -const domain = options.hostname +const domain = process.env.HOSTNAME if (!domain) { - console.error('No hostname configured in lamassu.json') + console.error('No hostname configured in the environment') process.exit(1) } diff --git a/dev/notify.js b/dev/notify.js index d99f77b7..5bb41bcf 100644 --- a/dev/notify.js +++ b/dev/notify.js @@ -2,7 +2,7 @@ require('es6-promise').polyfill() var notifier = require('../lib/notifier') var db = require('../lib/postgresql_interface') -var psqlUrl = require('../lib/options').postgres +const { PSQL_URL } = require('../lib/constants') function getBalances () { return [ @@ -11,7 +11,7 @@ function getBalances () { ] } -db.init(psqlUrl) +db.init(PSQL_URL) notifier.init(db, getBalances, {lowBalanceThreshold: 10}) console.log('DEBUG0') notifier.checkStatus() diff --git a/dev/recreate-seeds.js b/dev/recreate-seeds.js index 7ed801c6..b4027093 100644 --- a/dev/recreate-seeds.js +++ b/dev/recreate-seeds.js @@ -6,21 +6,21 @@ const fs = require('fs') const path = require('path') const os = require('os') const bip39 = require('bip39') -const options = require('../lib/options-loader')() +const setEnvVariable = require('../tools/set-env-var') -if (options.opts.mnemonicPath && !options.opts.seedPath) { - const mnemonic = fs.readFileSync(options.opts.mnemonicPath, 'utf8') +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) + +if (process.env.MNEMONIC_PATH && !process.env.SEED_PATH) { + const mnemonic = fs.readFileSync(process.env.MNEMONIC_PATH, 'utf8') const seed = bip39.mnemonicToEntropy(mnemonic.split('\n').join(' ').trim()).toString('hex') - options.opts.seedPath = path.resolve(os.homedir(), '.lamassu', 'seeds', 'seed.txt') + setEnvVariable('SEED_PATH', 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(path.dirname(process.env.SEED_PATH))) { + fs.mkdirSync(path.dirname(process.env.SEED_PATH)) } - if (!fs.existsSync(options.opts.seedPath)) { - fs.writeFileSync(options.opts.seedPath, seed, 'utf8') + if (!fs.existsSync(process.env.SEED_PATH)) { + fs.writeFileSync(process.env.SEED_PATH, seed, 'utf8') } - - fs.writeFileSync(options.path, JSON.stringify(options.opts, null, '\t'), 'utf8') } diff --git a/lib/admin/admin-server.js b/lib/admin/admin-server.js index f62ba24e..a510ed00 100644 --- a/lib/admin/admin-server.js +++ b/lib/admin/admin-server.js @@ -20,7 +20,6 @@ const _ = require('lodash/fp') const machineLoader = require('../machine-loader') const T = require('../time') const logger = require('../logger') -const options = require('../options') const accounts = require('./accounts') const config = require('./config') @@ -35,18 +34,20 @@ const supportServer = require('./admin-support') const NEVER = new Date(Date.now() + 100 * T.years) const REAUTHENTICATE_INTERVAL = T.minute -const idPhotoCardBasedir = _.get('idPhotoCardDir', options) -const frontCameraBasedir = _.get('frontCameraDir', options) -const operatorDataBasedir = _.get('operatorDataDir', options) + +const HOSTNAME = process.env.HOSTNAME +const KEY_PATH = process.env.KEY_PATH +const CERT_PATH = process.env.CERT_PATH +const ID_PHOTO_CARD_DIR = process.env.ID_PHOTO_CARD_DIR +const FRONT_CAMERA_DIR = process.env.FRONT_CAMERA_DIR +const OPERATOR_DATA_DIR = process.env.OPERATOR_DATA_DIR const devMode = argv.dev const version = require('../../package.json').version logger.info('Version: %s', version) -const hostname = options.hostname - -if (!hostname) { +if (!HOSTNAME) { logger.error('no hostname specified.') process.exit(1) } @@ -82,7 +83,7 @@ app.get('/api/totem', (req, res) => { if (!name) return res.status(400).send('Name is required') - return pairing.totem(hostname, name) + return pairing.totem(HOSTNAME, name) .then(totem => res.send(totem)) }) @@ -222,27 +223,27 @@ app.use((err, req, res, next) => { }) const certOptions = { - key: fs.readFileSync(options.keyPath), - cert: fs.readFileSync(options.certPath) + key: fs.readFileSync(KEY_PATH), + cert: fs.readFileSync(CERT_PATH) } app.use(serveStatic(path.resolve(__dirname, 'public'))) -if (!fs.existsSync(idPhotoCardBasedir)) { - makeDir.sync(idPhotoCardBasedir) +if (!fs.existsSync(ID_PHOTO_CARD_DIR)) { + makeDir.sync(ID_PHOTO_CARD_DIR) } -if (!fs.existsSync(frontCameraBasedir)) { - makeDir.sync(frontCameraBasedir) +if (!fs.existsSync(FRONT_CAMERA_DIR)) { + makeDir.sync(FRONT_CAMERA_DIR) } -if (!fs.existsSync(operatorDataBasedir)) { - makeDir.sync(operatorDataBasedir) +if (!fs.existsSync(OPERATOR_DATA_DIR)) { + makeDir.sync(OPERATOR_DATA_DIR) } -app.use('/id-card-photo', serveStatic(idPhotoCardBasedir, {index: false})) -app.use('/front-camera-photo', serveStatic(frontCameraBasedir, {index: false})) -app.use('/operator-data', serveStatic(operatorDataBasedir, {index: false})) +app.use('/id-card-photo', serveStatic(ID_PHOTO_CARD_DIR, {index: false})) +app.use('/front-camera-photo', serveStatic(FRONT_CAMERA_DIR, {index: false})) +app.use('/operator-data', serveStatic(OPERATOR_DATA_DIR, {index: false})) function register (req, res, next) { const otp = req.query.otp @@ -259,7 +260,7 @@ function register (req, res, next) { const cookieOpts = { httpOnly: true, secure: true, - domain: hostname, + domain: HOSTNAME, sameSite: true, expires: NEVER } diff --git a/lib/admin/admin-support.js b/lib/admin/admin-support.js index cd738610..13fd5f9d 100644 --- a/lib/admin/admin-support.js +++ b/lib/admin/admin-support.js @@ -9,7 +9,9 @@ const _ = require('lodash/fp') const serveStatic = require('serve-static') const path = require('path') -const options = require('../options') +const KEY_PATH = process.env.KEY_PATH +const CERT_PATH = process.env.CERT_PATH +const LAMASSU_CA_PATH = process.env.LAMASSU_CA_PATH app.use(morgan('dev')) app.use(helmet({noCache: true})) @@ -20,9 +22,9 @@ app.use(serveStatic(path.resolve(__dirname, '..', '..', 'public'), { })) const certOptions = { - key: fs.readFileSync(options.keyPath), - cert: fs.readFileSync(options.certPath), - ca: [fs.readFileSync(options.lamassuCaPath)], + key: fs.readFileSync(KEY_PATH), + cert: fs.readFileSync(CERT_PATH), + ca: [fs.readFileSync(LAMASSU_CA_PATH)], requestCert: true, rejectUnauthorized: true } diff --git a/lib/admin/pairing.js b/lib/admin/pairing.js index 0bdade02..7d520bbf 100644 --- a/lib/admin/pairing.js +++ b/lib/admin/pairing.js @@ -4,19 +4,18 @@ const readFile = pify(fs.readFile) const crypto = require('crypto') const baseX = require('base-x') -const options = require('../options') const db = require('../db') const pairing = require('../pairing') const ALPHA_BASE = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:' const bsAlpha = baseX(ALPHA_BASE) +const CA_PATH = process.env.CA_PATH + const unpair = pairing.unpair function totem (hostname, name) { - const caPath = options.caPath - - return readFile(caPath) + return readFile(CA_PATH) .then(data => { const caHash = crypto.createHash('sha256').update(data).digest() const token = crypto.randomBytes(32) diff --git a/lib/app.js b/lib/app.js index 72394605..449da86a 100644 --- a/lib/app.js +++ b/lib/app.js @@ -1,8 +1,11 @@ const fs = require('fs') +const path = require('path') const http = require('http') const https = require('https') const argv = require('minimist')(process.argv.slice(2)) +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) + const { asyncLocalStorage, defaultStore } = require('./async-storage') const routes = require('./routes') const logger = require('./logger') @@ -10,11 +13,13 @@ const poller = require('./poller') const settingsLoader = require('./new-settings-loader') const configManager = require('./new-config-manager') const complianceTriggers = require('./compliance-triggers') -const options = require('./options') const ofac = require('./ofac/index') const ofacUpdate = require('./ofac/update') -const devMode = argv.dev || options.http +const KEY_PATH = process.env.KEY_PATH +const CERT_PATH = process.env.CERT_PATH + +const devMode = argv.dev || process.env.HTTP const version = require('../package.json').version logger.info('Version: %s', version) @@ -66,8 +71,8 @@ function startServer (settings) { .then(() => { poller.setup(['public']) const httpsServerOptions = { - key: fs.readFileSync(options.keyPath), - cert: fs.readFileSync(options.certPath), + key: fs.readFileSync(KEY_PATH), + cert: fs.readFileSync(CERT_PATH), requestCert: true, rejectUnauthorized: false } @@ -80,7 +85,7 @@ function startServer (settings) { const localPort = 3030 const localServer = http.createServer(routes.localApp) - if (options.devMode) logger.info('In dev mode') + if (devMode) logger.info('In dev mode') server.listen(port, () => { logger.info('lamassu-server listening on port ' + diff --git a/lib/blockchain/do-volume.js b/lib/blockchain/do-volume.js index 061818c0..e3f5b825 100644 --- a/lib/blockchain/do-volume.js +++ b/lib/blockchain/do-volume.js @@ -1,10 +1,10 @@ const fs = require('fs') -const options = require('../options') - const common = require('./common') -const MOUNT_POINT = options.blockchainDir +const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR + +const MOUNT_POINT = BLOCKCHAIN_DIR module.exports = {prepareVolume} diff --git a/lib/blockchain/install.js b/lib/blockchain/install.js index 1191f20e..90cd1945 100644 --- a/lib/blockchain/install.js +++ b/lib/blockchain/install.js @@ -8,7 +8,6 @@ const inquirer = require('inquirer') const _ = require('lodash/fp') const { utils: coinUtils } = require('@lamassu/coins') -const options = require('../options') const settingsLoader = require('../new-settings-loader') const wallet = require('../wallet') @@ -29,10 +28,12 @@ const PLUGINS = { ZEC: require('./zcash.js') } +const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR + module.exports = {run} function installedVolumeFilePath (crypto) { - return path.resolve(coinUtils.cryptoDir(crypto, options.blockchainDir), '.installed') + return path.resolve(coinUtils.cryptoDir(crypto, BLOCKCHAIN_DIR), '.installed') } function isInstalledVolume (crypto) { @@ -63,7 +64,7 @@ function processCryptos (codes) { common.es('sudo supervisorctl reread') common.es('sudo supervisorctl update') - const blockchainDir = options.blockchainDir + const blockchainDir = BLOCKCHAIN_DIR const backupDir = path.resolve(os.homedir(), 'backups') const rsyncCmd = `( \ (crontab -l 2>/dev/null || echo -n "") | grep -v "@daily rsync ".*"wallet.dat"; \ @@ -83,7 +84,7 @@ function processCryptos (codes) { function setupCrypto (crypto) { logger.info(`Installing ${crypto.display}...`) - const cryptoDir = coinUtils.cryptoDir(crypto, options.blockchainDir) + const cryptoDir = coinUtils.cryptoDir(crypto, BLOCKCHAIN_DIR) makeDir.sync(cryptoDir) const cryptoPlugin = plugin(crypto) const oldDir = process.cwd() diff --git a/lib/coinatmradar/coinatmradar.js b/lib/coinatmradar/coinatmradar.js index 64660f4e..476cfd55 100644 --- a/lib/coinatmradar/coinatmradar.js +++ b/lib/coinatmradar/coinatmradar.js @@ -1,13 +1,9 @@ const axios = require('axios') const _ = require('lodash/fp') -const pify = require('pify') -const fs = pify(require('fs')) - const db = require('../db') const configManager = require('../new-config-manager') const complianceTriggers = require('../compliance-triggers') -const options = require('../options') const logger = require('../logger') const plugins = require('../plugins') const { getOperatorId } = require('../operator') @@ -15,6 +11,8 @@ const { getOperatorId } = require('../operator') const TIMEOUT = 10000 const MAX_CONTENT_LENGTH = 2000 +const COIN_ATM_RADAR_URL = process.env.COIN_ATM_RADAR_URL + // How long a machine can be down before it's considered offline const STALE_INTERVAL = '2 minutes' @@ -112,7 +110,7 @@ function getMachines (rates, settings) { } function sendRadar (data) { - const url = _.get(['coinAtmRadar', 'url'], options) + const url = COIN_ATM_RADAR_URL if (_.isEmpty(url)) { return Promise.reject(new Error('Missing coinAtmRadar url!')) diff --git a/lib/constants.js b/lib/constants.js index c4bc2fbc..ff1bc8f2 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,5 +1,13 @@ const T = require('./time') +const POSTGRES_USER = process.env.POSTGRES_USER +const POSTGRES_PASSWORD = process.env.POSTGRES_PASSWORD +const POSTGRES_HOST = process.env.POSTGRES_HOST +const POSTGRES_PORT = process.env.POSTGRES_PORT +const POSTGRES_DB = process.env.POSTGRES_DB + +const PSQL_URL = `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}` + const anonymousCustomer = { uuid: '47ac1184-8102-11e7-9079-8f13a7117867', name: 'anonymous' @@ -39,5 +47,6 @@ module.exports = { CASH_OUT_MINIMUM_AMOUNT_OF_CASSETTES, CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES, WALLET_SCORE_THRESHOLD, - RECEIPT + RECEIPT, + PSQL_URL } diff --git a/lib/customers.js b/lib/customers.js index 0f68f1ed..7246e021 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -13,20 +13,20 @@ const BN = require('./bn') const anonymous = require('../lib/constants').anonymousCustomer const complianceOverrides = require('./compliance_overrides') const users = require('./users') -const options = require('./options') const writeFile = util.promisify(fs.writeFile) const notifierQueries = require('./notifier/queries') const notifierUtils = require('./notifier/utils') const NUM_RESULTS = 1000 -const idPhotoCardBasedir = _.get('idPhotoCardDir', options) -const frontCameraBaseDir = _.get('frontCameraDir', options) -const operatorDataDir = _.get('operatorDataDir', options) const sms = require('./sms') const settingsLoader = require('./new-settings-loader') const logger = require('./logger') const TX_PASSTHROUGH_ERROR_CODES = ['operatorCancel'] +const ID_PHOTO_CARD_DIR = process.env.ID_PHOTO_CARD_DIR +const FRONT_CAMERA_DIR = process.env.FRONT_CAMERA_DIR +const OPERATOR_DATA_DIR = process.env.OPERATOR_DATA_DIR + /** * Add new customer * @@ -673,7 +673,7 @@ function updatePhotoCard (id, patch) { const rpath = _.join(path.sep, _.map(_.wrap(_.join, ''), _.take(3, _.chunk(2, _.split('', hash))))) // i.e. ..//idphotocard/24/0e/85 - const dirname = path.join(idPhotoCardBasedir, rpath) + const dirname = path.join(ID_PHOTO_CARD_DIR, rpath) // create the directory tree if needed _.attempt(() => makeDir.sync(dirname)) @@ -736,7 +736,7 @@ function updatePhotos (imagesData, id, dir) { function updateIdCardData (patch, id) { /* TODO: fetch operator id */ const operatorId = 'id-operator' - const directory = `${operatorDataDir}/${operatorId}/${id}/` + const directory = `${OPERATOR_DATA_DIR}/${operatorId}/${id}/` return Promise.resolve(patch) .then(patch => { @@ -755,7 +755,7 @@ function updateTxCustomerPhoto (imageData) { return Promise.resolve(imageData) .then(imageData => { const newPatch = {} - const directory = `${operatorDataDir}/customersphotos` + const directory = `${OPERATOR_DATA_DIR}/customersphotos` if (_.isEmpty(imageData)) { return @@ -826,7 +826,7 @@ function updateFrontCamera (id, patch) { const rpath = _.join(path.sep, _.map(_.wrap(_.join, ''), _.take(3, _.chunk(2, _.split('', hash))))) // i.e. ..//idphotocard/24/0e/85 - const dirname = path.join(frontCameraBaseDir, rpath) + const dirname = path.join(FRONT_CAMERA_DIR, rpath) // create the directory tree if needed _.attempt(() => makeDir.sync(dirname)) diff --git a/lib/db.js b/lib/db.js index 43c25537..4a66e566 100644 --- a/lib/db.js +++ b/lib/db.js @@ -2,7 +2,7 @@ const Pgp = require('pg-promise') const uuid = require('uuid') const _ = require('lodash/fp') -const psqlUrl = require('../lib/options').postgresql +const { PSQL_URL } = require('./constants') const logger = require('./logger') const eventBus = require('./event-bus') const { asyncLocalStorage, defaultStore } = require('./async-storage') @@ -87,7 +87,7 @@ const pgp = Pgp({ } }) -const db = stripDefaultDbFuncs(pgp(psqlUrl)) +const db = stripDefaultDbFuncs(pgp(PSQL_URL)) eventBus.subscribe('log', args => { if (process.env.SKIP_SERVER_LOGS) return diff --git a/lib/logger.js b/lib/logger.js index 5b21e3c1..65298e64 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -1,9 +1,11 @@ const winston = require('winston') const Postgres = require('./pg-transport') -const options = require('./options') +const { PSQL_URL } = require('./constants') + +const LOG_LEVEL = process.env.LOG_LEVEL const logger = new winston.Logger({ - level: options.logLevel, + level: LOG_LEVEL, transports: [ new (winston.transports.Console)({ timestamp: true, @@ -12,7 +14,7 @@ const logger = new winston.Logger({ humanReadableUnhandledException: true }), new Postgres({ - connectionString: options.postgresql, + connectionString: PSQL_URL, tableName: 'server_logs', handleExceptions: true, humanReadableUnhandledException: true diff --git a/lib/new-admin/admin-server.js b/lib/new-admin/admin-server.js index 53f86ccc..b6ec0221 100644 --- a/lib/new-admin/admin-server.js +++ b/lib/new-admin/admin-server.js @@ -8,13 +8,13 @@ const cors = require('cors') const helmet = require('helmet') const nocache = require('nocache') const cookieParser = require('cookie-parser') -const { ApolloServer, AuthenticationError } = require('apollo-server-express') const { graphqlUploadExpress } = require('graphql-upload') +const { ApolloServer } = require('apollo-server-express') const _ = require('lodash/fp') +require('dotenv').config({ path: path.resolve(__dirname, '../../.env') }) + const { asyncLocalStorage, defaultStore } = require('../async-storage') -const options = require('../options') -const users = require('../users') const logger = require('../logger') const { AuthDirective } = require('./graphql/directives') @@ -25,13 +25,16 @@ const { USER_SESSIONS_CLEAR_INTERVAL } = require('../constants') const { session, cleanUserSessions, buildApolloContext } = require('./middlewares') const devMode = require('minimist')(process.argv.slice(2)).dev -const idPhotoCardBasedir = _.get('idPhotoCardDir', options) -const frontCameraBasedir = _.get('frontCameraDir', options) -const operatorDataBasedir = _.get('operatorDataDir', options) -const hostname = options.hostname -if (!hostname) { - logger.error('no hostname specified.') +const HOSTNAME = process.env.HOSTNAME +const KEY_PATH = process.env.KEY_PATH +const CERT_PATH = process.env.CERT_PATH +const ID_PHOTO_CARD_DIR = process.env.ID_PHOTO_CARD_DIR +const FRONT_CAMERA_DIR = process.env.FRONT_CAMERA_DIR +const OPERATOR_DATA_DIR = process.env.OPERATOR_DATA_DIR + +if (!HOSTNAME) { + logger.error('No hostname specified.') process.exit(1) } @@ -77,16 +80,16 @@ apolloServer.applyMiddleware({ // cors on app for /api/register endpoint. app.use(cors({ credentials: true, origin: devMode && 'https://localhost:3001' })) -app.use('/id-card-photo', serveStatic(idPhotoCardBasedir, { index: false })) -app.use('/front-camera-photo', serveStatic(frontCameraBasedir, { index: false })) -app.use('/operator-data', serveStatic(operatorDataBasedir, { index: false })) +app.use('/id-card-photo', serveStatic(ID_PHOTO_CARD_DIR, { index: false })) +app.use('/front-camera-photo', serveStatic(FRONT_CAMERA_DIR, { index: false })) +app.use('/operator-data', serveStatic(OPERATOR_DATA_DIR, { index: false })) // Everything not on graphql or api/register is redirected to the front-end app.get('*', (req, res) => res.sendFile(path.resolve(__dirname, '..', '..', 'public', 'index.html'))) const certOptions = { - key: fs.readFileSync(options.keyPath), - cert: fs.readFileSync(options.certPath) + key: fs.readFileSync(KEY_PATH), + cert: fs.readFileSync(CERT_PATH) } function run () { diff --git a/lib/new-admin/graphql-dev-insecure.js b/lib/new-admin/graphql-dev-insecure.js index 8ec2b586..8d673d54 100644 --- a/lib/new-admin/graphql-dev-insecure.js +++ b/lib/new-admin/graphql-dev-insecure.js @@ -1,6 +1,9 @@ const express = require('express') +const path = require('path') const { ApolloServer } = require('apollo-server-express') +require('dotenv').config({ path: path.resolve(__dirname, '../../.env') }) + const { typeDefs, resolvers } = require('./graphql/schema') const logger = require('../logger') diff --git a/lib/new-admin/middlewares/session.js b/lib/new-admin/middlewares/session.js index 338e4b11..f85b6205 100644 --- a/lib/new-admin/middlewares/session.js +++ b/lib/new-admin/middlewares/session.js @@ -3,12 +3,9 @@ const router = express.Router() const session = require('express-session') const PgSession = require('connect-pg-simple')(session) const db = require('../../db') -const options = require('../../options') const { USER_SESSIONS_TABLE_NAME } = require('../../constants') const { getOperatorId } = require('../../operator') -const hostname = options.hostname - router.use('*', async (req, res, next) => getOperatorId('authentication').then(({ operatorId }) => session({ store: new PgSession({ pgPromise: db, diff --git a/lib/new-admin/services/pairing.js b/lib/new-admin/services/pairing.js index 0ae14dc0..d267c1a9 100644 --- a/lib/new-admin/services/pairing.js +++ b/lib/new-admin/services/pairing.js @@ -5,24 +5,25 @@ const crypto = require('crypto') const baseX = require('base-x') const { parse, NIL } = require('uuid') -const options = require('../../options') const db = require('../../db') const pairing = require('../../pairing') const ALPHA_BASE = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:' const bsAlpha = baseX(ALPHA_BASE) +const CA_PATH = process.env.CA_PATH +const HOSTNAME = process.env.HOSTNAME + const unpair = pairing.unpair function totem (name) { - const caPath = options.caPath - return readFile(caPath) + return readFile(CA_PATH) .then(data => { const caHash = crypto.createHash('sha256').update(data).digest() const token = crypto.randomBytes(32) const hexToken = token.toString('hex') const caHexToken = crypto.createHash('sha256').update(hexToken).digest('hex') - const buf = Buffer.concat([caHash, token, Buffer.from(options.hostname)]) + const buf = Buffer.concat([caHash, token, Buffer.from(HOSTNAME)]) const sql = 'insert into pairing_tokens (token, name) values ($1, $3), ($2, $3)' return db.none(sql, [hexToken, caHexToken, name]) diff --git a/lib/ofac/index.js b/lib/ofac/index.js index 4d352263..fff2f70e 100644 --- a/lib/ofac/index.js +++ b/lib/ofac/index.js @@ -4,23 +4,24 @@ const util = require('util') const loader = require('./loading') const matcher = require('./matching') const nameUtils = require('./name-utils') -const options = require('../options') const _ = require('lodash/fp') const logger = require('../logger') const debugLog = require('../pp')(__filename) // KOSTIS TODO: remove +const OFAC_DATA_DIR = process.env.OFAC_DATA_DIR + let structs = null const readdir = util.promisify(fs.readdir) function load () { - if (!options.ofacDataDir) { - const message = 'The ofacDataDir option has not been set in lamassu.json' + if (!OFAC_DATA_DIR) { + const message = 'The ofacDataDir option has not been set in the environment' return Promise.reject(new Error(message)) } - const ofacSourcesDir = path.join(options.ofacDataDir, 'sources') + const ofacSourcesDir = path.join(OFAC_DATA_DIR, 'sources') return readdir(ofacSourcesDir) .then(_.flow( diff --git a/lib/ofac/update.js b/lib/ofac/update.js index 5cf7a351..11fe480d 100644 --- a/lib/ofac/update.js +++ b/lib/ofac/update.js @@ -4,12 +4,23 @@ const url = require('url') const fs = require('fs') const path = require('path') const util = require('util') -const options = require('../options') const _ = require('lodash/fp') const logger = require('../logger') const DOWNLOAD_DIR = path.resolve('/tmp') +const OFAC_DATA_DIR = process.env.OFAC_DATA_DIR +const OFAC_SOURCES_NAMES = process.env.OFAC_SOURCES_NAMES.split(',') +const OFAC_SOURCES_URLS = process.env.OFAC_SOURCES_URLS.split(',') + +const ofacSources = _.map( + it => ({ + name: it[0], + url: it[1] + }), + _.zip(OFAC_SOURCES_NAMES, OFAC_SOURCES_URLS) +) + function mkdir (path) { return new Promise((resolve, reject) => { fs.mkdir(path, err => { @@ -97,14 +108,12 @@ const moveToSourcesDir = (srcFile, ofacSourcesDir) => { } function update () { - const OFAC_DATA_DIR = options.ofacDataDir - if (!OFAC_DATA_DIR) { - throw new Error('ofacDataDir must be defined in lamassu.json') + throw new Error('ofacDataDir must be defined in the environment') } - if (!options.ofacSources) { - logger.error('ofacSources must be defined in lamassu.json') + if (!ofacSources) { + logger.error('ofacSources must be defined in the environment') } const OFAC_SOURCES_DIR = path.join(OFAC_DATA_DIR, 'sources') @@ -125,7 +134,7 @@ function update () { return {} }) - const promiseNewEtags = Promise.resolve(options.ofacSources || []) + const promiseNewEtags = Promise.resolve(ofacSources || []) .then(sources => Promise.all(_.map(promiseGetEtag, sources)) .then(etags => _.map( ([source, etag]) => ({...source, etag}), diff --git a/lib/options-loader.js b/lib/options-loader.js index 9b9af1be..4f05ee5a 100644 --- a/lib/options-loader.js +++ b/lib/options-loader.js @@ -4,11 +4,12 @@ const os = require('os') const argv = require('minimist')(process.argv.slice(2)) const _ = require('lodash/fp') -require('dotenv').config() +require('dotenv').config({ path: path.resolve(__dirname, '../.env') }) const DATABASE = process.env.LAMASSU_DB ?? 'PROD' const dbMapping = psqlConf => ({ STRESS_TEST: _.replace('lamassu', 'lamassu_stress', psqlConf), + PAZUZ: _.replace('lamassu', 'lamassu_pazuz', psqlConf), RELEASE: _.replace('lamassu', 'lamassu_release', psqlConf), DEV: _.replace('lamassu', 'lamassu', psqlConf), PROD: _.replace('lamassu', 'lamassu', psqlConf) diff --git a/lib/pairing.js b/lib/pairing.js index 55cddc98..f6942591 100644 --- a/lib/pairing.js +++ b/lib/pairing.js @@ -2,13 +2,14 @@ const fs = require('fs') const pify = require('pify') const readFile = pify(fs.readFile) const db = require('./db') -const options = require('./options') const logger = require('./logger') const uuid = require('uuid') +const CA_PATH = process.env.CA_PATH + // A machine on an older version (no multicassette code) could be paired with a server with multicassette code. // This makes sure that the server stores a default value -const DEFAULT_NUMBER_OF_CASSETTES = 2 +const DEFAULT_NUMBER_OF_CASSETTES = 2 function pullToken (token) { const sql = `delete from pairing_tokens @@ -58,8 +59,7 @@ function authorizeCaDownload (caToken) { .then(r => { if (r.expired) throw new Error('Expired') - const caPath = options.caPath - return readFile(caPath, {encoding: 'utf8'}) + return readFile(CA_PATH, {encoding: 'utf8'}) }) } diff --git a/lib/plugins/common/json-rpc.js b/lib/plugins/common/json-rpc.js index 50372116..be82ac0b 100644 --- a/lib/plugins/common/json-rpc.js +++ b/lib/plugins/common/json-rpc.js @@ -6,9 +6,7 @@ const _ = require('lodash/fp') const request = require('request-promise') const { utils: coinUtils } = require('@lamassu/coins') -const options = require('../../options') - -const blockchainDir = options.blockchainDir +const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR module.exports = { fetch, fetchDigest, parseConf, rpcConfig @@ -108,7 +106,7 @@ function parseConf (confPath) { function rpcConfig (cryptoRec) { try { - const configPath = coinUtils.configPath(cryptoRec, blockchainDir) + const configPath = coinUtils.configPath(cryptoRec, BLOCKCHAIN_DIR) const config = parseConf(configPath) return { username: config.rpcuser, diff --git a/lib/plugins/layer2/strike/strike.js b/lib/plugins/layer2/strike/strike.js index 39f3cd01..d3469331 100644 --- a/lib/plugins/layer2/strike/strike.js +++ b/lib/plugins/layer2/strike/strike.js @@ -1,7 +1,7 @@ const axios = require('axios') const _ = require('lodash/fp') -const options = require('../../../options') +const STRIKE_BASE_URL = process.env.STRIKE_BASE_URL module.exports = { newAddress, @@ -9,7 +9,7 @@ module.exports = { cryptoNetwork } -axios.defaults.baseURL = _.get('strike.baseUrl', options) +axios.defaults.baseURL = STRIKE_BASE_URL if (_.isEmpty(axios.defaults.baseURL)) { throw new Error('Missing Strike baseUrl!') } diff --git a/lib/plugins/wallet/lnd/lnd.js b/lib/plugins/wallet/lnd/lnd.js index 8f7d3e72..f32cee37 100644 --- a/lib/plugins/wallet/lnd/lnd.js +++ b/lib/plugins/wallet/lnd/lnd.js @@ -3,13 +3,14 @@ const lnd = require('lnd-async') const BN = require('../../../bn') const E = require('../../../error') const { utils: coinUtils } = require('@lamassu/coins') -const options = require('../../../options') const _ = require('lodash/fp') const cryptoRec = coinUtils.getCryptoCurrency('BTC') const unitScale = cryptoRec.unitScale +const LND = process.env.LIGHTNING_NETWORK_DAEMON + module.exports = { balance, sendCoins, @@ -20,7 +21,7 @@ module.exports = { } function connect () { - return lnd.connect(options.lnd || {}) + return lnd.connect(LND || {}) } function cryptoNetwork (account, cryptoCode, settings, operatorId) { diff --git a/lib/plugins/wallet/monerod/monerod.js b/lib/plugins/wallet/monerod/monerod.js index f6f17fcd..0a5662a3 100644 --- a/lib/plugins/wallet/monerod/monerod.js +++ b/lib/plugins/wallet/monerod/monerod.js @@ -7,14 +7,13 @@ const { default: PQueue } = require('p-queue') const BN = require('../../../bn') const E = require('../../../error') const { logger } = require('../../../blockchain/common') -const options = require('../../../options') const jsonRpc = require('../../common/json-rpc') -const blockchainDir = options.blockchainDir +const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR const cryptoRec = utils.getCryptoCurrency(COINS.XMR) -const configPath = utils.configPath(cryptoRec, blockchainDir) -const walletDir = path.resolve(utils.cryptoDir(cryptoRec, blockchainDir), 'wallets') +const configPath = utils.configPath(cryptoRec, BLOCKCHAIN_DIR) +const walletDir = path.resolve(utils.cryptoDir(cryptoRec, BLOCKCHAIN_DIR), 'wallets') const DIGEST_QUEUE = new PQueue({ concurrency: 1, diff --git a/lib/plugins/wallet/pazuz-wallet/pazuz-wallet.js b/lib/plugins/wallet/pazuz-wallet/pazuz-wallet.js index 44a29f47..9ed8c3b7 100644 --- a/lib/plugins/wallet/pazuz-wallet/pazuz-wallet.js +++ b/lib/plugins/wallet/pazuz-wallet/pazuz-wallet.js @@ -4,11 +4,11 @@ const E = require('../../../error') const _ = require('lodash/fp') const ENV = process.env.NODE_ENV === undefined || process.env.NODE_ENV === 'development' ? 'development' : 'production' -const SUPPORTED_COINS = ['BTC', 'ZEC', 'LTC', 'BCH', 'DASH', 'ETH'] +const SUPPORTED_COINS = ['BTC'] const axios = require('axios').create({ // TODO: get rejectUnauthorized true to work - baseURL: ENV === 'development' ? 'https://localhost:5555/api/' : process.env.PAZUZ_API_WALLET_URL, + baseURL: `${process.env.WALLET_URL}/api`, httpsAgent: new https.Agent({ rejectUnauthorized: false }) @@ -22,9 +22,8 @@ function balance (account, cryptoCode, settings, operatorId) { return checkCryptoCode(cryptoCode) .then(() => { return axios.post('/balance', { - account, cryptoCode, - settings, + config: settings.config, operatorId }) }) @@ -39,9 +38,8 @@ function sendCoins (account, tx, settings, operatorId) { return checkCryptoCode(cryptoCode) .then(() => { return axios.post('/sendCoins', { - account, tx, - settings, + config: settings.config, operatorId }) }) @@ -57,10 +55,9 @@ function sendCoins (account, tx, settings, operatorId) { function newAddress (account, info, tx, settings, operatorId) { return checkCryptoCode(info.cryptoCode) .then(() => axios.post('/newAddress', { - account, info, tx, - settings, + config: settings.config, operatorId })) .then(({ data }) => { diff --git a/lib/routes.js b/lib/routes.js index 22b72bf2..7e5343ca 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -6,7 +6,6 @@ const morgan = require('morgan') const nocache = require('nocache') const logger = require('./logger') -const options = require('./options') const authorize = require('./middlewares/authorize') const errorHandler = require('./middlewares/errorHandler') @@ -41,7 +40,7 @@ const configRequiredRoutes = [ '/tx', '/verify_promo_code' ] -const devMode = argv.dev || options.http +const devMode = argv.dev || process.env.HTTP // middleware setup app.use(compression({ threshold: 500 })) diff --git a/lib/wallet.js b/lib/wallet.js index 1073a8a0..068ffc5b 100644 --- a/lib/wallet.js +++ b/lib/wallet.js @@ -7,7 +7,6 @@ const pify = require('pify') const fs = pify(require('fs')) const mnemonicHelpers = require('./mnemonic-helpers') -const options = require('./options') const ph = require('./plugin-helper') const layer2 = require('./layer2') const httpError = require('./route-helpers').httpError @@ -20,6 +19,8 @@ const INSUFFICIENT_FUNDS_CODE = 570 const INSUFFICIENT_FUNDS_NAME = 'InsufficientFunds' const ZERO_CONF_EXPIRATION = 60000 +const MNEMONIC_PATH = process.env.MNEMONIC_PATH + function computeSeed (masterSeed) { return hkdf(masterSeed, 32, { salt: 'lamassu-server-salt', info: 'wallet-seed' }) } @@ -29,7 +30,7 @@ function computeOperatorId (masterSeed) { } function fetchWallet (settings, cryptoCode) { - return fs.readFile(options.mnemonicPath, 'utf8') + return fs.readFile(MNEMONIC_PATH, 'utf8') .then(mnemonic => { const masterSeed = mnemonicHelpers.toEntropyBuffer(mnemonic) const plugin = configManager.getWalletSettings(cryptoCode, settings.config).wallet diff --git a/migrations/1623413776161-create-operator-ids.js b/migrations/1623413776161-create-operator-ids.js index 7ca4a31e..c9157f0f 100644 --- a/migrations/1623413776161-create-operator-ids.js +++ b/migrations/1623413776161-create-operator-ids.js @@ -5,7 +5,6 @@ const hkdf = require('futoin-hkdf') const state = require('../lib/middlewares/state') const mnemonicHelpers = require('../lib/mnemonic-helpers') -const options = require('../lib/options') function computeOperatorId (masterSeed) { return hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex') @@ -13,7 +12,7 @@ function computeOperatorId (masterSeed) { function getMnemonic () { if (state.mnemonic) return Promise.resolve(state.mnemonic) - return fs.readFile(options.mnemonicPath, 'utf8').then(mnemonic => { + return fs.readFile(process.env.MNEMONIC_PATH, 'utf8').then(mnemonic => { state.mnemonic = mnemonic return mnemonic }) diff --git a/new-lamassu-admin/.env b/new-lamassu-admin/.env index 074e97a8..81016f7c 100644 --- a/new-lamassu-admin/.env +++ b/new-lamassu-admin/.env @@ -2,4 +2,4 @@ SKIP_PREFLIGHT_CHECK=true HTTPS=true REACT_APP_TYPE_CHECK_SANCTUARY=false PORT=3001 -REACT_APP_BUILD_TARGET=LAMASSU \ No newline at end of file +REACT_APP_BUILD_TARGET=PAZUZ \ No newline at end of file diff --git a/new-lamassu-admin/src/pages/Accounting/Accounting.js b/new-lamassu-admin/src/pages/Accounting/Accounting.js index 7175cd3d..bd141bcb 100644 --- a/new-lamassu-admin/src/pages/Accounting/Accounting.js +++ b/new-lamassu-admin/src/pages/Accounting/Accounting.js @@ -170,22 +170,26 @@ const Accounting = () => { ] return ( - <> - - -

Fiat balance history

- - + !loading && ( + <> + + +

Fiat balance history

+ + + ) ) } diff --git a/tools/build-dev-env.js b/tools/build-dev-env.js new file mode 100644 index 00000000..ddc89de2 --- /dev/null +++ b/tools/build-dev-env.js @@ -0,0 +1,32 @@ +const fs = require('fs') +const os = require('os') +const path = require('path') + +const setEnvVariable = require('./set-env-var') + +fs.copyFileSync(path.resolve(__dirname, '../.sample.env'), path.resolve(__dirname, '../.env')) + +setEnvVariable('LAMASSU_DB', 'DEV') +setEnvVariable('POSTGRES_USER', 'postgres') +setEnvVariable('POSTGRES_PASSWORD', 'postgres123') +setEnvVariable('POSTGRES_HOST', 'localhost') +setEnvVariable('POSTGRES_PORT', '5432') +setEnvVariable('POSTGRES_DB', 'lamassu') + +setEnvVariable('CA_PATH', `${process.env.PWD}/certs/Lamassu_OP_Root_CA.pem`) +setEnvVariable('CERT_PATH', `${process.env.PWD}/certs/Lamassu_OP.pem`) +setEnvVariable('KEY_PATH', `${process.env.PWD}/certs/Lamassu_OP.key`) + +setEnvVariable('MNEMONIC_PATH', `${process.env.HOME}/.lamassu/mnemonics/mnemonic.txt`) +setEnvVariable('MIGRATE_STATE_PATH', `${process.env.HOME}/.lamassu/.migrate`) + +setEnvVariable('OFAC_DATA_DIR', `${process.env.HOME}/.lamassu/ofac`) +setEnvVariable('ID_PHOTO_CARD_DIR', `${process.env.HOME}/.lamassu/idphotocard`) +setEnvVariable('FRONT_CAMERA_DIR', `${process.env.HOME}/.lamassu/frontcamera`) +setEnvVariable('OPERATOR_DATA_DIR', `${process.env.HOME}/.lamassu/operatordata`) + +setEnvVariable('OFAC_SOURCES_NAMES', 'sdn_advanced,cons_advanced') +setEnvVariable('OFAC_SOURCES_URLS', 'https://www.treasury.gov/ofac/downloads/sanctions/1.0/sdn_advanced.xml,https://www.treasury.gov/ofac/downloads/sanctions/1.0/cons_advanced.xml') + +setEnvVariable('HOSTNAME', 'localhost') +setEnvVariable('LOG_LEVEL', 'debug') diff --git a/tools/build-prod-env.js b/tools/build-prod-env.js new file mode 100644 index 00000000..ba277224 --- /dev/null +++ b/tools/build-prod-env.js @@ -0,0 +1,45 @@ +const fs = require('fs') +const os = require('os') +const path = require('path') +const argv = require('minimist')(process.argv.slice(2)) +const _ = require('lodash/fp') + +const setEnvVariable = require('./set-env-var') + +const requiredParams = ['db-password', 'hostname'] + +if (!_.isEqual(_.intersection(_.keys(argv), requiredParams), requiredParams)) { + console.error('Usage: node tools/build-prod-env.js --db-password --hostname ') + process.exit(2) +} + +fs.copyFileSync(path.resolve(__dirname, '../.sample.env'), path.resolve(__dirname, '../.env')) + +setEnvVariable('POSTGRES_USER', 'lamassu_pg') +setEnvVariable('POSTGRES_PASSWORD', `${argv['db-password']}`) +setEnvVariable('POSTGRES_HOST', 'localhost') +setEnvVariable('POSTGRES_PORT', '5432') +setEnvVariable('POSTGRES_DB', 'lamassu') + +setEnvVariable('LAMASSU_CA_PATH', `/etc/ssl/certs/Lamassu_CA.pem`) +setEnvVariable('CA_PATH', `/etc/ssl/certs/Lamassu_OP_Root_CA.pem`) +setEnvVariable('CERT_PATH', `/etc/ssl/certs/Lamassu_OP.pem`) +setEnvVariable('KEY_PATH', `/etc/ssl/certs/Lamassu_OP.key`) + +setEnvVariable('MNEMONIC_PATH', `/etc/lamassu/mnemonics/mnemonic.txt`) +setEnvVariable('MIGRATE_STATE_PATH', `/etc/lamassu/.migrate`) + +setEnvVariable('BLOCKCHAIN_DIR', `/mnt/blockchains`) +setEnvVariable('OFAC_DATA_DIR', `/var/lamassu/ofac`) +setEnvVariable('ID_PHOTO_CARD_DIR', `/opt/lamassu-server/idphotocard`) +setEnvVariable('FRONT_CAMERA_DIR', `/opt/lamassu-server/frontcamera`) +setEnvVariable('OPERATOR_DATA_DIR', `/opt/lamassu-server/operatordata`) + +setEnvVariable('STRIKE_BASE_URL', `https://api.strike.acinq.co/api/`) +setEnvVariable('COIN_ATM_RADAR_URL', `https://coinatmradar.info/api/lamassu/`) + +setEnvVariable('OFAC_SOURCES_NAMES', 'sdn_advanced,cons_advanced') +setEnvVariable('OFAC_SOURCES_URLS', 'https://www.treasury.gov/ofac/downloads/sanctions/1.0/sdn_advanced.xml,https://www.treasury.gov/ofac/downloads/sanctions/1.0/cons_advanced.xml') + +setEnvVariable('HOSTNAME', `${argv.hostname}`) +setEnvVariable('LOG_LEVEL', 'info') diff --git a/tools/cert-gen.sh b/tools/cert-gen.sh index 2a5fe062..90d5dde4 100755 --- a/tools/cert-gen.sh +++ b/tools/cert-gen.sh @@ -91,32 +91,6 @@ rm /tmp/Lamassu_OP.csr.pem mkdir -p $OFAC_DATA_DIR/sources touch $OFAC_DATA_DIR/etags.json -cat < $CONFIG_DIR/lamassu.json -{ - "postgresql": "psql://postgres:$POSTGRES_PASS@localhost/lamassu", - "mnemonicPath": "$MNEMONIC_FILE", - "caPath": "$CA_PATH", - "certPath": "$SERVER_CERT_PATH", - "keyPath": "$SERVER_KEY_PATH", - "hostname": "$DOMAIN", - "logLevel": "debug", - "lamassuCaPath": "$LAMASSU_CA_PATH", - "migrateStatePath": "$MIGRATE_STATE_PATH", - "ofacDataDir": "$OFAC_DATA_DIR", - "ofacSources": [ - { - "name": "sdn_advanced", - "url": "https://www.treasury.gov/ofac/downloads/sanctions/1.0/sdn_advanced.xml" - }, - { - "name": "cons_advanced", - "url": "https://www.treasury.gov/ofac/downloads/sanctions/1.0/cons_advanced.xml" - } - ], - "idPhotoCardDir": "$IDPHOTOCARD_DIR", - "frontCameraDir": "$FRONTCAMERA_DIR", - "operatorDataDir": "$OPERATOR_DIR" -} -EOF +node tools/build-dev-env.js echo "Done." diff --git a/tools/set-env-var.js b/tools/set-env-var.js new file mode 100644 index 00000000..1b82cff0 --- /dev/null +++ b/tools/set-env-var.js @@ -0,0 +1,24 @@ +const fs = require('fs') +const os = require('os') +const path = require('path') + +const setEnvVariable = (key, value) => { + const ENV_VARIABLES = fs.readFileSync(path.resolve(__dirname, '../.env'), 'utf-8').split(os.EOL) + const target = ENV_VARIABLES.indexOf(ENV_VARIABLES.find(line => line.match(new RegExp(`^${key}=`)))) + + if (target < 0) { + // The variable doesn't exist, add it + ENV_VARIABLES.push(`${key}=${value}`) + } else { + // .env already has that variable set, or at least has the definition of its key + // + // This is currently circumventing a possible bug on dotenv + // where the variables on this script were showing up as undefined on the first run despite the key existing, + // while on a second run they'd appear as empty string, as intended + ENV_VARIABLES.splice(target, 1, `${key}=${value}`) + } + + fs.writeFileSync(path.resolve(__dirname, '../.env'), ENV_VARIABLES.join(os.EOL)) +} + +module.exports = setEnvVariable