nostr-tools 1.4.2 → 1.5.0
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 +9 -2
- package/event.ts +17 -5
- package/lib/nostr.bundle.js +39 -2
- package/lib/nostr.bundle.js.map +2 -2
- package/lib/nostr.cjs.js +39 -2
- package/lib/nostr.cjs.js.map +2 -2
- package/lib/nostr.esm.js +39 -2
- package/lib/nostr.esm.js.map +2 -2
- package/nip57.ts +34 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,13 @@ Tools for developing [Nostr](https://github.com/fiatjaf/nostr) clients.
|
|
|
4
4
|
|
|
5
5
|
Only depends on _@scure_ and _@noble_ packages.
|
|
6
6
|
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install nostr-tools # or yarn add nostr-tools
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
|
|
7
14
|
## Usage
|
|
8
15
|
|
|
9
16
|
### Generating a private key and a public key
|
|
@@ -53,8 +60,6 @@ import {
|
|
|
53
60
|
} from 'nostr-tools'
|
|
54
61
|
|
|
55
62
|
const relay = relayInit('wss://relay.example.com')
|
|
56
|
-
await relay.connect()
|
|
57
|
-
|
|
58
63
|
relay.on('connect', () => {
|
|
59
64
|
console.log(`connected to ${relay.url}`)
|
|
60
65
|
})
|
|
@@ -62,6 +67,8 @@ relay.on('error', () => {
|
|
|
62
67
|
console.log(`failed to connect to ${relay.url}`)
|
|
63
68
|
})
|
|
64
69
|
|
|
70
|
+
await relay.connect()
|
|
71
|
+
|
|
65
72
|
// let's query for an event that exists
|
|
66
73
|
let sub = relay.sub([
|
|
67
74
|
{
|
package/event.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as secp256k1 from '@noble/secp256k1'
|
|
|
2
2
|
import {sha256} from '@noble/hashes/sha256'
|
|
3
3
|
|
|
4
4
|
import {utf8Encoder} from './utils'
|
|
5
|
+
import {getPublicKey} from './keys'
|
|
5
6
|
|
|
6
7
|
/* eslint-disable no-unused-vars */
|
|
7
8
|
export enum Kind {
|
|
@@ -32,8 +33,11 @@ export type EventTemplate = {
|
|
|
32
33
|
created_at: number
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
export type
|
|
36
|
+
export type UnsignedEvent = EventTemplate & {
|
|
36
37
|
pubkey: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type Event = UnsignedEvent & {
|
|
37
41
|
id: string
|
|
38
42
|
sig: string
|
|
39
43
|
}
|
|
@@ -47,7 +51,15 @@ export function getBlankEvent(): EventTemplate {
|
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
53
|
|
|
50
|
-
export function
|
|
54
|
+
export function finishEvent(t: EventTemplate, privateKey: string): Event {
|
|
55
|
+
let event = t as Event
|
|
56
|
+
event.pubkey = getPublicKey(privateKey)
|
|
57
|
+
event.id = getEventHash(event)
|
|
58
|
+
event.sig = signEvent(event, privateKey)
|
|
59
|
+
return event
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function serializeEvent(evt: UnsignedEvent): string {
|
|
51
63
|
if (!validateEvent(evt))
|
|
52
64
|
throw new Error("can't serialize event with wrong or missing properties")
|
|
53
65
|
|
|
@@ -61,12 +73,12 @@ export function serializeEvent(evt: Event): string {
|
|
|
61
73
|
])
|
|
62
74
|
}
|
|
63
75
|
|
|
64
|
-
export function getEventHash(event:
|
|
76
|
+
export function getEventHash(event: UnsignedEvent): string {
|
|
65
77
|
let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))
|
|
66
78
|
return secp256k1.utils.bytesToHex(eventHash)
|
|
67
79
|
}
|
|
68
80
|
|
|
69
|
-
export function validateEvent(event:
|
|
81
|
+
export function validateEvent(event: UnsignedEvent): boolean {
|
|
70
82
|
if (typeof event !== 'object') return false
|
|
71
83
|
if (typeof event.content !== 'string') return false
|
|
72
84
|
if (typeof event.created_at !== 'number') return false
|
|
@@ -93,7 +105,7 @@ export function verifySignature(event: Event & {sig: string}): boolean {
|
|
|
93
105
|
)
|
|
94
106
|
}
|
|
95
107
|
|
|
96
|
-
export function signEvent(event:
|
|
108
|
+
export function signEvent(event: UnsignedEvent, key: string): string {
|
|
97
109
|
return secp256k1.utils.bytesToHex(
|
|
98
110
|
secp256k1.schnorr.signSync(getEventHash(event), key)
|
|
99
111
|
)
|
package/lib/nostr.bundle.js
CHANGED
|
@@ -3605,6 +3605,7 @@ zoo`.split("\n");
|
|
|
3605
3605
|
__export(nostr_tools_exports, {
|
|
3606
3606
|
Kind: () => Kind,
|
|
3607
3607
|
SimplePool: () => SimplePool,
|
|
3608
|
+
finishEvent: () => finishEvent,
|
|
3608
3609
|
fj: () => fakejson_exports,
|
|
3609
3610
|
generatePrivateKey: () => generatePrivateKey,
|
|
3610
3611
|
getBlankEvent: () => getBlankEvent,
|
|
@@ -5117,6 +5118,13 @@ zoo`.split("\n");
|
|
|
5117
5118
|
created_at: 0
|
|
5118
5119
|
};
|
|
5119
5120
|
}
|
|
5121
|
+
function finishEvent(t, privateKey) {
|
|
5122
|
+
let event = t;
|
|
5123
|
+
event.pubkey = getPublicKey(privateKey);
|
|
5124
|
+
event.id = getEventHash(event);
|
|
5125
|
+
event.sig = signEvent(event, privateKey);
|
|
5126
|
+
return event;
|
|
5127
|
+
}
|
|
5120
5128
|
function serializeEvent(evt) {
|
|
5121
5129
|
if (!validateEvent(evt))
|
|
5122
5130
|
throw new Error("can't serialize event with wrong or missing properties");
|
|
@@ -8459,7 +8467,8 @@ zoo`.split("\n");
|
|
|
8459
8467
|
getZapEndpoint: () => getZapEndpoint,
|
|
8460
8468
|
makeZapReceipt: () => makeZapReceipt,
|
|
8461
8469
|
makeZapRequest: () => makeZapRequest,
|
|
8462
|
-
useFetchImplementation: () => useFetchImplementation2
|
|
8470
|
+
useFetchImplementation: () => useFetchImplementation2,
|
|
8471
|
+
validateZapRequest: () => validateZapRequest
|
|
8463
8472
|
});
|
|
8464
8473
|
init_define_process();
|
|
8465
8474
|
var _fetch2;
|
|
@@ -8500,13 +8509,17 @@ zoo`.split("\n");
|
|
|
8500
8509
|
relays,
|
|
8501
8510
|
comment = ""
|
|
8502
8511
|
}) {
|
|
8512
|
+
if (!amount)
|
|
8513
|
+
throw new Error("amount not given");
|
|
8514
|
+
if (!profile)
|
|
8515
|
+
throw new Error("profile not given");
|
|
8503
8516
|
let zr = {
|
|
8504
8517
|
kind: 9734,
|
|
8505
8518
|
created_at: Math.round(Date.now() / 1e3),
|
|
8506
8519
|
content: comment,
|
|
8507
8520
|
tags: [
|
|
8508
8521
|
["p", profile],
|
|
8509
|
-
["amount", amount],
|
|
8522
|
+
["amount", amount.toString()],
|
|
8510
8523
|
["relays", ...relays]
|
|
8511
8524
|
]
|
|
8512
8525
|
};
|
|
@@ -8515,6 +8528,30 @@ zoo`.split("\n");
|
|
|
8515
8528
|
}
|
|
8516
8529
|
return zr;
|
|
8517
8530
|
}
|
|
8531
|
+
function validateZapRequest(zapRequestString) {
|
|
8532
|
+
let zapRequest;
|
|
8533
|
+
try {
|
|
8534
|
+
zapRequest = JSON.parse(zapRequestString);
|
|
8535
|
+
} catch (err) {
|
|
8536
|
+
return "Invalid zap request JSON.";
|
|
8537
|
+
}
|
|
8538
|
+
if (!validateEvent(zapRequest))
|
|
8539
|
+
return "Zap request is not a valid Nostr event.";
|
|
8540
|
+
if (!verifySignature(zapRequest))
|
|
8541
|
+
return "Invalid signature on zap request.";
|
|
8542
|
+
let p = zapRequest.tags.find(([t, v]) => t === "p" && v);
|
|
8543
|
+
if (!p)
|
|
8544
|
+
return "Zap request doesn't have a 'p' tag.";
|
|
8545
|
+
if (!p[1].match(/^[a-f0-9]{64}$/))
|
|
8546
|
+
return "Zap request 'p' tag is not valid hex.";
|
|
8547
|
+
let e = zapRequest.tags.find(([t, v]) => t === "e" && v);
|
|
8548
|
+
if (e && !e[1].match(/^[a-f0-9]{64}$/))
|
|
8549
|
+
return "Zap request 'e' tag is not valid hex.";
|
|
8550
|
+
let relays = zapRequest.tags.find(([t, v]) => t === "relays" && v);
|
|
8551
|
+
if (!relays)
|
|
8552
|
+
return "Zap request doesn't have a 'relays' tag.";
|
|
8553
|
+
return null;
|
|
8554
|
+
}
|
|
8518
8555
|
function makeZapReceipt({
|
|
8519
8556
|
zapRequest,
|
|
8520
8557
|
preimage,
|