Name signers after nips
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import {UnwrappedEvent, SignedEvent, HashedEvent, EventTemplate, WRAP, SEAL} from '@welshman/util'
|
||||
import {own, hash, decrypt, ISigner} from './util'
|
||||
import {Nip01Signer} from './signers/nip01'
|
||||
|
||||
export const seen = new Map<string, UnwrappedEvent | Error>()
|
||||
|
||||
export const now = (drift = 0) =>
|
||||
Math.round(Date.now() / 1000 - Math.random() * Math.pow(10, drift))
|
||||
|
||||
export const getRumor = async (signer: ISigner, template: EventTemplate) =>
|
||||
hash(own(await signer.getPubkey(), template))
|
||||
|
||||
export const getSeal = async (signer: ISigner, pubkey: string, rumor: HashedEvent) =>
|
||||
signer.sign(hash({
|
||||
kind: SEAL,
|
||||
pubkey: await signer.getPubkey(),
|
||||
content: await signer.nip44.encrypt(pubkey, JSON.stringify(rumor)),
|
||||
created_at: now(5),
|
||||
tags: [],
|
||||
}))
|
||||
|
||||
export const getWrap = async (wrapper: ISigner, pubkey: string, seal: SignedEvent, tags: string[][]) =>
|
||||
wrapper.sign(hash({
|
||||
kind: WRAP,
|
||||
pubkey: await wrapper.getPubkey(),
|
||||
content: await wrapper.nip44.encrypt(pubkey, JSON.stringify(seal)),
|
||||
created_at: now(5),
|
||||
tags: [...tags, ["p", pubkey]],
|
||||
}))
|
||||
|
||||
export const wrap = async (signer: ISigner, wrapper: ISigner, pubkey: string, template: EventTemplate, tags: string[][] = []) => {
|
||||
const rumor = await getRumor(signer, template)
|
||||
const seal = await getSeal(signer, pubkey, rumor)
|
||||
const wrap = await getWrap(wrapper, pubkey, seal, tags)
|
||||
|
||||
return Object.assign(rumor, {wrap}) as UnwrappedEvent
|
||||
}
|
||||
|
||||
export const unwrap = async (signer: ISigner, wrap: SignedEvent) => {
|
||||
// Avoid decrypting the same event multiple times
|
||||
if (seen.has(wrap.id)) {
|
||||
const rumorOrError = seen.get(wrap.id)
|
||||
|
||||
if (rumorOrError instanceof Error) {
|
||||
throw rumorOrError
|
||||
} else {
|
||||
return rumorOrError
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const seal = JSON.parse(await decrypt(signer, wrap.pubkey, wrap.content))
|
||||
const rumor = JSON.parse(await decrypt(signer, seal.pubkey, seal.content))
|
||||
|
||||
if (seal.pubkey !== rumor.pubkey) throw new Error("Seal pubkey does not match rumor pubkey")
|
||||
|
||||
seen.set(wrap.id, rumor)
|
||||
|
||||
return Object.assign(rumor, {wrap}) as UnwrappedEvent
|
||||
} catch (error) {
|
||||
seen.set(wrap.id, error as Error)
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// This is a utility that makes it harder to re-use wrapper signers, since that can result in
|
||||
// leaked metadata. It simultaneously makes it easier to wrap stuff, because it allows for
|
||||
// wrapping a single user signer and omit the wrapper signer argument to wrap, while still
|
||||
// making it possible to pass a wrapper signer if desired.
|
||||
export class Nip59 {
|
||||
constructor(private signer: ISigner, private wrapper?: ISigner) {}
|
||||
|
||||
static fromSigner = (signer: ISigner) => new Nip59(signer)
|
||||
|
||||
static fromSecret = (secret: string) => new Nip59(new Nip01Signer(secret))
|
||||
|
||||
withWrapper = (wrapper: ISigner) => new Nip59(this.signer, wrapper)
|
||||
|
||||
wrap = (pubkey: string, template: EventTemplate, tags: string[][] = []) =>
|
||||
wrap(this.signer, this.wrapper || Nip01Signer.ephemeral(), pubkey, template, tags)
|
||||
|
||||
unwrap = (event: SignedEvent) =>
|
||||
unwrap(this.signer, event)
|
||||
}
|
||||
Reference in New Issue
Block a user