Files
welshman/packages/app/src/session.ts
T
2024-09-09 10:26:59 -07:00

82 lines
2.2 KiB
TypeScript

import {derived} from "svelte/store"
import {ctx, memoize, omit, equals, assoc} from "@welshman/lib"
import {createEvent} from "@welshman/util"
import {withGetter, synced} from "@welshman/store"
import {type Nip46Handler} from "@welshman/signer"
import {Nip46Broker, Nip46Signer, Nip07Signer, Nip01Signer} from "@welshman/signer"
export type Session = {
method: string
pubkey: string
token?: string
secret?: string
handler?: Nip46Handler
}
export const pubkey = withGetter(synced<string | null>("pubkey", null))
export const sessions = withGetter(synced<Record<string, Session>>("sessions", {}))
export const session = withGetter(
derived([pubkey, sessions], ([$pubkey, $sessions]) => ($pubkey ? $sessions[$pubkey] : null)),
)
export const getSession = (pubkey: string) => sessions.get()[pubkey]
export const addSession = (session: Session) => {
sessions.update(assoc(session.pubkey, session))
pubkey.set(session.pubkey)
}
export const putSession = (session: Session) => {
if (!equals(getSession(session.pubkey), session)) {
sessions.update(assoc(session.pubkey, session))
}
}
export const updateSession = (pubkey: string, f: (session: Session) => Session) =>
putSession(f(getSession(pubkey)))
export const dropSession = (pubkey: string) =>
sessions.update($sessions => omit([pubkey], $sessions))
export const nip46Perms = "sign_event:22242,nip04_encrypt,nip04_decrypt,nip44_encrypt,nip44_decrypt"
export const getSigner = memoize((session: Session) => {
switch (session?.method) {
case "nip07":
return new Nip07Signer()
case "nip01":
return new Nip01Signer(session.secret!)
case "nip46":
return new Nip46Signer(Nip46Broker.get(session.pubkey, session.secret!, session.handler!))
default:
return null
}
})
export const signer = withGetter(derived(session, getSigner))
export const authChallenges = new Set()
export const onAuth = async (url: string, challenge: string) => {
if (authChallenges.has(challenge) || !signer.get()) {
return
}
authChallenges.add(challenge)
const event = await signer.get()!.sign(
createEvent(22242, {
tags: [
["relay", url],
["challenge", challenge],
],
}),
)
ctx.net.pool.get(url).send(["AUTH", event])
return event
}