Merge branch 'dev' into fix/lam-298/custom_info_requests_flow
This commit is contained in:
commit
c5bf50b932
46 changed files with 441 additions and 149 deletions
|
|
@ -14,13 +14,13 @@ function setup (dataDir) {
|
|||
const config = buildConfig(auth)
|
||||
common.writeFile(path.resolve(dataDir, coinRec.configFile), config)
|
||||
const cmd = `/usr/local/bin/${coinRec.daemon} --data-dir ${dataDir} --config-file ${dataDir}/${coinRec.configFile}`
|
||||
const walletCmd = `/usr/local/bin/${coinRec.wallet} --stagenet --rpc-login ${auth} --daemon-host 127.0.0.1 --daemon-port 38081 --trusted-daemon --daemon-login ${auth} --rpc-bind-port 38083 --wallet-dir ${dataDir}/wallets`
|
||||
const walletCmd = `/usr/local/bin/${coinRec.wallet} --stagenet --rpc-login ${auth} --daemon-host 127.0.0.1 --daemon-port 18081 --trusted-daemon --daemon-login ${auth} --rpc-bind-port 18082 --wallet-dir ${dataDir}/wallets`
|
||||
common.writeSupervisorConfig(coinRec, cmd, walletCmd)
|
||||
}
|
||||
|
||||
function buildConfig (auth) {
|
||||
return `rpc-login=${auth}
|
||||
stagenet=1
|
||||
stagenet=0
|
||||
restricted-rpc=1
|
||||
db-sync-mode=safe
|
||||
out-peers=20
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const E = require('../error')
|
|||
|
||||
const PENDING_INTERVAL_MS = 60 * T.minutes
|
||||
|
||||
const massageFields = ['direction', 'cryptoNetwork', 'bills', 'blacklisted', 'addressReuse', 'promoCodeApplied', 'failedWalletScore']
|
||||
const massageFields = ['direction', 'cryptoNetwork', 'bills', 'blacklisted', 'addressReuse', 'promoCodeApplied', 'validWalletScore']
|
||||
const massageUpdateFields = _.concat(massageFields, 'cryptoAtoms')
|
||||
|
||||
const massage = _.flow(_.omit(massageFields),
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ const cashInLow = require('./cash-in-low')
|
|||
|
||||
const PENDING_INTERVAL = '60 minutes'
|
||||
const MAX_PENDING = 10
|
||||
const WALLET_SCORE_THRESHOLD = 10
|
||||
|
||||
const TRANSACTION_STATES = `
|
||||
case
|
||||
|
|
@ -34,13 +33,13 @@ function post (machineTx, pi) {
|
|||
const updatedTx = r.tx
|
||||
let blacklisted = false
|
||||
let addressReuse = false
|
||||
let failedWalletScore = false
|
||||
let walletScore = {}
|
||||
|
||||
return Promise.all([settingsLoader.loadLatest(), checkForBlacklisted(updatedTx), doesTxReuseAddress(updatedTx), doesWalletScoreFail(updatedTx, pi)])
|
||||
.then(([{ config }, blacklistItems, isReusedAddress, walletScoreFailed]) => {
|
||||
return Promise.all([settingsLoader.loadLatest(), checkForBlacklisted(updatedTx), doesTxReuseAddress(updatedTx), getWalletScore(updatedTx, pi)])
|
||||
.then(([{ config }, blacklistItems, isReusedAddress, fetchedWalletScore]) => {
|
||||
const rejectAddressReuse = configManager.getCompliance(config).rejectAddressReuse
|
||||
|
||||
failedWalletScore = walletScoreFailed
|
||||
walletScore = fetchedWalletScore
|
||||
|
||||
if (_.some(it => it.address === updatedTx.toAddress)(blacklistItems)) {
|
||||
blacklisted = true
|
||||
|
|
@ -49,13 +48,14 @@ function post (machineTx, pi) {
|
|||
notifier.notifyIfActive('compliance', 'blacklistNotify', r.tx, true)
|
||||
addressReuse = true
|
||||
}
|
||||
return postProcess(r, pi, blacklisted, addressReuse, failedWalletScore)
|
||||
return postProcess(r, pi, blacklisted, addressReuse, walletScore)
|
||||
})
|
||||
.then(changes => cashInLow.update(db, updatedTx, changes))
|
||||
.then(tx => _.set('bills', machineTx.bills, tx))
|
||||
.then(tx => _.set('blacklisted', blacklisted, tx))
|
||||
.then(tx => _.set('addressReuse', addressReuse, tx))
|
||||
.then(tx => _.set('failedWalletScore', failedWalletScore, tx))
|
||||
.then(tx => _.set('validWalletScore', _.isNil(walletScore) ? true : walletScore.isValid, tx))
|
||||
.then(tx => _.set('walletScore', _.isNil(walletScore) ? null : walletScore.score, tx))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ function checkForBlacklisted (tx) {
|
|||
return Promise.resolve(false)
|
||||
}
|
||||
|
||||
function postProcess (r, pi, isBlacklisted, addressReuse, failedWalletScore) {
|
||||
function postProcess (r, pi, isBlacklisted, addressReuse, walletScore) {
|
||||
if (addressReuse) {
|
||||
return Promise.resolve({
|
||||
operatorCompleted: true,
|
||||
|
|
@ -108,10 +108,11 @@ function postProcess (r, pi, isBlacklisted, addressReuse, failedWalletScore) {
|
|||
})
|
||||
}
|
||||
|
||||
if (failedWalletScore) {
|
||||
if (!_.isNil(walletScore) && !walletScore.isValid) {
|
||||
return Promise.resolve({
|
||||
walletScore: walletScore.score,
|
||||
operatorCompleted: true,
|
||||
error: 'Failed wallet score'
|
||||
error: 'Ciphertrace score is above defined threshold'
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -171,12 +172,17 @@ function doesTxReuseAddress (tx) {
|
|||
return Promise.resolve(false)
|
||||
}
|
||||
|
||||
function doesWalletScoreFail (tx, pi) {
|
||||
function getWalletScore (tx, pi) {
|
||||
if (!tx.fiat || tx.fiat.isZero()) {
|
||||
return pi.rateWallet(tx.toAddress)
|
||||
.then(res => res >= WALLET_SCORE_THRESHOLD)
|
||||
return pi.rateWallet(tx.cryptoCode, tx.toAddress)
|
||||
}
|
||||
return Promise.resolve(false)
|
||||
// Passthrough the previous result
|
||||
return pi.isValidWalletScore(tx.walletScore)
|
||||
.then(isValid => ({
|
||||
address: tx.toAddress,
|
||||
score: tx.walletScore,
|
||||
isValid
|
||||
}))
|
||||
}
|
||||
|
||||
function monitorPending (settings) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ const MANUAL = 'manual'
|
|||
const CASH_OUT_DISPENSE_READY = 'cash_out_dispense_ready'
|
||||
const CONFIRMATION_CODE = 'sms_code'
|
||||
|
||||
const WALLET_SCORE_THRESHOLD = 9
|
||||
|
||||
module.exports = {
|
||||
anonymousCustomer,
|
||||
CASSETTE_MAX_CAPACITY,
|
||||
|
|
@ -34,5 +36,6 @@ module.exports = {
|
|||
CASH_OUT_DISPENSE_READY,
|
||||
CONFIRMATION_CODE,
|
||||
CASH_OUT_MINIMUM_AMOUNT_OF_CASSETTES,
|
||||
CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES
|
||||
CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES,
|
||||
WALLET_SCORE_THRESHOLD
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const SMS = 'sms'
|
|||
const ID_VERIFIER = 'idVerifier'
|
||||
const EMAIL = 'email'
|
||||
const ZERO_CONF = 'zeroConf'
|
||||
const WALLET_SCORING = 'wallet_scoring'
|
||||
|
||||
const ALL_ACCOUNTS = [
|
||||
{ code: 'binanceus', display: 'Binance.us', class: TICKER, cryptos: binanceus.CRYPTO },
|
||||
|
|
@ -50,7 +51,9 @@ const ALL_ACCOUNTS = [
|
|||
{ code: 'mailgun', display: 'Mailgun', class: EMAIL },
|
||||
{ code: 'none', display: 'None', class: ZERO_CONF, cryptos: [BTC, ZEC, LTC, DASH, BCH, ETH, XMR] },
|
||||
{ code: 'blockcypher', display: 'Blockcypher', class: ZERO_CONF, cryptos: [BTC] },
|
||||
{ code: 'mock-zero-conf', display: 'Mock 0-conf', class: ZERO_CONF, cryptos: ALL_CRYPTOS, dev: true }
|
||||
{ code: 'mock-zero-conf', display: 'Mock 0-conf', class: ZERO_CONF, cryptos: ALL_CRYPTOS, dev: true },
|
||||
{ code: 'ciphertrace', display: 'CipherTrace', class: WALLET_SCORING, cryptos: [BTC, ETH, LTC, BCH] },
|
||||
{ code: 'mock-scoring', display: 'Mock scoring', class: WALLET_SCORING, cryptos: ALL_CRYPTOS, dev: true }
|
||||
]
|
||||
|
||||
const devMode = require('minimist')(process.argv.slice(2)).dev
|
||||
|
|
|
|||
|
|
@ -4,25 +4,20 @@ const _ = require('lodash/fp')
|
|||
|
||||
const userManagement = require('../userManagement')
|
||||
const credentials = require('../../../../hardware-credentials')
|
||||
const options = require('../../../../options')
|
||||
const T = require('../../../../time')
|
||||
const users = require('../../../../users')
|
||||
|
||||
const domain = options.hostname
|
||||
const devMode = require('minimist')(process.argv.slice(2)).dev
|
||||
|
||||
const REMEMBER_ME_AGE = 90 * T.day
|
||||
|
||||
const rpID = devMode ? `localhost:3001` : domain
|
||||
const expectedOrigin = `https://${rpID}`
|
||||
|
||||
const generateAttestationOptions = (session, options) => {
|
||||
return users.getUserById(options.userId).then(user => {
|
||||
return Promise.all([credentials.getHardwareCredentialsByUserId(user.id), user])
|
||||
}).then(([userDevices, user]) => {
|
||||
const options = simpleWebauthn.generateAttestationOptions({
|
||||
const opts = simpleWebauthn.generateAttestationOptions({
|
||||
rpName: 'Lamassu',
|
||||
rpID,
|
||||
rpID: options.domain,
|
||||
userName: user.username,
|
||||
userID: user.id,
|
||||
timeout: 60000,
|
||||
|
|
@ -40,11 +35,11 @@ const generateAttestationOptions = (session, options) => {
|
|||
|
||||
session.webauthn = {
|
||||
attestation: {
|
||||
challenge: options.challenge
|
||||
challenge: opts.challenge
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
return opts
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +54,7 @@ const generateAssertionOptions = (session, options) => {
|
|||
transports: ['usb', 'ble', 'nfc', 'internal']
|
||||
})),
|
||||
userVerification: 'discouraged',
|
||||
rpID
|
||||
rpID: options.domain
|
||||
})
|
||||
|
||||
session.webauthn = {
|
||||
|
|
@ -82,8 +77,8 @@ const validateAttestation = (session, options) => {
|
|||
simpleWebauthn.verifyAttestationResponse({
|
||||
credential: options.attestationResponse,
|
||||
expectedChallenge: `${expectedChallenge}`,
|
||||
expectedOrigin,
|
||||
expectedRPID: rpID
|
||||
expectedOrigin: `https://${options.domain}${devMode ? `:3001` : ``}`,
|
||||
expectedRPID: options.domain
|
||||
})
|
||||
])
|
||||
.then(([user, verification]) => {
|
||||
|
|
@ -142,8 +137,8 @@ const validateAssertion = (session, options) => {
|
|||
verification = simpleWebauthn.verifyAssertionResponse({
|
||||
credential: options.assertionResponse,
|
||||
expectedChallenge: `${expectedChallenge}`,
|
||||
expectedOrigin,
|
||||
expectedRPID: rpID,
|
||||
expectedOrigin: `https://${options.domain}${devMode ? `:3001` : ``}`,
|
||||
expectedRPID: options.domain,
|
||||
authenticator: convertedAuthenticator
|
||||
})
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -3,25 +3,20 @@ const base64url = require('base64url')
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
const credentials = require('../../../../hardware-credentials')
|
||||
const options = require('../../../../options')
|
||||
const T = require('../../../../time')
|
||||
const users = require('../../../../users')
|
||||
|
||||
const domain = options.hostname
|
||||
const devMode = require('minimist')(process.argv.slice(2)).dev
|
||||
|
||||
const REMEMBER_ME_AGE = 90 * T.day
|
||||
|
||||
const rpID = devMode ? `localhost:3001` : domain
|
||||
const expectedOrigin = `https://${rpID}`
|
||||
|
||||
const generateAttestationOptions = (session, options) => {
|
||||
return users.getUserById(options.userId).then(user => {
|
||||
return Promise.all([credentials.getHardwareCredentialsByUserId(user.id), user])
|
||||
}).then(([userDevices, user]) => {
|
||||
const opts = simpleWebauthn.generateAttestationOptions({
|
||||
rpName: 'Lamassu',
|
||||
rpID,
|
||||
rpID: options.domain,
|
||||
userName: user.username,
|
||||
userID: user.id,
|
||||
timeout: 60000,
|
||||
|
|
@ -58,7 +53,7 @@ const generateAssertionOptions = (session, options) => {
|
|||
transports: ['usb', 'ble', 'nfc', 'internal']
|
||||
})),
|
||||
userVerification: 'discouraged',
|
||||
rpID
|
||||
rpID: options.domain
|
||||
})
|
||||
|
||||
session.webauthn = {
|
||||
|
|
@ -81,8 +76,8 @@ const validateAttestation = (session, options) => {
|
|||
simpleWebauthn.verifyAttestationResponse({
|
||||
credential: options.attestationResponse,
|
||||
expectedChallenge: `${expectedChallenge}`,
|
||||
expectedOrigin,
|
||||
expectedRPID: rpID
|
||||
expectedOrigin: `https://${options.domain}${devMode ? `:3001` : ``}`,
|
||||
expectedRPID: options.domain
|
||||
})
|
||||
])
|
||||
.then(([user, verification]) => {
|
||||
|
|
@ -141,8 +136,8 @@ const validateAssertion = (session, options) => {
|
|||
verification = simpleWebauthn.verifyAssertionResponse({
|
||||
credential: options.assertionResponse,
|
||||
expectedChallenge: `${expectedChallenge}`,
|
||||
expectedOrigin,
|
||||
expectedRPID: rpID,
|
||||
expectedOrigin: `https://${options.domain}${devMode ? `:3001` : ``}`,
|
||||
expectedRPID: options.domain,
|
||||
authenticator: convertedAuthenticator
|
||||
})
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -3,23 +3,18 @@ const base64url = require('base64url')
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
const credentials = require('../../../../hardware-credentials')
|
||||
const options = require('../../../../options')
|
||||
const T = require('../../../../time')
|
||||
const users = require('../../../../users')
|
||||
|
||||
const domain = options.hostname
|
||||
const devMode = require('minimist')(process.argv.slice(2)).dev
|
||||
|
||||
const REMEMBER_ME_AGE = 90 * T.day
|
||||
|
||||
const rpID = devMode ? `localhost:3001` : domain
|
||||
const expectedOrigin = `https://${rpID}`
|
||||
|
||||
const generateAttestationOptions = (session, options) => {
|
||||
return credentials.getHardwareCredentials().then(devices => {
|
||||
const opts = simpleWebauthn.generateAttestationOptions({
|
||||
rpName: 'Lamassu',
|
||||
rpID,
|
||||
rpID: options.domain,
|
||||
userName: `Usernameless user created at ${new Date().toISOString()}`,
|
||||
userID: options.userId,
|
||||
timeout: 60000,
|
||||
|
|
@ -46,9 +41,9 @@ const generateAttestationOptions = (session, options) => {
|
|||
})
|
||||
}
|
||||
|
||||
const generateAssertionOptions = session => {
|
||||
const generateAssertionOptions = (session, options) => {
|
||||
return credentials.getHardwareCredentials().then(devices => {
|
||||
const options = simpleWebauthn.generateAssertionOptions({
|
||||
const opts = simpleWebauthn.generateAssertionOptions({
|
||||
timeout: 60000,
|
||||
allowCredentials: devices.map(dev => ({
|
||||
id: dev.data.credentialID,
|
||||
|
|
@ -56,15 +51,15 @@ const generateAssertionOptions = session => {
|
|||
transports: ['usb', 'ble', 'nfc', 'internal']
|
||||
})),
|
||||
userVerification: 'discouraged',
|
||||
rpID
|
||||
rpID: options.domain
|
||||
})
|
||||
|
||||
session.webauthn = {
|
||||
assertion: {
|
||||
challenge: options.challenge
|
||||
challenge: opts.challenge
|
||||
}
|
||||
}
|
||||
return options
|
||||
return opts
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -77,8 +72,8 @@ const validateAttestation = (session, options) => {
|
|||
simpleWebauthn.verifyAttestationResponse({
|
||||
credential: options.attestationResponse,
|
||||
expectedChallenge: `${expectedChallenge}`,
|
||||
expectedOrigin,
|
||||
expectedRPID: rpID
|
||||
expectedOrigin: `https://${options.domain}${devMode ? `:3001` : ``}`,
|
||||
expectedRPID: options.domain
|
||||
})
|
||||
])
|
||||
.then(([user, verification]) => {
|
||||
|
|
@ -146,8 +141,8 @@ const validateAssertion = (session, options) => {
|
|||
verification = simpleWebauthn.verifyAssertionResponse({
|
||||
credential: options.assertionResponse,
|
||||
expectedChallenge: `${expectedChallenge}`,
|
||||
expectedOrigin,
|
||||
expectedRPID: rpID,
|
||||
expectedOrigin: `https://${options.domain}${devMode ? `:3001` : ``}`,
|
||||
expectedRPID: options.domain,
|
||||
authenticator: convertedAuthenticator
|
||||
})
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ const txLogFields = ['txClass', 'id', 'deviceId', 'toAddress', 'cryptoAtoms',
|
|||
'commissionPercentage', 'rawTickerPrice', 'receivedCryptoAtoms',
|
||||
'discount', 'txHash', 'customerPhone', 'customerIdCardDataNumber',
|
||||
'customerIdCardDataExpiration', 'customerIdCardData', 'customerName',
|
||||
'customerFrontCameraPath', 'customerIdCardPhotoPath', 'expired', 'machineName']
|
||||
'customerFrontCameraPath', 'customerIdCardPhotoPath', 'expired', 'machineName', 'walletScore']
|
||||
|
||||
const resolvers = {
|
||||
Customer: {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ const sessionManager = require('../../../session-manager')
|
|||
const getAttestationQueryOptions = variables => {
|
||||
switch (authentication.CHOSEN_STRATEGY) {
|
||||
case 'FIDO2FA':
|
||||
return { userId: variables.userID }
|
||||
return { userId: variables.userID, domain: variables.domain }
|
||||
case 'FIDOPasswordless':
|
||||
return { userId: variables.userID }
|
||||
return { userId: variables.userID, domain: variables.domain }
|
||||
case 'FIDOUsernameless':
|
||||
return { userId: variables.userID }
|
||||
return { userId: variables.userID, domain: variables.domain }
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
|
|
@ -19,11 +19,11 @@ const getAttestationQueryOptions = variables => {
|
|||
const getAssertionQueryOptions = variables => {
|
||||
switch (authentication.CHOSEN_STRATEGY) {
|
||||
case 'FIDO2FA':
|
||||
return { username: variables.username, password: variables.password }
|
||||
return { username: variables.username, password: variables.password, domain: variables.domain }
|
||||
case 'FIDOPasswordless':
|
||||
return { username: variables.username }
|
||||
return { username: variables.username, domain: variables.domain }
|
||||
case 'FIDOUsernameless':
|
||||
return {}
|
||||
return { domain: variables.domain }
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
|
|
@ -32,11 +32,11 @@ const getAssertionQueryOptions = variables => {
|
|||
const getAttestationMutationOptions = variables => {
|
||||
switch (authentication.CHOSEN_STRATEGY) {
|
||||
case 'FIDO2FA':
|
||||
return { userId: variables.userID, attestationResponse: variables.attestationResponse }
|
||||
return { userId: variables.userID, attestationResponse: variables.attestationResponse, domain: variables.domain }
|
||||
case 'FIDOPasswordless':
|
||||
return { userId: variables.userID, attestationResponse: variables.attestationResponse }
|
||||
return { userId: variables.userID, attestationResponse: variables.attestationResponse, domain: variables.domain }
|
||||
case 'FIDOUsernameless':
|
||||
return { userId: variables.userID, attestationResponse: variables.attestationResponse }
|
||||
return { userId: variables.userID, attestationResponse: variables.attestationResponse, domain: variables.domain }
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
|
|
@ -45,11 +45,11 @@ const getAttestationMutationOptions = variables => {
|
|||
const getAssertionMutationOptions = variables => {
|
||||
switch (authentication.CHOSEN_STRATEGY) {
|
||||
case 'FIDO2FA':
|
||||
return { username: variables.username, password: variables.password, rememberMe: variables.rememberMe, assertionResponse: variables.assertionResponse }
|
||||
return { username: variables.username, password: variables.password, rememberMe: variables.rememberMe, assertionResponse: variables.assertionResponse, domain: variables.domain }
|
||||
case 'FIDOPasswordless':
|
||||
return { username: variables.username, rememberMe: variables.rememberMe, assertionResponse: variables.assertionResponse }
|
||||
return { username: variables.username, rememberMe: variables.rememberMe, assertionResponse: variables.assertionResponse, domain: variables.domain }
|
||||
case 'FIDOUsernameless':
|
||||
return { assertionResponse: variables.assertionResponse }
|
||||
return { assertionResponse: variables.assertionResponse, domain: variables.domain }
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ const typeDef = gql`
|
|||
txCustomerPhotoAt: Date
|
||||
batched: Boolean
|
||||
batchTime: Date
|
||||
walletScore: Int
|
||||
}
|
||||
|
||||
type Filter {
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ const authentication = require('../modules/authentication')
|
|||
const getFIDOStrategyQueryTypes = () => {
|
||||
switch (authentication.CHOSEN_STRATEGY) {
|
||||
case 'FIDO2FA':
|
||||
return `generateAttestationOptions(userID: ID!): JSONObject
|
||||
generateAssertionOptions(username: String!, password: String!): JSONObject`
|
||||
return `generateAttestationOptions(userID: ID!, domain: String!): JSONObject
|
||||
generateAssertionOptions(username: String!, password: String!, domain: String!): JSONObject`
|
||||
case 'FIDOPasswordless':
|
||||
return `generateAttestationOptions(userID: ID!): JSONObject
|
||||
generateAssertionOptions(username: String!): JSONObject`
|
||||
return `generateAttestationOptions(userID: ID!, domain: String!): JSONObject
|
||||
generateAssertionOptions(username: String!, domain: String!): JSONObject`
|
||||
case 'FIDOUsernameless':
|
||||
return `generateAttestationOptions(userID: ID!): JSONObject
|
||||
generateAssertionOptions: JSONObject`
|
||||
return `generateAttestationOptions(userID: ID!, domain: String!): JSONObject
|
||||
generateAssertionOptions(domain: String!): JSONObject`
|
||||
default:
|
||||
return ``
|
||||
}
|
||||
|
|
@ -19,14 +19,14 @@ const getFIDOStrategyQueryTypes = () => {
|
|||
const getFIDOStrategyMutationsTypes = () => {
|
||||
switch (authentication.CHOSEN_STRATEGY) {
|
||||
case 'FIDO2FA':
|
||||
return `validateAttestation(userID: ID!, attestationResponse: JSONObject!): Boolean
|
||||
validateAssertion(username: String!, password: String!, rememberMe: Boolean!, assertionResponse: JSONObject!): Boolean`
|
||||
return `validateAttestation(userID: ID!, attestationResponse: JSONObject!, domain: String!): Boolean
|
||||
validateAssertion(username: String!, password: String!, rememberMe: Boolean!, assertionResponse: JSONObject!, domain: String!): Boolean`
|
||||
case 'FIDOPasswordless':
|
||||
return `validateAttestation(userID: ID!, attestationResponse: JSONObject!): Boolean
|
||||
validateAssertion(username: String!, rememberMe: Boolean!, assertionResponse: JSONObject!): Boolean`
|
||||
return `validateAttestation(userID: ID!, attestationResponse: JSONObject!, domain: String!): Boolean
|
||||
validateAssertion(username: String!, rememberMe: Boolean!, assertionResponse: JSONObject!, domain: String!): Boolean`
|
||||
case 'FIDOUsernameless':
|
||||
return `validateAttestation(userID: ID!, attestationResponse: JSONObject!): Boolean
|
||||
validateAssertion(assertionResponse: JSONObject!): Boolean`
|
||||
return `validateAttestation(userID: ID!, attestationResponse: JSONObject!, domain: String!): Boolean
|
||||
validateAssertion(assertionResponse: JSONObject!, domain: String!): Boolean`
|
||||
default:
|
||||
return ``
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ router.use('*', async (req, res, next) => getOperatorId('authentication').then((
|
|||
cookie: {
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
domain: hostname,
|
||||
sameSite: true,
|
||||
maxAge: 60 * 10 * 1000 // 10 minutes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ function batch (
|
|||
AND ($12 is null or txs.to_address = $12)
|
||||
AND ($13 is null or txs.txStatus = $13)
|
||||
${excludeTestingCustomers ? `AND c.is_test_customer is false` : ``}
|
||||
AND (fiat > 0)
|
||||
AND (error IS NOT null OR fiat > 0)
|
||||
ORDER BY created DESC limit $4 offset $5`
|
||||
|
||||
const cashOutSql = `SELECT 'cashOut' AS tx_class,
|
||||
|
|
|
|||
|
|
@ -828,9 +828,12 @@ function plugins (settings, deviceId) {
|
|||
.then(buildRates)
|
||||
}
|
||||
|
||||
function rateWallet (address) {
|
||||
return walletScoring.rateWallet(settings, address)
|
||||
.then(res => res.rating)
|
||||
function rateWallet (cryptoCode, address) {
|
||||
return walletScoring.rateWallet(settings, cryptoCode, address)
|
||||
}
|
||||
|
||||
function isValidWalletScore (score) {
|
||||
return walletScoring.isValidWalletScore(settings, score)
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -861,7 +864,8 @@ function plugins (settings, deviceId) {
|
|||
notifyOperator,
|
||||
fetchCurrentConfigVersion,
|
||||
pruneMachinesHeartbeat,
|
||||
rateWallet
|
||||
rateWallet,
|
||||
isValidWalletScore
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
47
lib/plugins/wallet-scoring/ciphertrace/ciphertrace.js
Normal file
47
lib/plugins/wallet-scoring/ciphertrace/ciphertrace.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
const axios = require('axios')
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const NAME = 'CipherTrace'
|
||||
const SUPPORTED_COINS = ['BTC', 'ETH', 'BCH', 'LTC', 'BNB', 'RSK']
|
||||
|
||||
function getClient(account) {
|
||||
if (_.isNil(account) || !account.enabled) return null
|
||||
|
||||
const [ctv1, username, secretKey] = account.authorizationValue.split(':')
|
||||
if (_.isNil(ctv1) || _.isNil(username) || _.isNil(secretKey)) {
|
||||
throw new Error('Invalid CipherTrace configuration')
|
||||
}
|
||||
|
||||
const apiVersion = ctv1.slice(-2)
|
||||
const authHeader = {
|
||||
"Authorization": account.authorizationValue
|
||||
}
|
||||
return { apiVersion, authHeader }
|
||||
}
|
||||
|
||||
function rateWallet(account, cryptoCode, address) {
|
||||
const client = getClient(account)
|
||||
if (!_.includes(_.toUpper(cryptoCode), SUPPORTED_COINS) || _.isNil(client)) return Promise.resolve(null)
|
||||
|
||||
const { apiVersion, authHeader } = client
|
||||
const threshold = account.scoreThreshold
|
||||
|
||||
return axios.get(`https://rest.ciphertrace.com/aml/${apiVersion}/${_.toLower(cryptoCode)}/risk?address=${address}`, {
|
||||
headers: authHeader
|
||||
})
|
||||
.then(res => ({ address, score: res.data.risk, isValid: res.data.risk < threshold }))
|
||||
}
|
||||
|
||||
function isValidWalletScore(account, score) {
|
||||
const client = getClient(account)
|
||||
if (_.isNil(client)) return Promise.resolve(true)
|
||||
|
||||
const threshold = account.scoreThreshold
|
||||
return Promise.resolve(score < threshold)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
NAME,
|
||||
rateWallet,
|
||||
isValidWalletScore
|
||||
}
|
||||
|
|
@ -1,15 +1,27 @@
|
|||
const NAME = 'FakeScoring'
|
||||
|
||||
function rateWallet (account, address) {
|
||||
const { WALLET_SCORE_THRESHOLD } = require('../../../constants')
|
||||
|
||||
function rateWallet (account, cryptoCode, address) {
|
||||
return new Promise((resolve, _) => {
|
||||
setTimeout(() => {
|
||||
console.log('[WALLET-SCORING] DEBUG: Mock scoring rating wallet address %s', address)
|
||||
return resolve({ address, rating: 5 })
|
||||
return Promise.resolve(7)
|
||||
.then(score => resolve({ address, score, isValid: score < WALLET_SCORE_THRESHOLD }))
|
||||
}, 100)
|
||||
})
|
||||
}
|
||||
|
||||
function isValidWalletScore (account, score) {
|
||||
return new Promise((resolve, _) => {
|
||||
setTimeout(() => {
|
||||
return resolve(score < WALLET_SCORE_THRESHOLD)
|
||||
}, 100)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
NAME,
|
||||
rateWallet
|
||||
rateWallet,
|
||||
isValidWalletScore
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ const configPath = utils.configPath(cryptoRec, blockchainDir)
|
|||
const walletDir = path.resolve(utils.cryptoDir(cryptoRec, blockchainDir), 'wallets')
|
||||
const unitScale = cryptoRec.unitScale
|
||||
|
||||
const SUPPORTS_BATCHING = false
|
||||
|
||||
function rpcConfig () {
|
||||
try {
|
||||
const config = jsonRpc.parseConf(configPath)
|
||||
|
|
@ -186,9 +188,9 @@ function cryptoNetwork (account, cryptoCode) {
|
|||
return checkCryptoCode(cryptoCode)
|
||||
.then(() => {
|
||||
switch(parseInt(rpcConfig().port, 10)) {
|
||||
case 18083:
|
||||
case 18082:
|
||||
return 'main'
|
||||
case 28083:
|
||||
case 28082:
|
||||
return 'test'
|
||||
case 38083:
|
||||
return 'stage'
|
||||
|
|
@ -198,11 +200,17 @@ function cryptoNetwork (account, cryptoCode) {
|
|||
})
|
||||
}
|
||||
|
||||
function supportsBatching (cryptoCode) {
|
||||
return checkCryptoCode(cryptoCode)
|
||||
.then(() => SUPPORTS_BATCHING)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
balance,
|
||||
sendCoins,
|
||||
newAddress,
|
||||
getStatus,
|
||||
newFunding,
|
||||
cryptoNetwork
|
||||
cryptoNetwork,
|
||||
supportsBatching
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,25 +3,32 @@ const _ = require('lodash/fp')
|
|||
const argv = require('minimist')(process.argv.slice(2))
|
||||
|
||||
function loadWalletScoring (settings) {
|
||||
if (_.isNil(argv.mockScoring)) {
|
||||
throw new Error('No wallet scoring API set!')
|
||||
}
|
||||
const pluginCode = argv.mockScoring ? 'mock-scoring' : ''
|
||||
const pluginCode = argv.mockScoring ? 'mock-scoring' : 'ciphertrace'
|
||||
const plugin = ph.load(ph.WALLET_SCORING, pluginCode)
|
||||
const account = settings.accounts[pluginCode]
|
||||
|
||||
return { plugin, account }
|
||||
}
|
||||
|
||||
function rateWallet (settings, address) {
|
||||
function rateWallet (settings, cryptoCode, address) {
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
const { plugin, account } = loadWalletScoring(settings)
|
||||
|
||||
return plugin.rateWallet(account, address)
|
||||
return plugin.rateWallet(account, cryptoCode, address)
|
||||
})
|
||||
}
|
||||
|
||||
function isValidWalletScore (settings, score) {
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
const { plugin, account } = loadWalletScoring(settings)
|
||||
|
||||
return plugin.isValidWalletScore(account, score)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
rateWallet
|
||||
rateWallet,
|
||||
isValidWalletScore
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue