refactor: implement bip39

This commit is contained in:
Derrick Hammer 2023-10-09 12:25:38 -04:00
parent cce13287c3
commit 39f3984ee4
Signed by: pcfreak30
GPG Key ID: C997C339BE476FF2
3 changed files with 51 additions and 73 deletions

View File

@ -11,13 +11,16 @@
"storybook": "storybook dev -p 6006", "storybook": "storybook dev -p 6006",
"build-storybook": "storybook build" "build-storybook": "storybook build"
}, },
"files": ["lib"], "files": [
"lib"
],
"dependencies": { "dependencies": {
"@lumeweb/kernel-network-registry-client": "0.1.0-develop.10", "@lumeweb/kernel-network-registry-client": "0.1.0-develop.10",
"@lumeweb/libkernel": "0.1.0-develop.65", "@lumeweb/libkernel": "0.1.0-develop.65",
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@scure/bip39": "^1.2.1",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"framer-motion": "^10.16.4", "framer-motion": "^10.16.4",

View File

@ -1,48 +1,26 @@
import React from "react"; import React, { useEffect, useState } from "react";
import {
login,
loginComplete,
logoutComplete,
} from "@lumeweb/libkernel/kernel";
export type Session = string;
export const LumeIdentityContext = React.createContext<
| {
session: Session | undefined;
setSession: React.Dispatch<React.SetStateAction<Session | undefined>>;
}
| undefined
>(undefined);
export function useLumeIndentity() { export function useLumeIndentity() {
const contextValue = React.useContext(LumeIdentityContext); const [loggedIn, setLoggedIn] = useState(false);
useEffect(() => {
// When the `session` changes we want to update the `session` in the local storage? loginComplete().then(() => {
React.useEffect(() => { setLoggedIn(true);
if (contextValue?.session) { });
localStorage.setItem("lume-session", contextValue.session); logoutComplete().then(() => {
} else { setLoggedIn(false);
localStorage.removeItem("lume-session"); });
} });
}, [contextValue?.session]);
// Get the session from the local storage
React.useEffect(() => {
const session = localStorage.getItem("lume-session");
if (session) {
contextValue?.setSession(session);
}
}, []);
if (contextValue === undefined) {
throw new Error(
"useLumeIdentity hook is being used outside of its context. Please ensure that it is wrapped within a <LumeIdentityProvider>."
);
}
return { return {
isSignedIn: !!contextValue.session, isSignedIn: loggedIn,
signIn: (key: string) => { async signIn(key: Uint8Array) {
console.log("signing in with key", key); await login(key);
// TODO: From the key generate a session, and store it
contextValue.setSession("session");
},
signOut: () => {
contextValue.setSession(undefined);
}, },
signOut: () => {},
}; };
} }

View File

