Files
regress/frontend/src/lib/nsec.ts
T

46 lines
1.5 KiB
TypeScript
Raw Normal View History

2026-08-05 13:56:50 +00:00
// Raw-nsec signing — an *unsafe* login fallback for when there's no NIP-07
// extension or NIP-46 signer available (testing, kiosk devices, etc). The
// private key only ever lives in page memory for the duration of one sign
// call; it's never persisted (no localStorage/sessionStorage), matching how
// the NIP-07 path also never retains key material — only the resulting
// session cookie survives.
import { nip19 } from 'nostr-tools';
import { finalizeEvent, getPublicKey } from 'nostr-tools/pure';
import type { SignedEvent, UnsignedEvent } from './nip07';
export function isValidNsec(nsec: string): boolean {
try {
return nip19.decode(nsec.trim()).type === 'nsec';
} catch {
return false;
}
}
function decodeNsec(nsec: string): Uint8Array {
const decoded = nip19.decode(nsec.trim());
if (decoded.type !== 'nsec') throw new Error('Not an nsec key');
return decoded.data;
}
export function nsecPubkey(nsec: string): string {
return getPublicKey(decodeNsec(nsec));
}
function signWithNsec(nsec: string, event: UnsignedEvent): SignedEvent {
return finalizeEvent(event, decodeNsec(nsec));
}
/** Sign a NIP-98 (kind 27235) event with a raw nsec and return the Authorization header value. */
export function buildNip98HeaderWithNsec(nsec: string, url: string, method: string): string {
const event = signWithNsec(nsec, {
kind: 27235,
created_at: Math.floor(Date.now() / 1000),
content: '',
tags: [
['u', url],
['method', method],
],
});
return `Nostr ${btoa(JSON.stringify(event))}`;
}