Merge pull request #68 from nostrband/develop
Add logic to confirm after login
This commit is contained in:
commit
4b1f7564e7
@ -8,12 +8,12 @@ import { CircularProgress, Stack, Typography } from '@mui/material'
|
||||
import { StyledAppLogo } from './styled'
|
||||
import { Input } from '@/shared/Input/Input'
|
||||
import { Button } from '@/shared/Button/Button'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { FormInputType, schema } from './const'
|
||||
import { yupResolver } from '@hookform/resolvers/yup'
|
||||
import { DOMAIN } from '@/utils/consts'
|
||||
import { fetchNip05 } from '@/utils/helpers/helpers'
|
||||
import { fetchNip05, fetchNpubNames } from '@/utils/helpers/helpers'
|
||||
import { usePassword } from '@/hooks/usePassword'
|
||||
import { dbi } from '@/modules/db'
|
||||
|
||||
@ -36,6 +36,7 @@ export const ModalLogin = () => {
|
||||
handleSubmit,
|
||||
reset,
|
||||
register,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<FormInputType>({
|
||||
defaultValues: FORM_DEFAULT_VALUES,
|
||||
@ -78,7 +79,10 @@ export const ModalLogin = () => {
|
||||
notify(`Fetched ${k.npub}`, 'success')
|
||||
dbi.addSynced(k.npub)
|
||||
cleanUpStates()
|
||||
navigate(`/key/${k.npub}`)
|
||||
setTimeout(() => {
|
||||
// give frontend time to read the new key first
|
||||
navigate(`/key/${k.npub}`)
|
||||
}, 300)
|
||||
} catch (error: any) {
|
||||
console.log('error', error)
|
||||
notify(error?.message || 'Something went wrong!', 'error')
|
||||
@ -86,6 +90,24 @@ export const ModalLogin = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const [searchParams] = useSearchParams()
|
||||
useEffect(() => {
|
||||
if (isModalOpened) {
|
||||
const isPopup = searchParams.get('popup') === 'true'
|
||||
const npub = searchParams.get('npub') || ''
|
||||
const appNpub = searchParams.get('appNpub') || ''
|
||||
if (isPopup && isModalOpened) {
|
||||
swicCall('fetchPendingRequests', npub, appNpub)
|
||||
|
||||
fetchNpubNames(npub).then(names => {
|
||||
if (names.length) {
|
||||
setValue('username', `${names[0]}@${DOMAIN}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [searchParams, isModalOpened, setValue])
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (isModalOpened) {
|
||||
|
@ -61,8 +61,11 @@ export const ModalSignUp = () => {
|
||||
setIsLoading(true)
|
||||
const k: any = await swicCall('generateKey', name)
|
||||
notify(`Account created for "${name}"`, 'success')
|
||||
navigate(`/key/${k.npub}`)
|
||||
setIsLoading(false)
|
||||
setTimeout(() => {
|
||||
// give frontend time to read the new key first
|
||||
navigate(`/key/${k.npub}`)
|
||||
}, 300)
|
||||
} catch (error: any) {
|
||||
notify(error?.message || 'Something went wrong!', 'error')
|
||||
setIsLoading(false)
|
||||
|
@ -46,6 +46,12 @@ interface IAllowCallbackParams {
|
||||
params?: any
|
||||
}
|
||||
|
||||
class Nip46Backend extends NDKNip46Backend {
|
||||
public async processEvent(event: NDKEvent) {
|
||||
this.handleIncomingEvent(event)
|
||||
}
|
||||
}
|
||||
|
||||
class Nip04KeyHandlingStrategy implements IEventHandlingStrategy {
|
||||
private privkey: string
|
||||
private nip04 = new Nip04()
|
||||
@ -137,10 +143,16 @@ export class NoauthBackend {
|
||||
private confirmBuffer: Pending[] = []
|
||||
private accessBuffer: DbPending[] = []
|
||||
private notifCallback: (() => void) | null = null
|
||||
private pendingNpubEvents = new Map<string, NDKEvent[]>()
|
||||
private ndk = new NDK({
|
||||
explicitRelayUrls: NIP46_RELAYS,
|
||||
enableOutboxModel: false
|
||||
})
|
||||
|
||||
public constructor(swg: ServiceWorkerGlobalScope) {
|
||||
this.swg = swg
|
||||
this.keysModule = new Keys(swg.crypto.subtle)
|
||||
this.ndk.connect()
|
||||
|
||||
const self = this
|
||||
swg.addEventListener('activate', (event) => {
|
||||
@ -568,22 +580,21 @@ export class NoauthBackend {
|
||||
}
|
||||
|
||||
private async connectApp({
|
||||
npub,
|
||||
appNpub,
|
||||
appUrl,
|
||||
perms,
|
||||
appName = '',
|
||||
appIcon = ''
|
||||
}: {
|
||||
npub: string,
|
||||
appNpub: string,
|
||||
appUrl: string,
|
||||
appName?: string,
|
||||
appIcon?: string,
|
||||
perms: string[]
|
||||
}) {
|
||||
|
||||
await dbi.addApp({
|
||||
npub,
|
||||
appNpub,
|
||||
appUrl,
|
||||
perms,
|
||||
appName = '',
|
||||
appIcon = '',
|
||||
}: {
|
||||
npub: string
|
||||
appNpub: string
|
||||
appUrl: string
|
||||
appName?: string
|
||||
appIcon?: string
|
||||
perms: string[]
|
||||
}) {
|
||||
await dbi.addApp({
|
||||
appNpub: appNpub,
|
||||
npub: npub,
|
||||
timestamp: Date.now(),
|
||||
@ -772,7 +783,7 @@ export class NoauthBackend {
|
||||
ndk.connect()
|
||||
|
||||
const signer = new NDKPrivateKeySigner(sk) // PrivateKeySigner
|
||||
const backend = new NDKNip46Backend(ndk, signer, () => Promise.resolve(true))
|
||||
const backend = new Nip46Backend(ndk, signer, () => Promise.resolve(true))
|
||||
this.keys.push({ npub, backend, signer, ndk, backoff })
|
||||
|
||||
// new method
|
||||
@ -829,6 +840,27 @@ export class NoauthBackend {
|
||||
r.on('connect', onConnect)
|
||||
r.on('disconnect', onDisconnect)
|
||||
}
|
||||
|
||||
const pendingEvents = this.pendingNpubEvents.get(npub)
|
||||
if (pendingEvents) {
|
||||
this.pendingNpubEvents.delete(npub)
|
||||
for (const e of pendingEvents) {
|
||||
backend.processEvent(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async fetchPendingRequests(npub: string, appNpub: string) {
|
||||
const { data: pubkey } = nip19.decode(npub)
|
||||
const { data: appPubkey } = nip19.decode(appNpub)
|
||||
|
||||
const events = await this.ndk.fetchEvents({
|
||||
kinds: [KIND_RPC],
|
||||
"#p": [pubkey as string],
|
||||
authors: [appPubkey as string]
|
||||
});
|
||||
console.log("fetched pending for", npub, events.size)
|
||||
this.pendingNpubEvents.set(npub, [...events.values()]);
|
||||
}
|
||||
|
||||
public async unlock(npub: string) {
|
||||
@ -1011,6 +1043,8 @@ export class NoauthBackend {
|
||||
result = await this.deletePerm(args[0])
|
||||
} else if (method === 'enablePush') {
|
||||
result = await this.enablePush()
|
||||
} else if (method === 'fetchPendingRequests') {
|
||||
result = await this.fetchPendingRequests(args[0], args[1])
|
||||
} else {
|
||||
console.log('unknown method from UI ', method)
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ export let swr: ServiceWorkerRegistration | null = null
|
||||
const reqs = new Map<number, { ok: (r: any) => void; rej: (r: any) => void }>()
|
||||
let nextReqId = 1
|
||||
let onRender: (() => void) | null = null
|
||||
const queue: (() => Promise<void>)[] = []
|
||||
|
||||
export async function swicRegister() {
|
||||
serviceWorkerRegistration.register({
|
||||
@ -17,14 +18,17 @@ export async function swicRegister() {
|
||||
},
|
||||
})
|
||||
|
||||
navigator.serviceWorker.ready.then((r) => {
|
||||
console.log('sw ready')
|
||||
navigator.serviceWorker.ready.then(async (r) => {
|
||||
console.log('sw ready, queue', queue.length)
|
||||
swr = r
|
||||
if (navigator.serviceWorker.controller) {
|
||||
console.log(`This page is currently controlled by: ${navigator.serviceWorker.controller}`)
|
||||
} else {
|
||||
console.log('This page is not currently controlled by a service worker.')
|
||||
}
|
||||
|
||||
while (queue.length)
|
||||
await (queue.shift()!)()
|
||||
})
|
||||
|
||||
navigator.serviceWorker.addEventListener('message', (event) => {
|
||||
@ -57,19 +61,25 @@ export async function swicCall(method: string, ...args: any[]) {
|
||||
nextReqId++
|
||||
|
||||
return new Promise((ok, rej) => {
|
||||
if (!swr || !swr.active) {
|
||||
rej(new Error('No active service worker'))
|
||||
return
|
||||
|
||||
const call = async () => {
|
||||
if (!swr || !swr.active) {
|
||||
rej(new Error('No active service worker'))
|
||||
return
|
||||
}
|
||||
|
||||
reqs.set(id, { ok, rej })
|
||||
const msg = {
|
||||
id,
|
||||
method,
|
||||
args: [...args],
|
||||
}
|
||||
console.log('sending to SW', msg)
|
||||
swr.active.postMessage(msg)
|
||||
}
|
||||
|
||||
reqs.set(id, { ok, rej })
|
||||
const msg = {
|
||||
id,
|
||||
method,
|
||||
args: [...args],
|
||||
}
|
||||
console.log('sending to SW', msg)
|
||||
swr.active.postMessage(msg)
|
||||
if (swr && swr.active) call()
|
||||
else queue.push(call)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useAppSelector } from '../../store/hooks/redux'
|
||||
import { Navigate, useParams } from 'react-router-dom'
|
||||
import { Navigate, useParams, useSearchParams } from 'react-router-dom'
|
||||
import { Stack } from '@mui/material'
|
||||
import { StyledIconButton } from './styled'
|
||||
import { SettingsIcon, ShareIcon } from '@/assets'
|
||||
@ -23,6 +23,7 @@ import { useCallback } from 'react'
|
||||
const KeyPage = () => {
|
||||
const { npub = '' } = useParams<{ npub: string }>()
|
||||
const { keys, apps, pending, perms } = useAppSelector((state) => state.content)
|
||||
const [searchParams] = useSearchParams()
|
||||
|
||||
const isSynced = useLiveQuery(checkNpubSyncQuerier(npub), [npub], false)
|
||||
const { handleOpen } = useModalSearchParams()
|
||||
@ -41,6 +42,14 @@ const KeyPage = () => {
|
||||
const { prepareEventPendings } = useTriggerConfirmModal(npub, pending, perms)
|
||||
|
||||
const isKeyExists = npub.trim().length && key
|
||||
const isPopup = searchParams.get('popup') === 'true'
|
||||
console.log({ isKeyExists, isPopup })
|
||||
if (isPopup && !isKeyExists) {
|
||||
searchParams.set('login', 'true')
|
||||
searchParams.set('npub', npub)
|
||||
const url = `/home?${searchParams.toString()}`
|
||||
return <Navigate to={url} />
|
||||
}
|
||||
if (!isKeyExists) return <Navigate to={`/home`} />
|
||||
|
||||
const handleOpenConnectAppModal = () => handleOpen(MODAL_PARAMS_KEYS.CONNECT_APP)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { nip19 } from 'nostr-tools'
|
||||
import { ACTIONS, ACTION_TYPE, DOMAIN, NIP46_RELAYS } from '../consts'
|
||||
import { ACTIONS, ACTION_TYPE, DOMAIN, NIP46_RELAYS, NOAUTHD_URL } from '../consts'
|
||||
import { DbHistory, DbPending, DbPerm } from '@/modules/db'
|
||||
import { MetaEvent } from '@/types/meta-event'
|
||||
|
||||
@ -97,6 +97,21 @@ export async function fetchNip05(value: string, origin?: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchNpubNames(npub: string) {
|
||||
try {
|
||||
const url = `${NOAUTHD_URL}/name?npub=${npub}`
|
||||
const response = await fetch(url)
|
||||
const names: {
|
||||
names: string[]
|
||||
} = await response.json()
|
||||
|
||||
return names.names
|
||||
} catch (e) {
|
||||
console.log('Failed to fetch names for', npub, 'error: ' + e)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export const getDomain = (url: string) => {
|
||||
try {
|
||||
return new URL(url).hostname
|
||||
|
@ -13,6 +13,7 @@
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"downlevelIteration": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": ".",
|
||||
|
Loading…
x
Reference in New Issue
Block a user