feat: new compliance options

This commit is contained in:
Taranto 2020-09-14 23:25:35 +01:00 committed by Josh Harvey
parent ccf7eacfad
commit f2080c32e9
23 changed files with 161 additions and 121 deletions

View file

@ -127,7 +127,7 @@ function postProcess (r, pi, isBlacklisted, addressReuse) {
settingsLoader.loadLatest().then(it => {
// TODO new-admin: addressReuse doesnt exist
// const config = configManager.unscoped(it.config)
if (true) {
if (false) {
blacklist.addToUsedAddresses(r.tx.toAddress, r.tx.cryptoCode)
.catch(err => logger.error('Failure adding to addressReuse', err))
}

View file

@ -1,7 +1,7 @@
const _ = require('lodash/fp')
function getBackwardsCompatibleTriggers (triggers) {
const filtered = _.filter(_.matches({ triggerType: 'txAmount', cashDirection: 'both' }))(triggers)
const filtered = _.filter(_.matches({ triggerType: 'txVolume', direction: 'both', thresholdDays: 1 }))(triggers)
const grouped = _.groupBy(_.prop('requirement'))(filtered)
return _.mapValues(_.compose(_.get('threshold'), _.minBy('threshold')))(grouped)
}

View file

@ -59,8 +59,10 @@ function matchOfac (deviceId, customer) {
})
}
function validateOfac (deviceId, config, customer) {
if (!config.sanctionsVerificationActive) return Promise.resolve(true)
// BACKWARDS_COMPATIBILITY 7.5
// machines before 7.5 need to test sanctionsActive here
function validateOfac (deviceId, sanctionsActive, customer) {
if (!sanctionsActive) return Promise.resolve(true)
if (customer.sanctionsOverride === 'blocked') return Promise.resolve(false)
if (customer.sanctionsOverride === 'verified') return Promise.resolve(true)
@ -68,8 +70,8 @@ function validateOfac (deviceId, config, customer) {
.then(didMatch => !didMatch)
}
function validationPatch (deviceId, config, customer) {
return validateOfac(deviceId, config, customer)
function validationPatch (deviceId, sanctionsActive, customer) {
return validateOfac(deviceId, sanctionsActive, customer)
.then(ofacValidation => {
if (_.isNil(customer.sanctions) || customer.sanctions !== ofacValidation) {
return {sanctions: ofacValidation}

View file

@ -5,8 +5,6 @@ const ph = require('./plugin-helper')
function sendMessage (settings, rec) {
return Promise.resolve()
.then(() => {
// TODO new-admin
// const pluginCode = configManager.unscoped(settings.config).email
const pluginCode = 'mailgun'
const plugin = ph.load(ph.EMAIL, pluginCode)
const account = settings.accounts[pluginCode]

View file

@ -3,8 +3,6 @@ const uuid = require('uuid')
const db = require('../db')
const NUM_RESULTS = 500
function getServerLogs (from = new Date(0).toISOString(), until = new Date().toISOString(), limit = null, offset = 0) {
const sql = `select id, log_level, timestamp, message from server_logs
where timestamp >= $1 and timestamp <= $2

View file

@ -342,7 +342,7 @@ function plugins (settings, deviceId) {
const notifications = configManager.getGlobalNotifications(settings.config)
const notificationsEnabled = notifications.sms.transactions || notifications.email.transactions
const highValueTx = tx.fiat.gt(notifications.highValueTransaction)
const highValueTx = tx.fiat.gt(notifications.highValueTransaction || Infinity)
if (!notificationsEnabled || !highValueTx) return Promise.resolve()

View file

@ -62,7 +62,6 @@ function poll (req, res, next) {
const hasLightning = checkHasLightning(settings)
const triggers = configManager.getTriggers(settings.config)
const compatTriggers = complianceTriggers.getBackwardsCompatibleTriggers(triggers)
const operatorInfo = configManager.getOperatorInfo(settings.config)
const cashOutConfig = configManager.getCashOut(deviceId, settings.config)
@ -91,18 +90,6 @@ function poll (req, res, next) {
error: null,
locale,
version,
smsVerificationActive: !!compatTriggers.sms,
smsVerificationThreshold: compatTriggers.sms,
hardLimitVerificationActive: !!compatTriggers.block,
hardLimitVerificationThreshold: compatTriggers.block,
idCardDataVerificationActive: !!compatTriggers.idData,
idCardDataVerificationThreshold: compatTriggers.idData,
idCardPhotoVerificationActive: !!compatTriggers.idPhoto,
idCardPhotoVerificationThreshold: compatTriggers.idPhoto,
sanctionsVerificationActive: !!compatTriggers.sancations,
sanctionsVerificationThreshold: compatTriggers.sancations,
frontCameraVerificationActive: !!compatTriggers.facephoto,
frontCameraVerificationThreshold: compatTriggers.facephoto,
receiptPrintingActive: receipt.active === "on",
cassettes,
twoWayMode: cashOutConfig.active,
@ -111,7 +98,24 @@ function poll (req, res, next) {
restartServices,
hasLightning,
receipt,
operatorInfo
operatorInfo,
triggers
}
// BACKWARDS_COMPATIBILITY 7.5
// machines before 7.5 expect old compliance
if (!machineVersion || semver.lt(machineVersion, '7.5.0-beta.0')) {
const compatTriggers = complianceTriggers.getBackwardsCompatibleTriggers(triggers)
response.smsVerificationActive = !!compatTriggers.sms
response.smsVerificationThreshold = compatTriggers.sms
response.idCardDataVerificationActive = !!compatTriggers.idData
response.idCardDataVerificationThreshold = compatTriggers.idData
response.idCardPhotoVerificationActive = !!compatTriggers.idPhoto
response.idCardPhotoVerificationThreshold = compatTriggers.idPhoto
response.sanctionsVerificationActive = !!compatTriggers.sancations
response.sanctionsVerificationThreshold = compatTriggers.sancations
response.frontCameraVerificationActive = !!compatTriggers.facephoto
response.frontCameraVerificationThreshold = compatTriggers.facephoto
}
// BACKWARDS_COMPATIBILITY 7.4.9
@ -208,6 +212,7 @@ function verifyTx (req, res, next) {
function addOrUpdateCustomer (req) {
const customerData = req.body
const machineVersion = req.query.version
const triggers = configManager.getTriggers(req.settings.config)
const compatTriggers = complianceTriggers.getBackwardsCompatibleTriggers(triggers)
@ -218,11 +223,24 @@ function addOrUpdateCustomer (req) {
return customers.add(req.body)
})
.then(customer => {
// BACKWARDS_COMPATIBILITY 7.5
// machines before 7.5 expect customer with sanctions result
const isOlderMachineVersion = !machineVersion || semver.lt(machineVersion, '7.5.0-beta.0')
const shouldRunOfacCompat = !compatTriggers.sanctions && isOlderMachineVersion
if (!shouldRunOfacCompat) return customer
return compliance.validationPatch(req.deviceId, !!compatTriggers.sanctions, customer)
.then(patch => {
if (_.isEmpty(patch)) return customer
return customers.update(customer.id, patch)
})
}).then(customer => {
// TODO new-admin: only get customer history till max needed for triggers
return Tx.customerHistory(customer.id)
.then(result => {
customer.txHistory = result
return customer
})
})
}
@ -244,6 +262,7 @@ function getCustomerWithPhoneCode (req, res, next) {
function updateCustomer (req, res, next) {
const id = req.params.id
const machineVersion = req.query.version
const txId = req.query.txId
const patch = req.body
const triggers = configManager.getTriggers(req.settings.config)
@ -254,16 +273,57 @@ function updateCustomer (req, res, next) {
if (!customer) { throw httpError('Not Found', 404) }
const mergedCustomer = _.merge(customer, patch)
return compliance.validationPatch(req.deviceId, !!compatTriggers.sanctions, mergedCustomer)
// BACKWARDS_COMPATIBILITY 7.5
// machines before 7.5 expect customer with sanctions result
const isOlderMachineVersion = !machineVersion || semver.lt(machineVersion, '7.5.0-beta.0')
Promise.resolve({})
.then(emptyObj => {
if (!isOlderMachineVersion) return Promise.resolve(emptyObj)
return compliance.validationPatch(req.deviceId, !!compatTriggers.sanctions, mergedCustomer)
})
.then(_.merge(patch))
.then(newPatch => customers.updatePhotoCard(id, newPatch))
.then(newPatch => customers.updateFrontCamera(id, newPatch))
.then(newPatch => customers.update(id, newPatch, null, txId))
})
.then(customer => respond(req, res, { customer }))
.catch(next)
}
function triggerSanctions (req, res, next) {
const id = req.params.id
customers.getById(id)
.then(customer => {
if (!customer) { throw httpError('Not Found', 404) }
return compliance.validationPatch(req.deviceId, true, customer)
.then(patch => customers.update(id, patch))
})
.then(customer => respond(req, res, { customer }))
.catch(next)
}
function triggerBlock (req, res, next) {
const id = req.params.id
customers.update(id, { authorizedOverride: 'blocked' })
.then(customer => respond(req, res, { customer }))
.catch(next)
}
function triggerSuspend (req, res, next) {
const id = req.params.id
customers.update(id, { authorizedOverride: 'blocked' })
.then(customer => respond(req, res, { customer }))
.catch(next)
}
function getLastSeen (req, res, next) {
const deviceId = req.deviceId
const timestamp = Date.now()
@ -409,6 +469,9 @@ app.post('/verify_transaction', verifyTx)
app.post('/phone_code', getCustomerWithPhoneCode)
app.patch('/customer/:id', updateCustomer)
app.patch('/customer/:id/sanctions', triggerSanctions)
app.patch('/customer/:id/block', triggerBlock)
app.patch('/customer/:id/suspend', triggerSuspend)
app.post('/tx', postTx)
app.get('/tx/:id', getTx)

View file

@ -1,12 +1,10 @@
// const configManager = require('./config-manager')
const ph = require('./plugin-helper')
const argv = require('minimist')(process.argv.slice(2))
function sendMessage (settings, rec) {
return Promise.resolve()
.then(() => {
// TODO new-admin: how to load mock here? Only on dev?
// const pluginCode = configManager.unscoped(settings.config).sms
const pluginCode = 'twilio'
const pluginCode = argv.mockSms ? 'mock-sms' : 'twilio'
const plugin = ph.load(ph.SMS, pluginCode)
const account = settings.accounts[pluginCode]

View file

@ -1,4 +1,5 @@
const _ = require('lodash/fp')
const db = require('./db')
const BN = require('./bn')
const CashInTx = require('./cash-in/cash-in-tx')
const CashOutTx = require('./cash-out/cash-out-tx')
@ -63,4 +64,15 @@ function cancel (txId) {
})
}
module.exports = {post, cancel}
function customerHistory (customerId) {
const sql = ` select txIn.id, txIn.created, txIn.fiat, 'cashIn' as direction from cash_in_txs txIn
where txIn.customer_id = $1
union
select txOut.id, txOut.created, txOut.fiat, 'cashOut' as direction from cash_out_txs txOut
where txOut.customer_id = $1
order by created;`
return db.any(sql, [customerId])
}
module.exports = {post, cancel, customerHistory}

View file

@ -139,7 +139,7 @@ function getWalletStatus (settings, tx) {
function authorizeZeroConf (settings, tx, machineId) {
const plugin = configManager.getWalletSettings(tx.cryptoCode, settings.config).zeroConf
const cashOutConfig = configManager.cashOutConfig(machineId, settings.config)
const cashOutConfig = configManager.getCashOut(machineId, settings.config)
const zeroConfLimit = cashOutConfig.zeroConfLimit
if (!_.isObject(tx.fiat)) {