import { EventTemplate } from 'nostr-tools' import { useCallback } from 'react' import { NostrController } from '../controllers' import { appPrivateRoutes } from '../routes' import { setAuthState, setRelayMapAction, setUserProfile } from '../store/actions' import { base64DecodeAuthToken, compareObjects, createAndSaveAuthToken, getAuthToken, getRelayMapFromNDKRelayList, unixNow } from '../utils' import { useAppDispatch, useAppSelector } from './store' import { useNDKContext } from './useNDKContext' import { useDvm } from './useDvm' import { getFileServerMap } from '../utils/file-servers.ts' import store from '../store/store.ts' import { setServerMapAction } from '../store/servers/action.ts' export const useAuth = () => { const dispatch = useAppDispatch() const { getRelayInfo } = useDvm() const { findMetadata, getNDKRelayList, fetchEvent } = useNDKContext() const authState = useAppSelector((state) => state.auth) const relaysState = useAppSelector((state) => state.relays) 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) => { try { const profile = await findMetadata(pubkey) dispatch(setUserProfile(profile)) } catch (err) { console.warn('Error occurred while finding metadata', err) } 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 ndkRelayListPromise = getNDKRelayList(pubkey) const serverMapPromise = getFileServerMap(pubkey, fetchEvent) const [ndkRelayList, serverMap] = await Promise.all([ ndkRelayListPromise, serverMapPromise ]) const relays = ndkRelayList.relays if (relays.length < 1) { // Navigate user to relays page if a relay map is empty return appPrivateRoutes.relays } if (Object.keys(serverMap).length < 1) { // Navigate user to servers page if a server map is empty return appPrivateRoutes.servers } getRelayInfo(relays) const relayMap = getRelayMapFromNDKRelayList(ndkRelayList) if (authState.loggedIn) { if (!compareObjects(relaysState?.map, relayMap)) dispatch(setRelayMapAction(relayMap)) if (!compareObjects(store.getState().servers?.map, serverMap.map)) dispatch(setServerMapAction(serverMap.map)) } return appPrivateRoutes.homePage }, [ dispatch, getNDKRelayList, fetchEvent, getRelayInfo, authState.loggedIn, findMetadata, relaysState?.map ] ) return { authAndGetMetadataAndRelaysMap, checkSession } }