nostr-tools 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,7 +21,7 @@ If using TypeScript, this package requires TypeScript >= 5.0.
21
21
  ```js
22
22
  import { generateSecretKey, getPublicKey } from 'nostr-tools'
23
23
 
24
- let sk = generateSecretKey() // `sk` is a hex string
24
+ let sk = generateSecretKey() // `sk` is a Uint8Array
25
25
  let pk = getPublicKey(sk) // `pk` is a hex string
26
26
  ```
27
27
 
package/lib/cjs/index.js CHANGED
@@ -45,6 +45,7 @@ __export(nostr_tools_exports, {
45
45
  nip30: () => nip30_exports,
46
46
  nip39: () => nip39_exports,
47
47
  nip42: () => nip42_exports,
48
+ nip44: () => nip44_exports,
48
49
  nip47: () => nip47_exports,
49
50
  nip57: () => nip57_exports,
50
51
  nip98: () => nip98_exports,
@@ -375,9 +376,9 @@ async function yieldThread() {
375
376
  }
376
377
 
377
378
  // relay.ts
378
- function relayConnect(url) {
379
+ async function relayConnect(url) {
379
380
  const relay = new Relay(url);
380
- relay.connect();
381
+ await relay.connect();
381
382
  return relay;
382
383
  }
383
384
  var Relay = class {
@@ -1633,6 +1634,128 @@ function makeAuthEvent(relayURL, challenge) {
1633
1634
  };
1634
1635
  }
1635
1636
 
1637
+ // nip44.ts
1638
+ var nip44_exports = {};
1639
+ __export(nip44_exports, {
1640
+ default: () => nip44_default,
1641
+ v2: () => v2
1642
+ });
1643
+ var import_chacha = require("@noble/ciphers/chacha");
1644
+ var import_utils9 = require("@noble/ciphers/utils");
1645
+ var import_secp256k13 = require("@noble/curves/secp256k1");
1646
+ var import_hkdf = require("@noble/hashes/hkdf");
1647
+ var import_hmac = require("@noble/hashes/hmac");
1648
+ var import_sha2562 = require("@noble/hashes/sha256");
1649
+ var import_utils10 = require("@noble/hashes/utils");
1650
+ var import_base3 = require("@scure/base");
1651
+ var decoder = new TextDecoder();
1652
+ var u = {
1653
+ minPlaintextSize: 1,
1654
+ maxPlaintextSize: 65535,
1655
+ utf8Encode: import_utils10.utf8ToBytes,
1656
+ utf8Decode(bytes) {
1657
+ return decoder.decode(bytes);
1658
+ },
1659
+ getConversationKey(privkeyA, pubkeyB) {
1660
+ const sharedX = import_secp256k13.secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
1661
+ return (0, import_hkdf.extract)(import_sha2562.sha256, sharedX, "nip44-v2");
1662
+ },
1663
+ getMessageKeys(conversationKey, nonce) {
1664
+ (0, import_utils9.ensureBytes)(conversationKey, 32);
1665
+ (0, import_utils9.ensureBytes)(nonce, 32);
1666
+ const keys = (0, import_hkdf.expand)(import_sha2562.sha256, conversationKey, nonce, 76);
1667
+ return {
1668
+ chacha_key: keys.subarray(0, 32),
1669
+ chacha_nonce: keys.subarray(32, 44),
1670
+ hmac_key: keys.subarray(44, 76)
1671
+ };
1672
+ },
1673
+ calcPaddedLen(len) {
1674
+ if (!Number.isSafeInteger(len) || len < 1)
1675
+ throw new Error("expected positive integer");
1676
+ if (len <= 32)
1677
+ return 32;
1678
+ const nextPower = 1 << Math.floor(Math.log2(len - 1)) + 1;
1679
+ const chunk = nextPower <= 256 ? 32 : nextPower / 8;
1680
+ return chunk * (Math.floor((len - 1) / chunk) + 1);
1681
+ },
1682
+ writeU16BE(num) {
1683
+ if (!Number.isSafeInteger(num) || num < u.minPlaintextSize || num > u.maxPlaintextSize)
1684
+ throw new Error("invalid plaintext size: must be between 1 and 65535 bytes");
1685
+ const arr = new Uint8Array(2);
1686
+ new DataView(arr.buffer).setUint16(0, num, false);
1687
+ return arr;
1688
+ },
1689
+ pad(plaintext) {
1690
+ const unpadded = u.utf8Encode(plaintext);
1691
+ const unpaddedLen = unpadded.length;
1692
+ const prefix = u.writeU16BE(unpaddedLen);
1693
+ const suffix = new Uint8Array(u.calcPaddedLen(unpaddedLen) - unpaddedLen);
1694
+ return (0, import_utils10.concatBytes)(prefix, unpadded, suffix);
1695
+ },
1696
+ unpad(padded) {
1697
+ const unpaddedLen = new DataView(padded.buffer).getUint16(0);
1698
+ const unpadded = padded.subarray(2, 2 + unpaddedLen);
1699
+ if (unpaddedLen < u.minPlaintextSize || unpaddedLen > u.maxPlaintextSize || unpadded.length !== unpaddedLen || padded.length !== 2 + u.calcPaddedLen(unpaddedLen))
1700
+ throw new Error("invalid padding");
1701
+ return u.utf8Decode(unpadded);
1702
+ },
1703
+ hmacAad(key, message, aad) {
1704
+ if (aad.length !== 32)
1705
+ throw new Error("AAD associated data must be 32 bytes");
1706
+ const combined = (0, import_utils10.concatBytes)(aad, message);
1707
+ return (0, import_hmac.hmac)(import_sha2562.sha256, key, combined);
1708
+ },
1709
+ decodePayload(payload) {
1710
+ if (typeof payload !== "string")
1711
+ throw new Error("payload must be a valid string");
1712
+ const plen = payload.length;
1713
+ if (plen < 132 || plen > 87472)
1714
+ throw new Error("invalid payload length: " + plen);
1715
+ if (payload[0] === "#")
1716
+ throw new Error("unknown encryption version");
1717
+ let data;
1718
+ try {
1719
+ data = import_base3.base64.decode(payload);
1720
+ } catch (error) {
1721
+ throw new Error("invalid base64: " + error.message);
1722
+ }
1723
+ const dlen = data.length;
1724
+ if (dlen < 99 || dlen > 65603)
1725
+ throw new Error("invalid data length: " + dlen);
1726
+ const vers = data[0];
1727
+ if (vers !== 2)
1728
+ throw new Error("unknown encryption version " + vers);
1729
+ return {
1730
+ nonce: data.subarray(1, 33),
1731
+ ciphertext: data.subarray(33, -32),
1732
+ mac: data.subarray(-32)
1733
+ };
1734
+ }
1735
+ };
1736
+ function encrypt2(plaintext, conversationKey, nonce = (0, import_utils10.randomBytes)(32)) {
1737
+ const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce);
1738
+ const padded = u.pad(plaintext);
1739
+ const ciphertext = (0, import_chacha.chacha20)(chacha_key, chacha_nonce, padded);
1740
+ const mac = u.hmacAad(hmac_key, ciphertext, nonce);
1741
+ return import_base3.base64.encode((0, import_utils10.concatBytes)(new Uint8Array([2]), nonce, ciphertext, mac));
1742
+ }
1743
+ function decrypt2(payload, conversationKey) {
1744
+ const { nonce, ciphertext, mac } = u.decodePayload(payload);
1745
+ const { chacha_key, chacha_nonce, hmac_key } = u.getMessageKeys(conversationKey, nonce);
1746
+ const calculatedMac = u.hmacAad(hmac_key, ciphertext, nonce);
1747
+ if (!(0, import_utils9.equalBytes)(calculatedMac, mac))
1748
+ throw new Error("invalid MAC");
1749
+ const padded = (0, import_chacha.chacha20)(chacha_key, chacha_nonce, ciphertext);
1750
+ return u.unpad(padded);
1751
+ }
1752
+ var v2 = {
1753
+ utils: u,
1754
+ encrypt: encrypt2,
1755
+ decrypt: decrypt2
1756
+ };
1757
+ var nip44_default = { v2 };
1758
+
1636
1759
  // nip47.ts
1637
1760
  var nip47_exports = {};
1638
1761
  __export(nip47_exports, {
@@ -1675,7 +1798,7 @@ __export(nip57_exports, {
1675
1798
  useFetchImplementation: () => useFetchImplementation4,
1676
1799
  validateZapRequest: () => validateZapRequest
1677
1800
  });
1678
- var import_base3 = require("@scure/base");
1801
+ var import_base4 = require("@scure/base");
1679
1802
  var _fetch4;
1680
1803
  try {
1681
1804
  _fetch4 = fetch;
@@ -1689,8 +1812,8 @@ async function getZapEndpoint(metadata) {
1689
1812
  let lnurl = "";
1690
1813
  let { lud06, lud16 } = JSON.parse(metadata.content);
1691
1814
  if (lud06) {
1692
- let { words } = import_base3.bech32.decode(lud06, 1e3);
1693
- let data = import_base3.bech32.fromWords(words);
1815
+ let { words } = import_base4.bech32.decode(lud06, 1e3);
1816
+ let data = import_base4.bech32.fromWords(words);
1694
1817
  lnurl = utf8Decoder.decode(data);
1695
1818
  } else if (lud16) {
1696
1819
  let [name, domain] = lud16.split("@");
@@ -1786,13 +1909,13 @@ __export(nip98_exports, {
1786
1909
  validateEvent: () => validateEvent2,
1787
1910
  validateToken: () => validateToken
1788
1911
  });
1789
- var import_utils10 = require("@noble/hashes/utils");
1790
- var import_sha2562 = require("@noble/hashes/sha256");
1791
- var import_base4 = require("@scure/base");
1912
+ var import_utils12 = require("@noble/hashes/utils");
1913
+ var import_sha2563 = require("@noble/hashes/sha256");
1914
+ var import_base5 = require("@scure/base");
1792
1915
  var _authorizationScheme = "Nostr ";
1793
1916
  function hashPayload(payload) {
1794
- const hash = (0, import_sha2562.sha256)(utf8Encoder.encode(JSON.stringify(payload)));
1795
- return (0, import_utils10.bytesToHex)(hash);
1917
+ const hash = (0, import_sha2563.sha256)(utf8Encoder.encode(JSON.stringify(payload)));
1918
+ return (0, import_utils12.bytesToHex)(hash);
1796
1919
  }
1797
1920
  async function getToken(loginUrl, httpMethod, sign, includeAuthorizationScheme = false, payload) {
1798
1921
  const event = {
@@ -1805,11 +1928,11 @@ async function getToken(loginUrl, httpMethod, sign, includeAuthorizationScheme =
1805
1928
  content: ""
1806
1929
  };
1807
1930
  if (payload) {
1808
- event.tags.push(["payload", (0, import_utils10.bytesToHex)((0, import_sha2562.sha256)(utf8Encoder.encode(JSON.stringify(payload))))]);
1931
+ event.tags.push(["payload", (0, import_utils12.bytesToHex)((0, import_sha2563.sha256)(utf8Encoder.encode(JSON.stringify(payload))))]);
1809
1932
  }
1810
1933
  const signedEvent = await sign(event);
1811
1934
  const authorizationScheme = includeAuthorizationScheme ? _authorizationScheme : "";
1812
- return authorizationScheme + import_base4.base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent)));
1935
+ return authorizationScheme + import_base5.base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent)));
1813
1936
  }
1814
1937
  async function validateToken(token, url, method) {
1815
1938
  const event = await unpackEventFromToken(token).catch((error) => {
@@ -1825,7 +1948,7 @@ async function unpackEventFromToken(token) {
1825
1948
  throw new Error("Missing token");
1826
1949
  }
1827
1950
  token = token.replace(_authorizationScheme, "");
1828
- const eventB64 = utf8Decoder.decode(import_base4.base64.decode(token));
1951
+ const eventB64 = utf8Decoder.decode(import_base5.base64.decode(token));
1829
1952
  if (!eventB64 || eventB64.length === 0 || !eventB64.startsWith("{")) {
1830
1953
  throw new Error("Invalid token");
1831
1954
  }
@@ -1858,7 +1981,7 @@ async function validateEvent2(event, url, method, body) {
1858
1981
  }
1859
1982
  if (Boolean(body) && Object.keys(body).length > 0) {
1860
1983
  const payloadTag = event.tags.find((t) => t[0] === "payload");
1861
- const payloadHash = (0, import_utils10.bytesToHex)((0, import_sha2562.sha256)(utf8Encoder.encode(JSON.stringify(body))));
1984
+ const payloadHash = (0, import_utils12.bytesToHex)((0, import_sha2563.sha256)(utf8Encoder.encode(JSON.stringify(body))));
1862
1985
  if (payloadTag?.[1] !== payloadHash) {
1863
1986
  throw new Error("Invalid payload tag hash, does not match request body hash");
1864
1987
  }