Add updateTimestamp to apps, start mergeAppPerms
This commit is contained in:
@ -10,7 +10,7 @@ import { isEmptyString } from '@/utils/helpers/helpers'
|
|||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
import { useAppDispatch, useAppSelector } from '@/store/hooks/redux'
|
import { useAppDispatch, useAppSelector } from '@/store/hooks/redux'
|
||||||
import { selectApps } from '@/store'
|
import { selectApps } from '@/store'
|
||||||
import { dbi } from '@/modules/db'
|
import { DbApp, dbi } from '@/modules/db'
|
||||||
import { useEnqueueSnackbar } from '@/hooks/useEnqueueSnackbar'
|
import { useEnqueueSnackbar } from '@/hooks/useEnqueueSnackbar'
|
||||||
import { setApps } from '@/store/reducers/content.slice'
|
import { setApps } from '@/store/reducers/content.slice'
|
||||||
import { LoadingSpinner } from '@/shared/LoadingSpinner/LoadingSpinner'
|
import { LoadingSpinner } from '@/shared/LoadingSpinner/LoadingSpinner'
|
||||||
@ -20,7 +20,7 @@ export const ModalAppDetails = () => {
|
|||||||
const isModalOpened = getModalOpened(MODAL_PARAMS_KEYS.APP_DETAILS)
|
const isModalOpened = getModalOpened(MODAL_PARAMS_KEYS.APP_DETAILS)
|
||||||
const handleCloseModal = createHandleCloseReplace(MODAL_PARAMS_KEYS.APP_DETAILS)
|
const handleCloseModal = createHandleCloseReplace(MODAL_PARAMS_KEYS.APP_DETAILS)
|
||||||
|
|
||||||
const { appNpub = '' } = useParams()
|
const { npub = '', appNpub = '' } = useParams()
|
||||||
const apps = useAppSelector(selectApps)
|
const apps = useAppSelector(selectApps)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
@ -33,8 +33,8 @@ export const ModalAppDetails = () => {
|
|||||||
})
|
})
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
|
||||||
|
const currentApp = apps.find((app) => app.appNpub === appNpub && app.npub === npub)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentApp = apps.find((app) => app.appNpub === appNpub)
|
|
||||||
if (!currentApp) return
|
if (!currentApp) return
|
||||||
|
|
||||||
setDetails({
|
setDetails({
|
||||||
@ -94,14 +94,15 @@ export const ModalAppDetails = () => {
|
|||||||
|
|
||||||
const submitHandler = async (e: FormEvent) => {
|
const submitHandler = async (e: FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (isLoading) return undefined
|
if (isLoading || !currentApp) return undefined
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
const updatedApp = {
|
const updatedApp: DbApp = {
|
||||||
|
...currentApp,
|
||||||
url,
|
url,
|
||||||
name,
|
name,
|
||||||
icon,
|
icon,
|
||||||
appNpub,
|
updateTimestamp: Date.now()
|
||||||
}
|
}
|
||||||
await dbi.updateApp(updatedApp)
|
await dbi.updateApp(updatedApp)
|
||||||
const apps = await dbi.listApps()
|
const apps = await dbi.listApps()
|
||||||
|
@ -248,6 +248,7 @@ export class NoauthBackend {
|
|||||||
private accessBuffer: DbPending[] = []
|
private accessBuffer: DbPending[] = []
|
||||||
private notifCallback: (() => void) | null = null
|
private notifCallback: (() => void) | null = null
|
||||||
private pendingNpubEvents = new Map<string, NDKEvent[]>()
|
private pendingNpubEvents = new Map<string, NDKEvent[]>()
|
||||||
|
private permSub?: NDKSubscription
|
||||||
private ndk = new NDK({
|
private ndk = new NDK({
|
||||||
explicitRelayUrls: [...NIP46_RELAYS, ...OUTBOX_RELAYS, BROADCAST_RELAY],
|
explicitRelayUrls: [...NIP46_RELAYS, ...OUTBOX_RELAYS, BROADCAST_RELAY],
|
||||||
enableOutboxModel: false,
|
enableOutboxModel: false,
|
||||||
@ -343,10 +344,19 @@ export class NoauthBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async subscribeToAppPerms() {
|
private async subscribeToAppPerms() {
|
||||||
const sub = this.ndk.subscribe(
|
if (this.permSub) {
|
||||||
|
this.permSub.stop()
|
||||||
|
this.permSub.removeAllListeners()
|
||||||
|
this.permSub = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const authors = this.keys.map((k) => nip19.decode(k.npub).data as string)
|
||||||
|
this.permSub = this.ndk.subscribe(
|
||||||
{
|
{
|
||||||
|
authors,
|
||||||
kinds: [KIND_DATA],
|
kinds: [KIND_DATA],
|
||||||
'#t': [APP_TAG],
|
'#t': [APP_TAG],
|
||||||
|
limit: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
closeOnEose: false,
|
closeOnEose: false,
|
||||||
@ -355,14 +365,58 @@ export class NoauthBackend {
|
|||||||
NDKRelaySet.fromRelayUrls(OUTBOX_RELAYS, this.ndk),
|
NDKRelaySet.fromRelayUrls(OUTBOX_RELAYS, this.ndk),
|
||||||
true // auto-start
|
true // auto-start
|
||||||
)
|
)
|
||||||
sub.on('event', (e) => {
|
this.permSub.on('event', async (e) => {
|
||||||
// parse,
|
const npub = nip19.npubEncode(e.pubkey)
|
||||||
// merge w/ existing apps/perms
|
const key = this.keys.find((k) => k.npub === npub)
|
||||||
// write to db
|
if (!key) return
|
||||||
// if written - notify UI
|
|
||||||
|
// parse
|
||||||
|
try {
|
||||||
|
const payload = await key.signer.decrypt(new NDKUser({ pubkey: e.pubkey }), e.content)
|
||||||
|
const data = JSON.parse(payload)
|
||||||
|
console.log('Got app perm event', { e, data })
|
||||||
|
// FIXME validate first!
|
||||||
|
await this.mergeAppPerms(key, data)
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Bad app perm event', e, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify UI
|
||||||
|
this.updateUI()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async mergeAppPerms(key: Key, data: any) {
|
||||||
|
let app = this.apps.find(a => a.appNpub === data.appNpub)
|
||||||
|
const appFromData = (): DbApp => {
|
||||||
|
return {
|
||||||
|
npub: data.npub,
|
||||||
|
appNpub: data.appNpub,
|
||||||
|
name: data.name,
|
||||||
|
icon: data.icon,
|
||||||
|
url: data.url,
|
||||||
|
// choose older creation timestamp
|
||||||
|
timestamp: app ? Math.min(app.timestamp, data.timestamp) : data.timestamp,
|
||||||
|
updateTimestamp: data.updateTimestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!app) {
|
||||||
|
// new app
|
||||||
|
app = appFromData()
|
||||||
|
console.log("New app from event", { data, app })
|
||||||
|
await dbi.addApp(app)
|
||||||
|
} else if (app.updateTimestamp < data.updateTimestamp) {
|
||||||
|
// update existing app
|
||||||
|
app = appFromData()
|
||||||
|
await dbi.updateApp(app)
|
||||||
|
} else {
|
||||||
|
// old data
|
||||||
|
console.log("skip old app perms", { data, app })
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME merge perms
|
||||||
|
}
|
||||||
|
|
||||||
public setNotifCallback(cb: () => void) {
|
public setNotifCallback(cb: () => void) {
|
||||||
if (this.notifCallback) {
|
if (this.notifCallback) {
|
||||||
// this.notify()
|
// this.notify()
|
||||||
@ -767,7 +821,7 @@ export class NoauthBackend {
|
|||||||
private async publishAppPerms({ npub, appNpub }: { npub: string; appNpub: string }) {
|
private async publishAppPerms({ npub, appNpub }: { npub: string; appNpub: string }) {
|
||||||
const key = this.keys.find((k) => k.npub === npub)
|
const key = this.keys.find((k) => k.npub === npub)
|
||||||
if (!key) throw new Error('Key not found')
|
if (!key) throw new Error('Key not found')
|
||||||
const app = this.apps.find((a) => a.appNpub === appNpub)
|
const app = this.apps.find((a) => a.appNpub === appNpub && a.npub === npub)
|
||||||
if (!app) throw new Error('App not found')
|
if (!app) throw new Error('App not found')
|
||||||
const perms = this.perms.filter((p) => p.appNpub === appNpub && p.npub === npub)
|
const perms = this.perms.filter((p) => p.appNpub === appNpub && p.npub === npub)
|
||||||
const data = {
|
const data = {
|
||||||
@ -777,6 +831,7 @@ export class NoauthBackend {
|
|||||||
icon: app.icon,
|
icon: app.icon,
|
||||||
url: app.url,
|
url: app.url,
|
||||||
timestamp: app.timestamp,
|
timestamp: app.timestamp,
|
||||||
|
updateTimestamp: app.updateTimestamp,
|
||||||
perms,
|
perms,
|
||||||
}
|
}
|
||||||
const id = await this.sha256(`nsec.app_${npub}_${appNpub}`)
|
const id = await this.sha256(`nsec.app_${npub}_${appNpub}`)
|
||||||
@ -821,6 +876,7 @@ export class NoauthBackend {
|
|||||||
name: appName,
|
name: appName,
|
||||||
icon: appIcon,
|
icon: appIcon,
|
||||||
url: appUrl,
|
url: appUrl,
|
||||||
|
updateTimestamp: Date.now()
|
||||||
})
|
})
|
||||||
|
|
||||||
// reload
|
// reload
|
||||||
@ -908,6 +964,7 @@ export class NoauthBackend {
|
|||||||
name: '',
|
name: '',
|
||||||
icon: '',
|
icon: '',
|
||||||
url: options.appUrl || '',
|
url: options.appUrl || '',
|
||||||
|
updateTimestamp: Date.now()
|
||||||
})
|
})
|
||||||
|
|
||||||
// reload
|
// reload
|
||||||
|
@ -18,6 +18,7 @@ export interface DbApp {
|
|||||||
icon: string
|
icon: string
|
||||||
url: string
|
url: string
|
||||||
timestamp: number
|
timestamp: number
|
||||||
|
updateTimestamp: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DbPerm {
|
export interface DbPerm {
|
||||||
@ -63,9 +64,9 @@ export interface DbSchema extends Dexie {
|
|||||||
|
|
||||||
export const db = new Dexie('noauthdb') as DbSchema
|
export const db = new Dexie('noauthdb') as DbSchema
|
||||||
|
|
||||||
db.version(8).stores({
|
db.version(9).stores({
|
||||||
keys: 'npub',
|
keys: 'npub',
|
||||||
apps: 'appNpub,npub,name,timestamp',
|
apps: 'appNpub,npub,name,timestamp,updateTimestamp',
|
||||||
perms: 'id,npub,appNpub,perm,value,timestamp',
|
perms: 'id,npub,appNpub,perm,value,timestamp',
|
||||||
pending: 'id,npub,appNpub,timestamp,method',
|
pending: 'id,npub,appNpub,timestamp,method',
|
||||||
history: 'id,npub,appNpub,timestamp,method,allowed',
|
history: 'id,npub,appNpub,timestamp,method,allowed',
|
||||||
@ -113,12 +114,13 @@ export const dbi = {
|
|||||||
console.log(`db addApp error: ${error}`)
|
console.log(`db addApp error: ${error}`)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateApp: async (app: Omit<DbApp, 'npub' | 'timestamp'>) => {
|
updateApp: async (app: DbApp) => {
|
||||||
try {
|
try {
|
||||||
await db.apps.where({ appNpub: app.appNpub }).modify({
|
await db.apps.where({ appNpub: app.appNpub }).modify({
|
||||||
name: app.name,
|
name: app.name,
|
||||||
icon: app.icon,
|
icon: app.icon,
|
||||||
url: app.url,
|
url: app.url,
|
||||||
|
updateTimestamp: app.updateTimestamp
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(`db updateApp error: ${error}`)
|
console.log(`db updateApp error: ${error}`)
|
||||||
|
Reference in New Issue
Block a user