Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add use two otp options on create wallet #65

Merged
merged 30 commits into from
Aug 5, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
658f052
Add use two otp options on create wallet
haolinj Aug 3, 2021
0d7ce6b
Use same name for second otp with suffix and adjust the instruction text
haolinj Aug 4, 2021
0f497a4
Preset second otp qr data and not overriding otp name in the state
haolinj Aug 4, 2021
bef6494
Merge branch 'master' of github.com:polymorpher/one-wallet into clien…
haolinj Aug 4, 2021
7a845ae
Add otp2 for transfer and potentially restore wallet
haolinj Aug 4, 2021
a9adb9d
Merge branch 'client-security' of github.com:polymorpher/one-wallet i…
haolinj Aug 4, 2021
e1bff30
Auto focus otp2 input box when otp1 input box is filled
haolinj Aug 4, 2021
f606270
fix issues with wasm in webpack compilation
polymorpher Aug 5, 2021
73deab0
improve Create screen texts, positioning, and user experience
polymorpher Aug 5, 2021
a5b9f93
remove redundant new lines
polymorpher Aug 5, 2021
41c3f4a
Merge branch 'client-security' into client-security-frontend
polymorpher Aug 5, 2021
266c747
Merge remote-tracking branch 'origin/client-security' into client-sec…
polymorpher Aug 5, 2021
57ef96b
minor
polymorpher Aug 5, 2021
f4346b8
clean up
polymorpher Aug 5, 2021
ace8dd7
ditto
polymorpher Aug 5, 2021
ca1f770
ONE Wallet -> 1wallet
polymorpher Aug 5, 2021
dc64057
otp entry name change
polymorpher Aug 5, 2021
b6ebe9b
text update
polymorpher Aug 5, 2021
26a0b54
better syntax for computeRecoveryHash
polymorpher Aug 5, 2021
e213814
v8 contract
polymorpher Aug 5, 2021
ec5ab14
revealRecovery with data
polymorpher Aug 5, 2021
36a3594
doRecovery
polymorpher Aug 5, 2021
8c3478e
skip checking minor version
polymorpher Aug 5, 2021
4d658c5
flow: allow index override
polymorpher Aug 5, 2021
344f9bd
relayer: show reveal params on verbose mode
polymorpher Aug 5, 2021
5970e3e
doRecovery: fix issues
polymorpher Aug 5, 2021
7c13508
rearrange ui elements
polymorpher Aug 5, 2021
45af94f
make restore work
polymorpher Aug 5, 2021
08834d7
Add 2 otp for recover address setup
haolinj Aug 5, 2021
e11ec8d
Merge branch 'client-security-frontend' of github.com:polymorpher/one…
haolinj Aug 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 94 additions & 21 deletions code/client/src/pages/Create.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import api from '../api'
import ONEUtil from '../../../lib/util'
import ONENames from '../../../lib/names'
// import { uniqueNamesGenerator, colors, animals } from 'unique-names-generator'
import { Button, Row, Space, Typography, Slider, Image, message, Progress, Timeline, Select } from 'antd'
import { Button, Row, Space, Typography, Slider, Image, message, Progress, Timeline, Select, Checkbox } from 'antd'
import { RedoOutlined, LoadingOutlined, SearchOutlined } from '@ant-design/icons'
import humanizeDuration from 'humanize-duration'
import AnimatedSection from '../components/AnimatedSection'
Expand Down Expand Up @@ -37,16 +37,32 @@ const genName = (existingNames) => {
return name
}

const generateOtpSeed = () => {
const otpSeedBuffer = new Uint8Array(20)
return window.crypto.getRandomValues(otpSeedBuffer)
}

const sectionViews = {
setupWalletDetails: 1,
setupOtp: 2,
setupSecondOtp: 3,
prepareWallet: 4,
walletSetupDone: 5
}

