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