Skip to content

Commit

Permalink
Merge pull request #66 from polymorpher/client-security-randomness
Browse files Browse the repository at this point in the history
Client security: enable randomness by default
  • Loading branch information
polymorpher committed Aug 6, 2021
2 parents f55ab96 + cdbec6e commit 4d4b1b5
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 29 deletions.
2 changes: 1 addition & 1 deletion code/client/src/components/CommitRevealProgress.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { Step } = Steps
export const CommitRevealProgress = ({ stage, style }) => {
return (
<>
{stage > 0 && (
{stage >= 0 && (
<Row style={style}>
<Steps current={stage}>
<Step title='Prepare' description='Preparing signature' />
Expand Down
20 changes: 17 additions & 3 deletions code/client/src/pages/Create.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { useDispatch, useSelector } from 'react-redux'
import { useHistory } from 'react-router'
import Paths from '../constants/paths'
import api from '../api'
import config from '../config'
import ONEUtil from '../../../lib/util'
import ONEConstants from '../../../lib/constants'
import ONENames from '../../../lib/names'
// import { uniqueNamesGenerator, colors, animals } from 'unique-names-generator'
import {
Expand Down Expand Up @@ -101,6 +103,11 @@ const Create = () => {

const otpRef = useRef()

const securityParameters = ONEUtil.securityParameters({
majorVersion: ONEConstants.MajorVersion,
minorVersion: ONEConstants.MinorVersion,
})

const getQRCodeUri = (otpSeed, otpDisplayName) => {
// otpauth://TYPE/LABEL?PARAMETERS
return `otpauth://totp/${otpDisplayName}?secret=${b32.encode(otpSeed)}&issuer=Harmony`
Expand All @@ -119,11 +126,17 @@ const Create = () => {

useEffect(() => {
if (section === sectionViews.setupOtp && worker) {
console.log('posting to worker')
console.log('Posting to worker. Security parameters:', securityParameters)
const t = Math.floor(Date.now() / WalletConstants.interval) * WalletConstants.interval
setEffectiveTime(t)
worker && worker.postMessage({
seed, seed2, effectiveTime: t, duration, slotSize, interval: WalletConstants.interval
seed,
seed2,
effectiveTime: t,
duration,
slotSize,
interval: WalletConstants.interval,
...securityParameters,
})
}
}, [section, worker])
Expand Down Expand Up @@ -194,6 +207,7 @@ const Create = () => {
hseed: ONEUtil.hexView(hseed),
network,
doubleOtp,
...securityParameters,
}
await storeLayers()
dispatch(walletActions.updateWallet(wallet))
Expand All @@ -210,7 +224,7 @@ const Create = () => {
}

useEffect(() => {
const worker = new Worker('ONEWalletWorker.js')
const worker = new Worker('/ONEWalletWorker.js')
worker.onmessage = (event) => {
const { status, current, total, stage, result } = event.data
if (status === 'working') {
Expand Down
21 changes: 18 additions & 3 deletions code/client/src/pages/Restore.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import util, { useWindowDimensions } from '../util'
import { handleAddressError } from '../handler'
import Paths from '../constants/paths'
import * as Sentry from '@sentry/browser'
import config from '../config'

const { Step } = Steps

Expand All @@ -29,6 +30,8 @@ const Restore = () => {
const [secret2, setSecret2] = useState()
const [name, setName] = useState()
const [device, setDevice] = useState()
const [majorVersion, setMajorVersion] = useState()
const [minorVersion, setMinorVersion] = useState()
const { isMobile } = useWindowDimensions()
const ref = useRef()
useEffect(() => {
Expand Down Expand Up @@ -109,6 +112,7 @@ const Restore = () => {
return
}
try {
const securityParameters = ONEUtil.securityParameters({ majorVersion, minorVersion })
const worker = new Worker('ONEWalletWorker.js')
worker.onmessage = (event) => {
const { status, current, total, stage, result } = event.data
Expand All @@ -134,7 +138,8 @@ const Restore = () => {
dailyLimit,
hseed: ONEUtil.hexView(hseed),
doubleOtp,
network
network,
...securityParameters
}
dispatch(walletActions.updateWallet(wallet))
dispatch(walletActions.fetchBalance({ address }))
Expand All @@ -145,7 +150,13 @@ const Restore = () => {
}
console.log('[Restore] Posting to worker')
worker && worker.postMessage({
seed: secret, seed2: secret2, effectiveTime, duration, slotSize, interval: WalletConstants.interval
seed: secret,
seed2: secret2,
effectiveTime,
duration,
slotSize,
interval: WalletConstants.interval,
...securityParameters
})
} catch (ex) {
Sentry.captureException(ex)
Expand Down Expand Up @@ -174,7 +185,9 @@ const Restore = () => {
duration,
slotSize,
lastResortAddress,
dailyLimit
dailyLimit,
majorVersion,
minorVersion
} = await api.blockchain.getWallet({ address })
console.log('Retrieved wallet:', {
root,
Expand All @@ -192,6 +205,8 @@ const Restore = () => {
setLastResortAddress(lastResortAddress)
setDailyLimit(dailyLimit)
setSection(2)
setMajorVersion(majorVersion)
setMinorVersion(minorVersion)
} catch (ex) {
Sentry.captureException(ex)
console.error(ex)
Expand Down
67 changes: 55 additions & 12 deletions code/client/src/pages/Show.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,33 @@ const Show = () => {

const wallet = wallets[address] || {}
const [section, setSection] = useState(action)
const [stage, setStage] = useState(0)
const [stage, setStage] = useState(-1)
const network = useSelector(state => state.wallet.network)
const [activeTab, setActiveTab] = useState('coins')
const walletOutdated = util.isWalletOutdated(wallet)
const [worker, setWorker] = useState()
const workerRef = useRef({ promise: null }).current
const resetWorkerPromise = (newWorker) => {
workerRef.promise = new Promise((resolve, reject) => {
newWorker.onmessage = (event) => {
const { status, error, result } = event.data
// console.log('Received: ', { status, result, error })
if (status === 'rand') {
const { rand } = result
resolve(rand)
} else if (status === 'error') {
reject(error)
}
}
})
}
useEffect(() => {
const worker = new Worker('/ONEWalletWorker.js')
setWorker(worker)
}, [])
useEffect(() => {
worker && resetWorkerPromise(worker)
}, [worker])

useEffect(() => {
if (!wallet) {
Expand Down Expand Up @@ -160,7 +183,7 @@ const Show = () => {
}

const restart = () => {
setStage(0)
setStage(-1)
resetOtp()
setInputAmount(0)
}
Expand Down Expand Up @@ -219,26 +242,26 @@ const Show = () => {
Sentry.captureException(ex)
console.error(ex)
message.error('Failed to commit. Error: ' + ex.toString())
setStage(0)
setStage(-1)
resetOtp()
}

const onCommitFailure = (error) => {
message.error(`Cannot commit transaction. Reason: ${error}`)
setStage(0)
setStage(-1)
resetOtp()
}

const onRevealFailure = (error) => {
message.error(`Transaction Failed: ${error}`)
setStage(0)
setStage(-1)
resetOtp()
}

const onRevealError = (ex) => {
Sentry.captureException(ex)
message.error(`Failed to finalize transaction. Error: ${ex.toString()}`)
setStage(0)
setStage(-1)
resetOtp()
}

Expand All @@ -257,18 +280,35 @@ const Show = () => {
setTimeout(restart, 3000)
}

const doSend = async () => {
const prepareProofFailed = () => {
setStage(-1)
resetOtp()
resetWorkerPromise(worker)
}

const doSend = () => {
const { otp, otp2, invalidOtp2, invalidOtp, dest, amount } = prepareValidation() || {}

if (invalidOtp || !dest || invalidOtp2) return

const recoverRandomness = async (args) => {
worker && worker.postMessage({
action: 'recoverRandomness',
...args
})
return workerRef.promise
}

if (selectedToken.key === 'one') {
SmartFlows.commitReveal({
wallet,
otp,
otp2,
recoverRandomness,
prepareProofFailed,
commitHashGenerator: ONE.computeTransferHash,
commitHashArgs: { dest, amount },
prepareProof: () => setStage(0),
beforeCommit: () => setStage(1),
afterCommit: () => setStage(2),
onCommitError,
Expand All @@ -288,6 +328,8 @@ const Show = () => {
wallet,
otp,
otp2,
recoverRandomness,
prepareProofFailed,
commitHashGenerator: ONE.computeTokenOperationHash,
commitHashArgs: { dest, amount, operationType: ONEConstants.OperationType.TRANSFER_TOKEN, tokenType: selectedToken.tokenType, contractAddress: selectedToken.contractAddress, tokenId: selectedToken.tokenId },
beforeCommit: () => setStage(1),
Expand Down Expand Up @@ -359,6 +401,7 @@ const Show = () => {
}
})
}

const { isMobile } = useWindowDimensions()
// UI Rendering below
if (!wallet || wallet.network !== network) {
Expand Down Expand Up @@ -562,9 +605,9 @@ const Show = () => {
</Space>
<Row justify='end' style={{ marginTop: 24 }}>
<Space>
{stage > 0 && stage < 3 && <LoadingOutlined />}
{stage >= 0 && stage < 3 && <LoadingOutlined />}
{stage === 3 && <CheckCircleOutlined />}
<Button type='primary' size='large' shape='round' disabled={stage > 0} onClick={doSend}>Send</Button>
<Button type='primary' size='large' shape='round' disabled={stage >= 0} onClick={doSend}>Send</Button>
</Space>
</Row>
<CommitRevealProgress stage={stage} style={{ marginTop: 32 }} />
Expand All @@ -584,7 +627,7 @@ const Show = () => {
<Text>Do you want to proceed?</Text>
</Space>
<Row justify='end' style={{ marginTop: 48 }}>
<Button type='primary' size='large' shape='round' disabled={stage > 0} onClick={doRecovery}>Sounds good!</Button>
<Button type='primary' size='large' shape='round' disabled={stage >= 0} onClick={doRecovery}>Sounds good!</Button>
</Row>
<CommitRevealProgress stage={stage} style={{ marginTop: 32 }} />
</>}
Expand Down Expand Up @@ -639,8 +682,8 @@ const Show = () => {
</Space>
<Row justify='end' style={{ marginTop: 24 }}>
<Space>
{stage > 0 && stage < 3 && <LoadingOutlined />}
<Button type='primary' size='large' shape='round' disabled={stage > 0} onClick={doSetRecoveryAddress}>Set</Button>
{stage >= 0 && stage < 3 && <LoadingOutlined />}
<Button type='primary' size='large' shape='round' disabled={stage >= 0} onClick={doSetRecoveryAddress}>Set</Button>
</Space>
</Row>
<CommitRevealProgress stage={stage} style={{ marginTop: 32 }} />
Expand Down
11 changes: 10 additions & 1 deletion code/client/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,16 @@ export default {
return false
},

compareVersion: (left, right) => left.majorVersion === right.majorVersion && left.minorVersion === right.minorVersion
compareVersion: (left, right) => left.majorVersion === right.majorVersion && left.minorVersion === right.minorVersion,

getRandomness: () => {
let r = config.clientSecurity.baseRandomness - config.clientSecurity.randomnessDamping
if (config.clientSecurity.hasher === 'argon2') {
r -= config.clientSecurity.argon2Damping
}
return r
},

}

function getWindowDimensions () {
Expand Down
30 changes: 29 additions & 1 deletion code/client/src/worker/ONEWalletWorker.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
const ONE = require('../../../lib/onewallet')
const ONEUtil = require('../../../lib/util')

async function recoverRandomness ({ randomness, hseed, otp, otp2, nonce, leaf, hasher }) {
const encodedOtp = ONEUtil.encodeNumericalOtp(otp)
const encodedOtp2 = otp2 !== undefined ? ONEUtil.encodeNumericalOtp(otp2) : undefined
try {
const rand = await ONE.recoverRandomness({
randomness,
hseed: ONEUtil.hexToBytes(hseed),
otp: encodedOtp,
otp2: encodedOtp2,
nonce,
leaf,
hasher: ONEUtil.getHasher(hasher)
})
postMessage({ status: 'rand', result: { rand } })
} catch (ex) {
console.error(ex)
postMessage({ status: 'error', result: { error: ex.toString() } })
}
}

onmessage = async function (event) {
const { seed, seed2, effectiveTime, duration, slotSize, interval } = event.data
const { seed, seed2, effectiveTime, duration, slotSize, interval, randomness, hasher, action } = event.data

if (action === 'recoverRandomness') {
return recoverRandomness(event.data)
}

if (!seed) {
// console.log('worker: received event but it has no valid data', event)
return
Expand All @@ -20,6 +46,8 @@ onmessage = async function (event) {
otpSeed2: seed2,
effectiveTime,
duration,
randomness,
hasher: ONEUtil.getHasher(hasher),
maxOperationsPerInterval: slotSize,
otpInterval: interval,
progressObserver: (current, total, stage) => {
Expand Down
Loading

0 comments on commit 4d4b1b5

Please sign in to comment.