-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #328 from shawakash/account_ui
feat: added acount/privatekey page
- Loading branch information
Showing
30 changed files
with
686 additions
and
166 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
"@paybox/common": patch | ||
"@paybox/recoil": patch | ||
"@paybox/api": patch | ||
"@paybox/backend-common": patch | ||
"@paybox/zeus": patch | ||
--- | ||
|
||
feat: encrypting private keys for account with password |
25 changes: 25 additions & 0 deletions
25
apps/web/app/account/[id]/privatekey/components/alert-msg.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { | ||
Alert, | ||
AlertDescription, | ||
AlertTitle, | ||
} from "@/components/ui/alert" | ||
import { RocketIcon } from "lucide-react" | ||
|
||
export function AlertMsg({ | ||
message, | ||
title = "Heads up!", | ||
variant = "default", | ||
}: { | ||
message: string | ||
title?: string | ||
variant?: "default" | "destructive", | ||
}) { | ||
return ( | ||
<Alert variant={variant}> | ||
<RocketIcon className="h-4 w-4" color="#ff4545" /> | ||
<AlertTitle className="text-[#ff4545]">{title}</AlertTitle> | ||
<AlertDescription>{message}</AlertDescription> | ||
</Alert> | ||
) | ||
|
||
} |
121 changes: 121 additions & 0 deletions
121
apps/web/app/account/[id]/privatekey/components/key-dialog-box.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import { CopyIcon } from "@radix-ui/react-icons" | ||
|
||
import { Button } from "@/components/ui/button" | ||
import { | ||
Dialog, | ||
DialogClose, | ||
DialogContent, | ||
DialogDescription, | ||
DialogFooter, | ||
DialogHeader, | ||
DialogTitle, | ||
} from "@/components/ui/dialog" | ||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" | ||
import { AlertTriangle } from 'lucide-react'; | ||
import { | ||
Card, | ||
CardContent, | ||
CardHeader, | ||
} from "@/components/ui/card" | ||
import { Input } from "@/components/ui/input" | ||
import { Label } from "@/components/ui/label" | ||
import { | ||
Tabs, | ||
TabsContent, | ||
TabsList, | ||
TabsTrigger, | ||
} from "@/components/ui/tabs" | ||
import { Textarea } from "@/components/ui/textarea"; | ||
import React from "react"; | ||
import { useRecoilValue } from "recoil"; | ||
import { accountPrivateKeysAtom } from "@paybox/recoil"; | ||
|
||
export function PrivateKeyDialogBox({ | ||
open, | ||
setOpen, | ||
// keys, | ||
}: { | ||
open: boolean, | ||
setOpen: (open: boolean) => void, | ||
// keys: { network: string, privateKey: string }[] | ||
}) { | ||
const keys = useRecoilValue(accountPrivateKeysAtom); | ||
const [copyText, setCopyText] = React.useState<string>("Copy") | ||
|
||
return ( | ||
<Dialog open={open} onOpenChange={setOpen}> | ||
<DialogContent className=""> | ||
<Tabs defaultValue={keys[0].network} className=""> | ||
<DialogHeader> | ||
<DialogTitle> | ||
<TabsList className="grid w-2/3 grid-cols-2"> | ||
{keys.map((key, index) => ( | ||
<TabsTrigger key={index} value={key.network}> | ||
{key.network} | ||
</TabsTrigger> | ||
))} | ||
</TabsList> | ||
|
||
</DialogTitle> | ||
<DialogDescription> | ||
|
||
</DialogDescription> | ||
</DialogHeader> | ||
|
||
{keys.map((key, index) => ( | ||
<TabsContent value={key.network} key={index}> | ||
<Card className="rounded-b-none"> | ||
<CardHeader> | ||
<Alert variant={"default"}> | ||
<AlertTriangle className="h-4 w-4" color="#ff4545" /> | ||
<AlertTitle className="text-[#ff4545]">Caution!</AlertTitle> | ||
<AlertDescription className="text-[#ff4545]">Do not share your private keys. Indiviual bearing this has full control on this account!</AlertDescription> | ||
</Alert> | ||
</CardHeader> | ||
<CardContent className="space-y-2"> | ||
<div className="flex flex-col items-center gap-y-4"> | ||
<div className="w-full"> | ||
<Label htmlFor="key" className="sr-only"> | ||
Key | ||
</Label> | ||
<Textarea | ||
id="key" | ||
defaultValue={key.privateKey} | ||
readOnly | ||
className="min-w-max resize-none w-full" | ||
/> | ||
</div> | ||
<Button | ||
type="submit" | ||
size="sm" | ||
className="px-3 flex gap-x-2 font-semibold" | ||
onClick={() => { | ||
navigator.clipboard.writeText(key.privateKey) | ||
setCopyText("Copied!") | ||
setTimeout(() => { | ||
setCopyText("Copy") | ||
}, 5000) | ||
}} | ||
> | ||
<CopyIcon className="h-4 w-4" /> | ||
<div className=""> | ||
{copyText} | ||
</div> | ||
</Button> | ||
</div> | ||
</CardContent> | ||
</Card> | ||
</TabsContent> | ||
))} | ||
<DialogFooter className="sm:justify-start"> | ||
<DialogClose asChild> | ||
<Button type="button" variant="secondary" className="w-full rounded-t-none"> | ||
Close | ||
</Button> | ||
</DialogClose> | ||
</DialogFooter> | ||
</Tabs> | ||
</DialogContent> | ||
</Dialog> | ||
) | ||
} |
140 changes: 140 additions & 0 deletions
140
apps/web/app/account/[id]/privatekey/components/private-key-form.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
"use client" | ||
|
||
import { zodResolver } from "@hookform/resolvers/zod" | ||
import { useForm } from "react-hook-form" | ||
import { z } from "zod" | ||
|
||
import { Button } from "@/components/ui/button" | ||
import { | ||
Form, | ||
FormControl, | ||
FormDescription, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
} from "@/components/ui/form" | ||
|
||
import { toast } from "sonner"; | ||
import React from 'react'; | ||
import { Input } from "@/components/ui/input"; | ||
import { Checkbox } from "@/components/ui/checkbox"; | ||
import { Label } from "@/components/ui/label"; | ||
import { AccountGetPrivateKey, BACKEND_URL, responseStatus } from "@paybox/common" | ||
import { CardContent, CardFooter } from "@/components/ui/card" | ||
import { PrivateKeyDialogBox } from "./key-dialog-box" | ||
import { useRecoilState, useSetRecoilState } from "recoil" | ||
import { accountPrivateKeysAtom } from "@paybox/recoil" | ||
import { decryptWithPassword } from "@/lib/helper" | ||
|
||
|
||
const PrivateKeyFrom = ({ | ||
accountId, | ||
jwt | ||
}: { | ||
accountId: string, | ||
jwt: string | ||
}) => { | ||
|
||
const [checked, setChecked] = React.useState<boolean>(false); | ||
const [open, setOpen] = React.useState<boolean>(false); | ||
const setPrivateKey = useSetRecoilState(accountPrivateKeysAtom); | ||
|
||
const form = useForm<z.infer<typeof AccountGetPrivateKey>>({ | ||
resolver: zodResolver(AccountGetPrivateKey), | ||
defaultValues: { | ||
password: "", | ||
accountId | ||
}, | ||
}); | ||
|
||
function onSubmit(data: z.infer<typeof AccountGetPrivateKey>) { | ||
const call = async () => { | ||
const {status, sol, eth, hashPassword, msg}: { | ||
status: responseStatus, sol: {privateKey: string}, eth: {privateKey: string}, hashPassword: string, msg: string | ||
} = await fetch(`${BACKEND_URL}/account/privateKey`, { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
"Authorization": `Bearer ${jwt}` | ||
}, | ||
body: JSON.stringify(data), | ||
cache: "force-cache" | ||
}).then(res => res.json()); | ||
|
||
if (status == responseStatus.Error) { | ||
return Promise.reject(msg); | ||
} | ||
return {status, sol, eth, hashPassword, msg}; | ||
} | ||
|
||
toast.promise(call(), { | ||
loading: "Fetching Private Key...", | ||
success: ({status, sol, eth, hashPassword}) => { | ||
setPrivateKey([ | ||
{network: "Solana", privateKey: decryptWithPassword(sol.privateKey, hashPassword)}, | ||
{network: "Ethereum", privateKey: decryptWithPassword(eth.privateKey, hashPassword)} | ||
]); | ||
setOpen(true); | ||
return toast.success("Private Key Fetched Successfully"); | ||
}, | ||
error: (error) => { | ||
return toast.error(error); | ||
} | ||
}); | ||
} | ||
|
||
const setCheckedFn = (check: boolean) => { | ||
setChecked(check) | ||
} | ||
|
||
return ( | ||
<> | ||
<Form {...form}> | ||
<form onSubmit={form.handleSubmit(onSubmit)} className=""> | ||
<CardContent> | ||
<FormField | ||
control={form.control} | ||
name="password" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>Password</FormLabel> | ||
<FormControl> | ||
<Input type="password" placeholder="Your Password..." {...field} /> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
</CardContent> | ||
<CardFooter className="flex flex-col gap-y-5"> | ||
<div className="flex items-center space-x-2"> | ||
<Checkbox | ||
id="terms_for_privateKey" | ||
checked={checked} | ||
onCheckedChange={setCheckedFn} | ||
/> | ||
<label | ||
htmlFor="terms_for_privateKey" | ||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" | ||
> | ||
I will not share my private key with anyone, including PayBox. | ||
</label> | ||
</div> | ||
<Button className="w-full" disabled={!checked} type="submit">Submit</Button> | ||
</CardFooter> | ||
</form> | ||
</Form> | ||
{open && | ||
<PrivateKeyDialogBox | ||
open={open} | ||
setOpen={setOpen} | ||
/>} | ||
</> | ||
) | ||
} | ||
|
||
|
||
|
||
export default PrivateKeyFrom | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,56 @@ | ||
export default function Page({ params }: { params: { id: string } }) { | ||
import { AlertMsg } from "./components/alert-msg"; | ||
import { | ||
Alert, | ||
AlertDescription, | ||
AlertTitle, | ||
} from "@/components/ui/alert" | ||
import { | ||
Card, | ||
CardHeader, | ||
CardTitle, | ||
} from "@/components/ui/card" | ||
import { EyeOff } from 'lucide-react'; | ||
import { RocketIcon } from "lucide-react" | ||
import PrivateKeyFrom from "./components/private-key-form"; | ||
import { getServerSession } from "next-auth"; | ||
import { authOptions } from "@/app/api/auth/[...nextauth]/util"; | ||
|
||
const getEncryptedPrivateKeys = async () => { | ||
|
||
} | ||
|
||
export default async function Page({ params }: { params: { id: string } }) { | ||
console.log(params); | ||
//TODO: FETCH THE TXN DATA FOR THIS FOR THIS ACCOUNT | ||
return <div>From Private key: {params.id}</div> | ||
const session = await getServerSession(authOptions); | ||
|
||
return ( | ||
<> | ||
<div className="flex flex-col gap-y-4 p-5"> | ||
<Card className="min-w-56 max-w-[500px]"> | ||
<CardHeader> | ||
{/* <CardTitle>Private key</CardTitle> */} | ||
<Alert variant={"default"}> | ||
<RocketIcon className="h-4 w-4" color="#ff4545" /> | ||
<AlertTitle className="text-[#ff4545]">Heads up!</AlertTitle> | ||
<AlertDescription>Your private is the only way to retreive your wallet!</AlertDescription> | ||
</Alert> | ||
<Alert variant={"default"}> | ||
<EyeOff className="h-4 w-4" color="#ff4545" /> | ||
<AlertTitle className="text-[#ff4545]">Caution!</AlertTitle> | ||
<AlertDescription>Don't let anyone see your private keys.</AlertDescription> | ||
</Alert> | ||
</CardHeader> | ||
<PrivateKeyFrom | ||
accountId={params.id} | ||
key={params.id} | ||
//@ts-ignore | ||
jwt={session?.user.jwt} | ||
/> | ||
</Card> | ||
</div> | ||
|
||
|
||
</> | ||
); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.