66 lines
1.9 KiB
TypeScript

/**
* NIP-98 HTTP Auth implementation
* Generates authentication tokens for HTTP requests using Nostr events
* See: https://github.com/nostr-protocol/nips/blob/master/98.md
*/
import type { EventTemplate } from 'nostr-tools'
import { nostrRemoteSigner } from './nostrRemoteSigner'
import { nostrService } from './nostr'
/**
* Generate NIP-98 authentication token for HTTP request
* @param method HTTP method (GET, POST, etc.)
* @param url Full URL of the request
* @param payloadHash Optional SHA256 hash of the request body (for POST/PUT)
* @returns Base64-encoded signed event token
*/
export async function generateNip98Token(method: string, url: string, payloadHash?: string): Promise<string> {
const pubkey = nostrService.getPublicKey()
if (!pubkey) {
throw new Error('Public key required for NIP-98 authentication. Please connect with a Nostr extension.')
}
// Parse URL to get components
const urlObj = new URL(url)
const path = urlObj.pathname + urlObj.search
// Build event template for NIP-98
const tags: string[][] = [
['u', urlObj.origin + path],
['method', method],
]
// Add payload hash if provided (for POST/PUT requests)
if (payloadHash) {
tags.push(['payload', payloadHash])
}
const eventTemplate: EventTemplate = {
kind: 27235, // NIP-98 kind for HTTP auth
created_at: Math.floor(Date.now() / 1000),
tags: tags,
content: '',
}
// Sign the event
const signedEvent = await nostrRemoteSigner.signEvent(eventTemplate)
if (!signedEvent) {
throw new Error('Failed to sign NIP-98 authentication event')
}
// Encode event as base64 JSON
const eventJson = JSON.stringify(signedEvent)
const eventBytes = new TextEncoder().encode(eventJson)
const base64Token = btoa(String.fromCharCode(...eventBytes))
return base64Token
}
/**
* Check if NIP-98 authentication is available
*/
export function isNip98Available(): boolean {
return nostrRemoteSigner.isAvailable()
}