Skip to content

Commit

Permalink
Add "Migrate to signing device" option in account manager
Browse files Browse the repository at this point in the history
  • Loading branch information
hzrd149 committed Dec 18, 2024
1 parent 2faa014 commit 697d4c6
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 28 deletions.
5 changes: 5 additions & 0 deletions .changeset/angry-flowers-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostrudel": minor
---

Add "Migrate to signing device" option in account manager
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"applesauce-lists": "^0.10.0",
"applesauce-net": "^0.10.0",
"applesauce-react": "^0.10.0",
"applesauce-signer": "^0.10.0",
"applesauce-signer": "0.0.0-next-20241218172722",
"bech32": "^2.0.0",
"blossom-client-sdk": "^2.1.0",
"blossom-drive-sdk": "^0.4.1",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 62 additions & 0 deletions src/views/settings/accounts/components/migrate-to-device.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Button, Flex, Heading, Link, useToast } from "@chakra-ui/react";
import { PasswordSigner, SerialPortSigner, SimpleSigner } from "applesauce-signer";
import { useState } from "react";

import useAsyncErrorHandler from "../../../../hooks/use-async-error-handler";
import useCurrentAccount from "../../../../hooks/use-current-account";
import SerialPortAccount from "../../../../classes/accounts/serial-port-account";
import accountService from "../../../../services/account";

export default function MigrateAccountToDevice() {
if (!SerialPortSigner.SUPPORTED) return null;

const toast = useToast();
const current = useCurrentAccount();
const [loading, setLoading] = useState(false);

const migrate = useAsyncErrorHandler(async () => {
try {
setLoading(true);
if (!current?.signer) throw new Error("Account missing signer");
const device = new SerialPortSigner();

if (current.signer instanceof SimpleSigner) {
// send key to device
await device.restore(current.signer.key);
} else if (current.signer instanceof PasswordSigner) {
// unlock the signer first
if (!current.signer.unlocked) {
const password = window.prompt("Decryption password");
if (password === null) throw new Error("Password required");
await current.signer.unlock(password);
}

await device.restore(current.signer.key!);
} else throw new Error("Unsupported signer type");

// replace existing account
const deviceAccount = new SerialPortAccount(current.pubkey);
accountService.replaceAccount(current.pubkey, deviceAccount);
accountService.switchAccount(deviceAccount.pubkey);
} catch (error) {
if (error instanceof Error) toast({ description: error.message, status: "error" });
}
setLoading(false);
}, [setLoading, current]);

return (
<Flex direction="column" gap="2">
<Heading size="md" mt="2">
Migrate to{" "}
<Link isExternal href="https://github.com/lnbits/nostr-signing-device" color="blue.500">
nostr-signing-device
</Link>
</Heading>
<Flex gap="2" maxW="lg">
<Button colorScheme="purple" isLoading={loading} onClick={migrate}>
Start migration
</Button>
</Flex>
</Flex>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import {
import { useForm } from "react-hook-form";
import { PasswordSigner } from "applesauce-signer";

import useCurrentAccount from "../../../hooks/use-current-account";
import EyeOff from "../../../components/icons/eye-off";
import Eye from "../../../components/icons/eye";
import { CopyIconButton } from "../../../components/copy-icon-button";
import useCurrentAccount from "../../../../hooks/use-current-account";
import EyeOff from "../../../../components/icons/eye-off";
import Eye from "../../../../components/icons/eye";
import { CopyIconButton } from "../../../../components/copy-icon-button";

const fake = Array(48).fill("x");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import { encrypt } from "nostr-tools/nip49";
import { useForm } from "react-hook-form";
import { SimpleSigner } from "applesauce-signer";

import useCurrentAccount from "../../../hooks/use-current-account";
import EyeOff from "../../../components/icons/eye-off";
import Eye from "../../../components/icons/eye";
import { CopyIconButton } from "../../../components/copy-icon-button";
import accountService from "../../../services/account";
import PasswordAccount from "../../../classes/accounts/password-account";
import useCurrentAccount from "../../../../hooks/use-current-account";
import EyeOff from "../../../../components/icons/eye-off";
import Eye from "../../../../components/icons/eye";
import { CopyIconButton } from "../../../../components/copy-icon-button";
import accountService from "../../../../services/account";
import PasswordAccount from "../../../../classes/accounts/password-account";

const fake = Array(48).fill("x");

Expand Down
25 changes: 13 additions & 12 deletions src/views/settings/accounts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box, Button, ButtonGroup, Divider, Flex, Heading, Text } from "@chakra-ui/react";
import { useNavigate } from "react-router-dom";
import { PasswordSigner, SimpleSigner } from "applesauce-signer";
import { PasswordSigner, SerialPortSigner, SimpleSigner } from "applesauce-signer";
import { useObservable } from "applesauce-react/hooks";

import VerticalPageLayout from "../../../components/vertical-page-layout";
Expand All @@ -10,21 +10,22 @@ import UserName from "../../../components/user/user-name";
import UserDnsIdentity from "../../../components/user/user-dns-identity";
import accountService from "../../../services/account";
import AccountTypeBadge from "../../../components/account-info-badge";
import SimpleSignerBackup from "./simple-signer-backup";
import PasswordSignerBackup from "./password-signer-backup";
import SimpleSignerBackup from "./components/simple-signer-backup";
import PasswordSignerBackup from "./components/password-signer-backup";
import { ReactNode } from "react";
import MigrateAccountToDevice from "./components/migrate-to-device";

function AccountBackup() {
const account = useCurrentAccount()!;

if (account.signer instanceof PasswordSigner && account.signer.ncryptsec) {
return <PasswordSignerBackup />;
}

if (account.signer instanceof SimpleSigner && account.signer.key) {
return <SimpleSignerBackup />;
}

return null;
return (
<>
{account.signer instanceof SimpleSigner && account.signer.key && <SimpleSignerBackup />}
{account.signer instanceof PasswordSigner && account.signer.ncryptsec && <SimpleSignerBackup />}
{(account.signer instanceof SimpleSigner || account.signer instanceof PasswordSigner) &&
SerialPortSigner.SUPPORTED && <MigrateAccountToDevice />}
</>
);
}

export default function AccountSettings() {
Expand Down

0 comments on commit 697d4c6

Please sign in to comment.