From 3c22429941f476b4c55f4f862580fe1520a665a8 Mon Sep 17 00:00:00 2001 From: enes Date: Fri, 26 Jul 2024 15:45:13 +0200 Subject: [PATCH] fix: move nostr login to nostr route --- src/pages/login/index.tsx | 382 +------------------ src/pages/nostr/index.tsx | 381 +++++++++++++++++- src/pages/{login => nostr}/style.module.scss | 0 3 files changed, 381 insertions(+), 382 deletions(-) rename src/pages/{login => nostr}/style.module.scss (100%) diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index 08e2e18..103e5a1 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -1,383 +1,3 @@ -import { Box, Button, TextField } from '@mui/material' -import { getPublicKey, nip19 } from 'nostr-tools' -import { useEffect, useState } from 'react' -import { useDispatch } from 'react-redux' -import { useNavigate, useSearchParams } from 'react-router-dom' -import { toast } from 'react-toastify' -import { LoadingSpinner } from '../../components/LoadingSpinner' -import { - AuthController, - MetadataController, - NostrController -} from '../../controllers' -import { - updateKeyPair, - updateLoginMethod, - updateNsecbunkerPubkey, - updateNsecbunkerRelays -} from '../../store/actions' -import { LoginMethods } from '../../store/auth/types' -import { Dispatch } from '../../store/store' -import { npubToHex, queryNip05 } from '../../utils' -import styles from './style.module.scss' -import { hexToBytes } from '@noble/hashes/utils' -import { NIP05_REGEX } from '../../constants' -import { appPublicRoutes } from '../../routes' - export const Login = () => { - const [searchParams] = useSearchParams() - - const dispatch: Dispatch = useDispatch() - const navigate = useNavigate() - - const authController = new AuthController() - const metadataController = new MetadataController() - const nostrController = NostrController.getInstance() - - const [isLoading, setIsLoading] = useState(false) - const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('') - const [inputValue, setInputValue] = useState('') - const [authUrl, setAuthUrl] = useState() - - const [isNostrExtensionAvailable, setIsNostrExtensionAvailable] = - useState(false) - - useEffect(() => { - setTimeout(() => { - setIsNostrExtensionAvailable(!!window.nostr) - }, 500) - }, []) - - /** - * Call login function when enter is pressed - */ - const handleInputKeyDown = (event: any) => { - if (event.code === 'Enter' || event.code === 'NumpadEnter') { - event.preventDefault() - login() - } - } - - const navigateAfterLogin = (path: string) => { - const callbackPath = searchParams.get('callbackPath') - - if (callbackPath) { - // base64 decoded path - const path = atob(callbackPath) - navigate(path) - return - } - - navigate(path) - } - - const loginWithExtension = async () => { - setIsLoading(true) - setLoadingSpinnerDesc('Capturing pubkey from nostr extension') - - nostrController - .capturePublicKey() - .then(async (pubkey) => { - dispatch(updateLoginMethod(LoginMethods.extension)) - - setLoadingSpinnerDesc('Authenticating and finding metadata') - const redirectPath = - await authController.authAndGetMetadataAndRelaysMap(pubkey) - - if (redirectPath) navigateAfterLogin(redirectPath) - }) - .catch((err) => { - toast.error('Error capturing public key from nostr extension: ' + err) - }) - .finally(() => { - setIsLoading(false) - setLoadingSpinnerDesc('') - }) - } - - /** - * Login with NSEC or HEX private key - * @param privateKey in HEX format - */ - const loginWithNsec = async (privateKey?: Uint8Array) => { - let nsec = '' - - if (privateKey) { - nsec = nip19.nsecEncode(privateKey) - } else { - nsec = inputValue - - try { - privateKey = nip19.decode(nsec).data as Uint8Array - } catch (err) { - toast.error(`Error decoding the nsec. ${err}`) - } - } - - if (!privateKey) { - toast.error( - 'Snap, we failed to convert the private key you provided. Please make sure key is valid.' - ) - setIsLoading(false) - return - } - - const publickey = getPublicKey(privateKey) - - dispatch( - updateKeyPair({ - private: nsec, - public: publickey - }) - ) - dispatch(updateLoginMethod(LoginMethods.privateKey)) - - setIsLoading(true) - setLoadingSpinnerDesc('Authenticating and finding metadata') - - const redirectPath = await authController - .authAndGetMetadataAndRelaysMap(publickey) - .catch((err) => { - toast.error('Error occurred in authentication: ' + err) - return null - }) - - if (redirectPath) navigateAfterLogin(redirectPath) - - setIsLoading(false) - setLoadingSpinnerDesc('') - } - - const loginWithNsecBunker = async () => { - let relays: string[] | undefined - let pubkey: string | undefined - - setIsLoading(true) - - const displayError = (message: string) => { - toast.error(message) - setIsLoading(false) - setLoadingSpinnerDesc('') - } - - if (inputValue.match(NIP05_REGEX)) { - const nip05Profile = await queryNip05(inputValue).catch((err) => { - toast.error('An error occurred while querying nip05 profile: ' + err) - return null - }) - - if (nip05Profile) { - pubkey = nip05Profile.pubkey - relays = nip05Profile.relays - } - } else if (inputValue.startsWith('npub')) { - pubkey = nip19.decode(inputValue).data as string - const metadataEvent = await metadataController - .findMetadata(pubkey) - .catch(() => { - return null - }) - - if (!metadataEvent) { - return displayError('metadata not found!') - } - - const metadataContent = - metadataController.extractProfileMetadataContent(metadataEvent) - - if (!metadataContent?.nip05) { - return displayError('nip05 not present in metadata') - } - - const nip05Profile = await queryNip05(inputValue).catch((err) => { - toast.error('An error occurred while querying nip05 profile: ' + err) - return null - }) - - if (nip05Profile) { - if (nip05Profile.pubkey !== pubkey) { - return displayError( - 'pubkey in nip05 does not match with provided npub' - ) - } - - relays = nip05Profile.relays - } - } - - if (!relays || relays.length === 0) { - return displayError('No relay found for nsecbunker') - } - - if (!pubkey) { - return displayError('pubkey not found') - } - - setLoadingSpinnerDesc('Initializing nsecBunker') - await nostrController.nsecBunkerInit(relays) - - setLoadingSpinnerDesc('Creating nsecbunker singer') - await nostrController - .createNsecBunkerSigner(pubkey) - .then(async (signer) => { - signer.on('authUrl', (url: string) => { - setAuthUrl(url) - }) - - dispatch(updateLoginMethod(LoginMethods.nsecBunker)) - dispatch(updateNsecbunkerPubkey(pubkey)) - dispatch(updateNsecbunkerRelays(relays)) - - setLoadingSpinnerDesc('Authenticating and finding metadata') - - const redirectPath = await authController - .authAndGetMetadataAndRelaysMap(pubkey!) - .catch((err) => { - toast.error('Error occurred in authentication: ' + err) - return null - }) - - if (redirectPath) navigateAfterLogin(redirectPath) - }) - .catch((err) => { - toast.error( - 'An error occurred while creating nsecbunker signer: ' + err - ) - }) - .finally(() => { - setIsLoading(false) - setLoadingSpinnerDesc('') - }) - } - - const loginWithBunkerConnectionString = async () => { - // Extract the key - const keyStartIndex = inputValue.indexOf('bunker://') + 'bunker://'.length - const keyEndIndex = inputValue.indexOf('?relay=') - const key = inputValue.substring(keyStartIndex, keyEndIndex) - - const pubkey = npubToHex(key) - - if (!pubkey) { - toast.error('Invalid pubkey in bunker connection string.') - setIsLoading(false) - return - } - - // Extract the relay value - const relayIndex = inputValue.indexOf('relay=') - const relay = inputValue.substring( - relayIndex + 'relay='.length, - inputValue.length - ) - - setIsLoading(true) - setLoadingSpinnerDesc('Initializing bunker NDK') - - await nostrController.nsecBunkerInit([relay]) - - setLoadingSpinnerDesc('Creating remote signer') - await nostrController - .createNsecBunkerSigner(pubkey) - .then(async (signer) => { - signer.on('authUrl', (url: string) => { - setAuthUrl(url) - }) - - dispatch(updateLoginMethod(LoginMethods.nsecBunker)) - dispatch(updateNsecbunkerPubkey(pubkey)) - dispatch(updateNsecbunkerRelays([relay])) - - setLoadingSpinnerDesc('Authenticating and finding metadata') - - const redirectPath = await authController - .authAndGetMetadataAndRelaysMap(pubkey!) - .catch((err) => { - toast.error('Error occurred in authentication: ' + err) - return null - }) - - if (redirectPath) navigateAfterLogin(redirectPath) - }) - .catch((err) => { - toast.error( - 'An error occurred while creating nsecbunker signer: ' + err - ) - }) - .finally(() => { - setIsLoading(false) - setLoadingSpinnerDesc('') - }) - } - - const login = () => { - if (inputValue.startsWith('bunker://')) { - return loginWithBunkerConnectionString() - } - - if (inputValue.startsWith('nsec')) { - return loginWithNsec() - } - if (inputValue.startsWith('npub')) { - return loginWithNsecBunker() - } - if (inputValue.match(NIP05_REGEX)) { - return loginWithNsecBunker() - } - - // Check if maybe hex nsec - try { - const privateKey = hexToBytes(inputValue) - const publickey = getPublicKey(privateKey) - - if (publickey) return loginWithNsec(privateKey) - } catch (err) { - console.warn('err', err) - } - - toast.error( - 'Invalid format, please use: private key (hex), nsec..., bunker:// or nip05 format.' - ) - return - } - - if (authUrl) { - return ( -