const Create = () => {
const generateNewOtpName = () => genName(Object.keys(wallets).map(k => wallets[k].name))

const { isMobile } = useWindowDimensions()
const dispatch = useDispatch()
const history = useHistory()
const network = useSelector(state => state.wallet.network)
const wallets = useSelector(state => state.wallet.wallets)
const [name, setName] = useState(genName(Object.keys(wallets).map(k => wallets[k].name)))
const otpSeedBuffer = new Uint8Array(20)
const [name, setName] = useState(generateNewOtpName())
// eslint-disable-next-line no-unused-vars
const [seed, setSeed] = useState(generateOtpSeed())
// eslint-disable-next-line no-unused-vars
const [seed, setSeed] = useState(window.crypto.getRandomValues(otpSeedBuffer))
const [seed2, setSeed2] = useState(generateOtpSeed())
const [duration, setDuration] = useState(WalletConstants.defaultDuration)
const [lastResortAddress, setLastResortAddress] = useState()
const [dailyLimit] = useState(WalletConstants.defaultDailyLimit)
Expand All @@ -60,52 +76,75 @@ const Create = () => {
const [progressStage, setProgressStage] = useState(0)
const [address, setAddress] = useState() // '0x12345678901234567890'
const [effectiveTime, setEffectiveTime] = useState()
const [doubleOtp, setDoubleOtp] = useState(false)

const [durationVisible, setDurationVisible] = useState(false)
const [section, setSection] = useState(2)
const [section, setSection] = useState(sectionViews.setupOtp)
const [qrCodeData, setQRCodeData] = useState()
const [secondOtpQrCodeData, setSecondOtpQrCodeData] = useState()
const [otp, setOtp] = useState('')

const [deploying, setDeploying] = useState()

const otpRef = useRef()

const getQRCodeUri = () => {
const getQRCodeUri = (otpSeed, otpDisplayName) => {
// otpauth://TYPE/LABEL?PARAMETERS
return `otpauth://totp/${name}?secret=${b32.encode(seed)}&issuer=Harmony`
return `otpauth://totp/${otpDisplayName}?secret=${b32.encode(otpSeed)}&issuer=Harmony`
}

useEffect(() => {
(async function () {
const uri = getQRCodeUri()
const data = await qrcode.toDataURL(uri, { errorCorrectionLevel: 'low', width: isMobile ? 192 : 256 })
setQRCodeData(data)
const otpUri = getQRCodeUri(seed, name)

const secondOtpUri = getQRCodeUri(seed2, `${name} (2nd)`)

const otpQrCodeData = await qrcode.toDataURL(otpUri, { errorCorrectionLevel: 'low', width: isMobile ? 192 : 256 })

const secondOtpQrCodeData = await qrcode.toDataURL(secondOtpUri, { errorCorrectionLevel: 'low', width: isMobile ? 192 : 256 })

setQRCodeData(otpQrCodeData)

setSecondOtpQrCodeData(secondOtpQrCodeData)
})()
}, [name])

useEffect(() => {
if (section === 2 && worker) {
if (section === sectionViews.setupOtp && worker) {
console.log('posting to worker')
const t = Math.floor(Date.now() / WalletConstants.interval) * WalletConstants.interval
setEffectiveTime(t)
worker && worker.postMessage({
seed, effectiveTime: t, duration, slotSize, interval: WalletConstants.interval
seed, seed2, effectiveTime: t, duration, slotSize, interval: WalletConstants.interval
})
}
}, [section, worker])

useEffect(() => {
const settingUpSecondOtp = section === sectionViews.setupSecondOtp

if (otp.length !== 6) {
return
}
const expected = ONEUtil.genOTP({ seed })

const currentSeed = settingUpSecondOtp ? seed2 : seed

const expected = ONEUtil.genOTP({ seed: currentSeed })

const code = new DataView(expected.buffer).getUint32(0, false).toString()

setOtp('')

if (code.padStart(6, '0') !== otp.padStart(6, '0')) {
console.log(`Expected: ${code}. Got: ${otp}`)
message.error('Code is incorrect. Please try again.')
setOtp('')

otpRef?.current?.focusInput(0)
} else if (doubleOtp && !settingUpSecondOtp) {
setSection(sectionViews.setupSecondOtp)

otpRef?.current?.focusInput(0)
} else {
setSection(3)
setSection(sectionViews.prepareWallet)
}
}, [otp])

Expand All @@ -124,14 +163,17 @@ const Create = () => {
}

let normalizedAddress = ''

if (lastResortAddress !== '') {
// Ensure valid address for both 0x and one1 formats
normalizedAddress = util.safeExec(util.normalizedAddress, [lastResortAddress], handleAddressError)
if (!normalizedAddress) {
return
}
}

setDeploying(true)

try {
const { address } = await api.relayer.create({
root: ONEUtil.hexString(root),
Expand All @@ -155,6 +197,7 @@ const Create = () => {
dailyLimit: ONEUtil.toFraction(dailyLimit).toString(),
hseed: ONEUtil.hexView(hseed),
network,
doubleOtp,
}
await storeLayers()
dispatch(walletActions.updateWallet(wallet))
Expand Down Expand Up @@ -193,7 +236,7 @@ const Create = () => {

return (
<>
<AnimatedSection show={section === 1} style={{ maxWidth: 640 }}>
<AnimatedSection show={section === sectionViews.setupWalletDetails} style={{ maxWidth: 640 }}>
<Heading>What do you want to call your wallet?</Heading>
<Hint>This is only stored on your computer to distinguish your wallets.</Hint>
<Row align='middle' style={{ marginBottom: 32, marginTop: 16 }}>
Expand All @@ -203,7 +246,7 @@ const Create = () => {
value={name} onChange={({ target: { value } }) => setName(value)}
style={{ padding: 0 }}
/>
<Button type='primary' shape='round' size='large' onClick={() => setSection(2)}>Next</Button>
<Button type='primary' shape='round' size='large' onClick={() => setSection(sectionViews.setupOtp)}>Next</Button>
</Space>
</Row>

Expand All @@ -221,7 +264,7 @@ const Create = () => {
</Space>}
</Space>
</AnimatedSection>
<AnimatedSection show={section === 2} style={{ maxWidth: 640 }}>
<AnimatedSection show={section === sectionViews.setupOtp} style={{ maxWidth: 640 }}>
<Row>
<Space direction='vertical'>
{/* <Heading>Now, scan the QR code with your Google Authenticator</Heading> */}
Expand All @@ -243,8 +286,38 @@ const Create = () => {
/>
</Space>
</Row>
<Row justify='center'>
<Checkbox onChange={() => setDoubleOtp(!doubleOtp)}>
<Hint>Setup second One Time Password for enhanced security</Hint>
<br />
<Hint>You will need to scan the QR code again in next step</Hint>
</Checkbox>
</Row>
</AnimatedSection>
<AnimatedSection show={section === sectionViews.setupSecondOtp} style={{ maxWidth: 640 }}>
<Row>
<Space direction='vertical'>
{/* <Heading>Now, scan the QR code with your Google Authenticator</Heading> */}
<Heading>Setup Second One Time Password</Heading>
<Hint align='center'>Use two One Time Password for enhanced security</Hint>
<Row justify='center'>
{secondOtpQrCodeData && <Image src={secondOtpQrCodeData} preview={false} width={isMobile ? 192 : 256} />}
</Row>
</Space>
</Row>
<Row>
<Space direction='vertical' size='large' align='center'>
<Hint>After you are done, type in the 6-digit code from Google authenticator.</Hint>
<OtpBox
shouldAutoFocus
ref={otpRef}
value={otp}
onChange={setOtp}
/>
</Space>
</Row>
</AnimatedSection>
<AnimatedSection show={section === 3} style={{ maxWidth: 640 }}>
<AnimatedSection show={section === sectionViews.prepareWallet} style={{ maxWidth: 640 }}>
<Row>
<Space direction='vertical'>
<Heading>Prepare Your ONE Wallet</Heading>
Expand Down Expand Up @@ -317,7 +390,7 @@ const Create = () => {
</Space>
</Row>
</AnimatedSection>
<AnimatedSection show={section === 4}>
<AnimatedSection show={section === sectionViews.walletSetupDone}>
<Space direction='vertical'>
<Heading>You are all set!</Heading>
<Space direction='vertical' size='small'>
Expand Down
Loading