Skip to content

Commit

Permalink
tkey email input
Browse files Browse the repository at this point in the history
  • Loading branch information
chaitanyapotti committed Nov 30, 2020
1 parent fbf17f6 commit 5af7e1d
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 14 deletions.
11 changes: 10 additions & 1 deletion src/components/NavigationFrame.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ import Tooltip from '@material-ui/core/Tooltip';
import AddAccountDialog from './AddAccountDialog';
import DeleteAccountDialog from './DeleteAccountDialog';
import TkeyShareInputDialog from './TkeyShareInputDialog';
import { useTkeyShareInput } from '../utils/tkey/tkey';
import TkeyEmailInputDialog from './TkeyEmailInput';
import {
useTkeyRecoveryEmailInput,
useTkeyShareInput,
} from '../utils/tkey/tkey';

const useStyles = makeStyles((theme) => ({
content: {
Expand Down Expand Up @@ -132,6 +136,10 @@ function NetworkSelector() {
function WalletSelector() {
const { accounts, setWalletSelector, addAccount } = useWalletSelector();
const { action, flag } = useTkeyShareInput();
const {
flag: recoveryFlag,
action: recoveryAction,
} = useTkeyRecoveryEmailInput();
const [anchorEl, setAnchorEl] = useState(null);
const [addAccountOpen, setAddAccountOpen] = useState(false);
const [deleteAccountOpen, setDeleteAccountOpen] = useState(false);
Expand Down Expand Up @@ -159,6 +167,7 @@ function WalletSelector() {
}}
/>
<TkeyShareInputDialog open={flag} onAdd={action} />
<TkeyEmailInputDialog open={recoveryFlag} onAdd={recoveryAction} />
<DeleteAccountDialog
open={deleteAccountOpen}
onClose={() => setDeleteAccountOpen(false)}
Expand Down
42 changes: 42 additions & 0 deletions src/components/TkeyEmailInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { useState } from 'react';
import {
DialogActions,
Button,
DialogTitle,
DialogContent,
TextField,
} from '@material-ui/core';
import DialogForm from './DialogForm';

export default function TkeyEmailInputDialog({ open, onAdd }) {
const [recoveryEmail, setRecoveryEmail] = useState('');

return (
<DialogForm open={open} onSubmit={() => onAdd(recoveryEmail)} fullWidth>
<DialogTitle>Enter Recovery Email</DialogTitle>
<DialogContent style={{ paddingTop: 16 }}>
<div
style={{
display: 'flex',
flexDirection: 'column',
}}
>
<TextField
label="Please enter a recovery email"
fullWidth
value={recoveryEmail}
variant="outlined"
margin="normal"
type="email"
onChange={(e) => setRecoveryEmail(e.target.value.trim())}
/>
</div>
</DialogContent>
<DialogActions>
<Button type="submit" color="primary">
Confirm
</Button>
</DialogActions>
</DialogForm>
);
}
2 changes: 1 addition & 1 deletion src/components/TkeyShareInputDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export default function TkeyShareInputDialog({ open, onAdd }) {
<TextField
label="Paste your share mnemonic"
fullWidth
type="password"
value={importedShare}
variant="outlined"
margin="normal"
multiline
onChange={(e) => setImportedShare(e.target.value.trim())}
/>
</div>
Expand Down
12 changes: 11 additions & 1 deletion src/pages/LoginPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ import FormControlLabel from '@material-ui/core/FormControlLabel';
import CardActions from '@material-ui/core/CardActions';
import Button from '@material-ui/core/Button';
import { useCallAsync } from '../utils/notifications';
import { useTkeyLogin, useTkeyShareInput } from '../utils/tkey/tkey';
import {
useTkeyLogin,
useTkeyRecoveryEmailInput,
useTkeyShareInput,
} from '../utils/tkey/tkey';
import Link from '@material-ui/core/Link';
import TkeyShareInputDialog from '../components/TkeyShareInputDialog';
import TkeyEmailInputDialog from '../components/TkeyEmailInput';

export default function LoginPage() {
const [restore, setRestore] = useState(false);
Expand Down Expand Up @@ -47,6 +52,10 @@ export default function LoginPage() {
function TkeyForm() {
const tkeyLogin = useTkeyLogin();
const { action, flag } = useTkeyShareInput();
const {
flag: recoveryFlag,
action: recoveryAction,
} = useTkeyRecoveryEmailInput();

return (
<>
Expand All @@ -64,6 +73,7 @@ function TkeyForm() {
</CardActions>
</Card>
<TkeyShareInputDialog open={flag} onAdd={action} />
<TkeyEmailInputDialog open={recoveryFlag} onAdd={recoveryAction} />
</>
);
}
Expand Down
19 changes: 14 additions & 5 deletions src/utils/tkey/ThresholdKeyController.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export class ThresholdKeyController {
this.isShareInputRequired = false;
this.isNewKey = false;
this.directAuthResponse = undefined;
this.isRecoveryMailRequired = false;
this.recoveryEmail = '';
console.log(this.tKey);
}

Expand All @@ -37,15 +39,18 @@ export class ThresholdKeyController {
}
};

_init = async (postboxKey) => {
_init = async (postboxKey, mnemonicShare) => {
this.postboxKey = postboxKey;
await this.checkIfTKeyExists(postboxKey);
this.tKey = await createTKeyInstance(postboxKey);
console.log(postboxKey, 'postboxkey');
if (postboxKey) {
await this._initializeAndCalculate();
await this.finalizeTKey();
}
if (mnemonicShare) {
await this.inputExternalShare(mnemonicShare);
}
if (postboxKey) await this.finalizeTKey();
};

_initializeAndCalculate = async () => {
Expand Down Expand Up @@ -147,8 +152,12 @@ export class ThresholdKeyController {
this.isShareInputRequired = false;
}
if (this.isShareInputRequired) return;
const { privKey } = await this.tKey.reconstructKey();
if (this.isNewKey && !this.recoveryEmail) {
this.isRecoveryMailRequired = true;
return;
}
if (this.isNewKey) await this.sendMail();
const { privKey } = await this.tKey.reconstructKey();
console.log(privKey.toString('hex'), 'reconstructed tkey');
this.privKey = privKey.toString('hex');
}
Expand All @@ -163,6 +172,7 @@ export class ThresholdKeyController {
const serializedShare = await this.tKey.modules[
SHARE_SERIALIZATION_MODULE_NAME
].serialize(requiredShareStore.share.share, 'mnemonic');
this.isRecoveryMailRequired = false;
// call api with new share
fetch(EMAIL_HOST, {
method: 'POST',
Expand All @@ -172,7 +182,7 @@ export class ThresholdKeyController {
body: JSON.stringify({
data: serializedShare,
name: DAPP_NAME,
email: this.directAuthResponse.userInfo.email,
email: this.recoveryEmail,
}),
})
.then((res) => {
Expand All @@ -195,7 +205,6 @@ export class ThresholdKeyController {
// call api with new share
await this.tKey.inputShare(deserialiedShare);
await this.calculateSettingsPageData();
await this.finalizeTKey();
};

exportDeviceShare = async () => {
Expand Down
57 changes: 51 additions & 6 deletions src/utils/tkey/tkey.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,33 @@ const TkeyContext = React.createContext(null);
export function TkeyProvider({ children }) {
// postboxKey is the google login key. If it's available, use it. Else, we need to log the user in
const [postboxKey, setPostboxKey] = useLocalStorageState('postboxKey', '');
const [mnemonicShare, setMnemonicShare] = useLocalStorageState(
'mnemonicShare',
'',
);
const [thresholdKeyInstance, setThresholdKeyInstance] = useState({});

useEffect(() => {
const init = async () => {
const instance = new ThresholdKeyController();
await instance._init(postboxKey);
setThresholdKeyInstance(instance);
if (Object.keys(thresholdKeyInstance).length === 0) {
const instance = new ThresholdKeyController();
await instance._init(postboxKey, mnemonicShare);
setThresholdKeyInstance(instance);
}
};
console.log('calling effect');
init();
}, [postboxKey]);
}, [mnemonicShare, postboxKey, thresholdKeyInstance]);

return (
<TkeyContext.Provider
value={{ thresholdKeyInstance, postboxKey, setPostboxKey }}
value={{
thresholdKeyInstance,
postboxKey,
setPostboxKey,
mnemonicShare,
setMnemonicShare,
}}
>
{children}
</TkeyContext.Provider>
Expand Down Expand Up @@ -65,10 +77,12 @@ export function useTkeyLogin() {
}

export function useTkeyShareInput() {
const { thresholdKeyInstance } = useContext(TkeyContext);
const { thresholdKeyInstance, setMnemonicShare } = useContext(TkeyContext);
const { addAccount, setWalletSelector } = useWalletSelector();
const fn = async (share) => {
await thresholdKeyInstance.inputExternalShare(share);
await thresholdKeyInstance.finalizeTKey();
setMnemonicShare(share);
const { privKey } = thresholdKeyInstance;
console.log('adding account', privKey);
if (!privKey) return;
Expand All @@ -93,5 +107,36 @@ export function useTkeyShareInput() {
};
}

export function useTkeyRecoveryEmailInput() {
const { thresholdKeyInstance } = useContext(TkeyContext);
const { addAccount, setWalletSelector } = useWalletSelector();

const fn = async (email) => {
thresholdKeyInstance.recoveryEmail = email;
await thresholdKeyInstance.finalizeTKey();
const { privKey } = thresholdKeyInstance;
console.log('adding account', privKey);
if (!privKey) return;
const tkeyAccount = new Account(
nacl.sign.keyPair.fromSeed(
fromHexString(privKey.padStart(64, 0)),
).secretKey,
);
addAccount({
name: 'TKey',
importedAccount: tkeyAccount,
isTkey: true,
});
setWalletSelector({
walletIndex: undefined,
importedPubkey: tkeyAccount.publicKey.toString(),
});
};
return {
flag: thresholdKeyInstance.isRecoveryMailRequired || false,
action: fn,
};
}

const fromHexString = (hexString) =>
new Uint8Array(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));

0 comments on commit 5af7e1d

Please sign in to comment.