feat: decouple l-s entrypoint
This commit is contained in:
parent
2a2c1fccc8
commit
f4d6b5e454
48 changed files with 411 additions and 232 deletions
1
.env
1
.env
|
|
@ -1 +0,0 @@
|
||||||
LAMASSU_DB=DEV
|
|
||||||
59
.sample.env
Normal file
59
.sample.env
Normal file
|
|
@ -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
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
var pgp = require('pg-promise')()
|
const path = require('path')
|
||||||
var psqlUrl = require('../lib/options').postgresql
|
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
|
db.manyOrNone(`select * from transactions where incoming=false
|
||||||
and stage='final_request' and authority='machine'`)
|
and stage='final_request' and authority='machine'`)
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const fs = require('fs')
|
const path = require('path')
|
||||||
const options = require('../lib/options-loader')()
|
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||||
|
|
||||||
if (!options.opts.frontCameraDir) {
|
const setEnvVariable = require('../tools/set-env-var')
|
||||||
options.opts.frontCameraDir = '/opt/lamassu-server/frontcamera'
|
|
||||||
|
|
||||||
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')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||||
const hdkey = require('ethereumjs-wallet/hdkey')
|
const hdkey = require('ethereumjs-wallet/hdkey')
|
||||||
const hkdf = require('futoin-hkdf')
|
const hkdf = require('futoin-hkdf')
|
||||||
const db = require('../lib/db')
|
const db = require('../lib/db')
|
||||||
|
|
@ -9,14 +11,14 @@ const mnemonicHelpers = require('../lib/mnemonic-helpers')
|
||||||
const pify = require('pify')
|
const pify = require('pify')
|
||||||
const fs = pify(require('fs'))
|
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 defaultPrefixPath = "m/44'/60'/1'/0'"
|
||||||
const paymentPrefixPath = "m/44'/60'/0'/0'"
|
const paymentPrefixPath = "m/44'/60'/0'/0'"
|
||||||
|
|
||||||
const address = process.argv[2]
|
const address = process.argv[2]
|
||||||
|
|
||||||
if (!options || !options.mnemonicPath) {
|
if (!MNEMONIC_PATH) {
|
||||||
console.error(`Unable to fetch mnemonic from your account!`)
|
console.error(`Unable to fetch mnemonic from your account!`)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +49,7 @@ function searchForHdIndex (address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchMnemonic () {
|
function fetchMnemonic () {
|
||||||
return fs.readFile(options.mnemonicPath, 'utf8')
|
return fs.readFile(MNEMONIC_PATH, 'utf8')
|
||||||
.then(mnemonic => computeSeed(mnemonic))
|
.then(mnemonic => computeSeed(mnemonic))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
const FileStore = require('migrate/lib/file-store')
|
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 db = require('../lib/db')
|
||||||
const migrate = require('../lib/migrate')
|
const migrate = require('../lib/migrate')
|
||||||
const options = require('../lib/options')
|
|
||||||
const { asyncLocalStorage, defaultStore } = require('../lib/async-storage')
|
const { asyncLocalStorage, defaultStore } = require('../lib/async-storage')
|
||||||
|
|
||||||
|
const MIGRATE_STATE_PATH = process.env.MIGRATE_STATE_PATH
|
||||||
|
|
||||||
const createMigration = `CREATE TABLE IF NOT EXISTS migrations (
|
const createMigration = `CREATE TABLE IF NOT EXISTS migrations (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
data json NOT NULL
|
data json NOT NULL
|
||||||
|
|
@ -14,7 +20,7 @@ const select = 'select * from migrations limit 1'
|
||||||
|
|
||||||
const getMigrateFile = () => {
|
const getMigrateFile = () => {
|
||||||
return new Promise((resolve, reject) => {
|
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)
|
if (err) return reject(err)
|
||||||
return resolve(store)
|
return resolve(store)
|
||||||
})
|
})
|
||||||
|
|
@ -26,7 +32,7 @@ asyncLocalStorage.run(store, () => {
|
||||||
db.none(createMigration)
|
db.none(createMigration)
|
||||||
.then(() => Promise.all([db.oneOrNone(select), getMigrateFile()]))
|
.then(() => Promise.all([db.oneOrNone(select), getMigrateFile()]))
|
||||||
.then(([qResult, migrateFile]) => {
|
.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) {
|
if (!qResult && migrateFile) {
|
||||||
return db.none('insert into migrations (id, data) values (1, $1)', [migrateFile])
|
return db.none('insert into migrations (id, data) values (1, $1)', [migrateFile])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const fs = require('fs')
|
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)
|
console.log(mnemonic)
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,12 @@
|
||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const fs = require('fs')
|
const setEnvVariable = require('../tools/set-env-var')
|
||||||
|
|
||||||
const ofacSources = [
|
const path = require('path')
|
||||||
{
|
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||||
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 options = require('../lib/options-loader')()
|
if (!process.env.OFAC_SOURCES_NAMES && !process.env.OFAC_SOURCES_URLS) {
|
||||||
|
setEnvVariable('OFAC_SOURCES_NAMES', 'sdn_advanced,cons_advanced')
|
||||||
if (!options.opts.ofacSources) {
|
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')
|
||||||
options.opts.ofacSources = ofacSources
|
|
||||||
fs.writeFileSync(options.path, JSON.stringify(options.opts, null, ' '), 'utf8')
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,14 @@
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const hkdf = require('futoin-hkdf')
|
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 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)
|
const masterSeed = mnemonicHelpers.toEntropyBuffer(mnemonic)
|
||||||
|
|
||||||
console.log(hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex'))
|
console.log(hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex'))
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||||
const { asyncLocalStorage, defaultStore } = require('../lib/async-storage')
|
const { asyncLocalStorage, defaultStore } = require('../lib/async-storage')
|
||||||
const userManagement = require('../lib/new-admin/graphql/modules/userManagement')
|
const userManagement = require('../lib/new-admin/graphql/modules/userManagement')
|
||||||
const authErrors = require('../lib/new-admin/graphql/errors/authentication')
|
const authErrors = require('../lib/new-admin/graphql/errors/authentication')
|
||||||
const options = require('../lib/options')
|
|
||||||
|
|
||||||
const name = process.argv[2]
|
const name = process.argv[2]
|
||||||
const role = process.argv[3]
|
const role = process.argv[3]
|
||||||
const domain = options.hostname
|
const domain = process.env.HOSTNAME
|
||||||
|
|
||||||
if (!domain) {
|
if (!domain) {
|
||||||
console.error('No hostname configured in lamassu.json')
|
console.error('No hostname configured in the environment')
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,25 +6,26 @@ const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const mnemonicHelpers = require('../lib/mnemonic-helpers')
|
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 path = require('path')
|
||||||
const seed = fs.readFileSync(options.opts.seedPath, 'utf8').trim()
|
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)
|
const mnemonic = mnemonicHelpers.fromSeed(seed)
|
||||||
|
|
||||||
if (process.argv[2] === '--prod') {
|
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 {
|
} 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))) {
|
if (!fs.existsSync(path.dirname(process.env.MNEMONIC_PATH))) {
|
||||||
fs.mkdirSync(path.dirname(options.opts.mnemonicPath))
|
fs.mkdirSync(path.dirname(process.env.MNEMONIC_PATH))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fs.existsSync(options.opts.mnemonicPath)) {
|
if (!fs.existsSync(process.env.MNEMONIC_PATH)) {
|
||||||
fs.writeFileSync(options.opts.mnemonicPath, mnemonic, 'utf8')
|
fs.writeFileSync(process.env.MNEMONIC_PATH, mnemonic, 'utf8')
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(options.path, JSON.stringify(options.opts, null, '\t'), 'utf8')
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,13 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const pgp = require('pg-promise')()
|
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')
|
db.many('select data from user_config', 'exchanges')
|
||||||
.then(rows => {
|
.then(rows => {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||||
|
|
||||||
const login = require('../lib/admin/login')
|
const login = require('../lib/admin/login')
|
||||||
const options = require('../lib/options')
|
|
||||||
|
|
||||||
const name = process.argv[2]
|
const name = process.argv[2]
|
||||||
const domain = options.hostname
|
const domain = process.env.HOSTNAME
|
||||||
|
|
||||||
if (!domain) {
|
if (!domain) {
|
||||||
console.error('No hostname configured in lamassu.json')
|
console.error('No hostname configured in the environment')
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ require('es6-promise').polyfill()
|
||||||
|
|
||||||
var notifier = require('../lib/notifier')
|
var notifier = require('../lib/notifier')
|
||||||
var db = require('../lib/postgresql_interface')
|
var db = require('../lib/postgresql_interface')
|
||||||
var psqlUrl = require('../lib/options').postgres
|
const { PSQL_URL } = require('../lib/constants')
|
||||||
|
|
||||||
function getBalances () {
|
function getBalances () {
|
||||||
return [
|
return [
|
||||||
|
|
@ -11,7 +11,7 @@ function getBalances () {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
db.init(psqlUrl)
|
db.init(PSQL_URL)
|
||||||
notifier.init(db, getBalances, {lowBalanceThreshold: 10})
|
notifier.init(db, getBalances, {lowBalanceThreshold: 10})
|
||||||
console.log('DEBUG0')
|
console.log('DEBUG0')
|
||||||
notifier.checkStatus()
|
notifier.checkStatus()
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,21 @@ const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const bip39 = require('bip39')
|
const bip39 = require('bip39')
|
||||||
const options = require('../lib/options-loader')()
|
const setEnvVariable = require('../tools/set-env-var')
|
||||||
|
|
||||||
if (options.opts.mnemonicPath && !options.opts.seedPath) {
|
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||||
const mnemonic = fs.readFileSync(options.opts.mnemonicPath, 'utf8')
|
|
||||||
|
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')
|
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))) {
|
if (!fs.existsSync(path.dirname(process.env.SEED_PATH))) {
|
||||||
fs.mkdirSync(path.dirname(options.opts.seedPath))
|
fs.mkdirSync(path.dirname(process.env.SEED_PATH))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fs.existsSync(options.opts.seedPath)) {
|
if (!fs.existsSync(process.env.SEED_PATH)) {
|
||||||
fs.writeFileSync(options.opts.seedPath, seed, 'utf8')
|
fs.writeFileSync(process.env.SEED_PATH, seed, 'utf8')
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(options.path, JSON.stringify(options.opts, null, '\t'), 'utf8')
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ const _ = require('lodash/fp')
|
||||||
const machineLoader = require('../machine-loader')
|
const machineLoader = require('../machine-loader')
|
||||||
const T = require('../time')
|
const T = require('../time')
|
||||||
const logger = require('../logger')
|
const logger = require('../logger')
|
||||||
const options = require('../options')
|
|
||||||
|
|
||||||
const accounts = require('./accounts')
|
const accounts = require('./accounts')
|
||||||
const config = require('./config')
|
const config = require('./config')
|
||||||
|
|
@ -35,18 +34,20 @@ const supportServer = require('./admin-support')
|
||||||
|
|
||||||
const NEVER = new Date(Date.now() + 100 * T.years)
|
const NEVER = new Date(Date.now() + 100 * T.years)
|
||||||
const REAUTHENTICATE_INTERVAL = T.minute
|
const REAUTHENTICATE_INTERVAL = T.minute
|
||||||
const idPhotoCardBasedir = _.get('idPhotoCardDir', options)
|
|
||||||
const frontCameraBasedir = _.get('frontCameraDir', options)
|
const HOSTNAME = process.env.HOSTNAME
|
||||||
const operatorDataBasedir = _.get('operatorDataDir', options)
|
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 devMode = argv.dev
|
||||||
|
|
||||||
const version = require('../../package.json').version
|
const version = require('../../package.json').version
|
||||||
logger.info('Version: %s', version)
|
logger.info('Version: %s', version)
|
||||||
|
|
||||||
const hostname = options.hostname
|
if (!HOSTNAME) {
|
||||||
|
|
||||||
if (!hostname) {
|
|
||||||
logger.error('no hostname specified.')
|
logger.error('no hostname specified.')
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +83,7 @@ app.get('/api/totem', (req, res) => {
|
||||||
|
|
||||||
if (!name) return res.status(400).send('Name is required')
|
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))
|
.then(totem => res.send(totem))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -222,27 +223,27 @@ app.use((err, req, res, next) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const certOptions = {
|
const certOptions = {
|
||||||
key: fs.readFileSync(options.keyPath),
|
key: fs.readFileSync(KEY_PATH),
|
||||||
cert: fs.readFileSync(options.certPath)
|
cert: fs.readFileSync(CERT_PATH)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(serveStatic(path.resolve(__dirname, 'public')))
|
app.use(serveStatic(path.resolve(__dirname, 'public')))
|
||||||
|
|
||||||
if (!fs.existsSync(idPhotoCardBasedir)) {
|
if (!fs.existsSync(ID_PHOTO_CARD_DIR)) {
|
||||||
makeDir.sync(idPhotoCardBasedir)
|
makeDir.sync(ID_PHOTO_CARD_DIR)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fs.existsSync(frontCameraBasedir)) {
|
if (!fs.existsSync(FRONT_CAMERA_DIR)) {
|
||||||
makeDir.sync(frontCameraBasedir)
|
makeDir.sync(FRONT_CAMERA_DIR)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fs.existsSync(operatorDataBasedir)) {
|
if (!fs.existsSync(OPERATOR_DATA_DIR)) {
|
||||||
makeDir.sync(operatorDataBasedir)
|
makeDir.sync(OPERATOR_DATA_DIR)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use('/id-card-photo', serveStatic(idPhotoCardBasedir, {index: false}))
|
app.use('/id-card-photo', serveStatic(ID_PHOTO_CARD_DIR, {index: false}))
|
||||||
app.use('/front-camera-photo', serveStatic(frontCameraBasedir, {index: false}))
|
app.use('/front-camera-photo', serveStatic(FRONT_CAMERA_DIR, {index: false}))
|
||||||
app.use('/operator-data', serveStatic(operatorDataBasedir, {index: false}))
|
app.use('/operator-data', serveStatic(OPERATOR_DATA_DIR, {index: false}))
|
||||||
|
|
||||||
function register (req, res, next) {
|
function register (req, res, next) {
|
||||||
const otp = req.query.otp
|
const otp = req.query.otp
|
||||||
|
|
@ -259,7 +260,7 @@ function register (req, res, next) {
|
||||||
const cookieOpts = {
|
const cookieOpts = {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: true,
|
secure: true,
|
||||||
domain: hostname,
|
domain: HOSTNAME,
|
||||||
sameSite: true,
|
sameSite: true,
|
||||||
expires: NEVER
|
expires: NEVER
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ const _ = require('lodash/fp')
|
||||||
const serveStatic = require('serve-static')
|
const serveStatic = require('serve-static')
|
||||||
const path = require('path')
|
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(morgan('dev'))
|
||||||
app.use(helmet({noCache: true}))
|
app.use(helmet({noCache: true}))
|
||||||
|
|
@ -20,9 +22,9 @@ app.use(serveStatic(path.resolve(__dirname, '..', '..', 'public'), {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const certOptions = {
|
const certOptions = {
|
||||||
key: fs.readFileSync(options.keyPath),
|
key: fs.readFileSync(KEY_PATH),
|
||||||
cert: fs.readFileSync(options.certPath),
|
cert: fs.readFileSync(CERT_PATH),
|
||||||
ca: [fs.readFileSync(options.lamassuCaPath)],
|
ca: [fs.readFileSync(LAMASSU_CA_PATH)],
|
||||||
requestCert: true,
|
requestCert: true,
|
||||||
rejectUnauthorized: true
|
rejectUnauthorized: true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,19 +4,18 @@ const readFile = pify(fs.readFile)
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const baseX = require('base-x')
|
const baseX = require('base-x')
|
||||||
|
|
||||||
const options = require('../options')
|
|
||||||
const db = require('../db')
|
const db = require('../db')
|
||||||
const pairing = require('../pairing')
|
const pairing = require('../pairing')
|
||||||
|
|
||||||
const ALPHA_BASE = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'
|
const ALPHA_BASE = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'
|
||||||
const bsAlpha = baseX(ALPHA_BASE)
|
const bsAlpha = baseX(ALPHA_BASE)
|
||||||
|
|
||||||
|
const CA_PATH = process.env.CA_PATH
|
||||||
|
|
||||||
const unpair = pairing.unpair
|
const unpair = pairing.unpair
|
||||||
|
|
||||||
function totem (hostname, name) {
|
function totem (hostname, name) {
|
||||||
const caPath = options.caPath
|
return readFile(CA_PATH)
|
||||||
|
|
||||||
return readFile(caPath)
|
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const caHash = crypto.createHash('sha256').update(data).digest()
|
const caHash = crypto.createHash('sha256').update(data).digest()
|
||||||
const token = crypto.randomBytes(32)
|
const token = crypto.randomBytes(32)
|
||||||
|
|
|
||||||
15
lib/app.js
15
lib/app.js
|
|
@ -1,8 +1,11 @@
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const http = require('http')
|
const http = require('http')
|
||||||
const https = require('https')
|
const https = require('https')
|
||||||
const argv = require('minimist')(process.argv.slice(2))
|
const argv = require('minimist')(process.argv.slice(2))
|
||||||
|
|
||||||
|
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||||
|
|
||||||
const { asyncLocalStorage, defaultStore } = require('./async-storage')
|
const { asyncLocalStorage, defaultStore } = require('./async-storage')
|
||||||
const routes = require('./routes')
|
const routes = require('./routes')
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
|
|
@ -10,11 +13,13 @@ const poller = require('./poller')
|
||||||
const settingsLoader = require('./new-settings-loader')
|
const settingsLoader = require('./new-settings-loader')
|
||||||
const configManager = require('./new-config-manager')
|
const configManager = require('./new-config-manager')
|
||||||
const complianceTriggers = require('./compliance-triggers')
|
const complianceTriggers = require('./compliance-triggers')
|
||||||
const options = require('./options')
|
|
||||||
const ofac = require('./ofac/index')
|
const ofac = require('./ofac/index')
|
||||||
const ofacUpdate = require('./ofac/update')
|
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
|
const version = require('../package.json').version
|
||||||
logger.info('Version: %s', version)
|
logger.info('Version: %s', version)
|
||||||
|
|
@ -66,8 +71,8 @@ function startServer (settings) {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
poller.setup(['public'])
|
poller.setup(['public'])
|
||||||
const httpsServerOptions = {
|
const httpsServerOptions = {
|
||||||
key: fs.readFileSync(options.keyPath),
|
key: fs.readFileSync(KEY_PATH),
|
||||||
cert: fs.readFileSync(options.certPath),
|
cert: fs.readFileSync(CERT_PATH),
|
||||||
requestCert: true,
|
requestCert: true,
|
||||||
rejectUnauthorized: false
|
rejectUnauthorized: false
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +85,7 @@ function startServer (settings) {
|
||||||
const localPort = 3030
|
const localPort = 3030
|
||||||
const localServer = http.createServer(routes.localApp)
|
const localServer = http.createServer(routes.localApp)
|
||||||
|
|
||||||
if (options.devMode) logger.info('In dev mode')
|
if (devMode) logger.info('In dev mode')
|
||||||
|
|
||||||
server.listen(port, () => {
|
server.listen(port, () => {
|
||||||
logger.info('lamassu-server listening on port ' +
|
logger.info('lamassu-server listening on port ' +
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
|
||||||
const options = require('../options')
|
|
||||||
|
|
||||||
const common = require('./common')
|
const common = require('./common')
|
||||||
|
|
||||||
const MOUNT_POINT = options.blockchainDir
|
const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR
|
||||||
|
|
||||||
|
const MOUNT_POINT = BLOCKCHAIN_DIR
|
||||||
|
|
||||||
module.exports = {prepareVolume}
|
module.exports = {prepareVolume}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ const inquirer = require('inquirer')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const { utils: coinUtils } = require('@lamassu/coins')
|
const { utils: coinUtils } = require('@lamassu/coins')
|
||||||
const options = require('../options')
|
|
||||||
const settingsLoader = require('../new-settings-loader')
|
const settingsLoader = require('../new-settings-loader')
|
||||||
const wallet = require('../wallet')
|
const wallet = require('../wallet')
|
||||||
|
|
||||||
|
|
@ -29,10 +28,12 @@ const PLUGINS = {
|
||||||
ZEC: require('./zcash.js')
|
ZEC: require('./zcash.js')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR
|
||||||
|
|
||||||
module.exports = {run}
|
module.exports = {run}
|
||||||
|
|
||||||
function installedVolumeFilePath (crypto) {
|
function installedVolumeFilePath (crypto) {
|
||||||
return path.resolve(coinUtils.cryptoDir(crypto, options.blockchainDir), '.installed')
|
return path.resolve(coinUtils.cryptoDir(crypto, BLOCKCHAIN_DIR), '.installed')
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInstalledVolume (crypto) {
|
function isInstalledVolume (crypto) {
|
||||||
|
|
@ -63,7 +64,7 @@ function processCryptos (codes) {
|
||||||
common.es('sudo supervisorctl reread')
|
common.es('sudo supervisorctl reread')
|
||||||
common.es('sudo supervisorctl update')
|
common.es('sudo supervisorctl update')
|
||||||
|
|
||||||
const blockchainDir = options.blockchainDir
|
const blockchainDir = BLOCKCHAIN_DIR
|
||||||
const backupDir = path.resolve(os.homedir(), 'backups')
|
const backupDir = path.resolve(os.homedir(), 'backups')
|
||||||
const rsyncCmd = `( \
|
const rsyncCmd = `( \
|
||||||
(crontab -l 2>/dev/null || echo -n "") | grep -v "@daily rsync ".*"wallet.dat"; \
|
(crontab -l 2>/dev/null || echo -n "") | grep -v "@daily rsync ".*"wallet.dat"; \
|
||||||
|
|
@ -83,7 +84,7 @@ function processCryptos (codes) {
|
||||||
|
|
||||||
function setupCrypto (crypto) {
|
function setupCrypto (crypto) {
|
||||||
logger.info(`Installing ${crypto.display}...`)
|
logger.info(`Installing ${crypto.display}...`)
|
||||||
const cryptoDir = coinUtils.cryptoDir(crypto, options.blockchainDir)
|
const cryptoDir = coinUtils.cryptoDir(crypto, BLOCKCHAIN_DIR)
|
||||||
makeDir.sync(cryptoDir)
|
makeDir.sync(cryptoDir)
|
||||||
const cryptoPlugin = plugin(crypto)
|
const cryptoPlugin = plugin(crypto)
|
||||||
const oldDir = process.cwd()
|
const oldDir = process.cwd()
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const pify = require('pify')
|
|
||||||
const fs = pify(require('fs'))
|
|
||||||
|
|
||||||
const db = require('../db')
|
const db = require('../db')
|
||||||
const configManager = require('../new-config-manager')
|
const configManager = require('../new-config-manager')
|
||||||
const complianceTriggers = require('../compliance-triggers')
|
const complianceTriggers = require('../compliance-triggers')
|
||||||
const options = require('../options')
|
|
||||||
const logger = require('../logger')
|
const logger = require('../logger')
|
||||||
const plugins = require('../plugins')
|
const plugins = require('../plugins')
|
||||||
const { getOperatorId } = require('../operator')
|
const { getOperatorId } = require('../operator')
|
||||||
|
|
@ -15,6 +11,8 @@ const { getOperatorId } = require('../operator')
|
||||||
const TIMEOUT = 10000
|
const TIMEOUT = 10000
|
||||||
const MAX_CONTENT_LENGTH = 2000
|
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
|
// How long a machine can be down before it's considered offline
|
||||||
const STALE_INTERVAL = '2 minutes'
|
const STALE_INTERVAL = '2 minutes'
|
||||||
|
|
||||||
|
|
@ -112,7 +110,7 @@ function getMachines (rates, settings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendRadar (data) {
|
function sendRadar (data) {
|
||||||
const url = _.get(['coinAtmRadar', 'url'], options)
|
const url = COIN_ATM_RADAR_URL
|
||||||
|
|
||||||
if (_.isEmpty(url)) {
|
if (_.isEmpty(url)) {
|
||||||
return Promise.reject(new Error('Missing coinAtmRadar url!'))
|
return Promise.reject(new Error('Missing coinAtmRadar url!'))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
const T = require('./time')
|
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 = {
|
const anonymousCustomer = {
|
||||||
uuid: '47ac1184-8102-11e7-9079-8f13a7117867',
|
uuid: '47ac1184-8102-11e7-9079-8f13a7117867',
|
||||||
name: 'anonymous'
|
name: 'anonymous'
|
||||||
|
|
@ -39,5 +47,6 @@ module.exports = {
|
||||||
CASH_OUT_MINIMUM_AMOUNT_OF_CASSETTES,
|
CASH_OUT_MINIMUM_AMOUNT_OF_CASSETTES,
|
||||||
CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES,
|
CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES,
|
||||||
WALLET_SCORE_THRESHOLD,
|
WALLET_SCORE_THRESHOLD,
|
||||||
RECEIPT
|
RECEIPT,
|
||||||
|
PSQL_URL
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,20 @@ const BN = require('./bn')
|
||||||
const anonymous = require('../lib/constants').anonymousCustomer
|
const anonymous = require('../lib/constants').anonymousCustomer
|
||||||
const complianceOverrides = require('./compliance_overrides')
|
const complianceOverrides = require('./compliance_overrides')
|
||||||
const users = require('./users')
|
const users = require('./users')
|
||||||
const options = require('./options')
|
|
||||||
const writeFile = util.promisify(fs.writeFile)
|
const writeFile = util.promisify(fs.writeFile)
|
||||||
const notifierQueries = require('./notifier/queries')
|
const notifierQueries = require('./notifier/queries')
|
||||||
const notifierUtils = require('./notifier/utils')
|
const notifierUtils = require('./notifier/utils')
|
||||||
const NUM_RESULTS = 1000
|
const NUM_RESULTS = 1000
|
||||||
const idPhotoCardBasedir = _.get('idPhotoCardDir', options)
|
|
||||||
const frontCameraBaseDir = _.get('frontCameraDir', options)
|
|
||||||
const operatorDataDir = _.get('operatorDataDir', options)
|
|
||||||
const sms = require('./sms')
|
const sms = require('./sms')
|
||||||
const settingsLoader = require('./new-settings-loader')
|
const settingsLoader = require('./new-settings-loader')
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
|
|
||||||
const TX_PASSTHROUGH_ERROR_CODES = ['operatorCancel']
|
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
|
* 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)))))
|
const rpath = _.join(path.sep, _.map(_.wrap(_.join, ''), _.take(3, _.chunk(2, _.split('', hash)))))
|
||||||
|
|
||||||
// i.e. ../<lamassu-server-home>/idphotocard/24/0e/85
|
// i.e. ../<lamassu-server-home>/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
|
// create the directory tree if needed
|
||||||
_.attempt(() => makeDir.sync(dirname))
|
_.attempt(() => makeDir.sync(dirname))
|
||||||
|
|
@ -736,7 +736,7 @@ function updatePhotos (imagesData, id, dir) {
|
||||||
function updateIdCardData (patch, id) {
|
function updateIdCardData (patch, id) {
|
||||||
/* TODO: fetch operator id */
|
/* TODO: fetch operator id */
|
||||||
const operatorId = 'id-operator'
|
const operatorId = 'id-operator'
|
||||||
const directory = `${operatorDataDir}/${operatorId}/${id}/`
|
const directory = `${OPERATOR_DATA_DIR}/${operatorId}/${id}/`
|
||||||
|
|
||||||
return Promise.resolve(patch)
|
return Promise.resolve(patch)
|
||||||
.then(patch => {
|
.then(patch => {
|
||||||
|
|
@ -755,7 +755,7 @@ function updateTxCustomerPhoto (imageData) {
|
||||||
return Promise.resolve(imageData)
|
return Promise.resolve(imageData)
|
||||||
.then(imageData => {
|
.then(imageData => {
|
||||||
const newPatch = {}
|
const newPatch = {}
|
||||||
const directory = `${operatorDataDir}/customersphotos`
|
const directory = `${OPERATOR_DATA_DIR}/customersphotos`
|
||||||
|
|
||||||
if (_.isEmpty(imageData)) {
|
if (_.isEmpty(imageData)) {
|
||||||
return
|
return
|
||||||
|
|
@ -826,7 +826,7 @@ function updateFrontCamera (id, patch) {
|
||||||
const rpath = _.join(path.sep, _.map(_.wrap(_.join, ''), _.take(3, _.chunk(2, _.split('', hash)))))
|
const rpath = _.join(path.sep, _.map(_.wrap(_.join, ''), _.take(3, _.chunk(2, _.split('', hash)))))
|
||||||
|
|
||||||
// i.e. ../<lamassu-server-home>/idphotocard/24/0e/85
|
// i.e. ../<lamassu-server-home>/idphotocard/24/0e/85
|
||||||
const dirname = path.join(frontCameraBaseDir, rpath)
|
const dirname = path.join(FRONT_CAMERA_DIR, rpath)
|
||||||
|
|
||||||
// create the directory tree if needed
|
// create the directory tree if needed
|
||||||
_.attempt(() => makeDir.sync(dirname))
|
_.attempt(() => makeDir.sync(dirname))
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ const Pgp = require('pg-promise')
|
||||||
const uuid = require('uuid')
|
const uuid = require('uuid')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const psqlUrl = require('../lib/options').postgresql
|
const { PSQL_URL } = require('./constants')
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const eventBus = require('./event-bus')
|
const eventBus = require('./event-bus')
|
||||||
const { asyncLocalStorage, defaultStore } = require('./async-storage')
|
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 => {
|
eventBus.subscribe('log', args => {
|
||||||
if (process.env.SKIP_SERVER_LOGS) return
|
if (process.env.SKIP_SERVER_LOGS) return
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
const winston = require('winston')
|
const winston = require('winston')
|
||||||
const Postgres = require('./pg-transport')
|
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({
|
const logger = new winston.Logger({
|
||||||
level: options.logLevel,
|
level: LOG_LEVEL,
|
||||||
transports: [
|
transports: [
|
||||||
new (winston.transports.Console)({
|
new (winston.transports.Console)({
|
||||||
timestamp: true,
|
timestamp: true,
|
||||||
|
|
@ -12,7 +14,7 @@ const logger = new winston.Logger({
|
||||||
humanReadableUnhandledException: true
|
humanReadableUnhandledException: true
|
||||||
}),
|
}),
|
||||||
new Postgres({
|
new Postgres({
|
||||||
connectionString: options.postgresql,
|
connectionString: PSQL_URL,
|
||||||
tableName: 'server_logs',
|
tableName: 'server_logs',
|
||||||
handleExceptions: true,
|
handleExceptions: true,
|
||||||
humanReadableUnhandledException: true
|
humanReadableUnhandledException: true
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ const cors = require('cors')
|
||||||
const helmet = require('helmet')
|
const helmet = require('helmet')
|
||||||
const nocache = require('nocache')
|
const nocache = require('nocache')
|
||||||
const cookieParser = require('cookie-parser')
|
const cookieParser = require('cookie-parser')
|
||||||
const { ApolloServer, AuthenticationError } = require('apollo-server-express')
|
|
||||||
const { graphqlUploadExpress } = require('graphql-upload')
|
const { graphqlUploadExpress } = require('graphql-upload')
|
||||||
|
const { ApolloServer } = require('apollo-server-express')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
|
require('dotenv').config({ path: path.resolve(__dirname, '../../.env') })
|
||||||
|
|
||||||
const { asyncLocalStorage, defaultStore } = require('../async-storage')
|
const { asyncLocalStorage, defaultStore } = require('../async-storage')
|
||||||
const options = require('../options')
|
|
||||||
const users = require('../users')
|
|
||||||
const logger = require('../logger')
|
const logger = require('../logger')
|
||||||
|
|
||||||
const { AuthDirective } = require('./graphql/directives')
|
const { AuthDirective } = require('./graphql/directives')
|
||||||
|
|
@ -25,13 +25,16 @@ const { USER_SESSIONS_CLEAR_INTERVAL } = require('../constants')
|
||||||
const { session, cleanUserSessions, buildApolloContext } = require('./middlewares')
|
const { session, cleanUserSessions, buildApolloContext } = require('./middlewares')
|
||||||
|
|
||||||
const devMode = require('minimist')(process.argv.slice(2)).dev
|
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
|
const HOSTNAME = process.env.HOSTNAME
|
||||||
if (!hostname) {
|
const KEY_PATH = process.env.KEY_PATH
|
||||||
logger.error('no hostname specified.')
|
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)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,16 +80,16 @@ apolloServer.applyMiddleware({
|
||||||
// cors on app for /api/register endpoint.
|
// cors on app for /api/register endpoint.
|
||||||
app.use(cors({ credentials: true, origin: devMode && 'https://localhost:3001' }))
|
app.use(cors({ credentials: true, origin: devMode && 'https://localhost:3001' }))
|
||||||
|
|
||||||
app.use('/id-card-photo', serveStatic(idPhotoCardBasedir, { index: false }))
|
app.use('/id-card-photo', serveStatic(ID_PHOTO_CARD_DIR, { index: false }))
|
||||||
app.use('/front-camera-photo', serveStatic(frontCameraBasedir, { index: false }))
|
app.use('/front-camera-photo', serveStatic(FRONT_CAMERA_DIR, { index: false }))
|
||||||
app.use('/operator-data', serveStatic(operatorDataBasedir, { 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
|
// 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')))
|
app.get('*', (req, res) => res.sendFile(path.resolve(__dirname, '..', '..', 'public', 'index.html')))
|
||||||
|
|
||||||
const certOptions = {
|
const certOptions = {
|
||||||
key: fs.readFileSync(options.keyPath),
|
key: fs.readFileSync(KEY_PATH),
|
||||||
cert: fs.readFileSync(options.certPath)
|
cert: fs.readFileSync(CERT_PATH)
|
||||||
}
|
}
|
||||||
|
|
||||||
function run () {
|
function run () {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
|
const path = require('path')
|
||||||
const { ApolloServer } = require('apollo-server-express')
|
const { ApolloServer } = require('apollo-server-express')
|
||||||
|
|
||||||
|
require('dotenv').config({ path: path.resolve(__dirname, '../../.env') })
|
||||||
|
|
||||||
const { typeDefs, resolvers } = require('./graphql/schema')
|
const { typeDefs, resolvers } = require('./graphql/schema')
|
||||||
const logger = require('../logger')
|
const logger = require('../logger')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,9 @@ const router = express.Router()
|
||||||
const session = require('express-session')
|
const session = require('express-session')
|
||||||
const PgSession = require('connect-pg-simple')(session)
|
const PgSession = require('connect-pg-simple')(session)
|
||||||
const db = require('../../db')
|
const db = require('../../db')
|
||||||
const options = require('../../options')
|
|
||||||
const { USER_SESSIONS_TABLE_NAME } = require('../../constants')
|
const { USER_SESSIONS_TABLE_NAME } = require('../../constants')
|
||||||
const { getOperatorId } = require('../../operator')
|
const { getOperatorId } = require('../../operator')
|
||||||
|
|
||||||
const hostname = options.hostname
|
|
||||||
|
|
||||||
router.use('*', async (req, res, next) => getOperatorId('authentication').then(({ operatorId }) => session({
|
router.use('*', async (req, res, next) => getOperatorId('authentication').then(({ operatorId }) => session({
|
||||||
store: new PgSession({
|
store: new PgSession({
|
||||||
pgPromise: db,
|
pgPromise: db,
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,25 @@ const crypto = require('crypto')
|
||||||
const baseX = require('base-x')
|
const baseX = require('base-x')
|
||||||
const { parse, NIL } = require('uuid')
|
const { parse, NIL } = require('uuid')
|
||||||
|
|
||||||
const options = require('../../options')
|
|
||||||
const db = require('../../db')
|
const db = require('../../db')
|
||||||
const pairing = require('../../pairing')
|
const pairing = require('../../pairing')
|
||||||
|
|
||||||
const ALPHA_BASE = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'
|
const ALPHA_BASE = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'
|
||||||
const bsAlpha = baseX(ALPHA_BASE)
|
const bsAlpha = baseX(ALPHA_BASE)
|
||||||
|
|
||||||
|
const CA_PATH = process.env.CA_PATH
|
||||||
|
const HOSTNAME = process.env.HOSTNAME
|
||||||
|
|
||||||
const unpair = pairing.unpair
|
const unpair = pairing.unpair
|
||||||
|
|
||||||
function totem (name) {
|
function totem (name) {
|
||||||
const caPath = options.caPath
|
return readFile(CA_PATH)
|
||||||
return readFile(caPath)
|
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const caHash = crypto.createHash('sha256').update(data).digest()
|
const caHash = crypto.createHash('sha256').update(data).digest()
|
||||||
const token = crypto.randomBytes(32)
|
const token = crypto.randomBytes(32)
|
||||||
const hexToken = token.toString('hex')
|
const hexToken = token.toString('hex')
|
||||||
const caHexToken = crypto.createHash('sha256').update(hexToken).digest('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)'
|
const sql = 'insert into pairing_tokens (token, name) values ($1, $3), ($2, $3)'
|
||||||
|
|
||||||
return db.none(sql, [hexToken, caHexToken, name])
|
return db.none(sql, [hexToken, caHexToken, name])
|
||||||
|
|
|
||||||
|
|
@ -4,23 +4,24 @@ const util = require('util')
|
||||||
const loader = require('./loading')
|
const loader = require('./loading')
|
||||||
const matcher = require('./matching')
|
const matcher = require('./matching')
|
||||||
const nameUtils = require('./name-utils')
|
const nameUtils = require('./name-utils')
|
||||||
const options = require('../options')
|
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
const logger = require('../logger')
|
const logger = require('../logger')
|
||||||
|
|
||||||
const debugLog = require('../pp')(__filename) // KOSTIS TODO: remove
|
const debugLog = require('../pp')(__filename) // KOSTIS TODO: remove
|
||||||
|
|
||||||
|
const OFAC_DATA_DIR = process.env.OFAC_DATA_DIR
|
||||||
|
|
||||||
let structs = null
|
let structs = null
|
||||||
|
|
||||||
const readdir = util.promisify(fs.readdir)
|
const readdir = util.promisify(fs.readdir)
|
||||||
|
|
||||||
function load () {
|
function load () {
|
||||||
if (!options.ofacDataDir) {
|
if (!OFAC_DATA_DIR) {
|
||||||
const message = 'The ofacDataDir option has not been set in lamassu.json'
|
const message = 'The ofacDataDir option has not been set in the environment'
|
||||||
return Promise.reject(new Error(message))
|
return Promise.reject(new Error(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
const ofacSourcesDir = path.join(options.ofacDataDir, 'sources')
|
const ofacSourcesDir = path.join(OFAC_DATA_DIR, 'sources')
|
||||||
|
|
||||||
return readdir(ofacSourcesDir)
|
return readdir(ofacSourcesDir)
|
||||||
.then(_.flow(
|
.then(_.flow(
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,23 @@ const url = require('url')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const util = require('util')
|
const util = require('util')
|
||||||
const options = require('../options')
|
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
const logger = require('../logger')
|
const logger = require('../logger')
|
||||||
|
|
||||||
const DOWNLOAD_DIR = path.resolve('/tmp')
|
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) {
|
function mkdir (path) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fs.mkdir(path, err => {
|
fs.mkdir(path, err => {
|
||||||
|
|
@ -97,14 +108,12 @@ const moveToSourcesDir = (srcFile, ofacSourcesDir) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function update () {
|
function update () {
|
||||||
const OFAC_DATA_DIR = options.ofacDataDir
|
|
||||||
|
|
||||||
if (!OFAC_DATA_DIR) {
|
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) {
|
if (!ofacSources) {
|
||||||
logger.error('ofacSources must be defined in lamassu.json')
|
logger.error('ofacSources must be defined in the environment')
|
||||||
}
|
}
|
||||||
|
|
||||||
const OFAC_SOURCES_DIR = path.join(OFAC_DATA_DIR, 'sources')
|
const OFAC_SOURCES_DIR = path.join(OFAC_DATA_DIR, 'sources')
|
||||||
|
|
@ -125,7 +134,7 @@ function update () {
|
||||||
return {}
|
return {}
|
||||||
})
|
})
|
||||||
|
|
||||||
const promiseNewEtags = Promise.resolve(options.ofacSources || [])
|
const promiseNewEtags = Promise.resolve(ofacSources || [])
|
||||||
.then(sources => Promise.all(_.map(promiseGetEtag, sources))
|
.then(sources => Promise.all(_.map(promiseGetEtag, sources))
|
||||||
.then(etags => _.map(
|
.then(etags => _.map(
|
||||||
([source, etag]) => ({...source, etag}),
|
([source, etag]) => ({...source, etag}),
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ const os = require('os')
|
||||||
const argv = require('minimist')(process.argv.slice(2))
|
const argv = require('minimist')(process.argv.slice(2))
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
require('dotenv').config()
|
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||||
|
|
||||||
const DATABASE = process.env.LAMASSU_DB ?? 'PROD'
|
const DATABASE = process.env.LAMASSU_DB ?? 'PROD'
|
||||||
const dbMapping = psqlConf => ({
|
const dbMapping = psqlConf => ({
|
||||||
STRESS_TEST: _.replace('lamassu', 'lamassu_stress', psqlConf),
|
STRESS_TEST: _.replace('lamassu', 'lamassu_stress', psqlConf),
|
||||||
|
PAZUZ: _.replace('lamassu', 'lamassu_pazuz', psqlConf),
|
||||||
RELEASE: _.replace('lamassu', 'lamassu_release', psqlConf),
|
RELEASE: _.replace('lamassu', 'lamassu_release', psqlConf),
|
||||||
DEV: _.replace('lamassu', 'lamassu', psqlConf),
|
DEV: _.replace('lamassu', 'lamassu', psqlConf),
|
||||||
PROD: _.replace('lamassu', 'lamassu', psqlConf)
|
PROD: _.replace('lamassu', 'lamassu', psqlConf)
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@ const fs = require('fs')
|
||||||
const pify = require('pify')
|
const pify = require('pify')
|
||||||
const readFile = pify(fs.readFile)
|
const readFile = pify(fs.readFile)
|
||||||
const db = require('./db')
|
const db = require('./db')
|
||||||
const options = require('./options')
|
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const uuid = require('uuid')
|
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.
|
// 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
|
// 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) {
|
function pullToken (token) {
|
||||||
const sql = `delete from pairing_tokens
|
const sql = `delete from pairing_tokens
|
||||||
|
|
@ -58,8 +59,7 @@ function authorizeCaDownload (caToken) {
|
||||||
.then(r => {
|
.then(r => {
|
||||||
if (r.expired) throw new Error('Expired')
|
if (r.expired) throw new Error('Expired')
|
||||||
|
|
||||||
const caPath = options.caPath
|
return readFile(CA_PATH, {encoding: 'utf8'})
|
||||||
return readFile(caPath, {encoding: 'utf8'})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,7 @@ const _ = require('lodash/fp')
|
||||||
const request = require('request-promise')
|
const request = require('request-promise')
|
||||||
const { utils: coinUtils } = require('@lamassu/coins')
|
const { utils: coinUtils } = require('@lamassu/coins')
|
||||||
|
|
||||||
const options = require('../../options')
|
const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR
|
||||||
|
|
||||||
const blockchainDir = options.blockchainDir
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fetch, fetchDigest, parseConf, rpcConfig
|
fetch, fetchDigest, parseConf, rpcConfig
|
||||||
|
|
@ -108,7 +106,7 @@ function parseConf (confPath) {
|
||||||
|
|
||||||
function rpcConfig (cryptoRec) {
|
function rpcConfig (cryptoRec) {
|
||||||
try {
|
try {
|
||||||
const configPath = coinUtils.configPath(cryptoRec, blockchainDir)
|
const configPath = coinUtils.configPath(cryptoRec, BLOCKCHAIN_DIR)
|
||||||
const config = parseConf(configPath)
|
const config = parseConf(configPath)
|
||||||
return {
|
return {
|
||||||
username: config.rpcuser,
|
username: config.rpcuser,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const options = require('../../../options')
|
const STRIKE_BASE_URL = process.env.STRIKE_BASE_URL
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
newAddress,
|
newAddress,
|
||||||
|
|
@ -9,7 +9,7 @@ module.exports = {
|
||||||
cryptoNetwork
|
cryptoNetwork
|
||||||
}
|
}
|
||||||
|
|
||||||
axios.defaults.baseURL = _.get('strike.baseUrl', options)
|
axios.defaults.baseURL = STRIKE_BASE_URL
|
||||||
if (_.isEmpty(axios.defaults.baseURL)) {
|
if (_.isEmpty(axios.defaults.baseURL)) {
|
||||||
throw new Error('Missing Strike baseUrl!')
|
throw new Error('Missing Strike baseUrl!')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@ const lnd = require('lnd-async')
|
||||||
const BN = require('../../../bn')
|
const BN = require('../../../bn')
|
||||||
const E = require('../../../error')
|
const E = require('../../../error')
|
||||||
const { utils: coinUtils } = require('@lamassu/coins')
|
const { utils: coinUtils } = require('@lamassu/coins')
|
||||||
const options = require('../../../options')
|
|
||||||
|
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const cryptoRec = coinUtils.getCryptoCurrency('BTC')
|
const cryptoRec = coinUtils.getCryptoCurrency('BTC')
|
||||||
const unitScale = cryptoRec.unitScale
|
const unitScale = cryptoRec.unitScale
|
||||||
|
|
||||||
|
const LND = process.env.LIGHTNING_NETWORK_DAEMON
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
balance,
|
balance,
|
||||||
sendCoins,
|
sendCoins,
|
||||||
|
|
@ -20,7 +21,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
|
|
||||||
function connect () {
|
function connect () {
|
||||||
return lnd.connect(options.lnd || {})
|
return lnd.connect(LND || {})
|
||||||
}
|
}
|
||||||
|
|
||||||
function cryptoNetwork (account, cryptoCode, settings, operatorId) {
|
function cryptoNetwork (account, cryptoCode, settings, operatorId) {
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,13 @@ const { default: PQueue } = require('p-queue')
|
||||||
const BN = require('../../../bn')
|
const BN = require('../../../bn')
|
||||||
const E = require('../../../error')
|
const E = require('../../../error')
|
||||||
const { logger } = require('../../../blockchain/common')
|
const { logger } = require('../../../blockchain/common')
|
||||||
const options = require('../../../options')
|
|
||||||
const jsonRpc = require('../../common/json-rpc')
|
const jsonRpc = require('../../common/json-rpc')
|
||||||
|
|
||||||
const blockchainDir = options.blockchainDir
|
const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR
|
||||||
|
|
||||||
const cryptoRec = utils.getCryptoCurrency(COINS.XMR)
|
const cryptoRec = utils.getCryptoCurrency(COINS.XMR)
|
||||||
const configPath = utils.configPath(cryptoRec, blockchainDir)
|
const configPath = utils.configPath(cryptoRec, BLOCKCHAIN_DIR)
|
||||||
const walletDir = path.resolve(utils.cryptoDir(cryptoRec, blockchainDir), 'wallets')
|
const walletDir = path.resolve(utils.cryptoDir(cryptoRec, BLOCKCHAIN_DIR), 'wallets')
|
||||||
|
|
||||||
const DIGEST_QUEUE = new PQueue({
|
const DIGEST_QUEUE = new PQueue({
|
||||||
concurrency: 1,
|
concurrency: 1,
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ const E = require('../../../error')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const ENV = process.env.NODE_ENV === undefined || process.env.NODE_ENV === 'development' ? 'development' : 'production'
|
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({
|
const axios = require('axios').create({
|
||||||
// TODO: get rejectUnauthorized true to work
|
// 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({
|
httpsAgent: new https.Agent({
|
||||||
rejectUnauthorized: false
|
rejectUnauthorized: false
|
||||||
})
|
})
|
||||||
|
|
@ -22,9 +22,8 @@ function balance (account, cryptoCode, settings, operatorId) {
|
||||||
return checkCryptoCode(cryptoCode)
|
return checkCryptoCode(cryptoCode)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return axios.post('/balance', {
|
return axios.post('/balance', {
|
||||||
account,
|
|
||||||
cryptoCode,
|
cryptoCode,
|
||||||
settings,
|
config: settings.config,
|
||||||
operatorId
|
operatorId
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -39,9 +38,8 @@ function sendCoins (account, tx, settings, operatorId) {
|
||||||
return checkCryptoCode(cryptoCode)
|
return checkCryptoCode(cryptoCode)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return axios.post('/sendCoins', {
|
return axios.post('/sendCoins', {
|
||||||
account,
|
|
||||||
tx,
|
tx,
|
||||||
settings,
|
config: settings.config,
|
||||||
operatorId
|
operatorId
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -57,10 +55,9 @@ function sendCoins (account, tx, settings, operatorId) {
|
||||||
function newAddress (account, info, tx, settings, operatorId) {
|
function newAddress (account, info, tx, settings, operatorId) {
|
||||||
return checkCryptoCode(info.cryptoCode)
|
return checkCryptoCode(info.cryptoCode)
|
||||||
.then(() => axios.post('/newAddress', {
|
.then(() => axios.post('/newAddress', {
|
||||||
account,
|
|
||||||
info,
|
info,
|
||||||
tx,
|
tx,
|
||||||
settings,
|
config: settings.config,
|
||||||
operatorId
|
operatorId
|
||||||
}))
|
}))
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ const morgan = require('morgan')
|
||||||
const nocache = require('nocache')
|
const nocache = require('nocache')
|
||||||
|
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const options = require('./options')
|
|
||||||
|
|
||||||
const authorize = require('./middlewares/authorize')
|
const authorize = require('./middlewares/authorize')
|
||||||
const errorHandler = require('./middlewares/errorHandler')
|
const errorHandler = require('./middlewares/errorHandler')
|
||||||
|
|
@ -41,7 +40,7 @@ const configRequiredRoutes = [
|
||||||
'/tx',
|
'/tx',
|
||||||
'/verify_promo_code'
|
'/verify_promo_code'
|
||||||
]
|
]
|
||||||
const devMode = argv.dev || options.http
|
const devMode = argv.dev || process.env.HTTP
|
||||||
|
|
||||||
// middleware setup
|
// middleware setup
|
||||||
app.use(compression({ threshold: 500 }))
|
app.use(compression({ threshold: 500 }))
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ const pify = require('pify')
|
||||||
const fs = pify(require('fs'))
|
const fs = pify(require('fs'))
|
||||||
|
|
||||||
const mnemonicHelpers = require('./mnemonic-helpers')
|
const mnemonicHelpers = require('./mnemonic-helpers')
|
||||||
const options = require('./options')
|
|
||||||
const ph = require('./plugin-helper')
|
const ph = require('./plugin-helper')
|
||||||
const layer2 = require('./layer2')
|
const layer2 = require('./layer2')
|
||||||
const httpError = require('./route-helpers').httpError
|
const httpError = require('./route-helpers').httpError
|
||||||
|
|
@ -20,6 +19,8 @@ const INSUFFICIENT_FUNDS_CODE = 570
|
||||||
const INSUFFICIENT_FUNDS_NAME = 'InsufficientFunds'
|
const INSUFFICIENT_FUNDS_NAME = 'InsufficientFunds'
|
||||||
const ZERO_CONF_EXPIRATION = 60000
|
const ZERO_CONF_EXPIRATION = 60000
|
||||||
|
|
||||||
|
const MNEMONIC_PATH = process.env.MNEMONIC_PATH
|
||||||
|
|
||||||
function computeSeed (masterSeed) {
|
function computeSeed (masterSeed) {
|
||||||
return hkdf(masterSeed, 32, { salt: 'lamassu-server-salt', info: 'wallet-seed' })
|
return hkdf(masterSeed, 32, { salt: 'lamassu-server-salt', info: 'wallet-seed' })
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +30,7 @@ function computeOperatorId (masterSeed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchWallet (settings, cryptoCode) {
|
function fetchWallet (settings, cryptoCode) {
|
||||||
return fs.readFile(options.mnemonicPath, 'utf8')
|
return fs.readFile(MNEMONIC_PATH, 'utf8')
|
||||||
.then(mnemonic => {
|
.then(mnemonic => {
|
||||||
const masterSeed = mnemonicHelpers.toEntropyBuffer(mnemonic)
|
const masterSeed = mnemonicHelpers.toEntropyBuffer(mnemonic)
|
||||||
const plugin = configManager.getWalletSettings(cryptoCode, settings.config).wallet
|
const plugin = configManager.getWalletSettings(cryptoCode, settings.config).wallet
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ const hkdf = require('futoin-hkdf')
|
||||||
|
|
||||||
const state = require('../lib/middlewares/state')
|
const state = require('../lib/middlewares/state')
|
||||||
const mnemonicHelpers = require('../lib/mnemonic-helpers')
|
const mnemonicHelpers = require('../lib/mnemonic-helpers')
|
||||||
const options = require('../lib/options')
|
|
||||||
|
|
||||||
function computeOperatorId (masterSeed) {
|
function computeOperatorId (masterSeed) {
|
||||||
return hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex')
|
return hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex')
|
||||||
|
|
@ -13,7 +12,7 @@ function computeOperatorId (masterSeed) {
|
||||||
|
|
||||||
function getMnemonic () {
|
function getMnemonic () {
|
||||||
if (state.mnemonic) return Promise.resolve(state.mnemonic)
|
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
|
state.mnemonic = mnemonic
|
||||||
return mnemonic
|
return mnemonic
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@ SKIP_PREFLIGHT_CHECK=true
|
||||||
HTTPS=true
|
HTTPS=true
|
||||||
REACT_APP_TYPE_CHECK_SANCTUARY=false
|
REACT_APP_TYPE_CHECK_SANCTUARY=false
|
||||||
PORT=3001
|
PORT=3001
|
||||||
REACT_APP_BUILD_TARGET=LAMASSU
|
REACT_APP_BUILD_TARGET=PAZUZ
|
||||||
|
|
@ -170,22 +170,26 @@ const Accounting = () => {
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
!loading && (
|
||||||
<TitleSection title="Accounting" />
|
<>
|
||||||
<Assets
|
<TitleSection title="Accounting" />
|
||||||
balance={operatorData.fiatBalances[operatorData.preferredFiatCurrency]}
|
<Assets
|
||||||
hedgingReserve={operatorData.hedgingReserve ?? 0}
|
balance={
|
||||||
currency={operatorData.preferredFiatCurrency}
|
operatorData.fiatBalances[operatorData.preferredFiatCurrency]
|
||||||
/>
|
}
|
||||||
<H4 className={classes.tableTitle}>Fiat balance history</H4>
|
hedgingReserve={operatorData.hedgingReserve ?? 0}
|
||||||
<DataTable
|
currency={operatorData.preferredFiatCurrency}
|
||||||
loading={loading}
|
/>
|
||||||
emptyText="No transactions so far"
|
<H4 className={classes.tableTitle}>Fiat balance history</H4>
|
||||||
elements={elements}
|
<DataTable
|
||||||
data={operatorData.fundings ?? []}
|
loading={loading}
|
||||||
rowSize="sm"
|
emptyText="No transactions so far"
|
||||||
/>
|
elements={elements}
|
||||||
</>
|
data={operatorData.fundings ?? []}
|
||||||
|
rowSize="sm"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
32
tools/build-dev-env.js
Normal file
32
tools/build-dev-env.js
Normal file
|
|
@ -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')
|
||||||
45
tools/build-prod-env.js
Normal file
45
tools/build-prod-env.js
Normal file
|
|
@ -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 <DB_PASSWORD> --hostname <IP>')
|
||||||
|
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')
|
||||||
|
|
@ -91,32 +91,6 @@ rm /tmp/Lamassu_OP.csr.pem
|
||||||
mkdir -p $OFAC_DATA_DIR/sources
|
mkdir -p $OFAC_DATA_DIR/sources
|
||||||
touch $OFAC_DATA_DIR/etags.json
|
touch $OFAC_DATA_DIR/etags.json
|
||||||
|
|
||||||
cat <<EOF > $CONFIG_DIR/lamassu.json
|
node tools/build-dev-env.js
|
||||||
{
|
|
||||||
"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
|
|
||||||
|
|
||||||
echo "Done."
|
echo "Done."
|
||||||
|
|
|
||||||
24
tools/set-env-var.js
Normal file
24
tools/set-env-var.js
Normal file
|
|
@ -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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue