on master help sign in
Merge pull request #235 from urbit/feat/ticket-masking

feat: implement conditional ticket masking following passwordmasking.com's recs

commit64dc3136a3db7280a0afb2e6d87665f3dedfd0ba authorMatt Condon <mattgcondon@gmail.com> dateTue 20 Aug 2019, 17:31 (7 years ago) parent314889ad572598
7 files changed+113−45
src/views/Activate/ActivateCode.js+20−6 src/views/Activate/PassportVerify.js+17−3 src/views/Admin/Reticket/ReticketConfirm.js+3−2 src/views/Admin/Reticket/ReticketDownload.js+2−1 src/views/Admin/Reticket/ReticketExecute.js+11−12 src/views/Admin/Reticket/ReticketVerify.js+7−3 src/views/Login/Ticket.js+53−18
src/views/Activate/ActivateCode.js+20−6
@@ -1,7 +1,7 @@
11import React, { useCallback, useMemo, useRef } from 'react';
22import { Just } from 'folktale/maybe';
33import * as azimuth from 'azimuth-js';
4−import { Grid, H4 } from 'indigo-react';
4+import { Grid, H4, CheckboxInput } from 'indigo-react';
55import { FORM_ERROR } from 'final-form';
66
77import View from 'components/View';
@@ -31,6 +31,7 @@ import {
3131 composeValidator,
3232 buildPatqValidator,
3333 hasErrors,
34+ buildCheckboxValidator,
3435} from 'form/validators';
3536import FormError from 'form/FormError';
3637
@@ -79,7 +80,11 @@ export default function ActivateCode() {
7980 }, []);
8081
8182 const validate = useMemo(
82− () => composeValidator({ ticket: buildPatqValidator() }, validateForm),
83+ () =>
84+ composeValidator(
85+ { ticket: buildPatqValidator(), showTicket: buildCheckboxValidator() },
86+ validateForm
87+ ),
8388 [validateForm]
8489 );
8590
@@ -132,9 +137,10 @@ export default function ActivateCode() {
132137 [contracts, setDerivedPoint, setDerivedWallet, setInviteWallet]
133138 );
134139
135− const initialValues = useMemo(() => ({ ticket: impliedTicket || '' }), [
136− impliedTicket,
137− ]);
140+ const initialValues = useMemo(
141+ () => ({ ticket: impliedTicket || '', showTicket: true }),
142+ [impliedTicket]
143+ );
138144
139145 return (
140146 <View inset>
@@ -148,16 +154,24 @@ export default function ActivateCode() {
148154 onSubmit={onSubmit}
149155 afterSubmit={goToPassport}
150156 initialValues={initialValues}>
151− {({ validating, submitting, handleSubmit }) => (
157+ {({ validating, values, submitting, handleSubmit }) => (
152158 <>
153159 <Grid.Item
154160 full
155161 as={TicketInput}
162+ type={values.showTicket ? 'text' : 'password'}
156163 name="ticket"
157164 label="Activation Code"
158165 disabled={!activationAllowed}
159166 />
160167
168+ <Grid.Item
169+ full
170+ as={CheckboxInput}
171+ name="showTicket"
172+ label="Show"
173+ />
174+
161175 <Grid.Item full as={FormError} />
162176
163177 <Grid.Item
src/views/Activate/PassportVerify.js+17−3
@@ -1,5 +1,5 @@
11import React, { useCallback, useMemo } from 'react';
2−import { Grid, P } from 'indigo-react';
2+import { Grid, P, CheckboxInput } from 'indigo-react';
33
44import * as need from 'lib/need';
55import { useLocalRouter } from 'lib/LocalRouter';
@@ -8,7 +8,11 @@ import { isDevelopment } from 'lib/flags';
88
99import SubmitButton from 'form/SubmitButton';
1010import { TicketInput } from 'form/Inputs';
11−import { composeValidator, buildPatqValidator } from 'form/validators';
11+import {
12+ composeValidator,
13+ buildPatqValidator,
14+ buildCheckboxValidator,
15+} from 'form/validators';
1216import BridgeForm from 'form/BridgeForm';
1317
1418import { useActivateFlow } from './ActivateFlow';
@@ -29,6 +33,7 @@ export default function PassportVerify({ className }) {
2933 ticket: buildPatqValidator([
3034 validateExactly(ticket, 'Does not match expected master ticket.'),
3135 ]),
36+ showTicket: buildCheckboxValidator(),
3237 }),
3338 [ticket]
3439 );
@@ -36,6 +41,7 @@ export default function PassportVerify({ className }) {
3641 const initialValues = useMemo(
3742 () => ({
3843 ticket: STUB_VERIFY_TICKET ? ticket : undefined,
44+ showTicket: true,
3945 }),
4046 [ticket]
4147 );
@@ -52,15 +58,23 @@ export default function PassportVerify({ className }) {
5258 validate={validate}
5359 afterSubmit={goToTransfer}
5460 initialValues={initialValues}>
55− {({ handleSubmit }) => (
61+ {({ values, handleSubmit }) => (
5662 <>
5763 <Grid.Item
5864 full
5965 as={TicketInput}
66+ type={values.showTicket ? 'text' : 'password'}
6067 name="ticket"
6168 label="Master Ticket"
6269 />
6370
71+ <Grid.Item
72+ full
73+ as={CheckboxInput}
74+ name="showTicket"
75+ label="Show"
76+ />
77+
6478 <Grid.Item full as={FormError} />
6579
6680 <Grid.Item
src/views/Admin/Reticket/ReticketConfirm.js+3−2
@@ -65,12 +65,12 @@ export default function ReticketConfirm({ newWallet, setNewWallet }) {
6565 });
6666
6767 return (
68− <Grid gap={4} className="mt4">
68+ <Grid className="mt4">
6969 <Grid.Item full as={Text}>
7070 Reticketing is the process of generating a completely fresh wallet and
7171 transferring ownership of your point to that wallet.
7272 </Grid.Item>
73− <Grid.Item full as={WarningBox}>
73+ <Grid.Item full as={WarningBox} className="mt4">
7474 Beware, this resets your proxy addresses; if you're using smart
7575 contracts, this might break them! It will also change your networking
7676 keys!
@@ -79,6 +79,7 @@ export default function ReticketConfirm({ newWallet, setNewWallet }) {
7979 full
8080 as={ForwardButton}
8181 solid
82+ className="mt4"
8283 accessory={blinkIf(Nothing.hasInstance(newWallet))}
8384 disabled={Nothing.hasInstance(newWallet)}
8485 onClick={goDownload}>
src/views/Admin/Reticket/ReticketDownload.js+2−1
@@ -20,13 +20,14 @@ export default function ReticketDownload({ newWallet }) {
2020 const goVerify = useCallback(() => push(names.VERIFY), [push, names]);
2121
2222 return (
23− <Grid gap={4} className="mt4">
23+ <Grid className="mt4">
2424 <Grid.Item full as={Text}>
2525 Download the thing, and keep it somewhere safe!
2626 </Grid.Item>
2727 <Grid.Item
2828 full
2929 as={!downloaded ? DownloadButton : ForwardButton}
30+ className="mt4"
3031 disabled={Nothing.hasInstance(newWallet)}
3132 onClick={!downloaded ? download : goVerify}
3233 success={downloaded}
src/views/Admin/Reticket/ReticketExecute.js+11−12
@@ -110,12 +110,12 @@ export default function ReticketExecute({ newWallet, setNewWallet }) {
110110 if (generalError) {
111111 return (
112112 <>
113− <Grid.Item full>
113+ <Grid.Item full className="mt4">
114114 <ErrorText>{generalError.message.toString()}</ErrorText>
115115 </Grid.Item>
116116 <Grid.Item
117117 full
118− className="mt3"
118+ className="mt4"
119119 as={RestartButton}
120120 solid
121121 onClick={goToRestart}>
@@ -127,7 +127,7 @@ export default function ReticketExecute({ newWallet, setNewWallet }) {
127127
128128 if (needFunds) {
129129 return (
130− <Grid.Item full>
130+ <Grid.Item full className="mt4">
131131 <Highlighted warning>
132132 The address {needFunds.address} needs at least{' '}
133133 {fromWei(needFunds.minBalance)} ETH and currently has{' '}
@@ -139,21 +139,21 @@ export default function ReticketExecute({ newWallet, setNewWallet }) {
139139 }
140140
141141 return (
142− <Grid.Item full as={WarningBox}>
142+ <Grid.Item full as={WarningBox} className="mt4">
143143 Never give your Master Ticket to anyone
144144 </Grid.Item>
145145 );
146146 };
147147
148148 return (
149− <Grid gap={4} className="mt4">
149+ <Grid className="mt4">
150150 <Grid.Item full as={H4}>
151151 {labelForProgress(progress)}
152152 </Grid.Item>
153153
154154 {isDone ? (
155155 <>
156− <Grid.Item full as={Text}>
156+ <Grid.Item full as={Text} className="mt4">
157157 Your changes are now reflected on-chain and you can use the new
158158 ticket to manage your point.
159159 </Grid.Item>
@@ -161,6 +161,7 @@ export default function ReticketExecute({ newWallet, setNewWallet }) {
161161 full
162162 as={ForwardButton}
163163 solid
164+ className="mt4"
164165 accessory="↺"
165166 onClick={loginAndGoHome}>
166167 Login with New Master Ticket
@@ -168,13 +169,11 @@ export default function ReticketExecute({ newWallet, setNewWallet }) {
168169 </>
169170 ) : (
170171 <>
171− <Grid.Item full as={Grid} className="mt3" gap={3}>
172+ <Grid.Item full as={Grid} className="mt4" gap={3}>
172173 <Grid.Item full as={LoadingBar} progress={progress} />
173− <Grid.Item full>
174− <Text className="f5 green4">
175− This process can take up to 5 minutes to complete. Don't close
176− this page until the process is complete.
177− </Text>
174+ <Grid.Item full as={Text} className="f5 green4">
175+ This process can take up to 5 minutes to complete. Don't close
176+ this page until the process is complete.
178177 </Grid.Item>
179178 </Grid.Item>
180179
src/views/Admin/Reticket/ReticketVerify.js+7−3
@@ -1,5 +1,5 @@
11import React, { useCallback, useMemo } from 'react';
2−import { Text, Grid } from 'indigo-react';
2+import { Text, Grid, CheckboxInput } from 'indigo-react';
33
44import { useLocalRouter } from 'lib/LocalRouter';
55import { validateExactly } from 'lib/validators';
@@ -37,7 +37,7 @@ export default function ReticketVerify({ newWallet }) {
3737 const goExecute = useCallback(() => push(names.EXECUTE), [push, names]);
3838
3939 return (
40− <Grid gap={4} className="mt4">
40+ <Grid className="mt4">
4141 <Grid.Item full as={Text}>
4242 Verify New Master Ticket
4343 </Grid.Item>
@@ -45,15 +45,19 @@ export default function ReticketVerify({ newWallet }) {
4545 validate={validate}
4646 afterSubmit={goExecute}
4747 initialValues={initialValues}>
48− {({ handleSubmit }) => (
48+ {({ handleSubmit, values }) => (
4949 <>
5050 <Grid.Item
5151 full
5252 as={TicketInput}
53+ className="mt4"
54+ type={values.showTicket ? 'text' : 'password'}
5355 name="ticket"
5456 label="New master ticket"
5557 />
5658
59+ <Grid.Item full as={CheckboxInput} name="showTicket" label="Show" />
60+
5761 <Grid.Item full as={FormError} />
5862
5963 <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
src/views/Login/Ticket.js+53−18
@@ -3,7 +3,7 @@ import { Just } from 'folktale/maybe';
33import cn from 'classnames';
44import * as azimuth from 'azimuth-js';
55import * as kg from 'urbit-key-generation/dist/index';
6−import { Grid, CheckboxInput } from 'indigo-react';
6+import { Grid, CheckboxInput, Flex, ToggleInput } from 'indigo-react';
77import { FORM_ERROR } from 'final-form';
88
99import { useNetwork } from 'store/network';
@@ -116,6 +116,7 @@ export default function Ticket({ className, goHome }) {
116116 () =>
117117 composeValidator(
118118 {
119+ useAdvanced: buildCheckboxValidator(),
119120 usePassphrase: buildCheckboxValidator(),
120121 useShards: buildCheckboxValidator(),
121122 point: buildPointValidator(4),
@@ -123,6 +124,7 @@ export default function Ticket({ className, goHome }) {
123124 shard1: buildPatqValidator(),
124125 shard2: buildPatqValidator(),
125126 shard3: buildPatqValidator(),
127+ showTicket: buildCheckboxValidator(),
126128 passphrase: buildPassphraseValidator(),
127129 },
128130 validateForm
@@ -135,6 +137,8 @@ export default function Ticket({ className, goHome }) {
135137 point: impliedPoint || '',
136138 usePasshrase: false,
137139 useShards: false,
140+ showTicket: true,
141+ useAdvanced: false,
138142 }),
139143 [impliedPoint]
140144 );
@@ -146,7 +150,7 @@ export default function Ticket({ className, goHome }) {
146150 onSubmit={onSubmit}
147151 afterSubmit={goHome}
148152 initialValues={initialValues}>
149− {({ handleSubmit, submitting }) => (
153+ {({ handleSubmit, values, submitting }) => (
150154 <>
151155 <Grid.Item full as={PointInput} name="point" />
152156
@@ -154,17 +158,38 @@ export default function Ticket({ className, goHome }) {
154158 <Grid.Item
155159 full
156160 as={TicketInput}
161+ type={values.showTicket ? 'text' : 'password'}
157162 name="ticket"
158163 label="Master Ticket"
159164 />
160165 </Condition>
161166
162167 <Condition when="useShards" is={true}>
163− <Grid.Item full as={TicketInput} name="shard1" label="Shard 1" />
164− <Grid.Item full as={TicketInput} name="shard2" label="Shard 2" />
165− <Grid.Item full as={TicketInput} name="shard3" label="Shard 3" />
168+ <Grid.Item
169+ full
170+ as={TicketInput}
171+ type={values.showTicket ? 'text' : 'password'}
172+ name="shard1"
173+ label="Shard 1"
174+ />
175+ <Grid.Item
176+ full
177+ as={TicketInput}
178+ type={values.showTicket ? 'text' : 'password'}
179+ name="shard2"
180+ label="Shard 2"
181+ />
182+ <Grid.Item
183+ full
184+ as={TicketInput}
185+ type={values.showTicket ? 'text' : 'password'}
186+ name="shard3"
187+ label="Shard 3"
188+ />
166189 </Condition>
167190
191+ <Grid.Item full as={CheckboxInput} name="showTicket" label="Show" />
192+
168193 <Condition when="usePassphrase" is={true}>
169194 <Grid.Item
170195 full
@@ -174,19 +199,6 @@ export default function Ticket({ className, goHome }) {
174199 />
175200 </Condition>
176201
177− <Grid.Item
178− full
179− as={CheckboxInput}
180− name="usePassphrase"
181− label="Passphrase"
182− />
183− <Grid.Item
184− full
185− as={CheckboxInput}
186− name="useShards"
187− label="Shards"
188− />
189−
190202 <Grid.Item full as={FormError} />
191203
192204 <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
@@ -198,6 +210,29 @@ export default function Ticket({ className, goHome }) {
198210 : 'Continue'
199211 }
200212 </Grid.Item>
213+
214+ <Grid.Item full as={Flex} justify="between">
215+ <Flex.Item
216+ as={ToggleInput}
217+ name="useAdvanced"
218+ label="Advanced"
219+ inverseLabel="Hide"
220+ />
221+ <Condition when="useAdvanced" is={true}>
222+ <Flex.Item as={Flex}>
223+ <Flex.Item
224+ as={CheckboxInput}
225+ name="usePassphrase"
226+ label="Passphrase"
227+ />
228+ <Flex.Item
229+ as={CheckboxInput}
230+ name="useShards"
231+ label="Shards"
232+ />
233+ </Flex.Item>
234+ </Condition>
235+ </Grid.Item>
201236 </>
202237 )}
203238 </BridgeForm>