nostr-helper.ts raw

   1  /* eslint-disable @typescript-eslint/no-unused-vars */
   2  import { bech32 } from '@scure/base';
   3  import * as utils from '@noble/curves/abstract/utils';
   4  import { getPublicKey } from 'nostr-tools';
   5  import { encrypt as nip49Encrypt } from 'nostr-tools/nip49';
   6  
   7  export interface NostrHexObject {
   8    represents: string;
   9    hex: string;
  10  }
  11  
  12  export interface NostrPubkeyObject {
  13    hex: string;
  14    npub: string;
  15  }
  16  
  17  export interface NostrPrivkeyObject {
  18    hex: string;
  19    nsec: string;
  20  }
  21  
  22  export class NostrHelper {
  23    static getNostrPrivkeyObject(nsec_OR_hex: string): NostrPrivkeyObject {
  24      // 1. Assume we got an nsec.
  25      // Try to generate hex value.
  26      try {
  27        const hexObject = this.#nSomething2hexObject(nsec_OR_hex);
  28        if (hexObject.represents !== 'nsec') {
  29          throw new Error('The provided string is NOT an nsec.');
  30        }
  31  
  32        // Everything is fine. The provided string IS an nsec.
  33        return {
  34          hex: hexObject.hex,
  35          nsec: nsec_OR_hex,
  36        };
  37      } catch (error) {
  38        // Continue.
  39      }
  40  
  41      // 2. Assume we got an hex.
  42      // Try to generate the nsec.
  43      try {
  44        const nsec = NostrHelper.privkey2nsec(nsec_OR_hex);
  45        return {
  46          hex: nsec_OR_hex,
  47          nsec,
  48        };
  49      } catch (error) {
  50        // Continue;
  51      }
  52  
  53      throw new Error('Could not convert the provided string into nsec/hex.');
  54    }
  55  
  56    static getNostrPubkeyObject(npub_OR_hex: string): NostrPubkeyObject {
  57      // 1. Assume we got an npub.
  58      // Try to generate hex value.
  59      try {
  60        const hexObject = this.#nSomething2hexObject(npub_OR_hex);
  61        if (hexObject.represents !== 'npub') {
  62          throw new Error('The provided string is NOT an npub.');
  63        }
  64  
  65        // Everything is fine. The provided string IS an npub.
  66        return {
  67          hex: hexObject.hex,
  68          npub: npub_OR_hex,
  69        };
  70      } catch (error) {
  71        // Continue.
  72      }
  73  
  74      // 2. Assume we got an hex.
  75      // Try to generate the npub.
  76      try {
  77        const npub = NostrHelper.pubkey2npub(npub_OR_hex);
  78        return {
  79          hex: npub_OR_hex,
  80          npub,
  81        };
  82      } catch (error) {
  83        // Continue;
  84      }
  85  
  86      throw new Error('Could not convert the provided string into npub/hex.');
  87    }
  88  
  89    static pubkey2npub(hex: string): string {
  90      const data = utils.hexToBytes(hex);
  91      const words = bech32.toWords(data);
  92      return bech32.encode('npub', words, 5000);
  93    }
  94  
  95    static privkey2nsec(hex: string): string {
  96      const data = utils.hexToBytes(hex);
  97      const words = bech32.toWords(data);
  98      return bech32.encode('nsec', words, 5000);
  99    }
 100  
 101    static pubkeyFromPrivkey(hex: string): string {
 102      const privkeyBytes = utils.hexToBytes(hex);
 103      return getPublicKey(privkeyBytes);
 104    }
 105  
 106    static hex2bytes(hex: string): Uint8Array {
 107      return utils.hexToBytes(hex);
 108    }
 109  
 110    static splitKey(text: string, first: number, last: number): string {
 111      const part1 = text.slice(0, first);
 112      const part2 = '...';
 113      const part3 = text.slice(-last);
 114      return `${part1}${part2}${part3}`;
 115    }
 116  
 117    static #nSomething2hexObject(nSomething: string): NostrHexObject {
 118      const { prefix, words } = bech32.decode(
 119        nSomething as `${string}1${string}`,
 120        5000
 121      );
 122      const data = new Uint8Array(bech32.fromWords(words));
 123  
 124      return {
 125        represents: prefix,
 126        hex: utils.bytesToHex(data),
 127      };
 128    }
 129  
 130    /**
 131     * Encrypts a private key (hex) with a password using NIP-49.
 132     * Returns an ncryptsec bech32 string.
 133     * @param privkeyHex - The private key in hex format
 134     * @param password - The password to encrypt with
 135     * @param logN - Optional log2(N) parameter for scrypt (default: 16)
 136     * @returns Promise<string> - The ncryptsec bech32 encoded encrypted key
 137     */
 138    static async privkeyToNcryptsec(
 139      privkeyHex: string,
 140      password: string,
 141      logN = 16
 142    ): Promise<string> {
 143      const privkeyBytes = utils.hexToBytes(privkeyHex);
 144      return nip49Encrypt(privkeyBytes, password, logN);
 145    }
 146  }
 147