@ -13,6 +13,13 @@ import { AnimatePresence, m } from "framer-motion";
import { useLumeIndentity } from "./LumeIdentityContext"; import { useLumeIndentity } from "./LumeIdentityContext";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import * as bip39 from "@scure/bip39";
import { wordlist } from "@scure/bip39/wordlists/english";
async function seedToKey(seed: string) {
return bip39.mnemonicToSeed(seed);
}
// Extracted components // Extracted components
const SubmitButtonComponent = () => { const SubmitButtonComponent = () => {
const { setVisibleComponent } = useSwitchableComponent(); const { setVisibleComponent } = useSwitchableComponent();
@ -20,8 +27,7 @@ const SubmitButtonComponent = () => {
<Button <Button
className="w-full h-12" className="w-full h-12"
variant={"outline"} variant={"outline"}
onClick={() => setVisibleComponent(SeedPhraseInput)} onClick={() => setVisibleComponent(SeedPhraseInput)}>
>
<span className="text-center text-lg font-normal leading-normal"> <span className="text-center text-lg font-normal leading-normal">
Sign in with Account Key Sign in with Account Key
</span> </span>
@ -34,7 +40,7 @@ const SeedPhraseInputComponent = () => {
return ( return (
<m.form <m.form
className="flex-col flex gap-y-4" className="flex-col flex gap-y-4"
onSubmit={(e) => { onSubmit={async (e) => {
e.preventDefault(); e.preventDefault();
const target = e.target as typeof e.target & { const target = e.target as typeof e.target & {
elements: { elements: {
@ -42,17 +48,15 @@ const SeedPhraseInputComponent = () => {
}; };
}; };
const seedPhrase = target.elements.seedPhrase.value; const seedPhrase = target.elements.seedPhrase.value;
signIn(seedPhrase); signIn(await seedToKey(seedPhrase));
}} }}>
>
<Input className="h-12 w-full text-lg" name="seedPhrase" /> <Input className="h-12 w-full text-lg" name="seedPhrase" />
<m.div <m.div
initial={{ y: 50 }} initial={{ y: 50 }}
animate={{ y: 0 }} animate={{ y: 0 }}
exit={{ y: -50 }} exit={{ y: -50 }}
transition={{ type: "just", delay: 0.1 }} transition={{ type: "just", delay: 0.1 }}
className="h-12" className="h-12">
>
<Button className="w-full h-full" role="submit"> <Button className="w-full h-full" role="submit">
<span className="text-center text-lg font-normal leading-normal"> <span className="text-center text-lg font-normal leading-normal">
Sign in Sign in
@ -77,12 +81,10 @@ const SetupAccountKeyComponent = () => {
style={{ maxWidth: width ?? "auto" }} style={{ maxWidth: width ?? "auto" }}
ref={(t) => ref={(t) =>
setTimeout(() => setWidth(t!.getBoundingClientRect().width!), 0) setTimeout(() => setWidth(t!.getBoundingClientRect().width!), 0)
} }>
>
<Button <Button
className="w-full h-full" className="w-full h-full"
onClick={() => setVisibleComponent(SeedPhraseGeneration)} onClick={() => setVisibleComponent(SeedPhraseGeneration)}>
>
<span className="text-center text-lg font-normal leading-normal"> <span className="text-center text-lg font-normal leading-normal">
I get it, I'll keep it safe. Let's see the key. I get it, I'll keep it safe. Let's see the key.
</span> </span>
@ -99,8 +101,7 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
const { signIn } = useLumeIndentity(); const { signIn } = useLumeIndentity();
const phrases = useMemo(() => { const phrases = useMemo(() => {
// TODO: Replace with actual BIP39 or whatever is used for phrase generation return bip39.generateMnemonic(wordlist, phraseLength).split(" ");
return Array(phraseLength).fill("a phrase");
}, [phraseLength]); }, [phraseLength]);
const key = useMemo(() => { const key = useMemo(() => {
@ -127,16 +128,14 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
right: -20, right: -20,
bottom: 120, bottom: 120,
}} }}
transition={{ type: "tween", duration: 0.1 }} transition={{ type: "tween", duration: 0.1 }}></m.div>
></m.div>
) : null} ) : null}
</AnimatePresence> </AnimatePresence>
<div className="z-20 relative mb-2.5 w-full h-full flex-wrap justify-center items-center gap-2.5 inline-flex"> <div className="z-20 relative mb-2.5 w-full h-full flex-wrap justify-center items-center gap-2.5 inline-flex">
{phrases.map((phrase, index) => ( {phrases.map((phrase, index) => (
<div <div
key={`SeedPhrase_${index}`} key={`SeedPhrase_${index}`}
className={`justify-center items-center gap-2.5 flex w-[calc(33%-10px)] h-10 rounded border border-current relative ring-current text-neutral-700`} className={`justify-center items-center gap-2.5 flex w-[calc(33%-10px)] h-10 rounded border border-current relative ring-current text-neutral-700`}>
>
<span className=" text-white text-md font-normal leading-normal w-full h-fit px-2.5 bg-transparent text-center"> <span className=" text-white text-md font-normal leading-normal w-full h-fit px-2.5 bg-transparent text-center">
{phrase} {phrase}
</span> </span>
@ -152,8 +151,7 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
initial={{ opacity: 0, y: 50 }} initial={{ opacity: 0, y: 50 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 50 }} exit={{ opacity: 0, y: 50 }}
transition={{ type: "linear", delay: 0.2, duration: 0.5 }} transition={{ type: "linear", delay: 0.2, duration: 0.5 }}>
>
<ExclamationTriangleIcon className="w-14 h-14" /> <ExclamationTriangleIcon className="w-14 h-14" />
<span>Make sure to write this down for safe keeping.</span> <span>Make sure to write this down for safe keeping.</span>
</m.div> </m.div>
@ -166,8 +164,7 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
: "" : ""
}`} }`}
variant="outline" variant="outline"
onClick={copyPhrasesToClipboard} onClick={copyPhrasesToClipboard}>
>
{buttonClickedState === "clicked" ? ( {buttonClickedState === "clicked" ? (
<CheckIcon className="w-5 h-5 mr-2.5" /> <CheckIcon className="w-5 h-5 mr-2.5" />
) : ( ) : (
@ -180,8 +177,7 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
<Button <Button
className="z-20 w-full h-12 text-white bg-neutral-700 hover:bg-neutral-800" className="z-20 w-full h-12 text-white bg-neutral-700 hover:bg-neutral-800"
variant="secondary" variant="secondary"
onClick={() => setStep(1)} onClick={() => setStep(1)}>
>
Continue Continue
</Button> </Button>
) : null} ) : null}
@ -192,9 +188,10 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
initial={{ opacity: 0, y: -50 }} initial={{ opacity: 0, y: -50 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 50 }} exit={{ opacity: 0, y: 50 }}
transition={{ type: "linear", delay: 2, duration: 0.5 }} transition={{ type: "linear", delay: 2, duration: 0.5 }}>
> <Button
<Button className="w-full h-full" onClick={() => signIn(key)}> className="w-full h-full"
onClick={async () => signIn(await seedToKey(key))}>
Sign In Sign In
</Button> </Button>
</m.div> </m.div>
@ -206,17 +203,17 @@ const SeedPhraseGenerationComponent = ({ phraseLength = 12 }) => {
export const SubmitButton = makeSwitchable( export const SubmitButton = makeSwitchable(
SubmitButtonComponent, SubmitButtonComponent,
"submit-button" "submit-button",
); );
export const SeedPhraseInput = makeSwitchable( export const SeedPhraseInput = makeSwitchable(
SeedPhraseInputComponent, SeedPhraseInputComponent,
"seed-phrase-input" "seed-phrase-input",
); );
export const SetupAccountKey = makeSwitchable( export const SetupAccountKey = makeSwitchable(
SetupAccountKeyComponent, SetupAccountKeyComponent,
"setup-account-key" "setup-account-key",
); );
export const SeedPhraseGeneration = makeSwitchable( export const SeedPhraseGeneration = makeSwitchable(
SeedPhraseGenerationComponent, SeedPhraseGenerationComponent,
"seed-phrase-form" "seed-phrase-form",
); );