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 +1 -1
- package/lib/cjs/index.js +137 -14
- package/lib/cjs/index.js.map +4 -4
- package/lib/cjs/nip44.js +141 -0
- package/lib/cjs/nip44.js.map +7 -0
- package/lib/cjs/pool.js.map +1 -1
- package/lib/cjs/relay.js +2 -2
- package/lib/cjs/relay.js.map +2 -2
- package/lib/esm/index.js +132 -9
- package/lib/esm/index.js.map +4 -4
- package/lib/esm/nip44.js +120 -0
- package/lib/esm/nip44.js.map +7 -0
- package/lib/esm/pool.js.map +1 -1
- package/lib/esm/relay.js +2 -2
- package/lib/esm/relay.js.map +2 -2
- package/lib/nostr.bundle.js +846 -107
- package/lib/nostr.bundle.js.map +4 -4
- package/lib/types/index.d.ts +1 -0
- package/lib/types/nip44.d.ts +58 -0
- package/lib/types/nip44.test.d.ts +1 -0
- package/lib/types/relay.d.ts +1 -1
- package/package.json +6 -1
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
|
|
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
|
|
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 } =
|
|
1693
|
-
let data =
|
|
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
|
|
1790
|
-
var
|
|
1791
|
-
var
|
|
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,
|
|
1795
|
-
return (0,
|
|
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,
|
|
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 +
|
|
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(
|
|
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,
|
|
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
|
}
|