This commit is contained in:
Josh Harvey 2016-06-01 02:35:29 +03:00
parent 35cbb46688
commit 0140e01c9f
5 changed files with 38 additions and 39 deletions

View file

@ -3,6 +3,7 @@
var fs = require('fs') var fs = require('fs')
var R = require('ramda') var R = require('ramda')
var async = require('async') var async = require('async')
var HKDF = require('node-hkdf-sync')
var BigNumber = require('bignumber.js') var BigNumber = require('bignumber.js')
BigNumber.config({CRYPTO: true}) BigNumber.config({CRYPTO: true})
@ -34,7 +35,7 @@ var idVerifierPlugin = null
var infoPlugin = null var infoPlugin = null
var emailPlugin = null var emailPlugin = null
var smsPlugin = null var smsPlugin = null
var masterSeed = null var hkdf = null
var currentlyUsedPlugins = {} var currentlyUsedPlugins = {}
@ -54,9 +55,9 @@ var coins = {
var alertFingerprint = null var alertFingerprint = null
var lastAlertTime = null var lastAlertTime = null
// that's basically a constructor
exports.init = function init () { exports.init = function init () {
fs.readFileSync('seeds/seed.txt') const masterSeed = fs.readFileSync('seeds/seed.txt').trim()
hkdf = new HKDF('sha256', 'lamassu-server-salt', masterSeed)
} }
function loadPlugin (name, config) { function loadPlugin (name, config) {
@ -175,15 +176,15 @@ exports.configure = function configure (config) {
} }
) )
// WALLET [required] configure (or load) // Give each crypto a different derived seed so as not to allow any
// plugin to spend another plugin's funds
const cryptoSeed = hkdf.derive(cryptoCode, 32)
loadOrConfigPlugin( loadOrConfigPlugin(
walletPlugins[cryptoCode], walletPlugins[cryptoCode],
'transfer', 'transfer',
cryptoCode, cryptoCode,
{ {masterSeed: cryptoSeed},
nextCashOutSerialHD: db.nextCashOutSerialHD(cryptoCode),
masterSeed: masterSeed
},
function onWalletChange (newWallet) { function onWalletChange (newWallet) {
walletPlugins[cryptoCode] = newWallet walletPlugins[cryptoCode] = newWallet
pollBalance(cryptoCode) pollBalance(cryptoCode)
@ -348,27 +349,25 @@ exports.sendCoins = function sendCoins (session, rawTx) {
} }
exports.cashOut = function cashOut (session, tx) { exports.cashOut = function cashOut (session, tx) {
var tmpInfo = {
label: 'TX ' + Date.now(),
account: 'deposit'
}
var cryptoCode = tx.cryptoCode || 'BTC' var cryptoCode = tx.cryptoCode || 'BTC'
var walletPlugin = walletPlugins[cryptoCode] var walletPlugin = walletPlugins[cryptoCode]
return new Promise((resolve, reject) => { return db.nextCashOutSerialHD(tx.sessionId, cryptoCode)
.then(serialNumber => new Promise((resolve, reject) => {
const tmpInfo = {
label: 'TX ' + Date.now(),
account: 'deposit',
serialNumber: serialNumber
}
walletPlugin.newAddress(tmpInfo, function (err, address) { walletPlugin.newAddress(tmpInfo, function (err, address) {
if (err) return reject(err) if (err) return reject(err)
const addressRec = R.is(String, address) const newTx = R.assoc('toAddress', address, tx)
? {address: address} return db.addInitialIncoming(session, newTx, address)
: address
const newTx = R.assoc('toAddress', addressRec.address, tx)
return db.addInitialIncoming(session, newTx, addressRec)
.then(() => resolve(address)) .then(() => resolve(address))
}) })
}) }))
} }
exports.dispenseAck = function dispenseAck (session, rec) { exports.dispenseAck = function dispenseAck (session, rec) {

View file

@ -3,6 +3,7 @@
const BigNumber = require('bignumber.js') const BigNumber = require('bignumber.js')
const pgp = require('pg-promise')() const pgp = require('pg-promise')()
const backoff = require('u-promised').backoff
const logger = require('./logger') const logger = require('./logger')
@ -113,7 +114,7 @@ exports.sentCoins = function sentCoins (session, tx, toSend, fee, error, txHash)
return db.none(sql, [txHash, error, session.id]) return db.none(sql, [txHash, error, session.id])
} }
exports.addInitialIncoming = function addInitialIncoming (session, tx, addressRec) { exports.addInitialIncoming = function addInitialIncoming (session, tx) {
const fields = ['session_id', 'device_fingerprint', 'to_address', const fields = ['session_id', 'device_fingerprint', 'to_address',
'crypto_atoms', 'crypto_code', 'currency_code', 'fiat', 'tx_hash', 'crypto_atoms', 'crypto_code', 'currency_code', 'fiat', 'tx_hash',
'phone', 'error' 'phone', 'error'
@ -133,15 +134,6 @@ exports.addInitialIncoming = function addInitialIncoming (session, tx, addressRe
] ]
return db.none(getInsertQuery('cash_out_txs', fields), values) return db.none(getInsertQuery('cash_out_txs', fields), values)
.then(() => {
const hd = addressRec.hd
if (hd) {
const fields2 = ['session_id', 'to_address', 'crypto_code',
'hd_path_prefix', 'hd_serial']
const values2 = [tx.sessionId, tx.toAddress, tx.cryptoCode, hd.pathPrefix, hd.serial]
return db.none(getInsertQuery('cash_out_hds', fields2), values2)
}
})
} }
function insertDispense (session, tx, cartridges) { function insertDispense (session, tx, cartridges) {
@ -434,9 +426,18 @@ exports.cacheResponse = function (session, path, method, body) {
return db.none(sql, values) return db.none(sql, values)
} }
exports.nextCashOutSerialHD = function nextCashOutSerialHD (cryptoCode) { exports.nextCashOutSerialHD = function nextCashOutSerialHD (sessionId, cryptoCode) {
const sql = `select hd_serial from cash_out_hds const sql = `select hd_serial from cash_out_hds
where crypto_code=$1 order by hd_serial desc limit 1` where crypto_code=$1 order by hd_serial desc limit 1`
return db.oneOrNone(sql, [cryptoCode]) const attempt = db.oneOrNone(sql, [cryptoCode])
.then(row => row ? row.hd_serial + 1 : 0) .then(row => {
const serialNumber = row ? row.hd_serial + 1 : 0
const fields2 = ['session_id', 'crypto_code', 'hd_serial']
const sql2 = getInsertQuery('cash_out_hds', fields2)
const values2 = [sessionId, cryptoCode, serialNumber]
return db.none(sql2, values2)
.then(() => serialNumber)
})
return backoff(100, 0, 5, attempt)
} }

View file

@ -4,12 +4,10 @@ exports.up = function (next) {
var sql = [ var sql = [
`create table cash_out_hds ( `create table cash_out_hds (
session_id uuid PRIMARY KEY, session_id uuid PRIMARY KEY,
to_address text NOT NULL,
crypto_code text NOT NULL, crypto_code text NOT NULL,
hd_path_prefix text NOT NULL,
hd_serial integer NOT NULL, hd_serial integer NOT NULL,
created timestamptz NOT NULL default now(), created timestamptz NOT NULL default now(),
unique (crypto_code, hd_serial) unique (crypto_code, hd_serial),
)` )`
] ]
db.multi(sql, next) db.multi(sql, next)

View file

@ -31,12 +31,14 @@
"lamassu-smtp2go": "^1.0.3", "lamassu-smtp2go": "^1.0.3",
"lamassu-twilio": "^1.1.0", "lamassu-twilio": "^1.1.0",
"minimist": "0.0.8", "minimist": "0.0.8",
"node-hkdf-sync": "^1.0.0",
"node-uuid": "^1.4.2", "node-uuid": "^1.4.2",
"numeral": "^1.5.3", "numeral": "^1.5.3",
"pg": "^4.5.5", "pg": "^4.5.5",
"pg-promise": "^4.3.3", "pg-promise": "^4.3.3",
"pretty-ms": "^2.1.0", "pretty-ms": "^2.1.0",
"ramda": "^0.21.0", "ramda": "^0.21.0",
"u-promised": "^0.2.4",
"wreck": "5.1.0" "wreck": "5.1.0"
}, },
"repository": { "repository": {

View file

@ -1,4 +1,3 @@
- l-m shouldn't keep polling l-s when not on pending screen (low priority) - l-m shouldn't keep polling l-s when not on pending screen (low priority)
- need more bulletproof way to ensure only unique serials for each coin - scrutinize hkdf, maybe use own simplified version
- use tx to read last, then insert new row