feat: reject address reuse

This commit is contained in:
Taranto 2020-09-22 09:01:43 +01:00 committed by Josh Harvey
parent f2080c32e9
commit f6547341f1
5 changed files with 69 additions and 27 deletions

View file

@ -7,7 +7,7 @@ const db = require('../db')
const plugins = require('../plugins') const plugins = require('../plugins')
const logger = require('../logger') const logger = require('../logger')
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 cashInAtomic = require('./cash-in-atomic') const cashInAtomic = require('./cash-in-atomic')
const cashInLow = require('./cash-in-low') const cashInLow = require('./cash-in-low')
@ -26,9 +26,7 @@ function post (machineTx, pi) {
return Promise.all([settingsLoader.loadLatest(), checkForBlacklisted(updatedTx)]) return Promise.all([settingsLoader.loadLatest(), checkForBlacklisted(updatedTx)])
.then(([{ config }, blacklistItems]) => { .then(([{ config }, blacklistItems]) => {
// TODO new-admin: addressReuse doesnt exist const rejectAddressReuseActive = configManager.getCompliance(config).rejectAddressReuse
// const rejectAddressReuseActive = configManager.unscoped(config).rejectAddressReuseActive
const rejectAddressReuseActive = false
if (_.some(it => it.created_by_operator === true)(blacklistItems)) { if (_.some(it => it.created_by_operator === true)(blacklistItems)) {
blacklisted = true blacklisted = true
@ -125,9 +123,8 @@ function postProcess (r, pi, isBlacklisted, addressReuse) {
}) })
.then(sendRec => { .then(sendRec => {
settingsLoader.loadLatest().then(it => { settingsLoader.loadLatest().then(it => {
// TODO new-admin: addressReuse doesnt exist const rejectAddressReuseActive = configManager.getCompliance(it.config).rejectAddressReuse
// const config = configManager.unscoped(it.config) if (rejectAddressReuseActive) {
if (false) {
blacklist.addToUsedAddresses(r.tx.toAddress, r.tx.cryptoCode) blacklist.addToUsedAddresses(r.tx.toAddress, r.tx.cryptoCode)
.catch(err => logger.error('Failure adding to addressReuse', err)) .catch(err => logger.error('Failure adding to addressReuse', err))
} }

View file

@ -10,7 +10,8 @@ const namespaces = {
RECEIPT: 'receipt', RECEIPT: 'receipt',
COIN_ATM_RADAR: 'coinAtmRadar', COIN_ATM_RADAR: 'coinAtmRadar',
TERMS_CONDITIONS: 'termsConditions', TERMS_CONDITIONS: 'termsConditions',
CASH_OUT: 'cashOut' CASH_OUT: 'cashOut',
COMPLIANCE: 'compliance'
} }
const stripl = _.curry((q, str) => _.startsWith(q, str) ? str.slice(q.length) : str) const stripl = _.curry((q, str) => _.startsWith(q, str) ? str.slice(q.length) : str)
@ -48,6 +49,7 @@ const getOperatorInfo = fromNamespace(namespaces.OPERATOR_INFO)
const getCoinAtmRadar = fromNamespace(namespaces.COIN_ATM_RADAR) const getCoinAtmRadar = fromNamespace(namespaces.COIN_ATM_RADAR)
const getTermsConditions = fromNamespace(namespaces.TERMS_CONDITIONS) const getTermsConditions = fromNamespace(namespaces.TERMS_CONDITIONS)
const getReceipt = fromNamespace(namespaces.RECEIPT) const getReceipt = fromNamespace(namespaces.RECEIPT)
const getCompliance = fromNamespace(namespaces.COMPLIANCE)
const getAllCryptoCurrencies = (config) => { const getAllCryptoCurrencies = (config) => {
const locale = fromNamespace(namespaces.LOCALE)(config) const locale = fromNamespace(namespaces.LOCALE)(config)
@ -85,6 +87,7 @@ module.exports = {
getGlobalLocale, getGlobalLocale,
getCommissions, getCommissions,
getReceipt, getReceipt,
getCompliance,
getCoinAtmRadar, getCoinAtmRadar,
getTermsConditions, getTermsConditions,
getAllCryptoCurrencies, getAllCryptoCurrencies,

View file

@ -124,6 +124,18 @@ function plugins (settings, deviceId) {
] ]
} }
function getLcmOrBigx2 (n1, n2) {
let big = Math.max(n1, n2);
let small = Math.min(n1, n2);
let i = big * 2;
while(i % small !== 0){
i += lar;
}
return i;
}
function buildAvailableCassettes (excludeTxId) { function buildAvailableCassettes (excludeTxId) {
const cashOutConfig = configManager.getCashOut(deviceId, settings.config) const cashOutConfig = configManager.getCashOut(deviceId, settings.config)
@ -131,8 +143,7 @@ function plugins (settings, deviceId) {
const denominations = [cashOutConfig.top, cashOutConfig.bottom] const denominations = [cashOutConfig.top, cashOutConfig.bottom]
// TODO new-admin: will this actually be calculated? const virtualCassettes = [getLcmOrBigx2(cashOutConfig.top, cashOutConfig.bottom)]
const virtualCassettes = [cashOutConfig.top + cashOutConfig.bottom]
return Promise.all([dbm.cassetteCounts(deviceId), cashOutHelper.redeemableTxs(deviceId, excludeTxId)]) return Promise.all([dbm.cassetteCounts(deviceId), cashOutHelper.redeemableTxs(deviceId, excludeTxId)])
.then(([rec, _redeemableTxs]) => { .then(([rec, _redeemableTxs]) => {

View file

@ -9,6 +9,7 @@ const useStyles = makeStyles({
border: 'none', border: 'none',
backgroundColor: 'transparent', backgroundColor: 'transparent',
marginTop: 4, marginTop: 4,
outline: 'none',
cursor: 'pointer' cursor: 'pointer'
}, },
popoverContent: ({ width }) => ({ popoverContent: ({ width }) => ({
@ -33,18 +34,19 @@ const Tooltip = memo(({ children, width, Icon = HelpIcon }) => {
return ( return (
<ClickAwayListener onClickAway={handleCloseHelpPopper}> <ClickAwayListener onClickAway={handleCloseHelpPopper}>
<button <div>
className={classes.transparentButton} <button
onClick={handleOpenHelpPopper}> className={classes.transparentButton}
<Icon /> onClick={handleOpenHelpPopper}>
<Icon />
</button>
<Popper <Popper
open={helpPopperOpen} open={helpPopperOpen}
anchorEl={helpPopperAnchorEl} anchorEl={helpPopperAnchorEl}
placement="bottom" placement="bottom">
onClose={handleCloseHelpPopper}>
<div className={classes.popoverContent}>{children}</div> <div className={classes.popoverContent}>{children}</div>
</Popper> </Popper>
</button> </div>
</ClickAwayListener> </ClickAwayListener>
) )
}) })

View file

@ -1,14 +1,17 @@
import { useQuery, useMutation } from '@apollo/react-hooks' import { useQuery, useMutation } from '@apollo/react-hooks'
import { makeStyles } from '@material-ui/core' import { makeStyles, Box } from '@material-ui/core'
import gql from 'graphql-tag' import gql from 'graphql-tag'
import * as R from 'ramda' import * as R from 'ramda'
import React, { useState } from 'react' import React, { useState } from 'react'
import { v4 } from 'uuid' import { v4 } from 'uuid'
import Title from 'src/components/Title' import Tooltip from 'src/components/Tooltip'
import { Link } from 'src/components/buttons' import { Link } from 'src/components/buttons'
import { Table as EditableTable } from 'src/components/editableTable' import { Table as EditableTable } from 'src/components/editableTable'
import { fromNamespace, namespaces } from 'src/utils/config' import { Switch } from 'src/components/inputs'
import TitleSection from 'src/components/layout/TitleSection'
import { P, Label2 } from 'src/components/typography'
import { fromNamespace, toNamespace, namespaces } from 'src/utils/config'
import { mainStyles } from './Triggers.styles' import { mainStyles } from './Triggers.styles'
import Wizard from './Wizard' import Wizard from './Wizard'
@ -36,6 +39,10 @@ const Triggers = () => {
const { data } = useQuery(GET_INFO) const { data } = useQuery(GET_INFO)
const triggers = fromServer(data?.config?.triggers ?? []) const triggers = fromServer(data?.config?.triggers ?? [])
const complianceConfig =
data?.config && fromNamespace('compliance')(data.config)
const rejectAddressReuse = complianceConfig?.rejectAddressReuse ?? false
const [saveConfig] = useMutation(SAVE_CONFIG, { const [saveConfig] = useMutation(SAVE_CONFIG, {
onCompleted: () => setWizard(false), onCompleted: () => setWizard(false),
onError: () => setError(true), onError: () => setError(true),
@ -48,6 +55,11 @@ const Triggers = () => {
return saveConfig({ variables: { config: { triggers: toServer(toSave) } } }) return saveConfig({ variables: { config: { triggers: toServer(toSave) } } })
} }
const addressReuseSave = rawConfig => {
const config = toNamespace('compliance')(rawConfig)
return saveConfig({ variables: { config } })
}
const save = config => { const save = config => {
setError(false) setError(false)
return saveConfig({ return saveConfig({
@ -61,16 +73,33 @@ const Triggers = () => {
return ( return (
<> <>
<div className={classes.titleWrapper}> <TitleSection title="Compliance Triggers">
<div className={classes.titleAndButtonsContainer}> <Box display="flex" alignItems="center">
<Title>Compliance Triggers</Title> <Box display="flex" alignItems="center" justifyContent="end" mr={3}>
</div> <P>Reject reused addresses</P>
<div className={classes.headerLabels}> <Switch
checked={rejectAddressReuse}
onChange={event => {
addressReuseSave({ rejectAddressReuse: event.target.checked })
}}
value={rejectAddressReuse}
/>
<Label2 className={classes.switchLabel}>
{rejectAddressReuse ? 'On' : 'Off'}
</Label2>
<Tooltip width={304}>
<P>
The "Reject reused addresses" option means that all addresses
that are used once will be automatically rejected if there's an
attempt to use them again on a new transaction.
</P>
</Tooltip>
</Box>
<Link color="primary" onClick={() => setWizard(true)}> <Link color="primary" onClick={() => setWizard(true)}>
+ Add new trigger + Add new trigger
</Link> </Link>
</div> </Box>
</div> </TitleSection>
<EditableTable <EditableTable
data={triggers} data={triggers}
name="triggers" name="triggers"