import { Event, EventTemplate } from 'nostr-tools' import { useCallback } from 'react' import { NostrController } from '../controllers' import { appPrivateRoutes } from '../routes' import { setAuthState, setMetadataEvent, setRelayMapAction } from '../store/actions' import { base64DecodeAuthToken, compareObjects, createAndSaveAuthToken, getAuthToken, getEmptyMetadataEvent, getRelayMap, unixNow } from '../utils' import { useAppDispatch, useAppSelector } from './store' import { useNDKContext } from './useNDKContext' export const useAuth = () => { const dispatch = useAppDispatch() const { findMetadata } = useNDKContext() const { auth: authState, relays: relaysState } = useAppSelector( (state) => state ) const checkSession = useCallback(() => { const savedAuthToken = getAuthToken() if (savedAuthToken) { const signedEvent = base64DecodeAuthToken(savedAuthToken) dispatch( setAuthState({ loggedIn: true, usersPubkey: signedEvent.pubkey }) ) return } dispatch( setAuthState({ loggedIn: false, usersPubkey: undefined }) ) }, [dispatch]) /** * Function will authenticate user by signing an auth event * which is done by calling the sign() function, where appropriate * method will be chosen (extension or keys) * * @param pubkey of the user trying to login * @returns url to redirect if authentication successfull * or error if otherwise */ const authAndGetMetadataAndRelaysMap = useCallback( async (pubkey: string) => { const emptyMetadata = getEmptyMetadataEvent() try { const profile = await findMetadata(pubkey, {}, true) if (profile && profile.profileEvent) { const event: Event = JSON.parse(profile.profileEvent) dispatch(setMetadataEvent(event)) } else { dispatch(setMetadataEvent(emptyMetadata)) } } catch (err) { console.warn('Error occurred while finding metadata', err) dispatch(setMetadataEvent(emptyMetadata)) } const timestamp = unixNow() const { href } = window.location const authEvent: EventTemplate = { kind: 27235, tags: [ ['u', href], ['method', 'GET'] ], content: '', created_at: timestamp } const nostrController = NostrController.getInstance() const signedAuthEvent = await nostrController.signEvent(authEvent) createAndSaveAuthToken(signedAuthEvent) dispatch( setAuthState({ loggedIn: true, usersPubkey: pubkey }) ) const relayMap = await getRelayMap(pubkey) if (Object.keys(relayMap).length < 1) { // Navigate user to relays page if relay map is empty return appPrivateRoutes.relays } if ( authState.loggedIn && !compareObjects(relaysState?.map, relayMap.map) ) { dispatch(setRelayMapAction(relayMap.map)) } return appPrivateRoutes.homePage }, [dispatch, findMetadata, authState, relaysState] ) return { authAndGetMetadataAndRelaysMap, checkSession } }