on master help sign in
- Add proper validation for ticket verification
f2e52b4Chris Johnson
src/bridge/components/Base.js+21
@@ -1,5 +1,6 @@
1// Helpers
1// Helpers
2import {
2import {
3+ simpleValidatorWrapper,
3 validateMnemonic,
4 validateMnemonic,
4 validateNotEmpty,
5 validateNotEmpty,
5 validateEthereumAddress,
6 validateEthereumAddress,
@@ -143,6 +144,25 @@ const TicketInput = advancedInput({
143 ]
144 ]
144});
145});
145
146
147+const VerifyTicketInput = matchingTicket => advancedInput({
148+ WrappedComponent: Input,
149+ validators: [
150+ validateTicket,
151+ validateNotEmpty,
152+
153+ // TODO: This should be in /lib/validators, but we'd need a way for
154+ // validators to compare against dynamic values
155+ m => simpleValidatorWrapper({
156+ prevMessage: m,
157+ validator: d => d === matchingTicket,
158+ errorMessage: 'This does not match the provided master ticket'
159+ })
160+ ],
161+ transformers: [
162+ prependSig,
163+ ]
164+});
165+
146const ShardInput = advancedInput({
166const ShardInput = advancedInput({
147 WrappedComponent: Input,
167 WrappedComponent: Input,
148 validators: [
168 validators: [
@@ -169,6 +189,7 @@ export {
169 GalaxyInput,
189 GalaxyInput,
170 PointInput,
190 PointInput,
171 TicketInput,
191 TicketInput,
192+ VerifyTicketInput,
172 ShardInput,
193 ShardInput,
173 RequiredInput,
194 RequiredInput,
174 NetworkKeyInput,
195 NetworkKeyInput,
src/bridge/components/advancedInput.js+1
@@ -75,6 +75,7 @@ const advancedInput = ({
75
75
76 // Run validation chain on the transformed value. Validators are executed
76 // Run validation chain on the transformed value. Validators are executed
77 // from right to left and exit on the first validation failure.
77 // from right to left and exit on the first validation failure.
78+
78 const report = compose(...validators, initMessage)(props.value)
79 const report = compose(...validators, initMessage)(props.value)
79
80
80 // Makes a uniform data structure to pass to display triggers. This
81 // Makes a uniform data structure to pass to display triggers. This
src/bridge/lib/validators.js+1−24
@@ -5,7 +5,6 @@ import { isValidAddress } from './wallet'
5
5
6const hexRegExp = /[0-9A-Fa-f]{64}/g
6const hexRegExp = /[0-9A-Fa-f]{64}/g
7
7
8−
9// // Note that this validator also transforms data
8// // Note that this validator also transforms data
10// const validateBase64 = ({ data, pass, error }) => {
9// const validateBase64 = ({ data, pass, error }) => {
11// if (pass !== true) return { data, pass, error }
10// if (pass !== true) return { data, pass, error }
@@ -30,10 +29,6 @@ const hexRegExp = /[0-9A-Fa-f]{64}/g
30// }
29// }
31// };
30// };
32
31
33−
34−
35−
36−
37// Validates a bip39 mnemonic
32// Validates a bip39 mnemonic
38const validateMnemonic = m => simpleValidatorWrapper({
33const validateMnemonic = m => simpleValidatorWrapper({
39 prevMessage: m,
34 prevMessage: m,
@@ -41,7 +36,6 @@ const validateMnemonic = m => simpleValidatorWrapper({
41 errorMessage: 'This is not a valid mnemonic.'
36 errorMessage: 'This is not a valid mnemonic.'
42});
37});
43
38
44−
45// Checks an empty field
39// Checks an empty field
46const validateNotEmpty = m => simpleValidatorWrapper({
40const validateNotEmpty = m => simpleValidatorWrapper({
47 prevMessage: m,
41 prevMessage: m,
@@ -49,8 +43,6 @@ const validateNotEmpty = m => simpleValidatorWrapper({
49 errorMessage: 'This field is required.'
43 errorMessage: 'This field is required.'
50});
44});
51
45
52−
53−
54// Checks if a patp is a valid galaxy
46// Checks if a patp is a valid galaxy
55const validateGalaxy = m => simpleValidatorWrapper({
47const validateGalaxy = m => simpleValidatorWrapper({
56 prevMessage: m,
48 prevMessage: m,
@@ -66,8 +58,6 @@ const validateGalaxy = m => simpleValidatorWrapper({
66 errorMessage: 'This is not a valid galaxy'
58 errorMessage: 'This is not a valid galaxy'
67});
59});
68
60
69−
70−
71const validatePoint = m => simpleValidatorWrapper({
61const validatePoint = m => simpleValidatorWrapper({
72 prevMessage: m,
62 prevMessage: m,
73 validator: d => {
63 validator: d => {
@@ -80,8 +70,6 @@ const validatePoint = m => simpleValidatorWrapper({
80 errorMessage: 'This is not a valid point'
70 errorMessage: 'This is not a valid point'
81});
71});
82
72
83−
84−
85const validateTicket = m => simpleValidatorWrapper({
73const validateTicket = m => simpleValidatorWrapper({
86 prevMessage: m,
74 prevMessage: m,
87 validator: d => {
75 validator: d => {
@@ -94,7 +82,6 @@ const validateTicket = m => simpleValidatorWrapper({
94 errorMessage: 'This is not a valid ticket'
82 errorMessage: 'This is not a valid ticket'
95});
83});
96
84
97−
98const validateShard = m => simpleValidatorWrapper({
85const validateShard = m => simpleValidatorWrapper({
99 prevMessage: m,
86 prevMessage: m,
100 validator: d => {
87 validator: d => {
@@ -107,29 +94,24 @@ const validateShard = m => simpleValidatorWrapper({
107 errorMessage: 'This is not a valid shard'
94 errorMessage: 'This is not a valid shard'
108});
95});
109
96
110−
111const validateLength = (m, l) => simpleValidatorWrapper({
97const validateLength = (m, l) => simpleValidatorWrapper({
112 prevMessage: m,
98 prevMessage: m,
113 validator: d => d.length === l,
99 validator: d => d.length === l,
114 errorMessage: 'This is of an invalid length'
100 errorMessage: 'This is of an invalid length'
115});
101});
116
102
117−
118const validateNetworkKey = m => simpleValidatorWrapper({
103const validateNetworkKey = m => simpleValidatorWrapper({
119 prevMessage: m,
104 prevMessage: m,
120 validator: d => hexRegExp.test(d),
105 validator: d => hexRegExp.test(d),
121 errorMessage: 'This is not a valid network key'
106 errorMessage: 'This is not a valid network key'
122});
107});
123
108
124−
125const validateNetworkSeed = m => simpleValidatorWrapper({
109const validateNetworkSeed = m => simpleValidatorWrapper({
126 prevMessage: m,
110 prevMessage: m,
127 validator: d => hexRegExp.test(d),
111 validator: d => hexRegExp.test(d),
128 errorMessage: 'This is not a valid network seed'
112 errorMessage: 'This is not a valid network seed'
129});
113});
130
114
131−
132−
133// Checks if a string is a valid ethereum address
115// Checks if a string is a valid ethereum address
134const validateEthereumAddress = m => simpleValidatorWrapper({
116const validateEthereumAddress = m => simpleValidatorWrapper({
135 prevMessage: m,
117 prevMessage: m,
@@ -137,10 +119,6 @@ const validateEthereumAddress = m => simpleValidatorWrapper({
137 errorMessage: 'This is not a valid Ethereum address'
119 errorMessage: 'This is not a valid Ethereum address'
138});
120});
139
121
140−
141−
142−
143−
144// Wraps single validation functions in a controlled and predictable way.
122// Wraps single validation functions in a controlled and predictable way.
145const simpleValidatorWrapper = config => {
123const simpleValidatorWrapper = config => {
146
124
@@ -172,11 +150,10 @@ const newMessage = (data, pass, error) => ({
172 error,
150 error,
173})
151})
174
152
175−
176−
177export {
153export {
178 // validateBase64,
154 // validateBase64,
179 // validateJSON,
155 // validateJSON,
156+ simpleValidatorWrapper,
180 validateMnemonic,
157 validateMnemonic,
181 validateNotEmpty,
158 validateNotEmpty,
182 validateGalaxy,
159 validateGalaxy,
src/bridge/views/InviteTicket.js+11−12
@@ -1,11 +1,12 @@
1import { Just, Nothing } from 'folktale/maybe'
1import { Just, Nothing } from 'folktale/maybe'
2import React from 'react'
2import React from 'react'
3−import { InnerLabel, ValidatedSigil, PointInput, Warning,
3+import { InnerLabel, ValidatedSigil, PointInput, Warning, Input, TicketInput,
4− TicketInput, Button, Row, Col, H1, P, Passport } from '../components/Base'
4+ VerifyTicketInput, Button, Row, Col, H1, P, Passport } from '../components/Base'
5import * as kg from '../../../node_modules/urbit-key-generation/dist/index'
5import * as kg from '../../../node_modules/urbit-key-generation/dist/index'
6import * as ob from 'urbit-ob'
6import * as ob from 'urbit-ob'
7import * as azimuth from 'azimuth-js'
7import * as azimuth from 'azimuth-js'
8
8
9+import { simpleValidatorWrapper } from '../lib/validators'
9import { ROUTE_NAMES } from '../lib/router'
10import { ROUTE_NAMES } from '../lib/router'
10import { DEFAULT_HD_PATH, urbitWalletFromTicket,
11import { DEFAULT_HD_PATH, urbitWalletFromTicket,
11 walletFromMnemonic, addressFromSecp256k1Public } from '../lib/wallet'
12 walletFromMnemonic, addressFromSecp256k1Public } from '../lib/wallet'
@@ -127,6 +128,7 @@ class InviteTicket extends React.Component {
127 realPoint,
128 realPoint,
128 realWallet,
129 realWallet,
129 inviteWallet: Just(inviteWallet),
130 inviteWallet: Just(inviteWallet),
131+ // verifyTicket: realWallet.value.ticket,
130 walletStates: this.state.walletStates.concat(WALLET_STATES.RENDERING),
132 walletStates: this.state.walletStates.concat(WALLET_STATES.RENDERING),
131 errors
133 errors
132 })
134 })
@@ -144,8 +146,13 @@ class InviteTicket extends React.Component {
144 let handler = isLogin ? this.handleInviteTicketInput : this.handleVerifyTicketInput
146 let handler = isLogin ? this.handleInviteTicketInput : this.handleVerifyTicketInput
145 let label = isLogin ? 'Activation code' : 'ticket'
147 let label = isLogin ? 'Activation code' : 'ticket'
146
148
149+ const TicketElem =
150+ isVerify && !Nothing.hasInstance(this.state.realWallet)
151+ ? VerifyTicketInput(this.state.realWallet.value.ticket)
152+ : TicketInput
153+
147 return (
154 return (
148− <TicketInput
155+ <TicketElem
149 className='mono mt-8'
156 className='mono mt-8'
150 prop-size='md'
157 prop-size='md'
151 prop-format='innerLabel'
158 prop-format='innerLabel'
@@ -156,7 +163,7 @@ class InviteTicket extends React.Component {
156 value={ value }
163 value={ value }
157 onChange={ handler }>
164 onChange={ handler }>
158 <InnerLabel>{ label }</InnerLabel>
165 <InnerLabel>{ label }</InnerLabel>
159− </TicketInput>
166+ </TicketElem>
160 )
167 )
161 } else {
168 } else {
162 return null
169 return null
@@ -258,13 +265,6 @@ class InviteTicket extends React.Component {
258 Nothing: null
265 Nothing: null
259 })
266 })
260
267
261− // if (realTicket !== verifyTicket) {
262− // const verifyError = "Incorrect ticket. Please double-check the Master Ticket field from your generated wallet and try again."
263− //
264− // this.setState({
265− // errors: [verifyError]
266− // })
267− // } else {
268 this.setState({
268 this.setState({
269 stage: INVITE_STAGES.INVITE_TRANSACTIONS,
269 stage: INVITE_STAGES.INVITE_TRANSACTIONS,
270 walletStates: this.state.walletStates.concat(WALLET_STATES.TRANSACTIONS)
270 walletStates: this.state.walletStates.concat(WALLET_STATES.TRANSACTIONS)
@@ -285,7 +285,6 @@ class InviteTicket extends React.Component {
285 this.props.popRoute()
285 this.props.popRoute()
286 }, 5000)
286 }, 5000)
287 })
287 })
288− // }
289 }
288 }
290 continueReady = true
289 continueReady = true
291 break
290 break