sigit.io/src/utils/nostr.ts

152 lines
3.7 KiB
TypeScript

import { nip19, verifyEvent } from 'nostr-tools'
import { SignedEvent } from '../types'
import axios from 'axios'
/**
* @param hexKey hex private or public key
* @returns whether or not is key valid
*/
const validateHex = (hexKey: string) => {
return hexKey.match(/^[a-f0-9]{64}$/)
}
/**
* NPUB provided - it will convert NPUB to HEX
* HEX provided - it will return HEX
*
* @param pubKey in NPUB, HEX format
* @returns HEX format
*/
export const pubToHex = async (pubKey: string): Promise<string | null> => {
// If key is NPUB
if (pubKey.startsWith('npub')) {
try {
return nip19.decode(pubKey).data as string
} catch (error) {
return Promise.resolve(null)
}
}
// valid hex key
if (validateHex(pubKey)) return Promise.resolve(pubKey)
// Not a valid hex key
return Promise.resolve(null)
}
/**
* If NSEC key is provided function will convert it to HEX
* If HEX key Is provided function will validate the HEX format and return
*
* @param nsec or private key in HEX format
*/
export const nsecToHex = (nsec: string): string | null => {
// If key is NSEC
if (nsec.startsWith('nsec')) {
try {
return nip19.decode(nsec).data as string
} catch (error) {
return null
}
}
// since it's not NSEC key we check if it's a valid hex key
if (validateHex(nsec)) return nsec
return null
}
export const hexToNpub = (hexPubkey: string | undefined): string => {
if (!hexPubkey) return 'n/a'
if (hexPubkey.includes('npub')) return hexPubkey
return nip19.npubEncode(hexPubkey)
}
export const verifySignedEvent = (event: SignedEvent) => {
const isGood = verifyEvent(event)
if (!isGood) {
throw new Error(
'Signed event did not pass verification. Check sig, id and pubkey.'
)
}
}
export const queryNip05 = async (
nip05: string
): Promise<{
pubkey: string
relays: string[]
}> => {
const NIP05_REGEX = /^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/
const match = nip05.match(NIP05_REGEX)
if (!match) throw new Error('Invalid nip05')
const [_, name = '_', domain] = match
const url = `https://${domain}/.well-known/nostr.json?name=${name}`
const res = await axios(url)
.then((res) => {
return res.data
})
.catch((err) => {
console.log('err :>> ', err)
throw err
})
const pubkey = res.names[name]
const relays: string[] = []
if (pubkey) {
// check nip46 for user pubkey, if relays found for user, return those
const userRelays = res.nip46?.[pubkey] as string[]
if (userRelays && userRelays.length > 0) {
relays.push(...userRelays)
} else {
// otherwise check nip46 for root user pubkey, if relays found, return those
const root = res.names['_']
if (root) {
const rootUserRelays = res.nip46?.[root] as string[]
if (rootUserRelays && rootUserRelays.length > 0)
relays.push(...rootUserRelays)
}
}
}
return {
pubkey,
relays
}
}
export const base64EncodeSignedEvent = (event: SignedEvent) => {
try {
const authEventSerialized = JSON.stringify(event)
const token = btoa(authEventSerialized)
return token
} catch (error) {
throw new Error('An error occurred in JSON.stringify of signedAuthEvent')
}
}
export const base64DecodeAuthToken = (authToken: string): SignedEvent => {
const decodedToken = atob(authToken)
try {
const signedEvent = JSON.parse(decodedToken)
return signedEvent
} catch (error) {
throw new Error('An error occurred in JSON.parse of the auth token')
}
}
/**
*
* @param pubkey in hex or npub format
* @returns robohash.org url for the avatar
*/
export const getRoboHashPicture = (pubkey: string): string => {
const npub = hexToNpub(pubkey)
return `https://robohash.org/${npub}.png?set=set3`
}