import { nip19, getPublicKey, generateSecretKey } from 'nostr-tools' import { bytesToHex, hexToBytes } from 'nostr-tools/utils' import { createAccountTwoLevel, unlockAccountTwoLevel, accountExistsTwoLevel, getPublicKeysTwoLevel, deleteAccountTwoLevel, } from './keyManagementTwoLevel' /** * Key management service */ export class KeyManagementService { /** * Generate a new Nostr key pair * Returns the private key (hex) and public key (hex) */ generateKeyPair(): { privateKey: string; publicKey: string; npub: string } { const secretKey = generateSecretKey() const privateKeyHex = bytesToHex(secretKey) const publicKeyHex = getPublicKey(secretKey) const npub = nip19.npubEncode(publicKeyHex) return { privateKey: privateKeyHex, publicKey: publicKeyHex, npub, } } /** * Import a private key (accepts hex or nsec format) * Returns the private key (hex), public key (hex), and npub */ importPrivateKey(privateKey: string): { privateKey: string; publicKey: string; npub: string } { let privateKeyHex: string // Try to decode as nsec try { const decoded = nip19.decode(privateKey) if (decoded.type === 'nsec' && typeof decoded.data === 'string') { privateKeyHex = decoded.data } else { throw new Error('Invalid nsec format') } } catch { // Assume it's already a hex string privateKeyHex = privateKey } const secretKey = hexToBytes(privateKeyHex) const publicKeyHex = getPublicKey(secretKey) const npub = nip19.npubEncode(publicKeyHex) return { privateKey: privateKeyHex, publicKey: publicKeyHex, npub, } } /** * Create a new account: generate/import key, encrypt it with two-level encryption * Returns the recovery phrase and npub * Uses two-level encryption: KEK encrypted with recovery phrase, private key encrypted with KEK */ async createAccount(privateKey?: string): Promise<{ recoveryPhrase: string[] npub: string publicKey: string }> { // Generate or import key pair const keyPair = privateKey ? this.importPrivateKey(privateKey) : this.generateKeyPair() // Use two-level encryption system const result = await createAccountTwoLevel( keyPair.privateKey, (secretKey: Uint8Array) => getPublicKey(secretKey), (publicKey: string) => nip19.npubEncode(publicKey) ) return result } /** * Check if an account exists (encrypted key is stored) */ async accountExists(): Promise { return await accountExistsTwoLevel() } /** * Get the public key and npub if account exists */ async getPublicKeys(): Promise<{ publicKey: string; npub: string } | null> { return await getPublicKeysTwoLevel() } /** * Decrypt and retrieve the private key using recovery phrase * Uses two-level decryption: decrypt KEK with recovery phrase, then decrypt private key with KEK */ async unlockAccount(recoveryPhrase: string[]): Promise<{ privateKey: string publicKey: string npub: string }> { const result = await unlockAccountTwoLevel( recoveryPhrase, (secretKey: Uint8Array) => getPublicKey(secretKey), (publicKey: string) => nip19.npubEncode(publicKey) ) return result } /** * Delete the account (remove all stored keys) */ async deleteAccount(): Promise { await deleteAccountTwoLevel() } } export const keyManagementService = new KeyManagementService()