From 49bde675c3034851a11f8cce5c3d97b2870b9826 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 18 Feb 2024 22:55:05 -0600 Subject: [PATCH] Add KeygenStep, only show ExtensionStep when window.nostr is present --- src/features/nostr/NKeyStorage.ts | 3 +- .../components/emoji-graphic.tsx | 2 +- .../nostr-signin-modal/nostr-signin-modal.tsx | 7 ++- .../steps/identity-step.tsx | 4 +- .../nostr-signin-modal/steps/key-step.tsx | 4 +- .../nostr-signin-modal/steps/keygen-step.tsx | 62 +++++++++++++++++++ src/utils/input.ts | 9 +++ 7 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 src/features/ui/components/modals/nostr-signin-modal/steps/keygen-step.tsx diff --git a/src/features/nostr/NKeyStorage.ts b/src/features/nostr/NKeyStorage.ts index 6100a8613..156733082 100644 --- a/src/features/nostr/NKeyStorage.ts +++ b/src/features/nostr/NKeyStorage.ts @@ -77,10 +77,11 @@ export class NKeyStorage implements ReadonlyMap { return this.#keypairs.has(pubkey); } - add(secretKey: Uint8Array): void { + add(secretKey: Uint8Array): NostrSigner { const pubkey = getPublicKey(secretKey); this.#keypairs.set(pubkey, secretKey); this.#syncStorage(); + return this.get(pubkey)!; } *entries(): IterableIterator<[string, NostrSigner]> { diff --git a/src/features/ui/components/modals/nostr-signin-modal/components/emoji-graphic.tsx b/src/features/ui/components/modals/nostr-signin-modal/components/emoji-graphic.tsx index 5d340f8a5..541920307 100644 --- a/src/features/ui/components/modals/nostr-signin-modal/components/emoji-graphic.tsx +++ b/src/features/ui/components/modals/nostr-signin-modal/components/emoji-graphic.tsx @@ -10,7 +10,7 @@ interface IEmojiGraphic { const EmojiGraphic: React.FC = ({ emoji }) => { return (
-
+
diff --git a/src/features/ui/components/modals/nostr-signin-modal/nostr-signin-modal.tsx b/src/features/ui/components/modals/nostr-signin-modal/nostr-signin-modal.tsx index 540707005..c0c45a4ab 100644 --- a/src/features/ui/components/modals/nostr-signin-modal/nostr-signin-modal.tsx +++ b/src/features/ui/components/modals/nostr-signin-modal/nostr-signin-modal.tsx @@ -1,9 +1,11 @@ +import { NostrSigner } from 'nspec'; import React, { useState } from 'react'; import AccountStep from './steps/account-step'; import ExtensionStep from './steps/extension-step'; import IdentityStep from './steps/identity-step'; import KeyStep from './steps/key-step'; +import KeygenStep from './steps/keygen-step'; import RegisterStep from './steps/register-step'; interface INostrSigninModal { @@ -11,8 +13,9 @@ interface INostrSigninModal { } const NostrSigninModal: React.FC = ({ onClose }) => { - const [step, setStep] = useState(0); + const [step, setStep] = useState(window.nostr ? 0 : 1); + const [, setSigner] = useState(); const [accountId, setAccountId] = useState(); const handleClose = () => onClose('NOSTR_SIGNIN'); @@ -28,6 +31,8 @@ const NostrSigninModal: React.FC = ({ onClose }) => { return ; case 4: return ; + case 5: + return ; default: return null; } diff --git a/src/features/ui/components/modals/nostr-signin-modal/steps/identity-step.tsx b/src/features/ui/components/modals/nostr-signin-modal/steps/identity-step.tsx index 57de1dd37..97e704436 100644 --- a/src/features/ui/components/modals/nostr-signin-modal/steps/identity-step.tsx +++ b/src/features/ui/components/modals/nostr-signin-modal/steps/identity-step.tsx @@ -53,7 +53,9 @@ const IdentityStep: React.FC = ({ setAccountId, setStep, onClose } onClose={onClose}>
- +
+ +
diff --git a/src/features/ui/components/modals/nostr-signin-modal/steps/key-step.tsx b/src/features/ui/components/modals/nostr-signin-modal/steps/key-step.tsx index f474b6b71..e8a97c9b8 100644 --- a/src/features/ui/components/modals/nostr-signin-modal/steps/key-step.tsx +++ b/src/features/ui/components/modals/nostr-signin-modal/steps/key-step.tsx @@ -14,13 +14,13 @@ interface IKeyStep { const KeyStep: React.FC = ({ setStep, onClose }) => { return ( } onClose={onClose}> - + - diff --git a/src/features/ui/components/modals/nostr-signin-modal/steps/keygen-step.tsx b/src/features/ui/components/modals/nostr-signin-modal/steps/keygen-step.tsx new file mode 100644 index 000000000..d1e1055ad --- /dev/null +++ b/src/features/ui/components/modals/nostr-signin-modal/steps/keygen-step.tsx @@ -0,0 +1,62 @@ +import { generateSecretKey, getPublicKey, nip19 } from 'nostr-tools'; +import { NostrSigner } from 'nspec'; +import React, { useMemo, useState } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { Button, Stack, Modal } from 'soapbox/components/ui'; +import { NKeys } from 'soapbox/features/nostr/keys'; +import { useInstance } from 'soapbox/hooks'; +import { download } from 'soapbox/utils/download'; +import { slugify } from 'soapbox/utils/input'; + +import EmojiGraphic from '../components/emoji-graphic'; + +interface IKeygenStep { + setSigner(signer: NostrSigner): void; + setStep(step: number): void; + onClose(): void; +} + +const KeygenStep: React.FC = ({ setSigner, setStep, onClose }) => { + const instance = useInstance(); + + const secretKey = useMemo(() => generateSecretKey(), []); + const pubkey = useMemo(() => getPublicKey(secretKey), [secretKey]); + + const nsec = useMemo(() => nip19.nsecEncode(secretKey), [secretKey]); + const npub = useMemo(() => nip19.npubEncode(pubkey), [pubkey]); + + const [downloaded, setDownloaded] = useState(false); + + const handleDownload = () => { + download(nsec, `${slugify(instance.title)}-${npub.slice(5, 9)}.nsec`); + setDownloaded(true); + }; + + const handleNext = () => { + const signer = NKeys.add(secretKey); + setSigner(signer); + }; + + return ( + } onClose={onClose}> + + + + + + + + + + + + + ); +}; + +export default KeygenStep; diff --git a/src/utils/input.ts b/src/utils/input.ts index e9d8c2d85..8a91edfcc 100644 --- a/src/utils/input.ts +++ b/src/utils/input.ts @@ -8,6 +8,15 @@ const normalizeUsername = (username: string): string => { } }; +function slugify(text: string): string { + return text + .trim() + .toLowerCase() + .replace(/[^\w]/g, '-') // replace non-word characters with a hyphen + .replace(/-+/g, '-'); // replace multiple hyphens with a single hyphen +} + export { normalizeUsername, + slugify, }; \ No newline at end of file