8 changed files with 289 additions and 130 deletions
@ -0,0 +1,104 @@ |
|||||
|
import { |
||||
|
Dialog, |
||||
|
DialogContent, |
||||
|
DialogDescription, |
||||
|
DialogFooter, |
||||
|
DialogHeader, |
||||
|
DialogTitle, |
||||
|
} from "@components/UI/Dialog.tsx"; |
||||
|
import { Button } from "@components/UI/Button"; |
||||
|
import { DownloadIcon, PrinterIcon } from "lucide-react"; |
||||
|
import React from "react"; |
||||
|
import { useDevice } from "@app/core/stores/deviceStore"; |
||||
|
import { fromByteArray } from "base64-js"; |
||||
|
|
||||
|
export interface PkiBackupDialogProps { |
||||
|
open: boolean; |
||||
|
onOpenChange: (open: boolean) => void; |
||||
|
} |
||||
|
|
||||
|
export const PkiBackupDialog = ({ |
||||
|
open, |
||||
|
onOpenChange, |
||||
|
}: PkiBackupDialogProps) => { |
||||
|
const { config } = useDevice(); |
||||
|
const privateKeyData = config.security?.privateKey |
||||
|
|
||||
|
// If the private data doesn't exist return null
|
||||
|
if (!privateKeyData) { |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
const getPrivateKey = React.useMemo(() => fromByteArray(config.security?.privateKey ?? new Uint8Array(0)), [config.security?.privateKey]); |
||||
|
|
||||
|
const renderPrintWindow = React.useCallback(() => { |
||||
|
const printWindow = window.open("", "_blank"); |
||||
|
if (printWindow) { |
||||
|
printWindow.document.write(` |
||||
|
<html> |
||||
|
<head> |
||||
|
<title>Your Private Key</title> |
||||
|
<style> |
||||
|
body { font-family: Arial, sans-serif; padding: 20px; } |
||||
|
h1 { font-size: 18px; } |
||||
|
p { font-size: 14px; word-break: break-all; } |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<h1>Your Private Key</h1> |
||||
|
<p>${getPrivateKey}</p> |
||||
|
</body> |
||||
|
</html> |
||||
|
`);
|
||||
|
printWindow.document.close(); |
||||
|
printWindow.print(); |
||||
|
} |
||||
|
}, [getPrivateKey]); |
||||
|
|
||||
|
const createDownloadKeyFile = React.useCallback(() => { |
||||
|
const blob = new Blob([getPrivateKey], { type: "text/plain" }); |
||||
|
const url = URL.createObjectURL(blob); |
||||
|
const link = document.createElement("a"); |
||||
|
link.href = url; |
||||
|
link.download = "meshtastic_private_key.txt"; |
||||
|
link.style.display = "none"; |
||||
|
document.body.appendChild(link); |
||||
|
link.click(); |
||||
|
document.body.removeChild(link); |
||||
|
URL.revokeObjectURL(url); |
||||
|
}, [getPrivateKey]); |
||||
|
|
||||
|
|
||||
|
return ( |
||||
|
<Dialog open={open} onOpenChange={onOpenChange}> |
||||
|
<DialogContent> |
||||
|
<DialogHeader> |
||||
|
<DialogTitle>Backup Key</DialogTitle> |
||||
|
<DialogDescription> |
||||
|
Its important to backup your private key and store your backup securely! |
||||
|
</DialogDescription> |
||||
|
<DialogDescription> |
||||
|
<span className="font-bold break-before-auto">If you lose your private key, you will need to reset your device.</span> |
||||
|
</DialogDescription> |
||||
|
</DialogHeader> |
||||
|
<DialogFooter className="mt-6"> |
||||
|
<Button |
||||
|
variant={'default'} |
||||
|
onClick={() => createDownloadKeyFile()} |
||||
|
className="" |
||||
|
> |
||||
|
<DownloadIcon size={20} className="mr-2" /> |
||||
|
Download |
||||
|
</Button> |
||||
|
<Button |
||||
|
variant={'default'} |
||||
|
onClick={() => renderPrintWindow()} |
||||
|
> |
||||
|
<PrinterIcon size={20} className="mr-2" /> |
||||
|
Print |
||||
|
</Button> |
||||
|
</DialogFooter> |
||||
|
</DialogContent> |
||||
|
</Dialog> |
||||
|
); |
||||
|
}; |
||||
Loading…
Reference in new issue