feat: new compliance options
This commit is contained in:
parent
ccf7eacfad
commit
f2080c32e9
23 changed files with 161 additions and 121 deletions
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
|
|
|
|||
14
lib/tx.js
14
lib/tx.js
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue